diff mbox series

[v6,2/7] target/mips: Support R5900 specific three-operand MULT and MULTU

Message ID 7c1bbedaf6753f0a3906edf231503726197d2299.1538240994.git.noring@nocrew.org
State New
Headers show
Series target/mips: Limited support for the R5900 | expand

Commit Message

Fredrik Noring Sept. 15, 2018, 9:25 a.m. UTC
The three-operand MULT and MULTU are the only R5900 specific
instructions emitted by GCC 7.3. The R5900 also implements the three-
operand MADD and MADDU instructions, but they are omitted in QEMU for
now since they are absent in programs compiled by current GCC versions.

Likewise, the R5900 specific pipeline 1 instruction variants MULT1,
MULTU1, DIV1, DIVU1, MADD1, MADDU1, MFHI1, MFLO1, MTHI1 and MTLO1
are omitted here as well.

Signed-off-by: Fredrik Noring <noring@nocrew.org>
---
 target/mips/translate.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

Comments

Philippe Mathieu-Daudé Sept. 30, 2018, 3:50 p.m. UTC | #1
On 9/15/18 11:25 AM, Fredrik Noring wrote:
> The three-operand MULT and MULTU are the only R5900 specific
> instructions emitted by GCC 7.3. The R5900 also implements the three-
> operand MADD and MADDU instructions, but they are omitted in QEMU for
> now since they are absent in programs compiled by current GCC versions.

I'm not sure this GCC information is worthless in the commit message.

> Likewise, the R5900 specific pipeline 1 instruction variants MULT1,
> MULTU1, DIV1, DIVU1, MADD1, MADDU1, MFHI1, MFLO1, MTHI1 and MTLO1
> are omitted here as well.
> 
> Signed-off-by: Fredrik Noring <noring@nocrew.org>
> ---
>  target/mips/translate.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 73 insertions(+)
> 
> diff --git a/target/mips/translate.c b/target/mips/translate.c
> index ab16cdb911..7e18ec0d03 100644
> --- a/target/mips/translate.c
> +++ b/target/mips/translate.c
> @@ -3768,6 +3768,77 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc,
>      tcg_temp_free(t1);
>  }
>  
> +/*
> + * These MULT and MULTU instructions implemented in for example the
> + * Toshiba/Sony R5900 and the Toshiba TX19, TX39 and TX79 core
> + * architectures are special three-operand variants with the syntax
> + *
> + *     MULT[U] rd, rs, rt
> + *
> + * such that
> + *
> + *     (rd, LO, HI) <- rs * rt
> + *
> + * where the low-order 32-bits of the result is placed into both the
> + * GPR rd and the special register LO. The high-order 32-bits of the
> + * result is placed into the special register HI.
> + *
> + * If the GPR rd is omitted in assembly language, it is taken to be 0,
> + * which is the zero register that always reads as 0.
> + */
> +static void gen_mul_txxx(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");

I'd use:

           MIPS_INVAL("mul/div Toshiba");

> +        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 +22449,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_txxx(ctx, op1, 0, rd, rs, rt);

Similarly, I'd name this gen_muldiv_txx9().

The code is correct, therefore:
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

Maybe the maintainer will agree to do these minor changes when taking
the patches.

>          } else {
>              gen_muldiv(ctx, op1, rd & 3, rs, rt);
>          }
>
Maciej W. Rozycki Sept. 30, 2018, 4:14 p.m. UTC | #2
On Sun, 30 Sep 2018, Philippe Mathieu-Daudé wrote:

> > +        MIPS_INVAL("mul R5900");
> 
> I'd use:
> 
>            MIPS_INVAL("mul/div Toshiba");

 But just like `gen_mul_vr54xx' this function doesn't handle division!

> > @@ -22378,6 +22449,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_txxx(ctx, op1, 0, rd, rs, rt);
> 
> Similarly, I'd name this gen_muldiv_txx9().

 Likewise.  I agree with the `_txx9' suffix update, it makes sense to me.

  Maciej
Philippe Mathieu-Daudé Sept. 30, 2018, 5:20 p.m. UTC | #3
On 9/30/18 6:14 PM, Maciej W. Rozycki wrote:
> On Sun, 30 Sep 2018, Philippe Mathieu-Daudé wrote:
> 
>>> +        MIPS_INVAL("mul R5900");
>>
>> I'd use:
>>
>>            MIPS_INVAL("mul/div Toshiba");
> 
>  But just like `gen_mul_vr54xx' this function doesn't handle division!

Per the commit message, I understood this function would eventually
handle "the R5900 specific pipeline 1 instruction variants MULT1,
MULTU1, DIV1, DIVU1, ..."

> 
>>> @@ -22378,6 +22449,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_txxx(ctx, op1, 0, rd, rs, rt);
>>
>> Similarly, I'd name this gen_muldiv_txx9().
> 
>  Likewise.  I agree with the `_txx9' suffix update, it makes sense to me.

