Add emulation of double word load and store instructions.

This commit is contained in:
Nick Clifton 2000-12-08 01:38:47 +00:00
parent 0aec643be7
commit 760a7bbec5
2 changed files with 348 additions and 3 deletions

View 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.

View 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)
{