aboutsummaryrefslogtreecommitdiff
path: root/sim/arm/armemu.c
diff options
context:
space:
mode:
Diffstat (limited to 'sim/arm/armemu.c')
-rw-r--r--sim/arm/armemu.c343
1 files changed, 340 insertions, 3 deletions
diff --git a/sim/arm/armemu.c b/sim/arm/armemu.c
index 6413728..e0b2dd2 100644
--- a/sim/arm/armemu.c
+++ b/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);
@@ -3831,6 +3954,220 @@ LoadByte (ARMul_State * state, ARMword instr, ARMword address, int signextend)
}
/***************************************************************************\
+* 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)
{