From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34146) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yn7oC-0000ok-75 for qemu-devel@nongnu.org; Tue, 28 Apr 2015 11:52:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Yn7o6-0006g2-FJ for qemu-devel@nongnu.org; Tue, 28 Apr 2015 11:52:28 -0400 Received: from mailapp01.imgtec.com ([195.59.15.196]:56483 helo=imgpgp01.kl.imgtec.org) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yn7o6-0006fW-1T for qemu-devel@nongnu.org; Tue, 28 Apr 2015 11:52:22 -0400 Message-ID: <553FACB3.2030603@imgtec.com> Date: Tue, 28 Apr 2015 16:52:19 +0100 From: James Hogan MIME-Version: 1.0 References: <1430224874-18513-1-git-send-email-leon.alrae@imgtec.com> <1430224874-18513-5-git-send-email-leon.alrae@imgtec.com> In-Reply-To: <1430224874-18513-5-git-send-email-leon.alrae@imgtec.com> Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="EBiBCg7j2w56H0vfl38n9MAsMAHckqUSs" Subject: Re: [Qemu-devel] [PATCH 4/7] target-mips: add MTHC0 and MFHC0 instructions List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Leon Alrae , qemu-devel@nongnu.org Cc: aurelien@aurel32.net --EBiBCg7j2w56H0vfl38n9MAsMAHckqUSs Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: quoted-printable Hi Leon, On 28/04/15 13:41, Leon Alrae wrote: > Implement MTHC0 and MFHC0 instructions. In MIPS32 they allow to access > upper word of extended to 64-bits CP0 registers. >=20 > In MIPS64, when CP0 destination register specified is the EntryLo0 or > EntryLo1, bits 1:0 of the GPR appear at bits 31:30 of EntryLo0 or > EntryLo1. This is to compensate for RI and XI, which were shifted to bi= ts > 63:62 by MTC0 to EntryLo0 or EntryLo1. Therefore creating separate > functions generating for EntryLo0 and EntryLo1. >=20 > Signed-off-by: Leon Alrae > --- > disas/mips.c | 2 + > target-mips/cpu.h | 1 + > target-mips/translate.c | 216 ++++++++++++++++++++++++++++++++++++++++= ++++++++ > 3 files changed, 219 insertions(+) >=20 > diff --git a/disas/mips.c b/disas/mips.c > index 1afe0c5..c236495 100644 > --- a/disas/mips.c > +++ b/disas/mips.c > @@ -2238,6 +2238,8 @@ const struct mips_opcode mips_builtin_opcodes[] =3D= > {"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I= 3|I33 }, > {"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I= 2 }, > {"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 },= > +{"mfhc0", "t,G,H", 0x40400000, 0xffe007f8, LCD|WR_t|RD_C0, = 0, I33 }, > +{"mthc0", "t,G,H", 0x40c00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, = 0, I33 }, whitespace appears to be inconsistent here (the context uses tabs). > {"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 }, > {"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1= }, > {"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1= }, > diff --git a/target-mips/cpu.h b/target-mips/cpu.h > index bcd1e2b..cfc6ac7 100644 > --- a/target-mips/cpu.h > +++ b/target-mips/cpu.h > @@ -473,6 +473,7 @@ struct CPUMIPSState { > #define CP0C5_UFE 9 > #define CP0C5_FRE 8 > #define CP0C5_SBRI 6 > +#define CP0C5_MVH 5 > #define CP0C5_UFR 2 > #define CP0C5_NFExists 0 > int32_t CP0_Config6; > diff --git a/target-mips/translate.c b/target-mips/translate.c > index bb219ea..f95b655 100644 > --- a/target-mips/translate.c > +++ b/target-mips/translate.c > @@ -868,8 +868,10 @@ enum { > enum { > OPC_MFC0 =3D (0x00 << 21) | OPC_CP0, > OPC_DMFC0 =3D (0x01 << 21) | OPC_CP0, > + OPC_MFHC0 =3D (0x02 << 21) | OPC_CP0, > OPC_MTC0 =3D (0x04 << 21) | OPC_CP0, > OPC_DMTC0 =3D (0x05 << 21) | OPC_CP0, > + OPC_MTHC0 =3D (0x06 << 21) | OPC_CP0, > OPC_MFTR =3D (0x08 << 21) | OPC_CP0, > OPC_RDPGPR =3D (0x0A << 21) | OPC_CP0, > OPC_MFMC0 =3D (0x0B << 21) | OPC_CP0, > @@ -1423,6 +1425,8 @@ typedef struct DisasContext { > int ie; > bool bi; > bool bp; > + uint64_t PAMask; > + bool mvh; > } DisasContext; > =20 > enum { > @@ -1769,6 +1773,13 @@ static inline void check_cp1_registers(DisasCont= ext *ctx, int regs) > This is enabled by CP0 Status register MX(24) bit. > */ > =20 > +static inline void check_mvh(DisasContext *ctx) > +{ > + if (unlikely(!(ctx->mvh))) { superfluous brackets around ctx->mvh. > + generate_exception(ctx, EXCP_RI); > + } > +} > + > static inline void check_dsp(DisasContext *ctx) > { > if (unlikely(!(ctx->hflags & MIPS_HFLAG_DSP))) { > @@ -4820,6 +4831,60 @@ static void gen_bshfl (DisasContext *ctx, uint32= _t op2, int rt, int rd) > =20 > #ifndef CONFIG_USER_ONLY > /* CP0 (MMU and control) */ > +static inline void gen_mthc0_entrylo(TCGv arg, target_ulong off) > +{ > + TCGv_i64 t0 =3D tcg_temp_new_i64(); > + TCGv_i64 t1 =3D tcg_temp_new_i64(); > + > + tcg_gen_ext_tl_i64(t0, arg); > + tcg_gen_ld_i64(t1, cpu_env, off); > +#if defined(TARGET_MIPS64) > + tcg_gen_deposit_i64(t1, t1, t0, 30, 32); > +#else > + tcg_gen_concat32_i64(t1, t1, t0); I don't get what this case is about. what's wrong with the above case for MIPS64 and MIPS32? > +#endif > + tcg_gen_st_i64(t1, cpu_env, off); > + tcg_temp_free_i64(t1); > + tcg_temp_free_i64(t0); > +} > + > +static inline void gen_mthc0_store64(TCGv arg, target_ulong off) > +{ > + TCGv_i64 t0 =3D tcg_temp_new_i64(); > + TCGv_i64 t1 =3D tcg_temp_new_i64(); > + > + tcg_gen_ext_tl_i64(t0, arg); > + tcg_gen_ld_i64(t1, cpu_env, off); > + tcg_gen_concat32_i64(t1, t1, t0); > + tcg_gen_st_i64(t1, cpu_env, off); > + tcg_temp_free_i64(t1); > + tcg_temp_free_i64(t0); simpler to just store a 32-bit value (st32_tl) to the appropriate half, depending on host endianness? (i.e. +4 if little endian) > +} > + > +static inline void gen_mfhc0_entrylo(TCGv arg, target_ulong off) > +{ > + TCGv_i64 t0 =3D tcg_temp_new_i64(); > + > + tcg_gen_ld_i64(t0, cpu_env, off); > +#if defined(TARGET_MIPS64) > + tcg_gen_shri_i64(t0, t0, 30); need to mask off the xi/ri bits? > +#else > + tcg_gen_shri_i64(t0, t0, 32); Again, I'm not convinced MIPS32 needs special handling here. > +#endif > + tcg_gen_trunc_i64_tl(arg, t0); > + tcg_temp_free_i64(t0); > +} > + > +static inline void gen_mfhc0_load64(TCGv arg, target_ulong off) > +{ > + TCGv_i64 t0 =3D tcg_temp_new_i64(); > + > + tcg_gen_ld_i64(t0, cpu_env, off); > + tcg_gen_shri_i64(t0, t0, 32); simpler to just load a signed 32-bit value (ld32s_tl) from the appropriate half, depending on host endianness? (i.e. +4 if little endian= ) > + tcg_gen_trunc_i64_tl(arg, t0); > + tcg_temp_free_i64(t0); > +} > + > static inline void gen_mfc0_load32 (TCGv arg, target_ulong off) > { > TCGv_i32 t0 =3D tcg_temp_new_i32(); > @@ -4850,6 +4915,134 @@ static inline void gen_mtc0_store64 (TCGv arg, = target_ulong off) > tcg_gen_st_tl(arg, cpu_env, off); > } > =20 > +static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel) > +{ > + const char *rn =3D "invalid"; > + > + if (!(ctx->hflags & MIPS_HFLAG_ELPA)) { worth reusing the CP0_CHECK stuff? > + goto mfhc0_read_zero; > + } > + > + switch (reg) { > + case 2: > + switch (sel) { > + case 0: > + gen_mfhc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo0= )); > + rn =3D "EntryLo0"; > + break; > + default: > + goto mfhc0_read_zero; > + } > + break; > + case 3: > + switch (sel) { > + case 0: > + gen_mfhc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo1= )); > + rn =3D "EntryLo1"; > + break; > + default: > + goto mfhc0_read_zero; > + } > + break; > + case 17: > + switch (sel) { > + case 0: > + gen_mfhc0_load64(arg, offsetof(CPUMIPSState, lladdr)); > + rn =3D "LLAddr"; > + break; > + default: > + goto mfhc0_read_zero; > + } > + break; > + case 28: > + switch (sel) { > + case 0: > + case 2: > + case 4: > + case 6: > + gen_mfhc0_load64(arg, offsetof(CPUMIPSState, CP0_TagLo)); > + rn =3D "TagLo"; > + break; > + default: > + goto mfhc0_read_zero; > + } > + break; > + default: > + goto mfhc0_read_zero; > + } > + > + (void)rn; /* avoid a compiler warning */ > + LOG_DISAS("mfhc0 %s (reg %d sel %d)\n", rn, reg, sel); > + return; > + > +mfhc0_read_zero: > + LOG_DISAS("mfhc0 %s (reg %d sel %d)\n", rn, reg, sel); > + tcg_gen_movi_tl(arg, 0); > +} > + > +static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel) > +{ > + const char *rn =3D "invalid"; > + > + if (!(ctx->hflags & MIPS_HFLAG_ELPA)) { > + goto mthc0_nop; > + } > + > + tcg_gen_andi_tl(arg, arg, ctx->PAMask >> 36); Shouldn't this depend on the register? LLAddr shift varies per core (CP0_LLAddr_shift), but EntryLo shift will be the same for each core. Cheers James > + > + switch (reg) { > + case 2: > + switch (sel) { > + case 0: > + gen_mthc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo0= )); > + rn =3D "EntryLo0"; > + break; > + default: > + goto mthc0_nop; > + } > + break; > + case 3: > + switch (sel) { > + case 0: > + gen_mthc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo1= )); > + rn =3D "EntryLo1"; > + break; > + default: > + goto mthc0_nop; > + } > + break; > + case 17: > + switch (sel) { > + case 0: > + gen_mthc0_store64(arg, offsetof(CPUMIPSState, lladdr)); > + rn =3D "LLAddr"; > + break; > + default: > + goto mthc0_nop; > + } > + break; > + case 28: > + switch (sel) { > + case 0: > + case 2: > + case 4: > + case 6: > + gen_mthc0_store64(arg, offsetof(CPUMIPSState, CP0_TagLo));= > + rn =3D "TagLo"; > + break; > + default: > + goto mthc0_nop; > + } > + break; > + default: > + goto mthc0_nop; > + } > + > + (void)rn; /* avoid a compiler warning */ > +mthc0_nop: > + LOG_DISAS("mthc0 %s (reg %d sel %d)\n", rn, reg, sel); > +} > + > static inline void gen_mfc0_unimplemented(DisasContext *ctx, TCGv arg)= > { > if (ctx->insn_flags & ISA_MIPS32R6) { > @@ -7847,6 +8040,25 @@ static void gen_cp0 (CPUMIPSState *env, DisasCon= text *ctx, uint32_t opc, int rt, > opn =3D "dmtc0"; > break; > #endif > + case OPC_MFHC0: > + check_mvh(ctx); > + if (rt =3D=3D 0) { > + /* Treat as NOP. */ > + return; > + } > + gen_mfhc0(ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7); > + opn =3D "mfhc0"; > + break; > + case OPC_MTHC0: > + check_mvh(ctx); > + { > + TCGv t0 =3D tcg_temp_new(); > + gen_load_gpr(t0, rt); > + gen_mthc0(ctx, t0, rd, ctx->opcode & 0x7); > + tcg_temp_free(t0); > + } > + opn =3D "mthc0"; > + break; > case OPC_MFTR: > check_insn(ctx, ASE_MT); > if (rd =3D=3D 0) { > @@ -18571,6 +18783,8 @@ static void decode_opc(CPUMIPSState *env, Disas= Context *ctx) > case OPC_MTC0: > case OPC_MFTR: > case OPC_MTTR: > + case OPC_MFHC0: > + case OPC_MTHC0: > #if defined(TARGET_MIPS64) > case OPC_DMFC0: > case OPC_DMTC0: > @@ -19141,6 +19355,8 @@ gen_intermediate_code_internal(MIPSCPU *cpu, Tr= anslationBlock *tb, > ctx.ie =3D (env->CP0_Config4 >> CP0C4_IE) & 3; > ctx.bi =3D (env->CP0_Config3 >> CP0C3_BI) & 1; > ctx.bp =3D (env->CP0_Config3 >> CP0C3_BP) & 1; > + ctx.mvh =3D (env->CP0_Config5 >> CP0C5_MVH) & 1; > + ctx.PAMask =3D env->PAMask; > /* Restore delay slot state from the tb context. */ > ctx.hflags =3D (uint32_t)tb->flags; /* FIXME: maybe use 64 bits he= re? */ > ctx.ulri =3D (env->CP0_Config3 >> CP0C3_ULRI) & 1; >=20 --EBiBCg7j2w56H0vfl38n9MAsMAHckqUSs Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBAgAGBQJVP6yzAAoJEGwLaZPeOHZ6hl0P/jY4+N6BKne5Sv1j5BBhSJVR ltZVCE9XodmFaa6xHX0I6m2W72WV0ffX8pckvTpOSD+aGgaTcnHCsedvByMWs16S RlKLMpb0UBcG5qkezbaO7CysZO/hmoVogyTdn+HXdY3/PFpZ3O5l5JyilFBSvr2Z Vi8w0Eo2/rY51TWotA9c5x/c/XgshtjbNhc4imZzQEliodgziUG440h1aCxDOQ6o 7umwvxIjax7BBPXqrtHIoa1lP7EYdXGmMefXUcdpOfEdQbz5vzPtAX157npe69LH VThLuC2A9V1r7Tigzf6Udr27y6LW7kIMqADYGavctRzktdq8arerW7rc5AkhR9ye mWrA50r7OcnS/OHxsPfG24f/UEUceCQYWSZIoJQnmzfhhKTW7kqJclmyXLC+kS5i Gsbd0pzlb8I4/kh04TFDOtQzSQ/6+4HoHfkISDIJeTYYRLr9ly4vEWzsq3Fes8kJ HTWVD80UbxQ08Pb5zKwIShu7bnpSPdm/XNXr+TPcZU4OZtBpfqbwEQvPlDlg0d45 MxbKsr+CtZngNkCHd1QfcubfLRwtqaFlboYshIf4FPSiubPybcrcJiAk+NBRGeTP 2+TW+SKCNaX4SHDH7SRghy7NjWnxT5gN1mLqbOaQNTsiT1VRM78ZMbmhhBHYCu+B OSobftBwYLAxBH9wvOwM =T2Nb -----END PGP SIGNATURE----- --EBiBCg7j2w56H0vfl38n9MAsMAHckqUSs--