Cool, thanks.
Maciej W. Rozycki Sept. 30, 2018, 6:43 p.m. UTC | #4
On Sun, 30 Sep 2018, Philippe Mathieu-Daudé wrote:

> >> I'd use:
> >>
> >>            MIPS_INVAL("mul/div Toshiba");
> > 
> >  But just like `gen_mul_vr54xx' this function doesn't handle division!
> 
> Per the commit message, I understood this function would eventually
> handle "the R5900 specific pipeline 1 instruction variants MULT1,
> MULTU1, DIV1, DIVU1, ..."

 Toshiba division instructions do not support the extra operand and always 
return their result in the MD accumulator only.  The same applies to the 
pipeline 1 instruction variants, so I've been thinking that a different 
handler would better be used for DIV1 and DIVU1.  But maybe we can fold it 
together after all and just force `rd' to be 0 at the call site for 
DIV1/DIVU1.

 I'm not sure at this point which approach would be most beneficial, but 
as it stands the function does not handle division operations.  If it 
starts in the future, then we can rename/update it accordingly.

 Note that while the R5900 (shouldn't that be called TX59 actually?) or 
TX79 do not implement DMULT or DMULTU, the Tx49 does and they do support 
the extra `rd' operand there[1].  Still no DMADD or DMADDU though.

References:

[1] "64-Bit TX System RISC TX49/H2, TX49/H3, TX49/H4 Core Architecture", 
    Rev 1.0, Toshiba Corporation, September 2004, Table 5-8 "Extensions to 
    the ISA: Multiply and Divide Instructions", p. 5-7

  Maciej
Philippe Mathieu-Daudé Sept. 30, 2018, 9:59 p.m. UTC | #5
On 9/30/18 8:43 PM, Maciej W. Rozycki wrote:
> On Sun, 30 Sep 2018, Philippe Mathieu-Daudé wrote:
> 
>>>> I'd use:
>>>>
>>>>            MIPS_INVAL("mul/div Toshiba");
>>>
>>>  But just like `gen_mul_vr54xx' this function doesn't handle division!
>>
>> Per the commit message, I understood this function would eventually
>> handle "the R5900 specific pipeline 1 instruction variants MULT1,
>> MULTU1, DIV1, DIVU1, ..."
> 
>  Toshiba division instructions do not support the extra operand and always 
> return their result in the MD accumulator only.  The same applies to the 
> pipeline 1 instruction variants, so I've been thinking that a different 
> handler would better be used for DIV1 and DIVU1.  But maybe we can fold it 
> together after all and just force `rd' to be 0 at the call site for 
> DIV1/DIVU1.
> 
>  I'm not sure at this point which approach would be most beneficial, but 
> as it stands the function does not handle division operations.  If it 
> starts in the future, then we can rename/update it accordingly.

OK, so I think both agree to name this gen_mul_txx9().

>  Note that while the R5900 (shouldn't that be called TX59 actually?) or 

I also think of the R5900 as the TX59 member of the Toshiba TX family
but I never read the TX59 name, I suppose this is where Sony comes into
the game.

> TX79 do not implement DMULT or DMULTU, the Tx49 does and they do support 
> the extra `rd' operand there[1].  Still no DMADD or DMADDU though.

As does the TX39.

There is also the TX99 series (based on 25Kf):
https://www.toshiba.co.jp/about/press/2002_02/pr1901.htm

> References:
> 
> [1] "64-Bit TX System RISC TX49/H2, TX49/H3, TX49/H4 Core Architecture", 
>     Rev 1.0, Toshiba Corporation, September 2004, Table 5-8 "Extensions to 
>     the ISA: Multiply and Divide Instructions", p. 5-7
> 
>   Maciej
>
Philippe Mathieu-Daudé Sept. 30, 2018, 9:59 p.m. UTC | #6
On 9/30/18 8:43 PM, Maciej W. Rozycki wrote:
> On Sun, 30 Sep 2018, Philippe Mathieu-Daudé wrote:
> 
>>>> I'd use:
>>>>
>>>>            MIPS_INVAL("mul/div Toshiba");
>>>
>>>  But just like `gen_mul_vr54xx' this function doesn't handle division!
>>
>> Per the commit message, I understood this function would eventually
>> handle "the R5900 specific pipeline 1 instruction variants MULT1,
>> MULTU1, DIV1, DIVU1, ..."
> 
>  Toshiba division instructions do not support the extra operand and always 
> return their result in the MD accumulator only.  The same applies to the 
> pipeline 1 instruction variants, so I've been thinking that a different 
> handler would better be used for DIV1 and DIVU1.  But maybe we can fold it 
> together after all and just force `rd' to be 0 at the call site for 
> DIV1/DIVU1.
> 
>  I'm not sure at this point which approach would be most beneficial, but 
> as it stands the function does not handle division operations.  If it 
> starts in the future, then we can rename/update it accordingly.

OK, so I think both agree to name this gen_mul_txx9().

>  Note that while the R5900 (shouldn't that be called TX59 actually?) or 

I also think of the R5900 as the TX59 member of the Toshiba TX family
but I never read the TX59 name, I suppose this is where Sony comes into
the game.

> TX79 do not implement DMULT or DMULTU, the Tx49 does and they do support 
> the extra `rd' operand there[1].  Still no DMADD or DMADDU though.

As does the TX39.

There is also the TX99 series (based on 25Kf):
https://www.toshiba.co.jp/about/press/2002_02/pr1901.htm

> References:
> 
> [1] "64-Bit TX System RISC TX49/H2, TX49/H3, TX49/H4 Core Architecture", 
>     Rev 1.0, Toshiba Corporation, September 2004, Table 5-8 "Extensions to 
>     the ISA: Multiply and Divide Instructions", p. 5-7
> 
>   Maciej
>
Maciej W. Rozycki Sept. 30, 2018, 10:20 p.m. UTC | #7
On Sun, 30 Sep 2018, Philippe Mathieu-Daudé wrote:

> > TX79 do not implement DMULT or DMULTU, the Tx49 does and they do support 
> > the extra `rd' operand there[1].  Still no DMADD or DMADDU though.
> 
> As does the TX39.

 Umm, the TX39 is 32-bit and does not have 64-bit instructions, so it 
can't have DMULT or DMULTU.

> There is also the TX99 series (based on 25Kf):
> https://www.toshiba.co.jp/about/press/2002_02/pr1901.htm

 Hmm, did the TX99 actually tape out?  I thought the 25Kf was withdrawn 
and never made it to market.  I only saw a couple of 25Kf LVs on Malta CPU 
daughtercards back in my MIPS UK days in mid 2000s.

  Maciej
Philippe Mathieu-Daudé Sept. 30, 2018, 11:21 p.m. UTC | #8
On 10/1/18 12:20 AM, Maciej W. Rozycki wrote:
> On Sun, 30 Sep 2018, Philippe Mathieu-Daudé wrote:
> 
>>> TX79 do not implement DMULT or DMULTU, the Tx49 does and they do support 
>>> the extra `rd' operand there[1].  Still no DMADD or DMADDU though.
>>
>> As does the TX39.
> 
>  Umm, the TX39 is 32-bit and does not have 64-bit instructions, so it 
> can't have DMULT or DMULTU.

I meant "As does the TX39 [with the MULT and MULTU:] support the extra
`rd' operand".

>> There is also the TX99 series (based on 25Kf):
>> https://www.toshiba.co.jp/about/press/2002_02/pr1901.htm
> 
>  Hmm, did the TX99 actually tape out?  I thought the 25Kf was withdrawn 
> and never made it to market.  I only saw a couple of 25Kf LVs on Malta CPU 
> daughtercards back in my MIPS UK days in mid 2000s.

Lucky you :)

I never fished any TX99 binary.
diff mbox series

Patch

diff --git a/target/mips/translate.c b/target/mips/translate.c
index ab16cdb911..7e18ec0d03 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -3768,6 +3768,77 @@  static void gen_muldiv(DisasContext *ctx, uint32_t opc,
     tcg_temp_free(t1);
 }
 
+/*
+ * These MULT and MULTU instructions implemented in for example the
+ * Toshiba/Sony R5900 and the Toshiba TX19, TX39 and TX79 core
+ * architectures are special three-operand variants with the syntax
+ *
+ *     MULT[U] rd, rs, rt
+ *
+ * such that
+ *
+ *     (rd, LO, HI) <- rs * rt
+ *
+ * where the low-order 32-bits of the result is placed into both the
+ * GPR rd and the special register LO. The high-order 32-bits of the
+ * result is placed into the special register HI.
+ *
+ * If the GPR rd is omitted in assembly language, it is taken to be 0,
+ * which is the zero register that always reads as 0.
+ */
+static void gen_mul_txxx(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 +22449,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_txxx(ctx, op1, 0, rd, rs, rt);
         } else {
             gen_muldiv(ctx, op1, rd & 3, rs, rt);
         }