Add emulation of double word load and store instructions.
authorNick Clifton <nickc@redhat.com>
Fri, 8 Dec 2000 01:38:47 +0000 (01:38 +0000)
committerNick Clifton <nickc@redhat.com>
Fri, 8 Dec 2000 01:38:47 +0000 (01:38 +0000)
sim/arm/ChangeLog
sim/arm/armemu.c

index ed472d4781a9b00ea63159c31f34def3f6cd1df6..1c21cb0d457c69318090015ebd2ce723180896a1 100644 (file)
@@ -1,3 +1,11 @@
+2000-12-07  Nick Clifton  <nickc@redhat.com>
+
+       * armemu.c (ARMul_Emulate26): Detect double word load and
+       store instructions and call emulation routines.
+       (Handle_Load_Double): Emulate a double word load instruction.
+       (Handle_Store_Double): Emulate a double word store
+       instruction.
+
 2000-12-03  Nick Clifton  <nickc@redhat.com>
 
        * armos.c: Fix formatting.
index 6413728b771206442498dbd2d81996e48298abaa..e0b2dd25a21c97fa8777d8ddb66857eeb37b9eff 100644 (file)
@@ -39,6 +39,8 @@ static unsigned StoreHalfWord (ARMul_State * state, ARMword instr,
                               ARMword address);
 static unsigned StoreByte (ARMul_State * state, ARMword instr,
                           ARMword address);
+static unsigned StoreDoubleWord (ARMul_State * state, ARMword instr,
+                                ARMword address);
 static void LoadMult (ARMul_State * state, ARMword address, ARMword instr,
                      ARMword WBBase);
 static void StoreMult (ARMul_State * state, ARMword address, ARMword instr,
@@ -51,6 +53,8 @@ static unsigned Multiply64 (ARMul_State * state, ARMword instr,
                            int signextend, int scc);
 static unsigned MultiplyAdd64 (ARMul_State * state, ARMword instr,
                               int signextend, int scc);
+static void Handle_Load_Double (ARMul_State * state, ARMword instr);
+static void Handle_Store_Double (ARMul_State * state, ARMword instr);
 
 #define LUNSIGNED (0)          /* unsigned operation */
 #define LSIGNED   (1)          /* signed operation */
@@ -407,7 +411,7 @@ ARMul_Emulate26 (register ARMul_State * state)
            }
          if (state->Debug)
            {
-             fprintf (stderr, "At %08lx Instr %08lx Mode %02lx\n", pc, instr,
+             fprintf (stderr, "sim: At %08lx Instr %08lx Mode %02lx\n", pc, instr,
                       state->Mode);
              (void) fgetc (stdin);
            }
@@ -610,7 +614,16 @@ ARMul_Emulate26 (register ARMul_State * state)
                  SHDOWNWB ();
                  break;
                }
-             /* TODO: CHECK: should 0xD and 0xF generate undefined intruction aborts? */
+             if (BITS (4, 7) == 0xD)
+               {
+                 Handle_Load_Double (state, instr);
+                 break;
+               }
+             if (BITS (4, 7) == 0xE)
+               {
+                 Handle_Store_Double (state, instr);
+                 break;
+               }
 #endif
              if (BITS (4, 7) == 9)
                {               /* MUL */
@@ -769,6 +782,16 @@ ARMul_Emulate26 (register ARMul_State * state)
                  SHDOWNWB ();
                  break;
                }
+             if (BITS (4, 7) == 0xD)
+               {
+                 Handle_Load_Double (state, instr);
+                 break;
+               }
+             if (BITS (4, 7) == 0xE)
+               {
+                 Handle_Store_Double (state, instr);
+                 break;
+               }
 #endif
              rhs = DPRegRHS;
              dest = LHS - rhs;
@@ -847,6 +870,16 @@ ARMul_Emulate26 (register ARMul_State * state)
                  SHUPWB ();
                  break;
                }
