* simops.c (syscall): Handle change in opcode # for syscall.
[binutils-gdb.git] / sim / mn10300 / simops.c
index 8f86609a6bb6f9c86e67b2e64787a8e605ad7ebf..7a190566bcb68b167e027053eb8946351e4286f3 100644 (file)
@@ -6,7 +6,8 @@
 #endif
 #include "mn10300_sim.h"
 #include "simops.h"
-#include "sys/syscall.h"
+#include "sim-types.h"
+#include "targ-vals.h"
 #include "bfd.h"
 #include <errno.h>
 #include <sys/stat.h>
@@ -1432,8 +1433,8 @@ void OP_F240 (insn, extension)
   unsigned long long temp;
   int n, z;
 
-  temp = ((signed long)State.regs[REG_D0 + REG0 (insn)]
-          *  (signed long)State.regs[REG_D0 + REG1 (insn)]);
+  temp = ((signed64)(signed32)State.regs[REG_D0 + REG0 (insn)]
+          *  (signed64)(signed32)State.regs[REG_D0 + REG1 (insn)]);
   State.regs[REG_D0 + REG0 (insn)] = temp & 0xffffffff;
   State.regs[REG_MDR] = (temp & 0xffffffff00000000LL) >> 32;;
   z = (State.regs[REG_D0 + REG0 (insn)] == 0);
@@ -1449,8 +1450,8 @@ void OP_F250 (insn, extension)
   unsigned long long temp;
   int n, z;
 
-  temp = (State.regs[REG_D0 + REG0 (insn)]
-          *  State.regs[REG_D0 + REG1 (insn)]);
+  temp = ((unsigned64)State.regs[REG_D0 + REG0 (insn)]
+          * (unsigned64)State.regs[REG_D0 + REG1 (insn)]);
   State.regs[REG_D0 + REG0 (insn)] = temp & 0xffffffff;
   State.regs[REG_MDR] = (temp & 0xffffffff00000000LL) >> 32;
   z = (State.regs[REG_D0 + REG0 (insn)] == 0);
@@ -1511,7 +1512,7 @@ void OP_40 (insn, extension)
 
   z = (value == 0);
   n = (value & 0x80000000);
-  c = (reg1 < imm);
+  c = (value < imm);
   v = ((reg1 & 0x80000000) == (imm & 0x80000000)
        && (reg1 & 0x80000000) != (value & 0x80000000));
 
@@ -2531,11 +2532,11 @@ void OP_DC000000 (insn, extension)
 void OP_CD000000 (insn, extension)
      unsigned long insn, extension;
 {
-  unsigned int next_pc, sp, adjust;
+  unsigned int next_pc, sp;
   unsigned long mask;
 
   sp = State.regs[REG_SP];
-  next_pc = State.regs[REG_PC] + 2;
+  next_pc = State.regs[REG_PC] + 5;
   State.mem[sp] = next_pc & 0xff;
   State.mem[sp+1] = (next_pc & 0xff00) >> 8;
   State.mem[sp+2] = (next_pc & 0xff0000) >> 16;
@@ -2543,51 +2544,52 @@ void OP_CD000000 (insn, extension)
 
   mask = insn & 0xff;
 
-  adjust = 0;
   if (mask & 0x80)
     {
-      adjust -= 4;
-      State.regs[REG_D0 + 2] = load_word (sp + adjust);
+      sp -= 4;
+      store_word (sp, State.regs[REG_D0 + 2]);
     }
 
   if (mask & 0x40)
     {
-      adjust -= 4;
-      State.regs[REG_D0 + 3] = load_word (sp + adjust);
+      sp -= 4;
+      store_word (sp, State.regs[REG_D0 + 3]);
     }
 
   if (mask & 0x20)
     {
-      adjust -= 4;
-      State.regs[REG_A0 + 2] = load_word (sp + adjust);
+      sp -= 4;
+      store_word (sp, State.regs[REG_A0 + 2]);
     }
 
   if (mask & 0x10)
     {
-      adjust -= 4;
-      State.regs[REG_A0 + 3] = load_word (sp + adjust);
+      sp -= 4;
+      store_word (sp, State.regs[REG_A0 + 3]);
     }
 
   if (mask & 0x8)
     {
-      adjust -= 4;
-      State.regs[REG_D0] = load_word (sp + adjust);
-      adjust -= 4;
-      State.regs[REG_D0 + 1] = load_word (sp + adjust);
-      adjust -= 4;
-      State.regs[REG_A0] = load_word (sp + adjust);
-      adjust -= 4;
-      State.regs[REG_A0 + 1] = load_word (sp + adjust);
-      adjust -= 4;
-      State.regs[REG_MDR] = load_word (sp + adjust);
-      adjust -= 4;
-      State.regs[REG_LIR] = load_word (sp + adjust);
-      adjust -= 4;
-      State.regs[REG_LAR] = load_word (sp + adjust);
-      adjust -= 4;
+      sp -= 4;
+      store_word (sp, State.regs[REG_D0]);
+      sp -= 4;
+      store_word (sp, State.regs[REG_D0 + 1]);
+      sp -= 4;
+      store_word (sp, State.regs[REG_A0]);
+      sp -= 4;
+      store_word (sp, State.regs[REG_A0 + 1]);
+      sp -= 4;
+      store_word (sp, State.regs[REG_MDR]);
+      sp -= 4;
+      store_word (sp, State.regs[REG_LIR]);
+      sp -= 4;
+      store_word (sp, State.regs[REG_LAR]);
+      sp -= 4;
     }
 
-  /* And make sure to update the stack pointer.  */
+  /* Update the stack pointer, note that the register saves to do not
+     modify SP.  The SP adjustment is derived totally from the imm8
+     field.  */
   State.regs[REG_SP] -= extension;
   State.regs[REG_MDR] = next_pc;
   State.regs[REG_PC] += SEXT16 ((insn & 0xffff00) >> 8) - 5;
@@ -2601,7 +2603,7 @@ void OP_DD000000 (insn, extension)
   unsigned long mask;
 
   sp = State.regs[REG_SP];
-  next_pc = State.regs[REG_PC] + 2;
+  next_pc = State.regs[REG_PC] + 7;
   State.mem[sp] = next_pc & 0xff;
   State.mem[sp+1] = (next_pc & 0xff00) >> 8;
   State.mem[sp+2] = (next_pc & 0xff0000) >> 16;
@@ -2609,51 +2611,52 @@ void OP_DD000000 (insn, extension)
 
   mask = (extension & 0xff00) >> 8;
 
-  adjust = 0;
   if (mask & 0x80)
     {
-      adjust -= 4;
-      State.regs[REG_D0 + 2] = load_word (sp + adjust);
+      sp -= 4;
+      store_word (sp, State.regs[REG_D0 + 2]);
     }
 
   if (mask & 0x40)
     {
-      adjust -= 4;
-      State.regs[REG_D0 + 3] = load_word (sp + adjust);
+      sp -= 4;
+      store_word (sp, State.regs[REG_D0 + 3]);
     }
 
   if (mask & 0x20)
     {
-      adjust -= 4;
-      State.regs[REG_A0 + 2] = load_word (sp + adjust);
+      sp -= 4;
+      store_word (sp, State.regs[REG_A0 + 2]);
     }
 
   if (mask & 0x10)
     {
-      adjust -= 4;
-      State.regs[REG_A0 + 3] = load_word (sp + adjust);
+      sp -= 4;
+      store_word (sp, State.regs[REG_A0 + 3]);
     }
 
   if (mask & 0x8)
     {
-      adjust -= 4;
-      State.regs[REG_D0] = load_word (sp + adjust);
-      adjust -= 4;
-      State.regs[REG_D0 + 1] = load_word (sp + adjust);
-      adjust -= 4;
-      State.regs[REG_A0] = load_word (sp + adjust);
-      adjust -= 4;
-      State.regs[REG_A0 + 1] = load_word (sp + adjust);
-      adjust -= 4;
-      State.regs[REG_MDR] = load_word (sp + adjust);
-      adjust -= 4;
-      State.regs[REG_LIR] = load_word (sp + adjust);
-      adjust -= 4;
-      State.regs[REG_LAR] = load_word (sp + adjust);
-      adjust -= 4;
+      sp -= 4;
+      store_word (sp, State.regs[REG_D0]);
+      sp -= 4;
+      store_word (sp, State.regs[REG_D0 + 1]);
+      sp -= 4;
+      store_word (sp, State.regs[REG_A0]);
+      sp -= 4;
+      store_word (sp, State.regs[REG_A0 + 1]);
+      sp -= 4;
+      store_word (sp, State.regs[REG_MDR]);
+      sp -= 4;
+      store_word (sp, State.regs[REG_LIR]);
+      sp -= 4;
+      store_word (sp, State.regs[REG_LAR]);
+      sp -= 4;
     }
 
-  /* And make sure to update the stack pointer.  */
+  /* Update the stack pointer, note that the register saves to do not
+     modify SP.  The SP adjustment is derived totally from the imm8
+     field.  */
   State.regs[REG_SP] -= (extension & 0xff);
   State.regs[REG_MDR] = next_pc;
   State.regs[REG_PC] += (((insn & 0xffffff) << 8) | ((extension & 0xff0000) >> 16)) - 7;
@@ -2711,60 +2714,57 @@ void OP_FCFF0000 (insn, extension)
 void OP_DF0000 (insn, extension)
      unsigned long insn, extension;
 {
-  unsigned int sp;
+  unsigned int sp, offset;
   unsigned long mask;
 
   State.regs[REG_SP] += insn & 0xff;
   sp = State.regs[REG_SP];
 
+  offset = -4;
   mask = (insn & 0xff00) >> 8;
 
-  if (mask & 0x8)
+  if (mask & 0x80)
     {
-      sp += 4;
-      State.regs[REG_LAR] = load_word (sp);
-      sp += 4;
-      State.regs[REG_LIR] = load_word (sp);
-      sp += 4;
-      State.regs[REG_MDR] = load_word (sp);
-      sp += 4;
-      State.regs[REG_A0 + 1] = load_word (sp);
-      sp += 4;
-      State.regs[REG_A0] = load_word (sp);
-      sp += 4;
-      State.regs[REG_D0 + 1] = load_word (sp);
-      sp += 4;
-      State.regs[REG_D0] = load_word (sp);
-      sp += 4;
+      State.regs[REG_D0 + 2] = load_word (sp + offset);
+      offset -= 4;
     }
 
-  if (mask & 0x10)
+  if (mask & 0x40)
     {
-      State.regs[REG_A0 + 3] = load_word (sp);
-      sp += 4;
+      State.regs[REG_D0 + 3] = load_word (sp + offset);
+      offset -= 4;
     }
 
   if (mask & 0x20)
     {
-      State.regs[REG_A0 + 2] = load_word (sp);
-      sp += 4;
+      State.regs[REG_A0 + 2] = load_word (sp + offset);
+      offset -= 4;
     }
 
-  if (mask & 0x40)
+  if (mask & 0x10)
     {
-      State.regs[REG_D0 + 3] = load_word (sp);
-      sp += 4;
+      State.regs[REG_A0 + 3] = load_word (sp + offset);
+      offset -= 4;
     }
 
-  if (mask & 0x80)
+  if (mask & 0x8)
     {
-      State.regs[REG_D0 + 2] = load_word (sp);
-      sp += 4;
+      State.regs[REG_D0] = load_word (sp + offset);
+      offset -= 4;
+      State.regs[REG_D0 + 1] = load_word (sp + offset);
+      offset -= 4;
+      State.regs[REG_A0] = load_word (sp + offset);
+      offset -= 4;
+      State.regs[REG_A0 + 1] = load_word (sp + offset);
+      offset -= 4;
+      State.regs[REG_MDR] = load_word (sp + offset);
+      offset -= 4;
+      State.regs[REG_LIR] = load_word (sp + offset);
+      offset -= 4;
+      State.regs[REG_LAR] = load_word (sp + offset);
+      offset -= 4;
     }
 
-  /* And make sure to update the stack pointer.  */
-  State.regs[REG_SP] = sp;
-
   /* Restore the PC value.  */
   State.regs[REG_PC] = (State.mem[sp] | (State.mem[sp+1] << 8)
              | (State.mem[sp+2] << 16) | (State.mem[sp+3] << 24));
@@ -2775,62 +2775,57 @@ void OP_DF0000 (insn, extension)
 void OP_DE0000 (insn, extension)
      unsigned long insn, extension;
 {
-  unsigned int sp;
+  unsigned int sp, offset;
   unsigned long mask;
 
-  sp = State.regs[REG_SP] + (insn & 0xff);
-  State.regs[REG_SP] = sp;
-  State.regs[REG_PC] = State.regs[REG_MDR] - 3;
-
+  State.regs[REG_SP] += (insn & 0xff);
   sp = State.regs[REG_SP];
+  State.regs[REG_PC] = State.regs[REG_MDR] - 3;
 
+  offset = -4;
   mask = (insn & 0xff00) >> 8;
 
-  if (mask & 0x8)
+  if (mask & 0x80)
     {
-      sp += 4;
-      State.regs[REG_LAR] = load_word (sp);
-      sp += 4;
-      State.regs[REG_LIR] = load_word (sp);
-      sp += 4;
-      State.regs[REG_MDR] = load_word (sp);
-      sp += 4;
-      State.regs[REG_A0 + 1] = load_word (sp);
-      sp += 4;
-      State.regs[REG_A0] = load_word (sp);
-      sp += 4;
-      State.regs[REG_D0 + 1] = load_word (sp);
-      sp += 4;
-      State.regs[REG_D0] = load_word (sp);
-      sp += 4;
+      State.regs[REG_D0 + 2] = load_word (sp + offset);
+      offset -= 4;
     }
 
-  if (mask & 0x10)
+  if (mask & 0x40)
     {
-      State.regs[REG_A0 + 3] = load_word (sp);
-      sp += 4;
+      State.regs[REG_D0 + 3] = load_word (sp + offset);
+      offset -= 4;
     }
 
   if (mask & 0x20)
     {
-      State.regs[REG_A0 + 2] = load_word (sp);
-      sp += 4;
+      State.regs[REG_A0 + 2] = load_word (sp + offset);
+      offset -= 4;
     }
 
-  if (mask & 0x40)
+  if (mask & 0x10)
     {
-      State.regs[REG_D0 + 3] = load_word (sp);
-      sp += 4;
+      State.regs[REG_A0 + 3] = load_word (sp + offset);
+      offset -= 4;
     }
 
-  if (mask & 0x80)
+  if (mask & 0x8)
     {
-      State.regs[REG_D0 + 2] = load_word (sp);
-      sp += 4;
+      State.regs[REG_D0] = load_word (sp + offset);
+      offset -= 4;
+      State.regs[REG_D0 + 1] = load_word (sp + offset);
+      offset -= 4;
+      State.regs[REG_A0] = load_word (sp + offset);
+      offset -= 4;
+      State.regs[REG_A0 + 1] = load_word (sp + offset);
+      offset -= 4;
+      State.regs[REG_MDR] = load_word (sp + offset);
+      offset -= 4;
+      State.regs[REG_LIR] = load_word (sp + offset);
+      offset -= 4;
+      State.regs[REG_LAR] = load_word (sp + offset);
+      offset -= 4;
     }
-
-  /* And make sure to update the stack pointer.  */
-  State.regs[REG_SP] = sp;
 }
 
 /* rets */
@@ -2851,6 +2846,7 @@ void OP_F0FD (insn, extension)
 {
   unsigned int sp, next_pc;
 
+  sp = State.regs[REG_SP];
   PSW = State.mem[sp] | (State.mem[sp + 1] << 8);
   State.regs[REG_PC] = (State.mem[sp+4] | (State.mem[sp+5] << 8)
              | (State.mem[sp+6] << 16) | (State.mem[sp+7] << 24));
@@ -2873,7 +2869,7 @@ void OP_F0FE (insn, extension)
 }
 
 /* syscall */
-void OP_F020 (insn, extension)
+void OP_F0C0 (insn, extension)
      unsigned long insn, extension;
 {
   /* We use this for simulated system calls; we may need to change
@@ -2904,47 +2900,52 @@ void OP_F020 (insn, extension)
   switch (FUNC)
     {
 #if !defined(__GO32__) && !defined(_WIN32)
-      case SYS_fork:
+#ifdef TARGET_SYS_fork
+      case TARGET_SYS_fork:
       RETVAL = fork ();
       break;
-    case SYS_execve:
+#endif
+#ifdef TARGET_SYS_execve
+    case TARGET_SYS_execve:
       RETVAL = execve (MEMPTR (PARM1), (char **) MEMPTR (PARM2),
                       (char **)MEMPTR (PARM3));
       break;
-#ifdef SYS_execv
-    case SYS_execv:
+#endif
+#ifdef TARGET_SYS_execv
+    case TARGET_SYS_execv:
       RETVAL = execve (MEMPTR (PARM1), (char **) MEMPTR (PARM2), NULL);
       break;
 #endif
-#endif
+#endif /* ! GO32 and ! WIN32 */
 
-    case SYS_read:
+    case TARGET_SYS_read:
       RETVAL = mn10300_callback->read (mn10300_callback, PARM1,
                                    MEMPTR (PARM2), PARM3);
       break;
-    case SYS_write:
+    case TARGET_SYS_write:
       RETVAL = (int)mn10300_callback->write (mn10300_callback, PARM1,
                                             MEMPTR (PARM2), PARM3);
       break;
-    case SYS_lseek:
+    case TARGET_SYS_lseek:
       RETVAL = mn10300_callback->lseek (mn10300_callback, PARM1, PARM2, PARM3);
       break;
-    case SYS_close:
+    case TARGET_SYS_close:
       RETVAL = mn10300_callback->close (mn10300_callback, PARM1);
       break;
-    case SYS_open:
+    case TARGET_SYS_open:
       RETVAL = mn10300_callback->open (mn10300_callback, MEMPTR (PARM1), PARM2);
       break;
-    case SYS_exit:
+    case TARGET_SYS_exit:
       /* EXIT - caller can look in PARM1 to work out the 
         reason */
       if (PARM1 == 0xdead)
        State.exception = SIGABRT;
       else
        State.exception = SIGQUIT;
+      State.exited = 1;
       break;
 
-    case SYS_stat:     /* added at hmsi */
+    case TARGET_SYS_stat:      /* added at hmsi */
       /* stat system call */
       {
        struct stat host_stat;
@@ -2969,19 +2970,21 @@ void OP_F020 (insn, extension)
       }
       break;
 
-    case SYS_chown:
+#ifdef TARGET_SYS_chown
+    case TARGET_SYS_chown:
       RETVAL = chown (MEMPTR (PARM1), PARM2, PARM3);
       break;
-    case SYS_chmod:
+#endif
+    case TARGET_SYS_chmod:
       RETVAL = chmod (MEMPTR (PARM1), PARM2);
       break;
-#ifdef SYS_time
-    case SYS_time:
+#ifdef TARGET_SYS_time
+    case TARGET_SYS_time:
       RETVAL = time ((void*) MEMPTR (PARM1));
       break;
 #endif
-#ifdef SYS_times
-    case SYS_times:
+#ifdef TARGET_SYS_times
+    case TARGET_SYS_times:
       {
        struct tms tms;
        RETVAL = times (&tms);
@@ -2992,7 +2995,8 @@ void OP_F020 (insn, extension)
        break;
       }
 #endif
-    case SYS_gettimeofday:
+#ifdef TARGET_SYS_gettimeofday
+    case TARGET_SYS_gettimeofday:
       {
        struct timeval t;
        struct timezone tz;
@@ -3003,8 +3007,9 @@ void OP_F020 (insn, extension)
        store_word (PARM2 + 4, tz.tz_dsttime);
        break;
       }
-#ifdef SYS_utime
-    case SYS_utime:
+#endif
+#ifdef TARGET_SYS_utime
+    case TARGET_SYS_utime:
       /* Cast the second argument to void *, to avoid type mismatch
         if a prototype is present.  */
       RETVAL = utime (MEMPTR (PARM1), (void *) MEMPTR (PARM2));
@@ -3057,8 +3062,8 @@ void OP_F600 (insn, extension)
   unsigned long long temp;
   int n, z;
 
-  temp = ((signed long)State.regs[REG_D0 + REG0 (insn)]
-          *  (signed long)State.regs[REG_D0 + REG1 (insn)]);
+  temp = ((signed64)(signed32)State.regs[REG_D0 + REG0 (insn)]
+          *  (signed64)(signed32)State.regs[REG_D0 + REG1 (insn)]);
   State.regs[REG_D0 + REG0 (insn)] = temp & 0xffffffff;
   State.regs[REG_MDRQ] = (temp & 0xffffffff00000000LL) >> 32;;
   z = (State.regs[REG_D0 + REG0 (insn)] == 0);
@@ -3074,8 +3079,8 @@ void OP_F90000 (insn, extension)
   unsigned long long temp;
   int n, z;
 
-  temp = ((signed long)State.regs[REG_D0 + REG0_8 (insn)]
-          * (signed long)SEXT8 (insn & 0xff));
+  temp = ((signed64)(signed32)State.regs[REG_D0 + REG0_8 (insn)]
+          * (signed64)(signed32)SEXT8 (insn & 0xff));
   State.regs[REG_D0 + REG0_8 (insn)] = temp & 0xffffffff;
   State.regs[REG_MDRQ] = (temp & 0xffffffff00000000LL) >> 32;;
   z = (State.regs[REG_D0 + REG0_8 (insn)] == 0);
@@ -3091,8 +3096,8 @@ void OP_FB000000 (insn, extension)
   unsigned long long temp;
   int n, z;
 
-  temp = ((signed long)State.regs[REG_D0 + REG0_16 (insn)]
-          * (signed long)SEXT16 (insn & 0xffff));
+  temp = ((signed64)(signed32)State.regs[REG_D0 + REG0_16 (insn)]
+          * (signed64)(signed32)SEXT16 (insn & 0xffff));
   State.regs[REG_D0 + REG0_16 (insn)] = temp & 0xffffffff;
   State.regs[REG_MDRQ] = (temp & 0xffffffff00000000LL) >> 32;;
   z = (State.regs[REG_D0 + REG0_16 (insn)] == 0);
@@ -3108,8 +3113,8 @@ void OP_FD000000 (insn, extension)
   unsigned long long temp;
   int n, z;
 
-  temp = ((signed long)State.regs[REG_D0 + REG0_16 (insn)]
-          * (signed long)(((insn & 0xffff) << 16) + extension));
+  temp = ((signed64)(signed32)State.regs[REG_D0 + REG0_16 (insn)]
+          * (signed64)(signed32)(((insn & 0xffff) << 16) + extension));
   State.regs[REG_D0 + REG0_16 (insn)] = temp & 0xffffffff;
   State.regs[REG_MDRQ] = (temp & 0xffffffff00000000LL) >> 32;;
   z = (State.regs[REG_D0 + REG0_16 (insn)] == 0);
@@ -3125,7 +3130,8 @@ void OP_F610 (insn, extension)
   unsigned long long temp;
   int n, z;
 
-  temp = (State.regs[REG_D0 + REG0 (insn)] * State.regs[REG_D0 + REG1 (insn)]);
+  temp = ((unsigned64) State.regs[REG_D0 + REG0 (insn)]
+         * (unsigned64) State.regs[REG_D0 + REG1 (insn)]);
   State.regs[REG_D0 + REG0 (insn)] = temp & 0xffffffff;
   State.regs[REG_MDRQ] = (temp & 0xffffffff00000000LL) >> 32;;
   z = (State.regs[REG_D0 + REG0 (insn)] == 0);
@@ -3141,7 +3147,8 @@ void OP_F91400 (insn, extension)
   unsigned long long temp;
   int n, z;
 
-  temp = (State.regs[REG_D0 + REG0_8 (insn)] * SEXT8 (insn & 0xff));
+  temp = ((unsigned64)State.regs[REG_D0 + REG0_8 (insn)]
+         * (unsigned64)SEXT8 (insn & 0xff));
   State.regs[REG_D0 + REG0_8 (insn)] = temp & 0xffffffff;
   State.regs[REG_MDRQ] = (temp & 0xffffffff00000000LL) >> 32;;
   z = (State.regs[REG_D0 + REG0_8 (insn)] == 0);
@@ -3157,7 +3164,8 @@ void OP_FB140000 (insn, extension)
   unsigned long long temp;
   int n, z;
 
-  temp = (State.regs[REG_D0 + REG0_16 (insn)] * SEXT16 (insn & 0xffff));
+  temp = ((unsigned64)State.regs[REG_D0 + REG0_16 (insn)]
+         * (unsigned64) SEXT16 (insn & 0xffff));
   State.regs[REG_D0 + REG0_16 (insn)] = temp & 0xffffffff;
   State.regs[REG_MDRQ] = (temp & 0xffffffff00000000LL) >> 32;;
   z = (State.regs[REG_D0 + REG0_16 (insn)] == 0);
@@ -3173,8 +3181,8 @@ void OP_FD140000 (insn, extension)
   unsigned long long temp;
   int n, z;
 
-  temp = (State.regs[REG_D0 + REG0_16 (insn)]
-          * (((insn & 0xffff) << 16) + extension));
+  temp = ((unsigned64)State.regs[REG_D0 + REG0_16 (insn)]
+          * (unsigned64)(((insn & 0xffff) << 16) + extension));
   State.regs[REG_D0 + REG0_16 (insn)] = temp & 0xffffffff;
   State.regs[REG_MDRQ] = (temp & 0xffffffff00000000LL) >> 32;;
   z = (State.regs[REG_D0 + REG0_16 (insn)] == 0);