qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] Add special MIPS multiply instructions


From: Dirk Behme
Subject: [Qemu-devel] [PATCH] Add special MIPS multiply instructions
Date: Fri, 21 Apr 2006 20:30:02 +0200
User-agent: Mozilla Thunderbird 1.0.7 (X11/20050923)

Hi,

while playing with different -march options of MIPS GCC, I
found that  GCC generates some special R5400 three register
multiply assembly commands if used with -march=vr5400 (MULS,
MULHI, MACC etc.). These commands use 11 bit extended
opcodes where the lowest 6 bits are the same as for the
standard MULT/MULTU instructions (0x18 & 0x19). See for
example chapter 17.4 of

www.necelam.com/docs/files/1375_V2.pdf

Unfortunately, because QEMU uses mask 0x3F to extract
opcode, it doesn't detect these special opcodes and instead
executes the (wrong) standard ones. No exception or
warning is given. Calculation is simply wrong and program
misbehaves while working with wrong values.

Patch below adds support for these special MIPS opcodes.

Regards

Dirk
--- ./target-mips/op_helper.c_orig      2006-04-21 19:47:43.000000000 +0200
+++ ./target-mips/op_helper.c   2006-04-21 20:18:38.000000000 +0200
@@ -129,6 +129,132 @@ void do_msubu (void)
     tmp = ((uint64_t)T0 * (uint64_t)T1);
     set_HILO(get_HILO() - tmp);
 }
