Add emulation of double word load and store instructions.
This commit is contained in:
parent
0aec643be7
commit
760a7bbec5
2 changed files with 348 additions and 3 deletions
|
@ -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.
|
||||
|
|
343
sim/arm/armemu.c
343
sim/arm/armemu.c
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue