Message ID | fd1b1f640912284963bb1d9974a80f35cc1d4a72.1537379317.git.noring@nocrew.org |
---|---|
State | New |
Headers | show |
Series | target/mips: Support R5900 GCC programs in user mode | expand |
Hi Fredrik, On 9/15/18 11:25 AM, Fredrik Noring wrote: > Signed-off-by: Fredrik Noring <noring@nocrew.org> > --- > target/mips/translate.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 53 insertions(+) > > diff --git a/target/mips/translate.c b/target/mips/translate.c > index ab16cdb911..fb571e278e 100644 > --- a/target/mips/translate.c > +++ b/target/mips/translate.c > @@ -3768,6 +3768,57 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc, > tcg_temp_free(t1); > } > > +static void gen_mul_r5900(DisasContext *ctx, uint32_t opc, > + int acc, int rd, int rs, int rt) > +{ > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + > + gen_load_gpr(t0, rs); > + gen_load_gpr(t1, rt); > + > + switch (opc) { > + case OPC_MULT: > + { > + TCGv_i32 t2 = tcg_temp_new_i32(); > + TCGv_i32 t3 = tcg_temp_new_i32(); > + tcg_gen_trunc_tl_i32(t2, t0); > + tcg_gen_trunc_tl_i32(t3, t1); > + tcg_gen_muls2_i32(t2, t3, t2, t3); > + if (rd) > + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); > + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); > + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); > + tcg_temp_free_i32(t2); > + tcg_temp_free_i32(t3); > + } > + break; > + case OPC_MULTU: > + { > + TCGv_i32 t2 = tcg_temp_new_i32(); > + TCGv_i32 t3 = tcg_temp_new_i32(); > + tcg_gen_trunc_tl_i32(t2, t0); > + tcg_gen_trunc_tl_i32(t3, t1); > + tcg_gen_mulu2_i32(t2, t3, t2, t3); > + if (rd) > + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); > + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); > + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); > + tcg_temp_free_i32(t2); > + tcg_temp_free_i32(t3); > + } > + break; > + default: > + MIPS_INVAL("mul R5900"); > + generate_exception_end(ctx, EXCP_RI); > + goto out; > + } > + > + out: > + tcg_temp_free(t0); > + tcg_temp_free(t1); > +} Why not simply modify gen_muldiv? -- >8 -- @@ -3630,29 +3630,35 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc, break; case OPC_MULT: { TCGv_i32 t2 = tcg_temp_new_i32(); TCGv_i32 t3 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(t2, t0); tcg_gen_trunc_tl_i32(t3, t1); tcg_gen_muls2_i32(t2, t3, t2, t3); + if (ctx->insn_flags & INSN_R5900 && rd) { + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); + } tcg_gen_ext_i32_tl(cpu_LO[acc], t2); tcg_gen_ext_i32_tl(cpu_HI[acc], t3); tcg_temp_free_i32(t2); tcg_temp_free_i32(t3); } break; case OPC_MULTU: { TCGv_i32 t2 = tcg_temp_new_i32(); TCGv_i32 t3 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(t2, t0); tcg_gen_trunc_tl_i32(t3, t1); tcg_gen_mulu2_i32(t2, t3, t2, t3); + if (ctx->insn_flags & INSN_R5900 && rd) { + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); + } tcg_gen_ext_i32_tl(cpu_LO[acc], t2); tcg_gen_ext_i32_tl(cpu_HI[acc], t3); tcg_temp_free_i32(t2); tcg_temp_free_i32(t3); } break; --- > + > static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc, > int rd, int rs, int rt) > { > @@ -22378,6 +22429,8 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) > check_insn(ctx, INSN_VR54XX); > op1 = MASK_MUL_VR54XX(ctx->opcode); > gen_mul_vr54xx(ctx, op1, rd, rs, rt); > + } else if (ctx->insn_flags & INSN_R5900) { > + gen_mul_r5900(ctx, op1, 0, rd, rs, rt); > } else { > gen_muldiv(ctx, op1, rd & 3, rs, rt); > } >
On 9/25/18 2:20 PM, Philippe Mathieu-Daudé wrote: > Hi Fredrik, > > On 9/15/18 11:25 AM, Fredrik Noring wrote: >> Signed-off-by: Fredrik Noring <noring@nocrew.org> >> --- >> target/mips/translate.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 53 insertions(+) >> >> diff --git a/target/mips/translate.c b/target/mips/translate.c >> index ab16cdb911..fb571e278e 100644 >> --- a/target/mips/translate.c >> +++ b/target/mips/translate.c >> @@ -3768,6 +3768,57 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc, >> tcg_temp_free(t1); >> } >> >> +static void gen_mul_r5900(DisasContext *ctx, uint32_t opc, >> + int acc, int rd, int rs, int rt) >> +{ >> + TCGv t0 = tcg_temp_new(); >> + TCGv t1 = tcg_temp_new(); >> + >> + gen_load_gpr(t0, rs); >> + gen_load_gpr(t1, rt); >> + >> + switch (opc) { >> + case OPC_MULT: >> + { >> + TCGv_i32 t2 = tcg_temp_new_i32(); >> + TCGv_i32 t3 = tcg_temp_new_i32(); >> + tcg_gen_trunc_tl_i32(t2, t0); >> + tcg_gen_trunc_tl_i32(t3, t1); >> + tcg_gen_muls2_i32(t2, t3, t2, t3); >> + if (rd) >> + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); >> + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); >> + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); >> + tcg_temp_free_i32(t2); >> + tcg_temp_free_i32(t3); >> + } >> + break; >> + case OPC_MULTU: >> + { >> + TCGv_i32 t2 = tcg_temp_new_i32(); >> + TCGv_i32 t3 = tcg_temp_new_i32(); >> + tcg_gen_trunc_tl_i32(t2, t0); >> + tcg_gen_trunc_tl_i32(t3, t1); >> + tcg_gen_mulu2_i32(t2, t3, t2, t3); >> + if (rd) >> + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); >> + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); >> + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); >> + tcg_temp_free_i32(t2); >> + tcg_temp_free_i32(t3); >> + } >> + break; >> + default: >> + MIPS_INVAL("mul R5900"); >> + generate_exception_end(ctx, EXCP_RI); >> + goto out; >> + } >> + >> + out: >> + tcg_temp_free(t0); >> + tcg_temp_free(t1); >> +} > > Why not simply modify gen_muldiv? Testing my own patch eh... I missed the check_dsp() call: if (acc != 0 && unlikely(!(ctx->insn_flags & INSN_R5900))) { check_dsp(ctx); } Anyway if we plan to also add MADD/MADDU, using another function might be cleaner. > > -- >8 -- > @@ -3630,29 +3630,35 @@ static void gen_muldiv(DisasContext *ctx, > uint32_t opc, > break; > case OPC_MULT: > { > TCGv_i32 t2 = tcg_temp_new_i32(); > TCGv_i32 t3 = tcg_temp_new_i32(); > tcg_gen_trunc_tl_i32(t2, t0); > tcg_gen_trunc_tl_i32(t3, t1); > tcg_gen_muls2_i32(t2, t3, t2, t3); > + if (ctx->insn_flags & INSN_R5900 && rd) { > + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); > + } > tcg_gen_ext_i32_tl(cpu_LO[acc], t2); > tcg_gen_ext_i32_tl(cpu_HI[acc], t3); > tcg_temp_free_i32(t2); > tcg_temp_free_i32(t3); > } > break; > case OPC_MULTU: > { > TCGv_i32 t2 = tcg_temp_new_i32(); > TCGv_i32 t3 = tcg_temp_new_i32(); > tcg_gen_trunc_tl_i32(t2, t0); > tcg_gen_trunc_tl_i32(t3, t1); > tcg_gen_mulu2_i32(t2, t3, t2, t3); > + if (ctx->insn_flags & INSN_R5900 && rd) { > + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); > + } > tcg_gen_ext_i32_tl(cpu_LO[acc], t2); > tcg_gen_ext_i32_tl(cpu_HI[acc], t3); > tcg_temp_free_i32(t2); > tcg_temp_free_i32(t3); > } > break; > --- > >> + >> static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc, >> int rd, int rs, int rt) >> { >> @@ -22378,6 +22429,8 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) >> check_insn(ctx, INSN_VR54XX); >> op1 = MASK_MUL_VR54XX(ctx->opcode); >> gen_mul_vr54xx(ctx, op1, rd, rs, rt); >> + } else if (ctx->insn_flags & INSN_R5900) { >> + gen_mul_r5900(ctx, op1, 0, rd, rs, rt); >> } else { >> gen_muldiv(ctx, op1, rd & 3, rs, rt); >> } >>
On 9/26/18 11:59 PM, Philippe Mathieu-Daudé wrote: > On 9/25/18 2:20 PM, Philippe Mathieu-Daudé wrote: >> Hi Fredrik, >> >> On 9/15/18 11:25 AM, Fredrik Noring wrote: >>> Signed-off-by: Fredrik Noring <noring@nocrew.org> >>> --- >>> target/mips/translate.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ >>> 1 file changed, 53 insertions(+) >>> >>> diff --git a/target/mips/translate.c b/target/mips/translate.c >>> index ab16cdb911..fb571e278e 100644 >>> --- a/target/mips/translate.c >>> +++ b/target/mips/translate.c >>> @@ -3768,6 +3768,57 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc, >>> tcg_temp_free(t1); >>> } >>> >>> +static void gen_mul_r5900(DisasContext *ctx, uint32_t opc, >>> + int acc, int rd, int rs, int rt) >>> +{ >>> + TCGv t0 = tcg_temp_new(); >>> + TCGv t1 = tcg_temp_new(); >>> + >>> + gen_load_gpr(t0, rs); >>> + gen_load_gpr(t1, rt); >>> + >>> + switch (opc) { >>> + case OPC_MULT: >>> + { >>> + TCGv_i32 t2 = tcg_temp_new_i32(); >>> + TCGv_i32 t3 = tcg_temp_new_i32(); >>> + tcg_gen_trunc_tl_i32(t2, t0); >>> + tcg_gen_trunc_tl_i32(t3, t1); >>> + tcg_gen_muls2_i32(t2, t3, t2, t3); >>> + if (rd) >>> + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); >>> + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); >>> + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); >>> + tcg_temp_free_i32(t2); >>> + tcg_temp_free_i32(t3); >>> + } >>> + break; >>> + case OPC_MULTU: >>> + { >>> + TCGv_i32 t2 = tcg_temp_new_i32(); >>> + TCGv_i32 t3 = tcg_temp_new_i32(); >>> + tcg_gen_trunc_tl_i32(t2, t0); >>> + tcg_gen_trunc_tl_i32(t3, t1); >>> + tcg_gen_mulu2_i32(t2, t3, t2, t3); >>> + if (rd) >>> + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); >>> + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); >>> + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); >>> + tcg_temp_free_i32(t2); >>> + tcg_temp_free_i32(t3); >>> + } >>> + break; >>> + default: >>> + MIPS_INVAL("mul R5900"); >>> + generate_exception_end(ctx, EXCP_RI); >>> + goto out; >>> + } >>> + >>> + out: >>> + tcg_temp_free(t0); >>> + tcg_temp_free(t1); >>> +} >> >> Why not simply modify gen_muldiv? > > Testing my own patch eh... > > I missed the check_dsp() call: > > if (acc != 0 && unlikely(!(ctx->insn_flags & INSN_R5900))) { > check_dsp(ctx); > } > > Anyway if we plan to also add MADD/MADDU, using another function might > be cleaner. > >> >> -- >8 -- >> @@ -3630,29 +3630,35 @@ static void gen_muldiv(DisasContext *ctx, >> uint32_t opc, >> break; >> case OPC_MULT: >> { >> TCGv_i32 t2 = tcg_temp_new_i32(); >> TCGv_i32 t3 = tcg_temp_new_i32(); >> tcg_gen_trunc_tl_i32(t2, t0); >> tcg_gen_trunc_tl_i32(t3, t1); >> tcg_gen_muls2_i32(t2, t3, t2, t3); >> + if (ctx->insn_flags & INSN_R5900 && rd) { >> + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); >> + } >> tcg_gen_ext_i32_tl(cpu_LO[acc], t2); >> tcg_gen_ext_i32_tl(cpu_HI[acc], t3); >> tcg_temp_free_i32(t2); >> tcg_temp_free_i32(t3); >> } >> break; >> case OPC_MULTU: >> { >> TCGv_i32 t2 = tcg_temp_new_i32(); >> TCGv_i32 t3 = tcg_temp_new_i32(); >> tcg_gen_trunc_tl_i32(t2, t0); >> tcg_gen_trunc_tl_i32(t3, t1); >> tcg_gen_mulu2_i32(t2, t3, t2, t3); >> + if (ctx->insn_flags & INSN_R5900 && rd) { >> + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); >> + } >> tcg_gen_ext_i32_tl(cpu_LO[acc], t2); >> tcg_gen_ext_i32_tl(cpu_HI[acc], t3); >> tcg_temp_free_i32(t2); >> tcg_temp_free_i32(t3); >> } >> break; >> --- >> >>> + >>> static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc, >>> int rd, int rs, int rt) >>> { >>> @@ -22378,6 +22429,8 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) >>> check_insn(ctx, INSN_VR54XX); >>> op1 = MASK_MUL_VR54XX(ctx->opcode); >>> gen_mul_vr54xx(ctx, op1, rd, rs, rt); >>> + } else if (ctx->insn_flags & INSN_R5900) { >>> + gen_mul_r5900(ctx, op1, 0, rd, rs, rt); And I now notice you take all the $rd bits, so my patch proposal should also require: } else if (ctx->insn_flags & INSN_R5900) { gen_muldiv(ctx, op1, 0, rd, rs, rt); Which a this point makes it pointless. I'll restart reviewing your patch :) >>> } else { >>> gen_muldiv(ctx, op1, rd & 3, rs, rt); >>> } >>>
On 9/15/18 11:25 AM, Fredrik Noring wrote: Can you copy/paste some info regarding those instructions from the ISA here, to note how they differ? ... > Signed-off-by: Fredrik Noring <noring@nocrew.org> > --- > target/mips/translate.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 53 insertions(+) > > diff --git a/target/mips/translate.c b/target/mips/translate.c > index ab16cdb911..fb571e278e 100644 > --- a/target/mips/translate.c > +++ b/target/mips/translate.c > @@ -3768,6 +3768,57 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc, > tcg_temp_free(t1); > } > ... Another option is to describe in a big comment here. > +static void gen_mul_r5900(DisasContext *ctx, uint32_t opc, > + int acc, int rd, int rs, int rt) Since we have acc = 0 we can directly use cpu_LO[0] and cpu_HI[0], removing needs for an 'acc' argument. > +{ > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + > + gen_load_gpr(t0, rs); > + gen_load_gpr(t1, rt); > + > + switch (opc) { > + case OPC_MULT: > + { > + TCGv_i32 t2 = tcg_temp_new_i32(); > + TCGv_i32 t3 = tcg_temp_new_i32(); > + tcg_gen_trunc_tl_i32(t2, t0); > + tcg_gen_trunc_tl_i32(t3, t1); > + tcg_gen_muls2_i32(t2, t3, t2, t3); > + if (rd) Check QEMU CODING_STYLE "Block structure": Every indented statement is braced; even if the block contains just one statement. The opening brace is on the line that contains the control flow statement that introduces the new block; the closing brace is on the same line as the else keyword, or on a line by itself if there is no else keyword. QEMU scripts/checkpatch.pl reports such mistakes. > + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); I'd use: gen_move_low32(cpu_gpr[rd], t2); > + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); So: tcg_gen_ext_i32_tl(cpu_LO[0], t2); > + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); And: tcg_gen_ext_i32_tl(cpu_HI[0], t3); > + tcg_temp_free_i32(t2); > + tcg_temp_free_i32(t3); > + } > + break; > + case OPC_MULTU: > + { > + TCGv_i32 t2 = tcg_temp_new_i32(); > + TCGv_i32 t3 = tcg_temp_new_i32(); > + tcg_gen_trunc_tl_i32(t2, t0); > + tcg_gen_trunc_tl_i32(t3, t1); > + tcg_gen_mulu2_i32(t2, t3, t2, t3); > + if (rd) > + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); > + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); > + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); Same comments from MULT apply here. > + tcg_temp_free_i32(t2); > + tcg_temp_free_i32(t3); > + } > + break; > + default: > + MIPS_INVAL("mul R5900"); > + generate_exception_end(ctx, EXCP_RI); > + goto out; > + } > + > + out: > + tcg_temp_free(t0); > + tcg_temp_free(t1); > +} > + > static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc, > int rd, int rs, int rt) > { > @@ -22378,6 +22429,8 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) > check_insn(ctx, INSN_VR54XX); > op1 = MASK_MUL_VR54XX(ctx->opcode); > gen_mul_vr54xx(ctx, op1, rd, rs, rt); > + } else if (ctx->insn_flags & INSN_R5900) { > + gen_mul_r5900(ctx, op1, 0, rd, rs, rt); Removing 'acc' arg: gen_mul_r5900(ctx, op1, rd, rs, rt); Note, these instructions are also valid on the R3900 (which also has MADD/MADDU). Would gen_mul_toshiba() be a better common name? I don't like it but can't think of another. > } else { > gen_muldiv(ctx, op1, rd & 3, rs, rt); > } > Regards, Phil.
On Thu, 27 Sep 2018, Philippe Mathieu-Daudé wrote: > > +static void gen_mul_r5900(DisasContext *ctx, uint32_t opc, > > + int acc, int rd, int rs, int rt) > > Since we have acc = 0 we can directly use cpu_LO[0] and cpu_HI[0], > removing needs for an 'acc' argument. Corresponding MULT1 and MULTU1 instructions use `acc = 1' though, as do similar variations of all the other MDU instructions. Maybe the addition of the required `acc' argument could be staged for a separate patch with all the pipeline 1 MDU instructions though. Maciej
Hi Philippe, > Can you copy/paste some info regarding those instructions from the ISA > here, to note how they differ? ... Yes. Other corresponding functions typically do not seem to have such ISA notes, but I can certainly write one for it. > Since we have acc = 0 we can directly use cpu_LO[0] and cpu_HI[0], > removing needs for an 'acc' argument. We could, but as Maciej replied there are pipeline 1 versions of these instructions which would have acc = 1. I retained the acc parameter mainly to avoid the error of forgetting to replace 0 with acc when introducing them later on. > > +{ > > + TCGv t0 = tcg_temp_new(); > > + TCGv t1 = tcg_temp_new(); > > + > > + gen_load_gpr(t0, rs); > > + gen_load_gpr(t1, rt); > > + > > + switch (opc) { > > + case OPC_MULT: > > + { > > + TCGv_i32 t2 = tcg_temp_new_i32(); > > + TCGv_i32 t3 = tcg_temp_new_i32(); > > + tcg_gen_trunc_tl_i32(t2, t0); > > + tcg_gen_trunc_tl_i32(t3, t1); > > + tcg_gen_muls2_i32(t2, t3, t2, t3); > > + if (rd) > > Check QEMU CODING_STYLE "Block structure": > > Every indented statement is braced; even if the block contains > just one statement. The opening brace is on the line that > contains the control flow statement that introduces the new block; > the closing brace is on the same line as the else keyword, or on > a line by itself if there is no else keyword. > > QEMU scripts/checkpatch.pl reports such mistakes. Done. > > + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); > > I'd use: > > gen_move_low32(cpu_gpr[rd], t2); Are you sure this is correct? The GPR rd must be sign-extended. > > + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); > > So: > > tcg_gen_ext_i32_tl(cpu_LO[0], t2); > > > + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); > > And: > > tcg_gen_ext_i32_tl(cpu_HI[0], t3); Done. > > + tcg_temp_free_i32(t2); > > + tcg_temp_free_i32(t3); > > + } > > + break; > > + case OPC_MULTU: > > + { > > + TCGv_i32 t2 = tcg_temp_new_i32(); > > + TCGv_i32 t3 = tcg_temp_new_i32(); > > + tcg_gen_trunc_tl_i32(t2, t0); > > + tcg_gen_trunc_tl_i32(t3, t1); > > + tcg_gen_mulu2_i32(t2, t3, t2, t3); > > + if (rd) > > + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); > > + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); > > + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); > > Same comments from MULT apply here. Done. > > + tcg_temp_free_i32(t2); > > + tcg_temp_free_i32(t3); > > + } > > + break; > > + default: > > + MIPS_INVAL("mul R5900"); > > + generate_exception_end(ctx, EXCP_RI); > > + goto out; > > + } > > + > > + out: > > + tcg_temp_free(t0); > > + tcg_temp_free(t1); > > +} > > + > > static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc, > > int rd, int rs, int rt) > > { > > @@ -22378,6 +22429,8 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) > > check_insn(ctx, INSN_VR54XX); > > op1 = MASK_MUL_VR54XX(ctx->opcode); > > gen_mul_vr54xx(ctx, op1, rd, rs, rt); > > + } else if (ctx->insn_flags & INSN_R5900) { > > + gen_mul_r5900(ctx, op1, 0, rd, rs, rt); > > Removing 'acc' arg: > > gen_mul_r5900(ctx, op1, rd, rs, rt); Done. > Note, these instructions are also valid on the R3900 (which also has > MADD/MADDU). > > Would gen_mul_toshiba() be a better common name? I don't like it but > can't think of another. I propose gen_mul_3op, since its distinctive feature is the three operands. Fredrik
On Fri, Sep 28, 2018 at 5:16 PM Fredrik Noring <noring@nocrew.org> wrote: > > Hi Philippe, > > > Can you copy/paste some info regarding those instructions from the ISA > > here, to note how they differ? ... > > Yes. Other corresponding functions typically do not seem to have such ISA > notes, but I can certainly write one for it. My guess is they don't have because they implement the generic ISA which is public. It is rather hard to find public manuals for the Toshiba/Sony ISA. > > Since we have acc = 0 we can directly use cpu_LO[0] and cpu_HI[0], > > removing needs for an 'acc' argument. > > We could, but as Maciej replied there are pipeline 1 versions of these > instructions which would have acc = 1. I retained the acc parameter mainly > to avoid the error of forgetting to replace 0 with acc when introducing > them later on. Yes, I was not aware of those instructions, so better keep the 'acc' argument. > > > +{ > > > + TCGv t0 = tcg_temp_new(); > > > + TCGv t1 = tcg_temp_new(); > > > + > > > + gen_load_gpr(t0, rs); > > > + gen_load_gpr(t1, rt); > > > + > > > + switch (opc) { > > > + case OPC_MULT: > > > + { > > > + TCGv_i32 t2 = tcg_temp_new_i32(); > > > + TCGv_i32 t3 = tcg_temp_new_i32(); > > > + tcg_gen_trunc_tl_i32(t2, t0); > > > + tcg_gen_trunc_tl_i32(t3, t1); > > > + tcg_gen_muls2_i32(t2, t3, t2, t3); > > > + if (rd) > > > > Check QEMU CODING_STYLE "Block structure": > > > > Every indented statement is braced; even if the block contains > > just one statement. The opening brace is on the line that > > contains the control flow statement that introduces the new block; > > the closing brace is on the same line as the else keyword, or on > > a line by itself if there is no else keyword. > > > > QEMU scripts/checkpatch.pl reports such mistakes. > > Done. > > > > + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); > > > > I'd use: > > > > gen_move_low32(cpu_gpr[rd], t2); > > Are you sure this is correct? The GPR rd must be sign-extended. Richard can you verify please? > > > + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); > > > > So: > > > > tcg_gen_ext_i32_tl(cpu_LO[0], t2); > > > > > + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); > > > > And: > > > > tcg_gen_ext_i32_tl(cpu_HI[0], t3); > > Done. > > > > + tcg_temp_free_i32(t2); > > > + tcg_temp_free_i32(t3); > > > + } > > > + break; > > > + case OPC_MULTU: > > > + { > > > + TCGv_i32 t2 = tcg_temp_new_i32(); > > > + TCGv_i32 t3 = tcg_temp_new_i32(); > > > + tcg_gen_trunc_tl_i32(t2, t0); > > > + tcg_gen_trunc_tl_i32(t3, t1); > > > + tcg_gen_mulu2_i32(t2, t3, t2, t3); > > > + if (rd) > > > + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); > > > + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); > > > + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); > > > > Same comments from MULT apply here. > > Done. > > > > + tcg_temp_free_i32(t2); > > > + tcg_temp_free_i32(t3); > > > + } > > > + break; > > > + default: > > > + MIPS_INVAL("mul R5900"); > > > + generate_exception_end(ctx, EXCP_RI); > > > + goto out; > > > + } > > > + > > > + out: > > > + tcg_temp_free(t0); > > > + tcg_temp_free(t1); > > > +} > > > + > > > static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc, > > > int rd, int rs, int rt) > > > { > > > @@ -22378,6 +22429,8 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) > > > check_insn(ctx, INSN_VR54XX); > > > op1 = MASK_MUL_VR54XX(ctx->opcode); > > > gen_mul_vr54xx(ctx, op1, rd, rs, rt); > > > + } else if (ctx->insn_flags & INSN_R5900) { > > > + gen_mul_r5900(ctx, op1, 0, rd, rs, rt); > > > > Removing 'acc' arg: > > > > gen_mul_r5900(ctx, op1, rd, rs, rt); > > Done. > > > Note, these instructions are also valid on the R3900 (which also has > > MADD/MADDU). > > > > Would gen_mul_toshiba() be a better common name? I don't like it but > > can't think of another. > > I propose gen_mul_3op, since its distinctive feature is the three operands. Fine by me.
On Fri, 28 Sep 2018, Philippe Mathieu-Daudé wrote: > > > Note, these instructions are also valid on the R3900 (which also has > > > MADD/MADDU). > > > > > > Would gen_mul_toshiba() be a better common name? I don't like it but > > > can't think of another. > > > > I propose gen_mul_3op, since its distinctive feature is the three operands. > > Fine by me. Bikeshedding, but... I haven't looked at how we implement it, however generic MIPS architecture also has a 3-operand MUL instruction defined, reusing, for R1-R5, the encoding used earlier on by IDT R4650 and NEC Vr5500, and using a different one for R6. So I'd rather we avoided confusion here. Perhaps `gen_mul_ee' then for Emotion Engine? -- EE is what libopcodes uses for R5900 instructions where brevity matters. Or `gen_mul_4op', because we have 4 operands really, with the HI/LO accumulator being an implicit one. What's wrong with `gen_mul_r5900' anyway? Maciej
On Fri, Sep 28, 2018 at 5:59 PM Maciej W. Rozycki <macro@linux-mips.org> wrote: > > On Fri, 28 Sep 2018, Philippe Mathieu-Daudé wrote: > > > > > Note, these instructions are also valid on the R3900 (which also has > > > > MADD/MADDU). > > > > > > > > Would gen_mul_toshiba() be a better common name? I don't like it but > > > > can't think of another. > > > > > > I propose gen_mul_3op, since its distinctive feature is the three operands. > > > > Fine by me. > > Bikeshedding, but... I haven't looked at how we implement it, however > generic MIPS architecture also has a 3-operand MUL instruction defined, > reusing, for R1-R5, the encoding used earlier on by IDT R4650 and NEC > Vr5500, and using a different one for R6. So I'd rather we avoided > confusion here. > > Perhaps `gen_mul_ee' then for Emotion Engine? -- EE is what libopcodes > uses for R5900 instructions where brevity matters. Or `gen_mul_4op', > because we have 4 operands really, with the HI/LO accumulator being an > implicit one. > > What's wrong with `gen_mul_r5900' anyway? I plan to use this function (adding MADD/MADDU) for R3900 based cores (which don't seemt related to Emotion Engine).
On Fri, 28 Sep 2018, Philippe Mathieu-Daudé wrote: > > What's wrong with `gen_mul_r5900' anyway? > > I plan to use this function (adding MADD/MADDU) for R3900 based cores > (which don't seemt related to Emotion Engine). Fair enough. I reached for documentation and these instructions seem to be shared by all members of Toshiba's TX System RISC family, i.e. TX19, TX39, etc. So I think `gen_mul_toshiba' or `gen_mul_tx' or `gen_mul_txxx' will do. Maciej
diff --git a/target/mips/translate.c b/target/mips/translate.c index ab16cdb911..fb571e278e 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -3768,6 +3768,57 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc, tcg_temp_free(t1); } +static void gen_mul_r5900(DisasContext *ctx, uint32_t opc, + int acc, int rd, int rs, int rt) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + + switch (opc) { + case OPC_MULT: + { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_muls2_i32(t2, t3, t2, t3); + if (rd) + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + break; + case OPC_MULTU: + { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_mulu2_i32(t2, t3, t2, t3); + if (rd) + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + break; + default: + MIPS_INVAL("mul R5900"); + generate_exception_end(ctx, EXCP_RI); + goto out; + } + + out: + tcg_temp_free(t0); + tcg_temp_free(t1); +} + static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) { @@ -22378,6 +22429,8 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx) check_insn(ctx, INSN_VR54XX); op1 = MASK_MUL_VR54XX(ctx->opcode); gen_mul_vr54xx(ctx, op1, rd, rs, rt); + } else if (ctx->insn_flags & INSN_R5900) { + gen_mul_r5900(ctx, op1, 0, rd, rs, rt); } else { gen_muldiv(ctx, op1, rd & 3, rs, rt); }
Signed-off-by: Fredrik Noring <noring@nocrew.org> --- target/mips/translate.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)