+
+void do_muls (void)
+{
+    int64_t tmp;
+
+    tmp = 0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp & 0xFFFFFFFF;
+}
+
+void do_mulsu (void)
+{
+    uint64_t tmp;
+
+    tmp = 0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp & 0xFFFFFFFF;
+}
+
+void do_macc (void)
+{
+    int64_t tmp;
+
+    tmp = ((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * 
(int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp & 0xFFFFFFFF;
+}
+
+void do_macchi (void)
+{
+    int64_t tmp;
+
+    tmp = ((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * 
(int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+}
+
+void do_maccu (void)
+{
+    uint64_t tmp;
+
+    tmp = ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * 
(uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp & 0xFFFFFFFF; 
+}
+
+void do_macchiu (void)
+{
+    uint64_t tmp;
+
+    tmp = ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * 
(uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+}
+
+void do_msac (void)
+{
+    int64_t tmp;
+
+    tmp = ((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * 
(int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp & 0xFFFFFFFF;
+}
+
+void do_msachi (void)
+{
+    int64_t tmp;
+
+    tmp = ((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * 
(int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+}
+
+void do_msacu (void)
+{
+    uint64_t tmp;
+
+    tmp = ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * 
(uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp & 0xFFFFFFFF;
+}
+
+void do_msachiu (void)
+{
+    uint64_t tmp;
+
+    tmp = ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * 
(uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+}
+
+void do_mulhi (void)
+{
+    int64_t tmp;
+
+    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+}
+
+void do_mulhiu (void)
+{
+    uint64_t tmp;
+
+    tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+}
+
+void do_mulshi (void)
+{
+    int64_t tmp;
+
+    tmp = 0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+}
+
+void do_mulshiu (void)
+{
+    uint64_t tmp;
+
+    tmp = 0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+}
 #endif
 
 #if defined(CONFIG_USER_ONLY) 
--- ./target-mips/op.c_orig     2006-04-21 19:47:43.000000000 +0200
+++ ./target-mips/op.c  2006-04-21 20:06:58.000000000 +0200
@@ -409,6 +409,146 @@ void op_msubu (void)
     set_HILO(get_HILO() - tmp);
     RETURN();
 }
+
+void op_muls (void)
+{
+    int64_t tmp;
+
+    tmp = 0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp & 0xFFFFFFFF;
+    RETURN();
+}
+
+void op_mulsu (void)
+{
+    uint64_t tmp;
+
+    tmp = 0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp & 0xFFFFFFFF;
+    RETURN();
+}
+
+void op_macc (void)
+{
+    int64_t tmp;
+
+    tmp = ((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * 
(int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp & 0xFFFFFFFF;
+    RETURN();
+}
+
+void op_macchi (void)
+{
+    int64_t tmp;
+
+    tmp = ((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * 
(int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+    RETURN();
+}
+
+void op_maccu (void)
+{
+    uint64_t tmp;
+
+    tmp = ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * 
(uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp & 0xFFFFFFFF;
+    RETURN();
+}
+
+void op_macchiu (void)
+{
+    uint64_t tmp;
+
+    tmp = ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * 
(uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+    RETURN();
+}
+
+void op_msac (void)
+{
+    int64_t tmp;
+
+    tmp = ((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * 
(int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp & 0xFFFFFFFF;
+    RETURN();
+}
+
+void op_msachi (void)
+{
+    int64_t tmp;
+
+    tmp = ((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * 
(int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+    RETURN();
+}
+
+void op_msacu (void)
+{
+    uint64_t tmp;
+
+    tmp = ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * 
(uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp & 0xFFFFFFFF;
+    RETURN();
+}
+
+void op_msachiu (void)
+{
+    uint64_t tmp;
+
+    tmp = ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * 
(uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+    RETURN();
+}
+
+void op_mulhi (void)
+{
+    int64_t tmp;
+
+    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+    RETURN();
+}
+
+void op_mulhiu (void)
+{
+    uint64_t tmp;
+
+    tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+    RETURN();
+}
+
+void op_mulshi (void)
+{
+    int64_t tmp;
+
+    tmp = 0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+    RETURN();
+}
+
+void op_mulshiu (void)
+{
+    uint64_t tmp;
+
+    tmp = 0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
+    set_HILO(tmp);
+    T0 = tmp >> 32;
+    RETURN();
+}
 #else
 void op_mult (void)
 {
@@ -445,6 +585,89 @@ void op_msubu (void)
     CALL_FROM_TB0(do_msubu);
     RETURN();
 }
+
+void op_muls (void)
+{
+    CALL_FROM_TB0(do_muls);
+    RETURN();
+}
+
+void op_mulsu (void)
+{
+    CALL_FROM_TB0(do_mulsu);
+    RETURN();
+}
+
+void op_macc (void)
+{
+    CALL_FROM_TB0(do_macc);
+    RETURN();
+}
+
+void op_macchi (void)
+{
+    CALL_FROM_TB0(do_macchi); 
+    RETURN();
+}
+
+void op_maccu (void)
+{
+    CALL_FROM_TB0(do_maccu); 
+    RETURN();
+}
+void op_macchiu (void)
+{
+    CALL_FROM_TB0(do_macchiu);
+    RETURN();
+}
+
+void op_msac (void)
+{
+    CALL_FROM_TB0(do_msac);
+    RETURN();
+}
+
+void op_msachi (void)
+{
+    CALL_FROM_TB0(do_msachi);
+    RETURN();
+}
+
+void op_msacu (void)
+{
+    CALL_FROM_TB0(do_msacu);
+    RETURN();
+}
+
+void op_msachiu (void)
+{
+    CALL_FROM_TB0(do_msachiu);
+    RETURN();
+}
+
+void op_mulhi (void)
+{
+    CALL_FROM_TB0(do_mulhi);
+    RETURN();
+}
+
+void op_mulhiu (void)
+{
+    CALL_FROM_TB0(do_mulhiu);
+    RETURN();
+}
+
+void op_mulshi (void)
+{
+    CALL_FROM_TB0(do_mulshi);
+    RETURN();
+}
+
+void op_mulshiu (void)
+{
+    CALL_FROM_TB0(do_mulshiu);
+    RETURN();
+}
 #endif
 
 /* Conditional moves */
--- ./target-mips/translate.c_orig      2006-04-21 19:47:43.000000000 +0200
+++ ./target-mips/translate.c   2006-04-21 20:12:15.000000000 +0200
@@ -186,6 +186,24 @@ enum {
     OPC_SDBBP    = 0x3F | EXT_SPECIAL2,
 };
 
+enum {
+    /* Extended three operand multiply operations with 11 bit opcode */
+    OPC_MULS     = 0x0D8,
+    OPC_MULSU    = 0x0D9,
+    OPC_MACC     = 0x158,
+    OPC_MACCU    = 0x159,
+    OPC_MSAC     = 0x1D8,
+    OPC_MSACU    = 0x1D9,
+    OPC_MULHI    = 0x258,
+    OPC_MULHIU   = 0x259,
+    OPC_MULSHI   = 0x2D8,
+    OPC_MULSHIU  = 0x2D9,
+    OPC_MACCHI   = 0x358,
+    OPC_MACCHIU  = 0x359,
+    OPC_MSACHI   = 0x3D8,
+    OPC_MSACHIU  = 0x3D9,
+};
+
 /* Branch REGIMM */
 enum {
     OPC_BLTZ     = 0x00 | EXT_REGIMM,
@@ -810,6 +828,79 @@ static void gen_muldiv (DisasContext *ct
     MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
 }
 
+static void gen_muldiv_ext (DisasContext *ctx, uint16_t opc,
+                            int rd, int rs, int rt)
+{
+    const unsigned char *opn = "unk";
+
+    GEN_LOAD_REG_TN(T0, rs);
+    GEN_LOAD_REG_TN(T1, rt);
+    switch (opc) {
+    case OPC_MULS:
+        gen_op_muls();
+        opn = "muls";
+       break;
+    case OPC_MULSU:
+        gen_op_mulsu();
+        opn = "mulsu";
+       break;
+    case OPC_MACC:
+        gen_op_macc();
+        opn = "macc";
+       break;
+    case OPC_MACCU:
+        gen_op_maccu();
+        opn = "maccu";
+       break;
+    case OPC_MSAC:
+        gen_op_msac();
+        opn = "msac";
+       break;
+    case OPC_MSACU:
+        gen_op_msacu();
+        opn = "msacu";
+       break;
+    case OPC_MULHI:
+        gen_op_mulhi();
+        opn = "mulhi";
+       break;
+    case OPC_MULHIU:
+        gen_op_mulhiu();
+        opn = "mulhiu";
+       break;
+    case OPC_MULSHI:
+        gen_op_mulshi();
+        opn = "mulshi";
+       break;
+    case OPC_MULSHIU:
+        gen_op_mulshiu();
+        opn = "mulshiu";
+       break;
+    case OPC_MACCHI:
+        gen_op_macchi();
+        opn = "macchi";
+       break;
+    case OPC_MACCHIU:
+        gen_op_macchiu();
+        opn = "macchiu";
+       break;
+    case OPC_MSACHI:
+        gen_op_msachi();
+        opn = "msachi";
+       break;
+    case OPC_MSACHIU:
+        gen_op_msachiu();
+        opn = "msachiu";
+       break;
+    default:
+        MIPS_INVAL("mul/div ext");
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+    GEN_STORE_TN_REG(rd, T0);
+    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
+}
+
 static void gen_cl (DisasContext *ctx, uint16_t opc,
                     int rd, int rs)
 {
@@ -1347,7 +1438,12 @@ static void decode_opc (DisasContext *ct
             gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
             break;
         case 0x18 ... 0x1B: /* MULT / DIV */
-            gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
+           if(!sa) {
+               gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
+           } else {
+              op1 = ctx->opcode & 0x7FF;
+              gen_muldiv_ext(ctx, op1, rd, rs, rt);
+           }
             break;
         case 0x08 ... 0x09: /* Jumps */
             gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
--- ./target-mips/exec.h_orig   2006-04-21 20:03:32.000000000 +0200
+++ ./target-mips/exec.h        2006-04-21 20:06:44.000000000 +0200
@@ -58,6 +58,20 @@ void do_madd (void);
 void do_maddu (void);
 void do_msub (void);
 void do_msubu (void);
+void do_muls (void);
+void do_mulsu (void);
+void do_macc (void);
+void do_macchi (void);
+void do_maccu (void);
+void do_macchiu (void);
+void do_msac (void);
+void do_msachi (void);
+void do_msacu (void);
+void do_msachiu (void);
+void do_mulhi (void);
+void do_mulhiu (void);
+void do_mulshi (void);
+void do_mulshiu (void);
 #endif
 void do_mfc0(int reg, int sel);
 void do_mtc0(int reg, int sel);


reply via email to

[Prev in Thread] Current Thread [Next in Thread]