qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH, MIPS64] dmult & dmultu emulation


From: Aurelien Jarno
Subject: [Qemu-devel] [PATCH, MIPS64] dmult & dmultu emulation
Date: Tue, 15 May 2007 22:49:05 +0200
User-agent: Mutt/1.5.13 (2006-08-11)

Hi,

The patch below fixes the emulation of dmult and dmultu by doing a real
64x64 -> 128 multiplication.

On x86_64, it uses the mul/imul instruction, an equivalent C code (but
much slower) is provided for other architectures.

Cheers,
Aurelien


Index: target-mips/op_helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op_helper.c,v
retrieving revision 1.45
diff -u -d -p -r1.45 op_helper.c
--- target-mips/op_helper.c     13 May 2007 19:22:13 -0000      1.45
+++ target-mips/op_helper.c     15 May 2007 20:40:12 -0000
@@ -230,16 +230,49 @@ void do_div (void)
 #ifdef TARGET_MIPS64
 void do_dmult (void)
 {
-    env->LO = (int64_t)T0 * (int64_t)T1;
-    /* XXX */
-    env->HI = (env->LO | (1ULL << 63)) ? ~0ULL : 0ULL;
+#if defined(__x86_64__)
+    __asm__ ("imul %0\n\t"
+             : "=d" (env->HI), "=a" (env->LO)
+             : "a" (T0), "0" (T1)
+             );
+#else
+    int64_t ph;
+    uint64_t pm1, pm2, pl;
+
+    pl = (uint64_t)((uint32_t)T0) * (uint64_t)((uint32_t)T1);
+    pm1 = ((int64_t)T0 >> 32) * (uint32_t)T1;
+    pm2 = (uint32_t)T0 * ((int64_t)T1 >> 32);
+    ph = ((int64_t)T0 >> 32) * ((int64_t)T1 >> 32);
+
+    ph += ((int64_t)pm1) >> 32;        
+    pm1 = (uint64_t)((uint32_t)pm1) + pm2 + (pl >> 32);
+
+    env->HI = ph + ((int64_t)pm1) >> 32;
+    env->LO = (pm1 << 32) + (uint32_t)pl;
+#endif
 }
 
 void do_dmultu (void)
 {
-    env->LO = T0 * T1;
-    /* XXX */
-    env->HI = 0;
+#if defined(__x86_64__)
+    __asm__ ("mul %0\n\t"
+             : "=d" (env->HI), "=a" (env->LO)
+             : "a" (T0), "0" (T1)
+            );
+#else
+    uint64_t ph, pm1, pm2, pl;
+
+    pl = (uint64_t)((uint32_t)T0) * (uint64_t)((uint32_t)T1);
+    pm1 = (T0 >> 32) * (uint32_t)T1;
+    pm2 = (uint32_t)T0 * (T1 >> 32);
+    ph = (T0 >> 32) * (T1 >> 32);
+
+    ph += pm1 >> 32;
+    pm1 = (uint64_t)((uint32_t)pm1) + pm2 + (pl >> 32);
+
+    env->HI = ph + (pm1 >> 32);
+    env->LO = (pm1 << 32) + (uint32_t)pl;
+#endif
 }
 
 void do_ddiv (void)

-- 
  .''`.  Aurelien Jarno             | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   address@hidden         | address@hidden
   `-    people.debian.org/~aurel32 | www.aurel32.net




reply via email to

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