+             if (BITS (4, 7) == 0xD)
+               {
+                 Handle_Load_Double (state, instr);
+                 break;
+               }
+             if (BITS (4, 7) == 0xE)
+               {
+                 Handle_Store_Double (state, instr);
+                 break;
+               }
 #endif
 #ifdef MODET
              if (BITS (4, 7) == 0x9)
@@ -971,6 +1004,16 @@ ARMul_Emulate26 (register ARMul_State * state)
                  SHUPWB ();
                  break;
                }
+             if (BITS (4, 7) == 0xD)
+               {
+                 Handle_Load_Double (state, instr);
+                 break;
+               }
+             if (BITS (4, 7) == 0xE)
+               {
+                 Handle_Store_Double (state, instr);
+                 break;
+               }
 #endif
 #ifdef MODET
              if (BITS (4, 7) == 0x9)
@@ -1130,6 +1173,16 @@ ARMul_Emulate26 (register ARMul_State * state)
                  SHPREDOWN ();
                  break;
                }
+             if (BITS (4, 7) == 0xD)
+               {
+                 Handle_Load_Double (state, instr);
+                 break;
+               }
+             if (BITS (4, 7) == 0xE)
+               {
+                 Handle_Store_Double (state, instr);
+                 break;
+               }
 #endif
              if (BITS (4, 11) == 9)
                {               /* SWP */
@@ -1274,6 +1327,16 @@ ARMul_Emulate26 (register ARMul_State * state)
                  WriteR15Branch (state, state->Reg[RHSReg]);
                  break;
                }
+             if (BITS (4, 7) == 0xD)
+               {
+                 Handle_Load_Double (state, instr);
+                 break;
+               }
+             if (BITS (4, 7) == 0xE)
+               {
+                 Handle_Store_Double (state, instr);
+                 break;
+               }
 #endif
              if (state->is_v5)
                {
@@ -1428,6 +1491,16 @@ ARMul_Emulate26 (register ARMul_State * state)
                  SHPREDOWN ();
                  break;
                }
+             if (BITS (4, 7) == 0xD)
+               {
+                 Handle_Load_Double (state, instr);
+                 break;
+               }
+             if (BITS (4, 7) == 0xE)
+               {
+                 Handle_Store_Double (state, instr);
+                 break;
+               }
 #endif
              if (BITS (4, 11) == 9)
                {               /* SWP */
@@ -1573,6 +1646,16 @@ ARMul_Emulate26 (register ARMul_State * state)
                  SHPREDOWNWB ();
                  break;
                }
+             if (BITS (4, 7) == 0xD)
+               {
+                 Handle_Load_Double (state, instr);
+                 break;
+               }
+             if (BITS (4, 7) == 0xE)
+               {
+                 Handle_Store_Double (state, instr);
+                 break;
+               }
 #endif
              if (DESTReg == 15)
                {               /* MSR */
@@ -1635,6 +1718,16 @@ ARMul_Emulate26 (register ARMul_State * state)
                  SHPREUP ();
                  break;
                }
+             if (BITS (4, 7) == 0xD)
+               {
+                 Handle_Load_Double (state, instr);
+                 break;
+               }
+             if (BITS (4, 7) == 0xE)
+               {
+                 Handle_Store_Double (state, instr);
+                 break;
+               }
 #endif
              rhs = DPRegRHS;
              dest = LHS | rhs;
@@ -1663,6 +1756,16 @@ ARMul_Emulate26 (register ARMul_State * state)
                  SHPREUPWB ();
                  break;
                }
+             if (BITS (4, 7) == 0xD)
+               {
+                 Handle_Load_Double (state, instr);
+                 break;
+               }
+             if (BITS (4, 7) == 0xE)
+               {
+                 Handle_Store_Double (state, instr);
+                 break;
+               }
 #endif
              dest = DPRegRHS;
              WRITEDEST (dest);
@@ -1689,6 +1792,16 @@ ARMul_Emulate26 (register ARMul_State * state)
                  SHPREUP ();
                  break;
                }
