qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Dirk Behme <dirk.behme@googlemail.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] Add special MIPS multiply instructions
Date: Fri, 21 Apr 2006 20:30:02 +0200	[thread overview]
Message-ID: <444924AA.3010605@gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 757 bytes --]

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

[-- Attachment #2: qemu-mips-r54xx-multiply-patch.txt --]
[-- Type: text/plain, Size: 10478 bytes --]

--- ./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	other threads:[~2006-04-21 18:29 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-04-21 18:30 Dirk Behme [this message]
  -- strict thread matches above, loose matches on Subject: below --
2006-07-22  6:04 [Qemu-devel] [PATCH] Add special MIPS multiply instructions Dirk Behme

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=444924AA.3010605@gmail.com \
    --to=dirk.behme@googlemail.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).