This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[patch] ARM Simulator support for LDRD and STRD


Hi Guys,

  One thing omitted from the recent XScale contribution was emulation
  for the double word load and store instructions present on the
  StrongARM and XScale.  The patch below adds this support.

Cheers
	Nick

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.

Index: sim/arm/armemu.c
===================================================================
RCS file: /cvs/src//src/sim/arm/armemu.c,v
retrieving revision 1.14
diff -p -r1.14 armemu.c
*** armemu.c	2000/11/30 01:55:12	1.14
--- armemu.c	2000/12/08 01:32:09
*************** static unsigned StoreHalfWord (ARMul_Sta
*** 39,44 ****
--- 39,46 ----
  			       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,
*************** static unsigned Multiply64 (ARMul_State 
*** 51,56 ****
--- 53,60 ----
  			    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 */
*************** ARMul_Emulate26 (register ARMul_State * 
*** 610,616 ****
  		  SHDOWNWB ();
  		  break;
  		}
! 	      /* TODO: CHECK: should 0xD and 0xF generate undefined intruction aborts? */
  #endif
  	      if (BITS (4, 7) == 9)
  		{		/* MUL */
--- 614,629 ----
  		  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
  	      if (BITS (4, 7) == 9)
  		{		/* MUL */
*************** ARMul_Emulate26 (register ARMul_State * 
*** 769,774 ****
--- 782,797 ----
  		  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;
*************** ARMul_Emulate26 (register ARMul_State * 
*** 847,852 ****
--- 870,885 ----
  		  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)
*************** ARMul_Emulate26 (register ARMul_State * 
*** 971,976 ****
--- 1004,1019 ----
  		  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)
*************** ARMul_Emulate26 (register ARMul_State * 
*** 1130,1135 ****
--- 1173,1188 ----
  		  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 */
*************** ARMul_Emulate26 (register ARMul_State * 
*** 1274,1279 ****
--- 1327,1342 ----
  		  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)
  		{
*************** ARMul_Emulate26 (register ARMul_State * 
*** 1428,1433 ****
--- 1491,1506 ----
  		  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 */
*************** ARMul_Emulate26 (register ARMul_State * 
*** 1573,1578 ****
--- 1646,1661 ----
  		  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 */
*************** ARMul_Emulate26 (register ARMul_State * 
*** 1635,1640 ****
--- 1718,1733 ----
  		  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;
*************** ARMul_Emulate26 (register ARMul_State * 
*** 1663,1668 ****
--- 1756,1771 ----
  		  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);
*************** ARMul_Emulate26 (register ARMul_State * 
*** 1689,1694 ****
--- 1792,1807 ----
  		  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;
*************** ARMul_Emulate26 (register ARMul_State * 
*** 1717,1722 ****
--- 1830,1845 ----
  		  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);
*************** LoadByte (ARMul_State * state, ARMword i
*** 3831,3836 ****
--- 3954,4173 ----
  }
  
  /***************************************************************************\
+ * 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.     *
  \***************************************************************************/
  

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]