+             if (BITS (4, 7) == 0xD)
+               {
+                 Handle_Load_Double (state, instr);
+                 break;
+               }
+             else if (BITS (4, 7) == 0xE)
+               {
+                 Handle_Store_Double (state, instr);
+                 break;
+               }
 #endif
              rhs = DPRegRHS;
              dest = LHS & ~rhs;
@@ -1717,6 +1830,16 @@ ARMul_Emulate26 (register ARMul_State * state)
                  SHPREUPWB ();
                  break;
                }
+             if (BITS (4, 7) == 0xD)
+               {
+                 Handle_Load_Double (state, instr);
+                 break;
+               }
+             if (BITS (4, 7) == 0xE)
+               {
+                 Handle_Store_Double (state, instr);
+                 break;
+               }
 #endif
              dest = ~DPRegRHS;
              WRITEDEST (dest);
@@ -3830,6 +3953,220 @@ LoadByte (ARMul_State * state, ARMword instr, ARMword address, int signextend)
   return (DESTReg != LHSReg);
 }
 
+/***************************************************************************\
+* This function does the work of loading two words for a LDRD instruction. *
+\***************************************************************************/
+
+static void
+Handle_Load_Double (ARMul_State * state, ARMword instr)
+{
+  ARMword dest_reg;
+  ARMword addr_reg;
+  ARMword write_back  = BIT (21);
+  ARMword immediate   = BIT (22);
+  ARMword add_to_base = BIT (23);        
+  ARMword pre_indexed = BIT (24);
+  ARMword offset;
+  ARMword addr;
+  ARMword sum;
+  ARMword base;
+  ARMword value1;
+  ARMword value2;
+  
+  BUSUSEDINCPCS;
+
+  /* If the writeback bit is set, the pre-index bit must be clear.  */
+  if (write_back && ! pre_indexed)
+    {
+      ARMul_UndefInstr (state, instr);
+      return;
+    }
+  
+  /* Extract the base address register.  */
+  addr_reg = LHSReg;
+  
+  /* Extract the destination register and check it.  */
+  dest_reg = DESTReg;
+  
+  /* Destination register must be even.  */
+  if ((dest_reg & 1)
+    /* Destination register cannot be LR.  */
+      || (dest_reg == 14))
+    {
+      ARMul_UndefInstr (state, instr);
+      return;
+    }
+
+  /* Compute the base address.  */
+  base = state->Reg[addr_reg];
+
+  /* Compute the offset.  */
+  offset = immediate ? ((BITS (8, 11) << 4) | BITS (0, 3)) : state->Reg[RHSReg];
+
+  /* Compute the sum of the two.  */
+  if (add_to_base)
+    sum = base + offset;
+  else
+    sum = base - offset;
+  
+  /* If this is a pre-indexed mode use the sum.  */
+  if (pre_indexed)
+    addr = sum;
+  else
+    addr = base;
+
+  /* The address must be aligned on a 8 byte boundary.  */
+  if (addr & 0x7)
+    {
+#ifdef ABORTS
+      ARMul_DATAABORT (addr);
+#else
+      ARMul_UndefInstr (state, instr);
+#endif
+      return;
+    }
+
+  /* For pre indexed or post indexed addressing modes,
+     check that the destination registers do not overlap
+     the address registers.  */
+  if ((! pre_indexed || write_back)
+      && (   addr_reg == dest_reg
+         || addr_reg == dest_reg + 1))
+    {
+      ARMul_UndefInstr (state, instr);
+      return;
+    }
+
+  /* Load the words.  */
+  value1 = ARMul_LoadWordN (state, addr);
+  value2 = ARMul_LoadWordN (state, addr + 4);
+
+  /* Check for data aborts.  */
+  if (state->Aborted)
+    {
+      TAKEABORT;
+      return;
+    }
+  
+  ARMul_Icycles (state, 2, 0L);
+
+  /* Store the values.  */
+  state->Reg[dest_reg] = value1;
+  state->Reg[dest_reg + 1] = value2;
+  
+  /* Do the post addressing and writeback.  */
+  if (! pre_indexed)
+    addr = sum;
+  
+  if (! pre_indexed || write_back)
+    state->Reg[addr_reg] = addr;
+}
+
+/***************************************************************************\
+* This function does the work of storing two words for a STRD instruction. *
+\***************************************************************************/
+
+static void
+Handle_Store_Double (ARMul_State * state, ARMword instr)
+{
+  ARMword src_reg;
+  ARMword addr_reg;
+  ARMword write_back  = BIT (21);
+  ARMword immediate   = BIT (22);
+  ARMword add_to_base = BIT (23);        
+  ARMword pre_indexed = BIT (24);
+  ARMword offset;
+  ARMword addr;
+  ARMword sum;
+  ARMword base;
+
+  BUSUSEDINCPCS;
+
+  /* If the writeback bit is set, the pre-index bit must be clear.  */
+  if (write_back && ! pre_indexed)
+    {
+      ARMul_UndefInstr (state, instr);
+      return;
+    }
+  
+  /* Extract the base address register.  */
+  addr_reg = LHSReg;
+  
+  /* Base register cannot be PC.  */
+  if (addr_reg == 15)
+    {
+      ARMul_UndefInstr (state, instr);
+      return;
+    }
+  
+  /* Extract the source register.  */
+  src_reg = DESTReg;
+  
+  /* Source register must be even.  */
+  if (src_reg & 1)
+    {
+      ARMul_UndefInstr (state, instr);
+      return;
+    }
+
+  /* Compute the base address.  */
+  base = state->Reg[addr_reg];
+
+  /* Compute the offset.  */
+  offset = immediate ? ((BITS (8, 11) << 4) | BITS (0, 3)) : state->Reg[RHSReg];
+
+  /* Compute the sum of the two.  */
+  if (add_to_base)
+    sum = base + offset;
+  else
+    sum = base - offset;
+  
+  /* If this is a pre-indexed mode use the sum.  */
+  if (pre_indexed)
+    addr = sum;
+  else
+    addr = base;
+
+  /* The address must be aligned on a 8 byte boundary.  */
+  if (addr & 0x7)
+    {
+#ifdef ABORTS
+      ARMul_DATAABORT (addr);
+#else
+      ARMul_UndefInstr (state, instr);
+#endif
+      return;
+    }
+
+  /* For pre indexed or post indexed addressing modes,
+     check that the destination registers do not overlap
+     the address registers.  */
+  if ((! pre_indexed || write_back)
+      && (   addr_reg == src_reg
+         || addr_reg == src_reg + 1))
+    {
+      ARMul_UndefInstr (state, instr);
+      return;
+    }
+
+  /* Load the words.  */
+  ARMul_StoreWordN (state, addr, state->Reg[src_reg]);
+  ARMul_StoreWordN (state, addr + 4, state->Reg[src_reg + 1]);
+  
+  if (state->Aborted)
+    {
+      TAKEABORT;
+      return;
+    }
+  
+  /* Do the post addressing and writeback.  */
+  if (! pre_indexed)
+    addr = sum;
+  
+  if (! pre_indexed || write_back)
+    state->Reg[addr_reg] = addr;
+}
+
 /***************************************************************************\
 * This function does the work of storing a word from a STR instruction.     *
 \***************************************************************************/
@@ -4325,7 +4662,7 @@ Multiply64 (ARMul_State * state, ARMword instr, int msigned, int scc)
       state->Reg[nRdHi] = RdHi;
     }                          /* else undefined result */
   else
-    fprintf (stderr, "MULTIPLY64 - INVALID ARGUMENTS\n");
+    fprintf (stderr, "sim: MULTIPLY64 - INVALID ARGUMENTS\n");
 
   if (scc)
     {