aboutsummaryrefslogtreecommitdiff
path: root/sim/arm
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2000-11-30 01:55:12 +0000
committerNick Clifton <nickc@redhat.com>2000-11-30 01:55:12 +0000
commitf1129fb8ff9938330168992fb23ed35e37d82d61 (patch)
treeacb0e04459f40941f698cb91b1382354c885bb72 /sim/arm
parent2a1aa0e97cefed26213a2b124e91e8d74d11a5d6 (diff)
downloadgdb-f1129fb8ff9938330168992fb23ed35e37d82d61.zip
gdb-f1129fb8ff9938330168992fb23ed35e37d82d61.tar.gz
gdb-f1129fb8ff9938330168992fb23ed35e37d82d61.tar.bz2
Add support for ARM's v5TE architecture and Intel's XScale extenstions
Diffstat (limited to 'sim/arm')
-rw-r--r--sim/arm/ChangeLog28
-rw-r--r--sim/arm/armcopro.c1208
-rw-r--r--sim/arm/armdefs.h9
-rw-r--r--sim/arm/armemu.c496
-rw-r--r--sim/arm/armemu.h23
-rw-r--r--sim/arm/arminit.c22
-rw-r--r--sim/arm/armos.c67
-rw-r--r--sim/arm/armsupp.c2
-rw-r--r--sim/arm/thumbemu.c101
-rw-r--r--sim/arm/wrapper.c57
10 files changed, 1763 insertions, 250 deletions
diff --git a/sim/arm/ChangeLog b/sim/arm/ChangeLog
index b66a340..2c893e0 100644
--- a/sim/arm/ChangeLog
+++ b/sim/arm/ChangeLog
@@ -1,3 +1,30 @@
+2000-11-29 Nick Clifton <nickc@redhat.com>
+
+ * armdefs.h (State): Add 'v5e' and 'xscale' fields.
+ (ARM_v5e_Prop): Define.
+ (ARM_XScale_Prop): Define.
+
+ * wrapper.c (sim_create_inferior): Select processor based on
+ machine number.
+ (SWI_vector_installed): New boolean. Set to true if the SWI
+ vector address is written to by the executable.
+
+ * arminit.c (ARMul_NewState): Switch default to 32 bit mode.
+ (ARMul_SelectProcessor): Initialise v5e and xscale signals.
+ (ARMul_Abort): Fix calculation of LR address.
+
+ * armos.c (ARMul_OSHandleSWI): If a SWI vector has been installed
+ and a SWI is not handled by the simulator, pass the SWI off to the
+ vector, otherwise issue a warning message and continue.
+
+ * armsupp.c (ARMul_CPSRAltered): Set S bit aswell.
+
+ * thumbemu.c: Add v5 instruction simulation.
+ * armemu.c: Add v5, XScale and El Segundo instruction simulation.
+
+ * armcopro.c: Add XScale co-processor emulation.
+ * armemu.h: Add exported XScale co-processor functions.
+
2000-09-15 Nick Clifton <nickc@redhat.com>
* armdefs.h: Rename StrongARM property to v4_ARM and add v5 ARM
@@ -189,7 +216,6 @@ Thu Sep 2 18:15:53 1999 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
-
1999-05-08 Felix Lee <flee@cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
diff --git a/sim/arm/armcopro.c b/sim/arm/armcopro.c
index 48be680..db7ee60 100644
--- a/sim/arm/armcopro.c
+++ b/sim/arm/armcopro.c
@@ -19,37 +19,880 @@
#include "armemu.h"
#include "ansidecl.h"
-extern unsigned ARMul_CoProInit (ARMul_State * state);
-extern void ARMul_CoProExit (ARMul_State * state);
-extern void ARMul_CoProAttach (ARMul_State * state, unsigned number,
- ARMul_CPInits * init, ARMul_CPExits * exit,
- ARMul_LDCs * ldc, ARMul_STCs * stc,
- ARMul_MRCs * mrc, ARMul_MCRs * mcr,
- ARMul_CDPs * cdp,
- ARMul_CPReads * read, ARMul_CPWrites * write);
-extern void ARMul_CoProDetach (ARMul_State * state, unsigned number);
+/* Dummy Co-processors. */
+static unsigned
+NoCoPro3R (ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned a ATTRIBUTE_UNUSED,
+ ARMword b ATTRIBUTE_UNUSED)
+{
+ return ARMul_CANT;
+}
-/***************************************************************************\
-* Dummy Co-processors *
-\***************************************************************************/
+static unsigned
+NoCoPro4R (ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned a ATTRIBUTE_UNUSED,
+ ARMword b ATTRIBUTE_UNUSED,
+ ARMword c ATTRIBUTE_UNUSED)
+{
+ return ARMul_CANT;
+}
+
+static unsigned
+NoCoPro4W (ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned a ATTRIBUTE_UNUSED,
+ ARMword b ATTRIBUTE_UNUSED,
+ ARMword * c ATTRIBUTE_UNUSED)
+{
+ return ARMul_CANT;
+}
-static unsigned NoCoPro3R (ARMul_State * state, unsigned, ARMword);
-static unsigned NoCoPro4R (ARMul_State * state, unsigned, ARMword, ARMword);
-static unsigned NoCoPro4W (ARMul_State * state, unsigned, ARMword, ARMword *);
+/* The XScale Co-processors. */
-/***************************************************************************\
-* Define Co-Processor instruction handlers here *
-\***************************************************************************/
+/* Coprocessor 15: System Control. */
+
+/* There are two sets of registers for copro 15.
+ One set is available when opcode_2 is 0 and
+ the other set when opcode_2 >= 1. */
+static ARMword XScale_cp15_opcode_2_is_0_Regs[16];
+static ARMword XScale_cp15_opcode_2_is_not_0_Regs[16];
+/* There are also a set of breakpoint registers
+ which are accessed via CRm instead of opcode_2. */
+static ARMword XScale_cp15_DBR1;
+static ARMword XScale_cp15_DBCON;
+static ARMword XScale_cp15_IBCR0;
+static ARMword XScale_cp15_IBCR1;
+
+static unsigned
+XScale_cp15_init (ARMul_State * state ATTRIBUTE_UNUSED)
+{
+ int i;
+
+ for (i = 16; i--;)
+ {
+ XScale_cp15_opcode_2_is_0_Regs[i] = 0;
+ XScale_cp15_opcode_2_is_not_0_Regs[i] = 0;
+ }
+
+ /* Initialise the processor ID. */
+ XScale_cp15_opcode_2_is_0_Regs[0] = 0x69052000;
+
+ /* Initialise the cache type. */
+ XScale_cp15_opcode_2_is_not_0_Regs[0] = 0x0B1AA1AA;
+
+ /* Initialise the ARM Control Register. */
+ XScale_cp15_opcode_2_is_0_Regs[1] = 0x00000078;
+
+}
+
+/* Check an access to a register. */
+
+static unsigned
+check_cp15_access (ARMul_State * state,
+ unsigned reg,
+ unsigned CRm,
+ unsigned opcode_1,
+ unsigned opcode_2)
+{
+ /* Do not allow access to these register in USER mode. */
+ if (state->Mode == USER26MODE || state->Mode == USER32MODE)
+ return ARMul_CANT;
+
+ /* Opcode_1should be zero. */
+ if (opcode_1 != 0)
+ return ARMul_CANT;
+
+ /* Different register have different access requirements. */
+ switch (reg)
+ {
+ case 0:
+ case 1:
+ /* CRm must be 0. Opcode_2 can be anything. */
+ if (CRm != 0)
+ return ARMul_CANT;
+ break;
+ case 2:
+ case 3:
+ /* CRm must be 0. Opcode_2 must be zero. */
+ if ((CRm != 0) || (opcode_2 != 0))
+ return ARMul_CANT;
+ break;
+ case 4:
+ /* Access not allowed. */
+ return ARMul_CANT;
+ case 5:
+ case 6:
+ /* Opcode_2 must be zero. CRm must be 0. */
+ if ((CRm != 0) || (opcode_2 != 0))
+ return ARMul_CANT;
+ break;
+ case 7:
+ /* Permissable combinations:
+ Opcode_2 CRm
+ 0 5
+ 0 6
+ 0 7
+ 1 5
+ 1 6
+ 1 10
+ 4 10
+ 5 2
+ 6 5 */
+ switch (opcode_2)
+ {
+ default: return ARMul_CANT;
+ case 6: if (CRm != 5) return ARMul_CANT; break;
+ case 5: if (CRm != 2) return ARMul_CANT; break;
+ case 4: if (CRm != 10) return ARMul_CANT; break;
+ case 1: if ((CRm != 5) && (CRm != 6) && (CRm != 10)) return ARMul_CANT; break;
+ case 0: if ((CRm < 5) || (CRm > 7)) return ARMul_CANT; break;
+ }
+ break;
+
+ case 8:
+ /* Permissable combinations:
+ Opcode_2 CRm
+ 0 5
+ 0 6
+ 0 7
+ 1 5
+ 1 6 */
+ if (opcode_2 > 1)
+ return ARMul_CANT;
+ if ((CRm < 5) || (CRm > 7))
+ return ARMul_CANT;
+ if (opcode_2 == 1 && CRm == 7)
+ return ARMul_CANT;
+ break;
+ case 9:
+ /* Opcode_2 must be zero or one. CRm must be 1 or 2. */
+ if ( ((CRm != 0) && (CRm != 1))
+ || ((opcode_2 != 1) && (opcode_2 != 2)))
+ return ARMul_CANT;
+ break;
+ case 10:
+ /* Opcode_2 must be zero or one. CRm must be 4 or 8. */
+ if ( ((CRm != 0) && (CRm != 1))
+ || ((opcode_2 != 4) && (opcode_2 != 8)))
+ return ARMul_CANT;
+ break;
+ case 11:
+ /* Access not allowed. */
+ return ARMul_CANT;
+ case 12:
+ /* Access not allowed. */
+ return ARMul_CANT;
+ case 13:
+ /* Opcode_2 must be zero. CRm must be 0. */
+ if ((CRm != 0) || (opcode_2 != 0))
+ return ARMul_CANT;
+ break;
+ case 14:
+ /* Opcode_2 must be 0. CRm must be 0, 3, 4, 8 or 9. */
+ if (opcode_2 != 0)
+ return ARMul_CANT;
+
+ if ((CRm != 0) && (CRm != 3) && (CRm != 4) && (CRm != 8) && (CRm != 9))
+ return ARMul_CANT;
+ break;
+ case 15:
+ /* Opcode_2 must be zero. CRm must be 1. */
+ if ((CRm != 1) || (opcode_2 != 0))
+ return ARMul_CANT;
+ break;
+ default:
+ /* Should never happen. */
+ return ARMul_CANT;
+ }
+
+ return ARMul_DONE;
+}
+
+/* Store a value into one of coprocessor 15's registers. */
+
+void
+write_cp15_reg (unsigned reg, unsigned opcode_2, unsigned CRm, ARMword value)
+{
+ if (opcode_2)
+ {
+ switch (reg)
+ {
+ case 0: /* Cache Type. */
+ /* Writes are not allowed. */
+ return;
+
+ case 1: /* Auxillary Control. */
+ /* Only BITS (5, 4) and BITS (1, 0) can be written. */
+ value &= 0x33;
+ break;
+
+ default:
+ return;
+ }
+
+ XScale_cp15_opcode_2_is_not_0_Regs [reg] = value;
+ }
+ else
+ {
+ switch (reg)
+ {
+ case 0: /* ID. */
+ /* Writes are not allowed. */
+ return;
+
+ case 1: /* ARM Control. */
+ /* Only BITS (13, 11), BITS (9, 7) and BITS (2, 0) can be written.
+ BITS (31, 14) and BIT (10) write as zero, BITS (6, 3) write as one. */
+ value &= 0x00003b87;
+ value |= 0x00000078;
+ break;
+
+ case 2: /* Translation Table Base. */
+ /* Only BITS (31, 14) can be written. */
+ value &= 0xffffc000;
+ break;
+
+ case 3: /* Domain Access Control. */
+ /* All bits writable. */
+ break;
+
+ case 5: /* Fault Status Register. */
+ /* BITS (10, 9) and BITS (7, 0) can be written. */
+ value &= 0x000006ff;
+ break;
+
+ case 6: /* Fault Address Register. */
+ /* All bits writable. */
+ break;
+
+ case 7: /* Cache Functions. */
+ case 8: /* TLB Operations. */
+ case 10: /* TLB Lock Down. */
+ /* Ignore writes. */
+ return;
+
+ case 9: /* Data Cache Lock. */
+ /* Only BIT (0) can be written. */
+ value &= 0x1;
+ break;
+
+ case 13: /* Process ID. */
+ /* Only BITS (31, 25) are writable. */
+ value &= 0xfe000000;
+ break;
+
+ case 14: /* DBR0, DBR1, DBCON, IBCR0, IBCR1 */
+ /* All bits can be written. Which register is accessed is
+ dependent upon CRm. */
+ switch (CRm)
+ {
+ case 0: /* DBR0 */
+ break;
+ case 3: /* DBR1 */
+ XScale_cp15_DBR1 = value;
+ break;
+ case 4: /* DBCON */
+ XScale_cp15_DBCON = value;
+ break;
+ case 8: /* IBCR0 */
+ XScale_cp15_IBCR0 = value;
+ break;
+ case 9: /* IBCR1 */
+ XScale_cp15_IBCR1 = value;
+ break;
+ default:
+ return;
+ }
+ break;
+
+ case 15: /* Coprpcessor Access Register. */
+ /* Access is only valid if CRm == 1. */
+ if (CRm != 1)
+ return;
+
+ /* Only BITS (13, 0) may be written. */
+ value &= 0x00003fff;
+ break;
+
+ default:
+ return;
+ }
+
+ XScale_cp15_opcode_2_is_0_Regs [reg] = value;
+ }
+
+ return;
+}
+
+/* Return the value in a cp13 register. */
+
+static ARMword
+read_cp15_reg (unsigned reg, unsigned opcode_2, unsigned CRm)
+{
+ if (opcode_2 == 0)
+ {
+ if (reg == 15 && CRm != 1)
+ return 0;
+
+ if (reg == 14)
+ {
+ switch (CRm)
+ {
+ case 3: return XScale_cp15_DBR1;
+ case 4: return XScale_cp15_DBCON;
+ case 8: return XScale_cp15_IBCR0;
+ case 9: return XScale_cp15_IBCR1;
+ default:
+ break;
+ }
+ }
+
+ return XScale_cp15_opcode_2_is_0_Regs [reg];
+ }
+ else
+ return XScale_cp15_opcode_2_is_not_0_Regs [reg];
+
+ return 0;
+}
+
+static unsigned
+XScale_cp15_LDC (ARMul_State * state, unsigned type, ARMword instr, ARMword data)
+{
+ unsigned reg = BITS (12, 15);
+ unsigned result;
+
+ result = check_cp15_access (state, reg, 0, 0, 0);
+
+ if (result == ARMul_DONE && type == ARMul_DATA)
+ write_cp15_reg (reg, 0, 0, data);
+
+ return result;
+}
+
+static unsigned
+XScale_cp15_STC (ARMul_State * state, unsigned type, ARMword instr, ARMword * data)
+{
+ unsigned reg = BITS (12, 15);
+ unsigned result;
+
+ result = check_cp15_access (state, reg, 0, 0, 0);
+
+ if (result == ARMul_DONE && type == ARMul_DATA)
+ * data = read_cp15_reg (reg, 0, 0);
+
+ return result;
+}
+
+static unsigned
+XScale_cp15_MRC (ARMul_State * state,
+ unsigned type ATTRIBUTE_UNUSED,
+ ARMword instr,
+ ARMword * value)
+{
+ unsigned opcode_2 = BITS (5, 7);
+ unsigned CRm = BITS (0, 3);
+ unsigned reg = BITS (16, 19);
+ unsigned result;
+
+ result = check_cp15_access (state, reg, CRm, BITS (21, 23), opcode_2);
+
+ if (result == ARMul_DONE)
+ * value = read_cp15_reg (reg, opcode_2, CRm);
+
+ return result;
+}
+
+static unsigned
+XScale_cp15_MCR (ARMul_State * state,
+ unsigned type ATTRIBUTE_UNUSED,
+ ARMword instr,
+ ARMword value)
+{
+ unsigned opcode_2 = BITS (5, 7);
+ unsigned CRm = BITS (0, 3);
+ unsigned reg = BITS (16, 19);
+ unsigned result;
+
+ result = check_cp15_access (state, reg, CRm, BITS (21, 23), opcode_2);
+
+ if (result == ARMul_DONE)
+ write_cp15_reg (reg, opcode_2, CRm, value);
+
+ return result;
+}
+
+static unsigned
+XScale_cp15_read_reg (ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned reg,
+ ARMword * value)
+{
+ /* FIXME: Not sure what to do about the alternative register set
+ here. For now default to just accessing CRm == 0 registers. */
+ * value = read_cp15_reg (reg, 0, 0);
+
+ return TRUE;
+}
+
+static unsigned
+XScale_cp15_write_reg (ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned reg,
+ ARMword value)
+{
+ /* FIXME: Not sure what to do about the alternative register set
+ here. For now default to just accessing CRm == 0 registers. */
+ write_cp15_reg (reg, 0, 0, value);
+
+ return TRUE;
+}
+
+/* Coprocessor 13: Interrupt Controller and Bus Controller. */
+
+/* There are two sets of registers for copro 13.
+ One set (of three registers) is available when CRm is 0
+ and the other set (of six registers) when CRm is 1. */
+
+static ARMword XScale_cp13_CR0_Regs[16];
+static ARMword XScale_cp13_CR1_Regs[16];
+
+static unsigned
+XScale_cp13_init (ARMul_State * state ATTRIBUTE_UNUSED)
+{
+ int i;
+
+ for (i = 16; i--;)
+ {
+ XScale_cp13_CR0_Regs[i] = 0;
+ XScale_cp13_CR1_Regs[i] = 0;
+ }
+}
+
+/* Check an access to a register. */
+
+static unsigned
+check_cp13_access (ARMul_State * state,
+ unsigned reg,
+ unsigned CRm,
+ unsigned opcode_1,
+ unsigned opcode_2)
+{
+ /* Do not allow access to these register in USER mode. */
+ if (state->Mode == USER26MODE || state->Mode == USER32MODE)
+ return ARMul_CANT;
+
+ /* The opcodes should be zero. */
+ if ((opcode_1 != 0) || (opcode_2 != 0))
+ return ARMul_CANT;
+
+ /* Do not allow access to these register if bit 13 of coprocessor
+ 15's register 15 is zero. */
+ if ((XScale_cp15_opcode_2_is_0_Regs[15] & (1 << 13)) == 0)
+ return ARMul_CANT;
+
+ /* Registers 0, 4 and 8 are defined when CRm == 0.
+ Registers 0, 4, 5, 6, 7, 8 are defined when CRm == 1.
+ For all other CRm values undefined behaviour results. */
+ if (CRm == 0)
+ {
+ if (reg == 0 || reg == 4 || reg == 8)
+ return ARMul_DONE;
+ }
+ else if (CRm == 1)
+ {
+ if (reg == 0 || (reg >= 4 && reg <= 8))
+ return ARMul_DONE;
+ }
+
+ return ARMul_CANT;
+}
+
+/* Store a value into one of coprocessor 13's registers. */
+
+static void
+write_cp13_reg (unsigned reg, unsigned CRm, ARMword value)
+{
+ switch (CRm)
+ {
+ case 0:
+ switch (reg)
+ {
+ case 0: /* INTCTL */
+ /* Only BITS (3:0) can be written. */
+ value &= 0xf;
+ break;
+
+ case 4: /* INTSRC */
+ /* No bits may be written. */
+ return;
+
+ case 8: /* INTSTR */
+ /* Only BITS (1:0) can be written. */
+ value &= 0x3;
+ break;
+
+ default:
+ /* Should not happen. Ignore any writes to unimplemented registers. */
+ return;
+ }
+
+ XScale_cp13_CR0_Regs [reg] = value;
+ break;
+
+ case 1:
+ switch (reg)
+ {
+ case 0: /* BCUCTL */
+ /* Only BITS (30:28) and BITS (3:0) can be written.
+ BIT(31) is write ignored. */
+ value &= 0x7000000f;
+ value |= XScale_cp13_CR1_Regs[0] & (1UL << 31);
+ break;
+
+ case 4: /* ELOG0 */
+ case 5: /* ELOG1 */
+ case 6: /* ECAR0 */
+ case 7: /* ECAR1 */
+ /* No bits can be written. */
+ return;
+
+ case 8: /* ECTST */
+ /* Only BITS (7:0) can be written. */
+ value &= 0xff;
+ break;
+
+ default:
+ /* Should not happen. Ignore any writes to unimplemented registers. */
+ return;
+ }
+
+ XScale_cp13_CR1_Regs [reg] = value;
+ break;
+
+ default:
+ /* Should not happen. */
+ break;
+ }
+
+ return;
+}
+
+/* Return the value in a cp13 register. */
+
+static ARMword
+read_cp13_reg (unsigned reg, unsigned CRm)
+{
+ if (CRm == 0)
+ return XScale_cp13_CR0_Regs [reg];
+ else if (CRm == 1)
+ return XScale_cp13_CR1_Regs [reg];
+
+ return 0;
+}
+
+static unsigned
+XScale_cp13_LDC (ARMul_State * state, unsigned type, ARMword instr, ARMword data)
+{
+ unsigned reg = BITS (12, 15);
+ unsigned result;
+
+ result = check_cp13_access (state, reg, 0, 0, 0);
+
+ if (result == ARMul_DONE && type == ARMul_DATA)
+ write_cp13_reg (reg, 0, data);
+
+ return result;
+}
+
+static unsigned
+XScale_cp13_STC (ARMul_State * state, unsigned type, ARMword instr, ARMword * data)
+{
+ unsigned reg = BITS (12, 15);
+ unsigned result;
+
+ result = check_cp13_access (state, reg, 0, 0, 0);
+
+ if (result == ARMul_DONE && type == ARMul_DATA)
+ * data = read_cp13_reg (reg, 0);
+
+ return result;
+}
+
+static unsigned
+XScale_cp13_MRC (ARMul_State * state,
+ unsigned type ATTRIBUTE_UNUSED,
+ ARMword instr,
+ ARMword * value)
+{
+ unsigned CRm = BITS (0, 3);
+ unsigned reg = BITS (16, 19);
+ unsigned result;
+
+ result = check_cp13_access (state, reg, CRm, BITS (21, 23), BITS (5, 7));
+
+ if (result == ARMul_DONE)
+ * value = read_cp13_reg (reg, CRm);
+
+ return result;
+}
+
+static unsigned
+XScale_cp13_MCR (ARMul_State * state,
+ unsigned type ATTRIBUTE_UNUSED,
+ ARMword instr,
+ ARMword value)
+{
+ unsigned CRm = BITS (0, 3);
+ unsigned reg = BITS (16, 19);
+ unsigned result;
+
+ result = check_cp13_access (state, reg, CRm, BITS (21, 23), BITS (5, 7));
+
+ if (result == ARMul_DONE)
+ write_cp13_reg (reg, CRm, value);
+
+ return result;
+}
+
+static unsigned
+XScale_cp13_read_reg
+(
+ ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned reg,
+ ARMword * value
+)
+{
+ /* FIXME: Not sure what to do about the alternative register set
+ here. For now default to just accessing CRm == 0 registers. */
+ * value = read_cp13_reg (reg, 0);
+
+ return TRUE;
+}
+
+static unsigned
+XScale_cp13_write_reg
+(
+ ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned reg,
+ ARMword value
+)
+{
+ /* FIXME: Not sure what to do about the alternative register set
+ here. For now default to just accessing CRm == 0 registers. */
+ write_cp13_reg (reg, 0, value);
+
+ return TRUE;
+}
+
+/* Coprocessor 14: Performance Monitoring, Clock and Power management,
+ Software Debug. */
+
+static ARMword XScale_cp14_Regs[16];
+
+static unsigned
+XScale_cp14_init (ARMul_State * state ATTRIBUTE_UNUSED)
+{
+ int i;
+
+ for (i = 16; i--;)
+ XScale_cp14_Regs[i] = 0;
+}
+
+/* Check an access to a register. */
+
+static unsigned
+check_cp14_access (ARMul_State * state,
+ unsigned reg,
+ unsigned CRm,
+ unsigned opcode1,
+ unsigned opcode2)
+{
+ /* Not allowed to access these register in USER mode. */
+ if (state->Mode == USER26MODE || state->Mode == USER32MODE)
+ return ARMul_CANT;
+
+ /* CRm should be zero. */
+ if (CRm != 0)
+ return ARMul_CANT;
+
+ /* OPcodes should be zero. */
+ if (opcode1 != 0 || opcode2 != 0)
+ return ARMul_CANT;
+
+ /* Accessing registers 4 or 5 has unpredicatable results. */
+ if (reg >= 4 && reg <= 5)
+ return ARMul_CANT;
+
+ return ARMul_DONE;
+}
+
+/* Store a value into one of coprocessor 14's registers. */
+
+void
+write_cp14_reg (unsigned reg, ARMword value)
+{
+ switch (reg)
+ {
+ case 0: /* PMNC */
+ /* Only BITS (27:12), BITS (10:8) and BITS (6:0) can be written. */
+ value &= 0x0ffff77f;
+ break;
+
+ case 4:
+ case 5:
+ /* We should not normally reach this code. The debugger interface
+ can bypass the normal checks though, so it could happen. */
+ value = 0;
+ break;
+
+ case 6: /* CCLKCFG */
+ /* Only BITS (3:0) can be written. */
+ value &= 0xf;
+ break;
+
+ case 7: /* PWRMODE */
+ /* Although BITS (1:0) can be written with non-zero values, this would
+ have the side effect of putting the processor to sleep. Thus in
+ order for the register to be read again, it would have to go into
+ ACTIVE mode, which means that any read will see these bits as zero.
+
+ Rather than trying to implement complex reset-to-zero-upon-read logic
+ we just override the write value with zero. */
+ value = 0;
+ break;
+
+ case 10: /* DCSR */
+ /* Only BITS (31:30), BITS (23:22), BITS (20:16) and BITS (5:0) can
+ be written. */
+ value &= 0xc0df003f;
+ break;
+
+ case 11: /* TBREG */
+ /* No writes are permitted. */
+ value = 0;
+ break;
+
+ case 14: /* TXRXCTRL */
+ /* Only BITS (31:30) can be written. */
+ value &= 0xc0000000;
+ break;
+
+ default:
+ /* All bits can be written. */
+ break;
+ }
+
+ XScale_cp14_Regs [reg] = value;
+}
+
+/* Return the value in a cp14 register. Not a static function since
+ it is used by the code to emulate the BKPT instruction in armemu.c. */
+
+ARMword
+read_cp14_reg (unsigned reg)
+{
+ return XScale_cp14_Regs [reg];
+}
+
+static unsigned
+XScale_cp14_LDC (ARMul_State * state, unsigned type, ARMword instr, ARMword data)
+{
+ unsigned reg = BITS (12, 15);
+ unsigned result;
+
+ result = check_cp14_access (state, reg, 0, 0, 0);
+
+ if (result == ARMul_DONE && type == ARMul_DATA)
+ write_cp14_reg (reg, data);
+
+ return result;
+}
+
+static unsigned
+XScale_cp14_STC (ARMul_State * state, unsigned type, ARMword instr, ARMword * data)
+{
+ unsigned reg = BITS (12, 15);
+ unsigned result;
+
+ result = check_cp14_access (state, reg, 0, 0, 0);
+
+ if (result == ARMul_DONE && type == ARMul_DATA)
+ * data = read_cp14_reg (reg);
+
+ return result;
+}
+
+static unsigned
+XScale_cp14_MRC
+(
+ ARMul_State * state,
+ unsigned type ATTRIBUTE_UNUSED,
+ ARMword instr,
+ ARMword * value
+)
+{
+ unsigned reg = BITS (16, 19);
+ unsigned result;
+
+ result = check_cp14_access (state, reg, BITS (0, 3), BITS (21, 23), BITS (5, 7));
+
+ if (result == ARMul_DONE)
+ * value = read_cp14_reg (reg);
+
+ return result;
+}
+
+static unsigned
+XScale_cp14_MCR
+(
+ ARMul_State * state,
+ unsigned type ATTRIBUTE_UNUSED,
+ ARMword instr,
+ ARMword value
+)
+{
+ unsigned reg = BITS (16, 19);
+ unsigned result;
+
+ result = check_cp14_access (state, reg, BITS (0, 3), BITS (21, 23), BITS (5, 7));
+
+ if (result == ARMul_DONE)
+ write_cp14_reg (reg, value);
+
+ return result;
+}
+
+static unsigned
+XScale_cp14_read_reg
+(
+ ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned reg,
+ ARMword * value
+)
+{
+ * value = read_cp14_reg (reg);
+
+ return TRUE;
+}
+
+static unsigned
+XScale_cp14_write_reg
+(
+ ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned reg,
+ ARMword value
+)
+{
+ write_cp14_reg (reg, value);
+
+ return TRUE;
+}
/* Here's ARMulator's MMU definition. A few things to note:
-1) it has eight registers, but only two are defined.
-2) you can only access its registers with MCR and MRC.
-3) MMU Register 0 (ID) returns 0x41440110
-4) Register 1 only has 4 bits defined. Bits 0 to 3 are unused, bit 4
-controls 32/26 bit program space, bit 5 controls 32/26 bit data space,
-bit 6 controls late abort timimg and bit 7 controls big/little endian.
-*/
+ 1) It has eight registers, but only two are defined.
+ 2) You can only access its registers with MCR and MRC.
+ 3) MMU Register 0 (ID) returns 0x41440110
+ 4) Register 1 only has 4 bits defined. Bits 0 to 3 are unused, bit 4
+ controls 32/26 bit program space, bit 5 controls 32/26 bit data space,
+ bit 6 controls late abort timimg and bit 7 controls big/little endian. */
static ARMword MMUReg[8];
@@ -58,12 +901,17 @@ MMUInit (ARMul_State * state)
{
MMUReg[1] = state->prog32Sig << 4 |
state->data32Sig << 5 | state->lateabtSig << 6 | state->bigendSig << 7;
+
ARMul_ConsolePrint (state, ", MMU present");
- return (TRUE);
+
+ return TRUE;
}
static unsigned
-MMUMRC (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword * value)
+MMUMRC (ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned type ATTRIBUTE_UNUSED,
+ ARMword instr,
+ ARMword * value)
{
int reg = BITS (16, 19) & 7;
@@ -71,16 +919,20 @@ MMUMRC (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type ATTRIBUTE_UNUSED, AR
*value = 0x41440110;
else
*value = MMUReg[reg];
- return (ARMul_DONE);
+
+ return ARMul_DONE;
}
static unsigned
-MMUMCR (ARMul_State * state, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword value)
+MMUMCR (ARMul_State * state,
+ unsigned type ATTRIBUTE_UNUSED,
+ ARMword instr,
+ ARMword value)
{
int reg = BITS (16, 19) & 7;
MMUReg[reg] = value;
-
+
if (reg == 1)
{
ARMword p,d,l,b;
@@ -90,22 +942,22 @@ MMUMCR (ARMul_State * state, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMw
l = state->lateabtSig;
b = state->bigendSig;
- state->prog32Sig = value >> 4 & 1;
- state->data32Sig = value >> 5 & 1;
+ state->prog32Sig = value >> 4 & 1;
+ state->data32Sig = value >> 5 & 1;
state->lateabtSig = value >> 6 & 1;
- state->bigendSig = value >> 7 & 1;
+ state->bigendSig = value >> 7 & 1;
- if (p != state->prog32Sig
+ if ( p != state->prog32Sig
|| d != state->data32Sig
|| l != state->lateabtSig
|| b != state->bigendSig)
- state->Emulate = CHANGEMODE; /* Force ARMulator to notice these now. */
+ /* Force ARMulator to notice these now. */
+ state->Emulate = CHANGEMODE;
}
-
+
return ARMul_DONE;
}
-
static unsigned
MMURead (ARMul_State * state ATTRIBUTE_UNUSED, unsigned reg, ARMword * value)
{
@@ -113,7 +965,8 @@ MMURead (ARMul_State * state ATTRIBUTE_UNUSED, unsigned reg, ARMword * value)
*value = 0x41440110;
else if (reg < 8)
*value = MMUReg[reg];
- return (TRUE);
+
+ return TRUE;
}
static unsigned
@@ -121,7 +974,7 @@ MMUWrite (ARMul_State * state, unsigned reg, ARMword value)
{
if (reg < 8)
MMUReg[reg] = value;
-
+
if (reg == 1)
{
ARMword p,d,l,b;
@@ -131,126 +984,132 @@ MMUWrite (ARMul_State * state, unsigned reg, ARMword value)
l = state->lateabtSig;
b = state->bigendSig;
- state->prog32Sig = value >> 4 & 1;
- state->data32Sig = value >> 5 & 1;
+ state->prog32Sig = value >> 4 & 1;
+ state->data32Sig = value >> 5 & 1;
state->lateabtSig = value >> 6 & 1;
- state->bigendSig = value >> 7 & 1;
-
+ state->bigendSig = value >> 7 & 1;
- if (p != state->prog32Sig
+ if ( p != state->prog32Sig
|| d != state->data32Sig
|| l != state->lateabtSig
|| b != state->bigendSig)
- state->Emulate = CHANGEMODE; /* Force ARMulator to notice these now. */
+ /* Force ARMulator to notice these now. */
+ state->Emulate = CHANGEMODE;
}
-
+
return TRUE;
}
/* What follows is the Validation Suite Coprocessor. It uses two
-co-processor numbers (4 and 5) and has the follwing functionality.
-Sixteen registers. Both co-processor nuimbers can be used in an MCR and
-MRC to access these registers. CP 4 can LDC and STC to and from the
-registers. CP 4 and CP 5 CDP 0 will busy wait for the number of cycles
-specified by a CP register. CP 5 CDP 1 issues a FIQ after a number of
-cycles (specified in a CP register), CDP 2 issues an IRQW in the same
-way, CDP 3 and 4 turn of the FIQ and IRQ source, and CDP 5 stores a 32
-bit time value in a CP register (actually it's the total number of N, S,
-I, C and F cyles) */
+ co-processor numbers (4 and 5) and has the follwing functionality.
+ Sixteen registers. Both co-processor nuimbers can be used in an MCR
+ and MRC to access these registers. CP 4 can LDC and STC to and from
+ the registers. CP 4 and CP 5 CDP 0 will busy wait for the number of
+ cycles specified by a CP register. CP 5 CDP 1 issues a FIQ after a
+ number of cycles (specified in a CP register), CDP 2 issues an IRQW
+ in the same way, CDP 3 and 4 turn of the FIQ and IRQ source, and CDP 5
+ stores a 32 bit time value in a CP register (actually it's the total
+ number of N, S, I, C and F cyles). */
static ARMword ValReg[16];
static unsigned
-ValLDC (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type, ARMword instr, ARMword data)
+ValLDC (ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned type,
+ ARMword instr,
+ ARMword data)
{
static unsigned words;
if (type != ARMul_DATA)
- {
- words = 0;
- return (ARMul_DONE);
- }
- if (BIT (22))
- { /* it's a long access, get two words */
- ValReg[BITS (12, 15)] = data;
- if (words++ == 4)
- return (ARMul_DONE);
- else
- return (ARMul_INC);
- }
+ words = 0;
else
- { /* get just one word */
+ {
ValReg[BITS (12, 15)] = data;
- return (ARMul_DONE);
+
+ if (BIT (22))
+ /* It's a long access, get two words. */
+ if (words++ != 4)
+ return ARMul_INC;
}
+
+ return ARMul_DONE;
}
static unsigned
-ValSTC (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type, ARMword instr, ARMword * data)
+ValSTC (ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned type,
+ ARMword instr,
+ ARMword * data)
{
static unsigned words;
if (type != ARMul_DATA)
- {
- words = 0;
- return (ARMul_DONE);
- }
- if (BIT (22))
- { /* it's a long access, get two words */
- *data = ValReg[BITS (12, 15)];
- if (words++ == 4)
- return (ARMul_DONE);
- else
- return (ARMul_INC);
- }
+ words = 0;
else
- { /* get just one word */
- *data = ValReg[BITS (12, 15)];
- return (ARMul_DONE);
+ {
+ * data = ValReg[BITS (12, 15)];
+
+ if (BIT (22))
+ /* It's a long access, get two words. */
+ if (words++ != 4)
+ return ARMul_INC;
}
+
+ return ARMul_DONE;
}
static unsigned
-ValMRC (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword * value)
+ValMRC (ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned type ATTRIBUTE_UNUSED,
+ ARMword instr,
+ ARMword * value)
{
*value = ValReg[BITS (16, 19)];
- return (ARMul_DONE);
+
+ return ARMul_DONE;
}
static unsigned
-ValMCR (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword value)
+ValMCR (ARMul_State * state ATTRIBUTE_UNUSED,
+ unsigned type ATTRIBUTE_UNUSED,
+ ARMword instr,
+ ARMword value)
{
ValReg[BITS (16, 19)] = value;
- return (ARMul_DONE);
+
+ return ARMul_DONE;
}
static unsigned
ValCDP (ARMul_State * state, unsigned type, ARMword instr)
{
static unsigned long finish = 0;
- ARMword howlong;
- howlong = ValReg[BITS (0, 3)];
- if (BITS (20, 23) == 0)
+ if (BITS (20, 23) != 0)
+ return ARMul_CANT;
+
+ if (type == ARMul_FIRST)
{
- if (type == ARMul_FIRST)
- { /* First cycle of a busy wait */
- finish = ARMul_Time (state) + howlong;
- if (howlong == 0)
- return (ARMul_DONE);
- else
- return (ARMul_BUSY);
- }
- else if (type == ARMul_BUSY)
- {
- if (ARMul_Time (state) >= finish)
- return (ARMul_DONE);
- else
- return (ARMul_BUSY);
- }
+ ARMword howlong;
+
+ howlong = ValReg[BITS (0, 3)];
+
+ /* First cycle of a busy wait. */
+ finish = ARMul_Time (state) + howlong;
+
+ return howlong == 0 ? ARMul_DONE : ARMul_BUSY;
+ }
+ else if (type == ARMul_BUSY)
+ {
+ if (ARMul_Time (state) >= finish)
+ return ARMul_DONE;
+ else
+ return ARMul_BUSY;
}
- return (ARMul_CANT);
+
+ return ARMul_CANT;
}
static unsigned
@@ -258,7 +1117,7 @@ DoAFIQ (ARMul_State * state)
{
state->NfiqSig = LOW;
state->Exception++;
- return (0);
+ return 0;
}
static unsigned
@@ -266,7 +1125,7 @@ DoAIRQ (ARMul_State * state)
{
state->NirqSig = LOW;
state->Exception++;
- return (0);
+ return 0;
}
static unsigned
@@ -276,50 +1135,56 @@ IntCDP (ARMul_State * state, unsigned type, ARMword instr)
ARMword howlong;
howlong = ValReg[BITS (0, 3)];
+
switch ((int) BITS (20, 23))
{
case 0:
if (type == ARMul_FIRST)
- { /* First cycle of a busy wait */
+ {
+ /* First cycle of a busy wait. */
finish = ARMul_Time (state) + howlong;
- if (howlong == 0)
- return (ARMul_DONE);
- else
- return (ARMul_BUSY);
+
+ return howlong == 0 ? ARMul_DONE : ARMul_BUSY;
}
else if (type == ARMul_BUSY)
{
if (ARMul_Time (state) >= finish)
- return (ARMul_DONE);
+ return ARMul_DONE;
else
- return (ARMul_BUSY);
+ return ARMul_BUSY;
}
- return (ARMul_DONE);
+ return ARMul_DONE;
+
case 1:
if (howlong == 0)
ARMul_Abort (state, ARMul_FIQV);
else
ARMul_ScheduleEvent (state, howlong, DoAFIQ);
- return (ARMul_DONE);
+ return ARMul_DONE;
+
case 2:
if (howlong == 0)
ARMul_Abort (state, ARMul_IRQV);
else
ARMul_ScheduleEvent (state, howlong, DoAIRQ);
- return (ARMul_DONE);
+ return ARMul_DONE;
+
case 3:
state->NfiqSig = HIGH;
state->Exception--;
- return (ARMul_DONE);
+ return ARMul_DONE;
+
case 4:
state->NirqSig = HIGH;
state->Exception--;
- return (ARMul_DONE);
+ return ARMul_DONE;
+
case 5:
ValReg[BITS (0, 3)] = ARMul_Time (state);
- return (ARMul_DONE);
+ return ARMul_DONE;
}
- return (ARMul_CANT);
+
+ return ARMul_CANT;
}
/***************************************************************************\
@@ -329,18 +1194,20 @@ IntCDP (ARMul_State * state, unsigned type, ARMword instr)
unsigned
ARMul_CoProInit (ARMul_State * state)
{
- register unsigned i;
+ unsigned int i;
- for (i = 0; i < 16; i++) /* initialise tham all first */
+ /* Initialise tham all first. */
+ for (i = 0; i < 16; i++)
ARMul_CoProDetach (state, i);
- /* Install CoPro Instruction handlers here
- The format is
- ARMul_CoProAttach(state, CP Number, Init routine, Exit routine
- LDC routine, STC routine, MRC routine, MCR routine,
- CDP routine, Read Reg routine, Write Reg routine) ;
- */
-
+ /* Install CoPro Instruction handlers here.
+ The format is:
+ ARMul_CoProAttach (state, CP Number,
+ Init routine, Exit routine
+ LDC routine, STC routine,
+ MRC routine, MCR routine,
+ CDP routine,
+ Read Reg routine, Write Reg routine). */
ARMul_CoProAttach (state, 4, NULL, NULL,
ValLDC, ValSTC, ValMRC, ValMCR, ValCDP, NULL, NULL);
@@ -350,13 +1217,28 @@ ARMul_CoProInit (ARMul_State * state)
ARMul_CoProAttach (state, 15, MMUInit, NULL,
NULL, NULL, MMUMRC, MMUMCR, NULL, MMURead, MMUWrite);
+ ARMul_CoProAttach (state, 13, XScale_cp13_init, NULL,
+ XScale_cp13_LDC, XScale_cp13_STC, XScale_cp13_MRC,
+ XScale_cp13_MCR, NULL, XScale_cp13_read_reg,
+ XScale_cp13_write_reg);
+
+ ARMul_CoProAttach (state, 14, XScale_cp14_init, NULL,
+ XScale_cp14_LDC, XScale_cp14_STC, XScale_cp14_MRC,
+ XScale_cp14_MCR, NULL, XScale_cp14_read_reg,
+ XScale_cp14_write_reg);
+
+ ARMul_CoProAttach (state, 15, XScale_cp15_init, NULL,
+ NULL, NULL, XScale_cp15_MRC, XScale_cp15_MCR,
+ NULL, XScale_cp15_read_reg, XScale_cp15_write_reg);
- /* No handlers below here */
+ /* No handlers below here. */
- for (i = 0; i < 16; i++) /* Call all the initialisation routines */
+ /* Call all the initialisation routines. */
+ for (i = 0; i < 16; i++)
if (state->CPInit[i])
(state->CPInit[i]) (state);
- return (TRUE);
+
+ return TRUE;
}
/***************************************************************************\
@@ -371,7 +1253,8 @@ ARMul_CoProExit (ARMul_State * state)
for (i = 0; i < 16; i++)
if (state->CPExit[i])
(state->CPExit[i]) (state);
- for (i = 0; i < 16; i++) /* Detach all handlers */
+
+ for (i = 0; i < 16; i++) /* Detach all handlers. */
ARMul_CoProDetach (state, i);
}
@@ -380,11 +1263,17 @@ ARMul_CoProExit (ARMul_State * state)
\***************************************************************************/
void
-ARMul_CoProAttach (ARMul_State * state, unsigned number,
- ARMul_CPInits * init, ARMul_CPExits * exit,
- ARMul_LDCs * ldc, ARMul_STCs * stc,
- ARMul_MRCs * mrc, ARMul_MCRs * mcr, ARMul_CDPs * cdp,
- ARMul_CPReads * read, ARMul_CPWrites * write)
+ARMul_CoProAttach (ARMul_State * state,
+ unsigned number,
+ ARMul_CPInits * init,
+ ARMul_CPExits * exit,
+ ARMul_LDCs * ldc,
+ ARMul_STCs * stc,
+ ARMul_MRCs * mrc,
+ ARMul_MCRs * mcr,
+ ARMul_CDPs * cdp,
+ ARMul_CPReads * read,
+ ARMul_CPWrites * write)
{
if (init != NULL)
state->CPInit[number] = init;
@@ -412,40 +1301,9 @@ ARMul_CoProDetach (ARMul_State * state, unsigned number)
ARMul_CoProAttach (state, number, NULL, NULL,
NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R,
NoCoPro3R, NULL, NULL);
+
state->CPInit[number] = NULL;
state->CPExit[number] = NULL;
state->CPRead[number] = NULL;
state->CPWrite[number] = NULL;
}
-
-/***************************************************************************\
-* There is no CoPro around, so Undefined Instruction trap *
-\***************************************************************************/
-
-static unsigned
-NoCoPro3R (ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned a ATTRIBUTE_UNUSED,
- ARMword b ATTRIBUTE_UNUSED)
-{
- return (ARMul_CANT);
-}
-
-static unsigned
-NoCoPro4R (
- ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned a ATTRIBUTE_UNUSED,
- ARMword b ATTRIBUTE_UNUSED,
- ARMword c ATTRIBUTE_UNUSED)
-{
- return (ARMul_CANT);
-}
-
-static unsigned
-NoCoPro4W (
- ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned a ATTRIBUTE_UNUSED,
- ARMword b ATTRIBUTE_UNUSED,
- ARMword * c ATTRIBUTE_UNUSED)
-{
- return (ARMul_CANT);
-}
diff --git a/sim/arm/armdefs.h b/sim/arm/armdefs.h
index 61ab9c5..204dc6b 100644
--- a/sim/arm/armdefs.h
+++ b/sim/arm/armdefs.h
@@ -30,6 +30,7 @@ typedef char *VoidStar;
#endif
typedef unsigned long ARMword; /* must be 32 bits wide */
+typedef unsigned long long ARMdword; /* Must be at least 64 bits wide. */
typedef struct ARMul_State ARMul_State;
typedef unsigned ARMul_CPInits (ARMul_State * state);
@@ -56,9 +57,13 @@ struct ARMul_State
unsigned ErrorCode; /* type of illegal instruction */
ARMword Reg[16]; /* the current register file */
ARMword RegBank[7][16]; /* all the registers */
+ /* 40 bit accumulator. We always keep this 64 bits wide,
+ and move only 40 bits out of it in an MRA insn. */
+ ARMdword Accumulator;
ARMword Cpsr; /* the current psr */
ARMword Spsr[7]; /* the exception psr's */
ARMword NFlag, ZFlag, CFlag, VFlag, IFFlags; /* dummy flags for speed */
+ ARMword SFlag;
#ifdef MODET
ARMword TFlag; /* Thumb state */
#endif
@@ -125,6 +130,8 @@ struct ARMul_State
unsigned is_v4; /* Are we emulating a v4 architecture (or higher) ? */
unsigned is_v5; /* Are we emulating a v5 architecture ? */
+ unsigned is_v5e; /* Are we emulating a v5e architecture ? */
+ unsigned is_XScale; /* Are we emulating an XScale architecture ? */
unsigned verbose; /* Print various messages like the banner */
};
@@ -150,6 +157,8 @@ struct ARMul_State
#define ARM_Lock_Prop 0x20
#define ARM_v4_Prop 0x40
#define ARM_v5_Prop 0x80
+#define ARM_v5e_Prop 0x100
+#define ARM_XScale_Prop 0x200
/***************************************************************************\
* Macros to extract instruction fields *
diff --git a/sim/arm/armemu.c b/sim/arm/armemu.c
index 9d3dcba..6413728 100644
--- a/sim/arm/armemu.c
+++ b/sim/arm/armemu.c
@@ -459,6 +459,30 @@ ARMul_Emulate26 (register ARMul_State * state)
temp = TRUE;
break;
case NV:
+ if (state->is_v5)
+ {
+ if (BITS (25, 27) == 5) /* BLX(1) */
+ {
+ ARMword dest;
+
+ state->Reg[14] = pc + 4;
+
+ dest = pc + 8 + 1; /* Force entry into Thumb mode. */
+ if (BIT (23))
+ dest += (NEGBRANCH + (BIT (24) << 1));
+ else
+ dest += POSBRANCH + (BIT (24) << 1);
+
+ WriteR15Branch (state, dest);
+ goto donext;
+ }
+ else if ((instr & 0xFC70F000) == 0xF450F000)
+ /* The PLD instruction. Ignored. */
+ goto donext;
+ else
+ /* UNDEFINED in v5, UNPREDICTABLE in v3, v4, non executed in v1, v2. */
+ ARMul_UndefInstr (state, instr);
+ }
temp = FALSE;
break;
case EQ:
@@ -513,6 +537,63 @@ ARMul_Emulate26 (register ARMul_State * state)
{ /* if the condition codes don't match, stop here */
mainswitch:
+ if (state->is_XScale)
+ {
+ if (BIT (20) == 0 && BITS (25, 27) == 0)
+ {
+ if (BITS (4, 7) == 0xD)
+ {
+ /* XScale Load Consecutive insn. */
+ ARMword temp = GetLS7RHS (state, instr);
+ ARMword temp2 = BIT (23) ? LHS + temp : LHS - temp;
+ ARMword addr = BIT (24) ? temp2 : temp;
+
+ if (BIT (12))
+ ARMul_UndefInstr (state, instr);
+ else if (addr & 7)
+ /* Alignment violation. */
+ ARMul_Abort (state, ARMul_DataAbortV);
+ else
+ {
+ int wb = BIT (24) && BIT (21);
+
+ state->Reg[BITS (12, 15)] =
+ ARMul_LoadWordN (state, addr);
+ state->Reg[BITS (12, 15) + 1] =
+ ARMul_LoadWordN (state, addr + 4);
+ if (wb)
+ LSBase = addr;
+ }
+
+ goto donext;
+ }
+ else if (BITS (4, 7) == 0xF)
+ {
+ /* XScale Store Consecutive insn. */
+ ARMword temp = GetLS7RHS (state, instr);
+ ARMword temp2 = BIT (23) ? LHS + temp : LHS - temp;
+ ARMword addr = BIT (24) ? temp2 : temp;
+
+ if (BIT (12))
+ ARMul_UndefInstr (state, instr);
+ else if (addr & 7)
+ /* Alignment violation. */
+ ARMul_Abort (state, ARMul_DataAbortV);
+ else
+ {
+ ARMul_StoreWordN (state, addr,
+ state->Reg[BITS (12, 15)]);
+ ARMul_StoreWordN (state, addr + 4,
+ state->Reg[BITS (12, 15) + 1]);
+
+ if (BIT (21))
+ LSBase = addr;
+ }
+
+ goto donext;
+ }
+ }
+ }
switch ((int) BITS (20, 27))
{
@@ -1000,6 +1081,48 @@ ARMul_Emulate26 (register ARMul_State * state)
break;
case 0x10: /* TST reg and MRS CPSR and SWP word */
+ if (state->is_v5e)
+ {
+ if (BIT (4) == 0 && BIT (7) == 1)
+ {
+ /* ElSegundo SMLAxy insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ ARMword op2 = state->Reg[BITS (8, 11)];
+ ARMword Rn = state->Reg[BITS (12, 15)];
+
+ if (BIT (5))
+ op1 >>= 16;
+ if (BIT (6))
+ op2 >>= 16;
+ op1 &= 0xFFFF;
+ op2 &= 0xFFFF;
+ if (op1 & 0x8000)
+ op1 -= 65536;
+ if (op2 & 0x8000)
+ op2 -= 65536;
+ op1 *= op2;
+
+ if (AddOverflow (op1, Rn, op1 + Rn))
+ SETS;
+ state->Reg[BITS (16, 19)] = op1 + Rn;
+ break;
+ }
+
+ if (BITS (4, 11) == 5)
+ {
+ /* ElSegundo QADD insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ ARMword op2 = state->Reg[BITS (16, 19)];
+ ARMword result = op1 + op2;
+ if (AddOverflow (op1, op2, result))
+ {
+ result = POS (result) ? 0x80000000 : 0x7fffffff;
+ SETS;
+ }
+ state->Reg[BITS (12, 15)] = result;
+ break;
+ }
+ }
#ifdef MODET
if (BITS (4, 11) == 0xB)
{
@@ -1072,6 +1195,72 @@ ARMul_Emulate26 (register ARMul_State * state)
break;
case 0x12: /* TEQ reg and MSR reg to CPSR (ARM6) */
+ if (state->is_v5)
+ {
+ if (BITS (4, 7) == 3)
+ {
+ /* BLX(2) */
+ ARMword temp;
+
+ if (TFLAG)
+ temp = (pc + 2) | 1;
+ else
+ temp = pc + 4;
+
+ WriteR15Branch (state, state->Reg[RHSReg]);
+ state->Reg[14] = temp;
+ break;
+ }
+ }
+
+ if (state->is_v5e)
+ {
+ if (BIT (4) == 0 && BIT (7) == 1
+ && (BIT (5) == 0 || BITS (12, 15) == 0))
+ {
+ /* ElSegundo SMLAWy/SMULWy insn. */
+ unsigned long long op1 = state->Reg[BITS (0, 3)];
+ unsigned long long op2 = state->Reg[BITS (8, 11)];
+ unsigned long long result;
+
+ if (BIT (6))
+ op2 >>= 16;
+ if (op1 & 0x80000000)
+ op1 -= 1ULL << 32;
+ op2 &= 0xFFFF;
+ if (op2 & 0x8000)
+ op2 -= 65536;
+ result = (op1 * op2) >> 16;
+
+ if (BIT (5) == 0)
+ {
+ ARMword Rn = state->Reg[BITS (12, 15)];
+
+ if (AddOverflow (result, Rn, result + Rn))
+ SETS;
+ result += Rn;
+ }
+ state->Reg[BITS (16, 19)] = result;
+ break;
+ }
+
+ if (BITS (4, 11) == 5)
+ {
+ /* ElSegundo QSUB insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ ARMword op2 = state->Reg[BITS (16, 19)];
+ ARMword result = op1 - op2;
+
+ if (SubOverflow (op1, op2, result))
+ {
+ result = POS (result) ? 0x80000000 : 0x7fffffff;
+ SETS;
+ }
+
+ state->Reg[BITS (12, 15)] = result;
+ break;
+ }
+ }
#ifdef MODET
if (BITS (4, 11) == 0xB)
{
@@ -1079,18 +1268,68 @@ ARMul_Emulate26 (register ARMul_State * state)
SHPREDOWNWB ();
break;
}
-#endif
-#ifdef MODET
if (BITS (4, 27) == 0x12FFF1)
- { /* BX */
+ {
+ /* BX */
WriteR15Branch (state, state->Reg[RHSReg]);
break;
}
#endif
+ if (state->is_v5)
+ {
+ if (BITS (4, 7) == 0x7)
+ {
+ ARMword value;
+ extern int SWI_vector_installed;
+
+ /* Hardware is allowed to optionally override this
+ instruction and treat it as a breakpoint. Since
+ this is a simulator not hardware, we take the position
+ that if a SWI vector was not installed, then an Abort
+ vector was probably not installed either, and so
+ normally this instruction would be ignored, even if an
+ Abort is generated. This is a bad thing, since GDB
+ uses this instruction for its breakpoints (at least in
+ Thumb mode it does). So intercept the instruction here
+ and generate a breakpoint SWI instead. */
+ if (! SWI_vector_installed)
+ ARMul_OSHandleSWI (state, SWI_Breakpoint);
+ else
+
+ /* BKPT - normally this will cause an abort, but for the
+ XScale if bit 31 in register 10 of coprocessor 14 is
+ clear, then this is treated as a no-op. */
+ if (state->is_XScale)
+ {
+ if (read_cp14_reg (10) & (1UL << 31))
+ {
+ ARMword value;
+
+ value = read_cp14_reg (10);
+ value &= ~0x1c;
+ value |= 0xc;
+
+ write_cp14_reg (10, value);
+ write_cp15_reg (5, 0, 0, 0x200); /* Set FSR. */
+ write_cp15_reg (6, 0, 0, pc); /* Set FAR. */
+ }
+ else
+ break;
+ }
+
+ ARMul_Abort (state, ARMul_PrefetchAbortV);
+ break;
+ }
+ }
if (DESTReg == 15)
- { /* MSR reg to CPSR */
+ {
+ /* MSR reg to CPSR */
UNDEF_MSRPC;
temp = DPRegRHS;
+#ifdef MODET
+ /* Don't allow TBIT to be set by MSR. */
+ temp &= ~ TBIT;
+#endif
ARMul_FixCPSR (state, instr, temp);
}
else
@@ -1128,6 +1367,60 @@ ARMul_Emulate26 (register ARMul_State * state)
break;
case 0x14: /* CMP reg and MRS SPSR and SWP byte */
+ if (state->is_v5e)
+ {
+ if (BIT (4) == 0 && BIT (7) == 1)
+ {
+ /* ElSegundo SMLALxy insn. */
+ unsigned long long op1 = state->Reg[BITS (0, 3)];
+ unsigned long long op2 = state->Reg[BITS (8, 11)];
+ unsigned long long dest;
+ unsigned long long result;
+
+ if (BIT (5))
+ op1 >>= 16;
+ if (BIT (6))
+ op2 >>= 16;
+ op1 &= 0xFFFF;
+ if (op1 & 0x8000)
+ op1 -= 65536;
+ op2 &= 0xFFFF;
+ if (op2 & 0x8000)
+ op2 -= 65536;
+
+ dest = (unsigned long long) state->Reg[BITS (16, 19)] << 32;
+ dest |= state->Reg[BITS (12, 15)];
+ dest += op1 * op2;
+ state->Reg[BITS (12, 15)] = dest;
+ state->Reg[BITS (16, 19)] = dest >> 32;
+ break;
+ }
+
+ if (BITS (4, 11) == 5)
+ {
+ /* ElSegundo QDADD insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ ARMword op2 = state->Reg[BITS (16, 19)];
+ ARMword op2d = op2 + op2;
+ ARMword result;
+
+ if (AddOverflow (op2, op2, op2d))
+ {
+ SETS;
+ op2d = POS (op2d) ? 0x80000000 : 0x7fffffff;
+ }
+
+ result = op1 + op2d;
+ if (AddOverflow (op1, op2d, result))
+ {
+ SETS;
+ result = POS (result) ? 0x80000000 : 0x7fffffff;
+ }
+
+ state->Reg[BITS (12, 15)] = result;
+ break;
+ }
+ }
#ifdef MODET
if (BITS (4, 7) == 0xB)
{
@@ -1207,6 +1500,72 @@ ARMul_Emulate26 (register ARMul_State * state)
break;
case 0x16: /* CMN reg and MSR reg to SPSR */
+ if (state->is_v5e)
+ {
+ if (BIT (4) == 0 && BIT (7) == 1 && BITS (12, 15) == 0)
+ {
+ /* ElSegundo SMULxy insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ ARMword op2 = state->Reg[BITS (8, 11)];
+ ARMword Rn = state->Reg[BITS (12, 15)];
+
+ if (BIT (5))
+ op1 >>= 16;
+ if (BIT (6))
+ op2 >>= 16;
+ op1 &= 0xFFFF;
+ op2 &= 0xFFFF;
+ if (op1 & 0x8000)
+ op1 -= 65536;
+ if (op2 & 0x8000)
+ op2 -= 65536;
+
+ state->Reg[BITS (16, 19)] = op1 * op2;
+ break;
+ }
+
+ if (BITS (4, 11) == 5)
+ {
+ /* ElSegundo QDSUB insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ ARMword op2 = state->Reg[BITS (16, 19)];
+ ARMword op2d = op2 + op2;
+ ARMword result;
+
+ if (AddOverflow (op2, op2, op2d))
+ {
+ SETS;
+ op2d = POS (op2d) ? 0x80000000 : 0x7fffffff;
+ }
+
+ result = op1 - op2d;
+ if (SubOverflow (op1, op2d, result))
+ {
+ SETS;
+ result = POS (result) ? 0x80000000 : 0x7fffffff;
+ }
+
+ state->Reg[BITS (12, 15)] = result;
+ break;
+ }
+ }
+
+ if (state->is_v5)
+ {
+ if (BITS (4, 11) == 0xF1 && BITS (16, 19) == 0xF)
+ {
+ /* ARM5 CLZ insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ int result = 32;
+
+ if (op1)
+ for (result = 0; (op1 & 0x80000000) == 0; op1 <<= 1)
+ result++;
+
+ state->Reg[BITS (12, 15)] = result;
+ break;
+ }
+ }
#ifdef MODET
if (BITS (4, 7) == 0xB)
{
@@ -2393,7 +2752,7 @@ ARMul_Emulate26 (register ARMul_State * state)
{
/* Check for the special breakpoint opcode.
This value should correspond to the value defined
- as ARM_BE_BREAKPOINT in gdb/arm-tdep.c. */
+ as ARM_BE_BREAKPOINT in gdb/arm/tm-arm.h. */
if (BITS (0, 19) == 0xfdefe)
{
if (!ARMul_OSHandleSWI (state, SWI_Breakpoint))
@@ -2642,11 +3001,56 @@ ARMul_Emulate26 (register ARMul_State * state)
\***************************************************************************/
case 0xc4:
+ if (state->is_XScale)
+ {
+ if (BITS (4, 7) != 0x00)
+ ARMul_UndefInstr (state, instr);
+
+ if (BITS (8, 11) != 0x00)
+ ARMul_UndefInstr (state, instr); /* Not CP0. */
+
+ /* XScale MAR insn. Move two registers into accumulator. */
+ if (BITS (0, 3) == 0x00)
+ {
+ state->Accumulator = state->Reg[BITS (12, 15)];
+ state->Accumulator += (ARMdword) state->Reg[BITS (16, 19)] << 32;
+ break;
+ }
+ /* Access to any other acc is unpredicatable. */
+ break;
+ }
+ /* Drop through. */
+
case 0xc0: /* Store , No WriteBack , Post Dec */
ARMul_STC (state, instr, LHS);
break;
case 0xc5:
+ if (state->is_XScale)
+ {
+ if (BITS (4, 7) != 0x00)
+ ARMul_UndefInstr (state, instr);
+
+ if (BITS (8, 11) != 0x00)
+ ARMul_UndefInstr (state, instr); /* Not CP0. */
+
+ /* XScale MRA insn. Move accumulator into two registers. */
+ if (BITS (0, 3) == 0x00)
+ {
+ ARMword t1 = (state->Accumulator >> 32) & 255;
+
+ if (t1 & 128)
+ t1 -= 256;
+
+ state->Reg[BITS (12, 15)] = state->Accumulator;
+ state->Reg[BITS (16, 19)] = t1;
+ break;
+ }
+ /* Access to any other acc is unpredicatable. */
+ break;
+ }
+ /* Drop through. */
+
case 0xc1: /* Load , No WriteBack , Post Dec */
ARMul_LDC (state, instr, LHS);
break;
@@ -2743,6 +3147,88 @@ ARMul_Emulate26 (register ARMul_State * state)
\***************************************************************************/
case 0xe2:
+ if (state->is_XScale)
+ switch (BITS (18, 19))
+ {
+ case 0x0:
+ {
+ /* XScale MIA instruction. Signed multiplication of two 32 bit
+ values and addition to 40 bit accumulator. */
+ long long Rm = state->Reg[MULLHSReg];
+ long long Rs = state->Reg[MULACCReg];
+
+ if (Rm & (1 << 31))
+ Rm -= 1ULL << 32;
+ if (Rs & (1 << 31))
+ Rs -= 1ULL << 32;
+ state->Accumulator += Rm * Rs;
+ }
+ goto donext;
+
+ case 0x2:
+ {
+ /* XScale MIAPH instruction. */
+ ARMword t1 = state->Reg[MULLHSReg] >> 16;
+ ARMword t2 = state->Reg[MULACCReg] >> 16;
+ ARMword t3 = state->Reg[MULLHSReg] & 0xffff;
+ ARMword t4 = state->Reg[MULACCReg] & 0xffff;
+ long long t5;
+
+ if (t1 & (1 << 15))
+ t1 -= 1 << 16;
+ if (t2 & (1 << 15))
+ t2 -= 1 << 16;
+ if (t3 & (1 << 15))
+ t3 -= 1 << 16;
+ if (t4 & (1 << 15))
+ t4 -= 1 << 16;
+ t1 *= t2;
+ t5 = t1;
+ if (t5 & (1 << 31))
+ t5 -= 1ULL << 32;
+ state->Accumulator += t5;
+ t3 *= t4;
+ t5 = t3;
+ if (t5 & (1 << 31))
+ t5 -= 1ULL << 32;
+ state->Accumulator += t5;
+ }
+ goto donext;
+
+ case 0x3:
+ {
+ /* XScale MIAxy instruction. */
+ ARMword t1;
+ ARMword t2;
+ long long t5;
+
+ if (BIT (17))
+ t1 = state->Reg[MULLHSReg] >> 16;
+ else
+ t1 = state->Reg[MULLHSReg] & 0xffff;
+
+ if (BIT (16))
+ t2 = state->Reg[MULACCReg] >> 16;
+ else
+ t2 = state->Reg[MULACCReg] & 0xffff;
+
+ if (t1 & (1 << 15))
+ t1 -= 1 << 16;
+ if (t2 & (1 << 15))
+ t2 -= 1 << 16;
+ t1 *= t2;
+ t5 = t1;
+ if (t5 & (1 << 31))
+ t5 -= 1ULL << 32;
+ state->Accumulator += t5;
+ }
+ goto donext;
+
+ default:
+ break;
+ }
+ /* Drop through. */
+
case 0xe0:
case 0xe4:
case 0xe6:
diff --git a/sim/arm/armemu.h b/sim/arm/armemu.h
index 81ecd52..8fd5f35 100644
--- a/sim/arm/armemu.h
+++ b/sim/arm/armemu.h
@@ -55,6 +55,7 @@ extern ARMword isize;
#define ZBIT (1L << 30)
#define CBIT (1L << 29)
#define VBIT (1L << 28)
+#define SBIT (1L << 27)
#define IBIT (1L << 7)
#define FBIT (1L << 6)
#define IFBITS (3L << 6)
@@ -98,6 +99,10 @@ extern ARMword isize;
#define CLEARV state->VFlag = 0
#define ASSIGNV(res) state->VFlag = res
+#define SFLAG state->SFlag
+#define SETS state->SFlag = 1
+#define CLEARS state->SFlag = 0
+#define ASSIGNS(res) state->SFlag = res
#define IFLAG (state->IFFlags >> 1)
#define FFLAG (state->IFFlags & 1)
@@ -110,7 +115,12 @@ extern ARMword isize;
#define PSR_XBITS (0x0000ff00L)
#define PSR_CBITS (0x000000ffL)
+#if defined MODE32 || defined MODET
+#define CCBITS (0xf8000000L)
+#else
#define CCBITS (0xf0000000L)
+#endif
+
#define INTBITS (0xc0L)
#if defined MODET && defined MODE32
@@ -149,7 +159,7 @@ extern ARMword isize;
#define R15PCMODE (state->Reg[15] & (R15PCBITS | R15MODEBITS))
#define R15MODE (state->Reg[15] & R15MODEBITS)
-#define ECC ((NFLAG << 31) | (ZFLAG << 30) | (CFLAG << 29) | (VFLAG << 28))
+#define ECC ((NFLAG << 31) | (ZFLAG << 30) | (CFLAG << 29) | (VFLAG << 28) | (SFLAG << 27))
#define EINT (IFFLAGS << 6)
#define ER15INT (IFFLAGS << 26)
#define EMODE (state->Mode)
@@ -472,3 +482,14 @@ extern tdstate ARMul_ThumbDecode (ARMul_State * state, ARMword pc,
#define UNDEF_IllegalMode
#define UNDEF_Prog32SigChange
#define UNDEF_Data32SigChange
+
+/* Coprocessor support functions. */
+extern unsigned ARMul_CoProInit (ARMul_State *);
+extern void ARMul_CoProExit (ARMul_State *);
+extern void ARMul_CoProAttach (ARMul_State *, unsigned, ARMul_CPInits *, ARMul_CPExits *,
+ ARMul_LDCs *, ARMul_STCs *, ARMul_MRCs *, ARMul_MCRs *,
+ ARMul_CDPs *, ARMul_CPReads *, ARMul_CPWrites *);
+extern void ARMul_CoProDetach (ARMul_State *, unsigned);
+extern void write_cp15_reg (unsigned, unsigned, unsigned, ARMword);
+extern void write_cp14_reg (unsigned, ARMword);
+extern ARMword read_cp14_reg (unsigned);
diff --git a/sim/arm/arminit.c b/sim/arm/arminit.c
index a3f0001..2f6e73d 100644
--- a/sim/arm/arminit.c
+++ b/sim/arm/arminit.c
@@ -86,7 +86,8 @@ ARMul_NewState (void)
for (i = 0; i < 7; i++)
state->Spsr[i] = 0;
- state->Mode = USER26MODE;
+ /* state->Mode = USER26MODE; */
+ state->Mode = USER32MODE;
state->CallDebug = FALSE;
state->Debug = FALSE;
@@ -113,19 +114,16 @@ ARMul_NewState (void)
for (i = 0; i < EVENTLISTSIZE; i++)
*(state->EventPtr + i) = NULL;
-#ifdef ARM61
- state->prog32Sig = LOW;
- state->data32Sig = LOW;
-#else
state->prog32Sig = HIGH;
state->data32Sig = HIGH;
-#endif
state->lateabtSig = LOW;
state->bigendSig = LOW;
state->is_v4 = LOW;
state->is_v5 = LOW;
+ state->is_v5e = LOW;
+ state->is_XScale = LOW;
ARMul_Reset (state);
@@ -154,6 +152,8 @@ ARMul_SelectProcessor (ARMul_State * state, unsigned properties)
state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) ? HIGH : LOW;
state->is_v5 = (properties & ARM_v5_Prop) ? HIGH : LOW;
+ state->is_v5e = (properties & ARM_v5e_Prop) ? HIGH : LOW;
+ state->is_XScale = (properties & ARM_XScale_Prop) ? HIGH : LOW;
}
/***************************************************************************\
@@ -261,6 +261,8 @@ ARMul_Abort (ARMul_State * state, ARMword vector)
{
ARMword temp;
int isize = INSN_SIZE;
+ int esize = (TFLAG ? 0 : 4);
+ int e2size = (TFLAG ? -4 : 0);
state->Aborted = FALSE;
@@ -288,19 +290,19 @@ ARMul_Abort (ARMul_State * state, ARMword vector)
break;
case ARMul_PrefetchAbortV: /* Prefetch Abort */
state->AbortAddr = 1;
- SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, isize);
+ SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, esize);
break;
case ARMul_DataAbortV: /* Data Abort */
- SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, isize);
+ SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, e2size);
break;
case ARMul_AddrExceptnV: /* Address Exception */
SETABORT (IBIT, SVC26MODE, isize);
break;
case ARMul_IRQV: /* IRQ */
- SETABORT (IBIT, state->prog32Sig ? IRQ32MODE : IRQ26MODE, isize);
+ SETABORT (IBIT, state->prog32Sig ? IRQ32MODE : IRQ26MODE, esize);
break;
case ARMul_FIQV: /* FIQ */
- SETABORT (INTBITS, state->prog32Sig ? FIQ32MODE : FIQ26MODE, isize);
+ SETABORT (INTBITS, state->prog32Sig ? FIQ32MODE : FIQ26MODE, esize);
break;
}
if (ARMul_MODE32BIT)
diff --git a/sim/arm/armos.c b/sim/arm/armos.c
index 958d4cd..62b3ff5 100644
--- a/sim/arm/armos.c
+++ b/sim/arm/armos.c
@@ -70,6 +70,8 @@ extern int _fisatty (FILE *);
#include "armdefs.h"
#include "armos.h"
+#include "armemu.h"
+
#ifndef NOOS
#ifndef VALIDATE
/* #ifndef ASIM */
@@ -445,11 +447,6 @@ ARMul_OSHandleSWI (ARMul_State * state, ARMword number)
state->Reg[0] = OSptr->ErrorNo;
return (TRUE);
- case SWI_Breakpoint:
- state->EndCondition = RDIError_BreakpointReached;
- state->Emulate = FALSE;
- return (TRUE);
-
case SWI_GetEnv:
state->Reg[0] = ADDRCMDLINE;
if (state->MemSize)
@@ -459,6 +456,11 @@ ARMul_OSHandleSWI (ARMul_State * state, ARMword number)
WriteCommandLineTo (state, state->Reg[0]);
return (TRUE);
+
+ case SWI_Breakpoint:
+ state->EndCondition = RDIError_BreakpointReached;
+ state->Emulate = FALSE;
+ return (TRUE);
/* Handle Angel SWIs as well as Demon ones */
case AngelSWI_ARM:
@@ -587,29 +589,58 @@ ARMul_OSHandleSWI (ARMul_State * state, ARMword number)
return TRUE;
}
+ case 0x90:
+ case 0x92:
+ /* These are used by the FPE code. */
+ return TRUE;
+
default:
- state->Emulate = FALSE;
- return (FALSE);
+ {
+ /* If there is a SWI vector installed use it. */
+ extern int SWI_vector_installed;
+
+ if (SWI_vector_installed && number != SWI_Breakpoint)
+ {
+ ARMword cpsr;
+ ARMword i_size;
+
+ cpsr = ARMul_GetCPSR (state);
+ i_size = INSN_SIZE;
+
+ ARMul_SetSPSR (state, SVC32MODE, cpsr);
+
+ cpsr &= ~0xbf;
+ cpsr |= SVC32MODE | 0x80;
+ ARMul_SetCPSR (state, cpsr);
+
+ state->RegBank[SVCBANK][14] = state->Reg[14] = state->Reg[15] - i_size;
+ state->NextInstr = RESUME;
+ state->Reg[15] = state->pc = ARMSWIV;
+ FLUSHPIPE;
+ }
+ else
+ fprintf (stderr, "unknown SWI encountered - %x - ignoring\n", number);
+ return TRUE;
+ }
}
}
#ifndef NOOS
#ifndef ASIM
-/***************************************************************************\
-* The emulator calls this routine when an Exception occurs. The second *
-* parameter is the address of the relevant exception vector. Returning *
-* FALSE from this routine causes the trap to be taken, TRUE causes it to *
-* be ignored (so set state->Emulate to FALSE!). *
-\***************************************************************************/
+/* The emulator calls this routine when an Exception occurs. The second
+ parameter is the address of the relevant exception vector. Returning
+ FALSE from this routine causes the trap to be taken, TRUE causes it to
+ be ignored (so set state->Emulate to FALSE!). */
unsigned
-ARMul_OSException (ARMul_State * state ATTRIBUTE_UNUSED, ARMword vector ATTRIBUTE_UNUSED, ARMword pc ATTRIBUTE_UNUSED)
-{ /* don't use this here */
- return (FALSE);
+ARMul_OSException (
+ ARMul_State * state ATTRIBUTE_UNUSED,
+ ARMword vector ATTRIBUTE_UNUSED,
+ ARMword pc ATTRIBUTE_UNUSED)
+{
+ return FALSE;
}
#endif
-
-
#endif /* NOOS */
diff --git a/sim/arm/armsupp.c b/sim/arm/armsupp.c
index 27ee35b..2d0390d 100644
--- a/sim/arm/armsupp.c
+++ b/sim/arm/armsupp.c
@@ -302,6 +302,8 @@ ARMul_CPSRAltered (ARMul_State * state)
state->Cpsr &= ~CBIT;
ASSIGNV ((state->Cpsr & VBIT) != 0);
state->Cpsr &= ~VBIT;
+ ASSIGNS ((state->Cpsr & SBIT) != 0);
+ state->Cpsr &= ~SBIT;
#ifdef MODET
ASSIGNT ((state->Cpsr & TBIT) != 0);
state->Cpsr &= ~TBIT;
diff --git a/sim/arm/thumbemu.c b/sim/arm/thumbemu.c
index dc90dd7..3351c2f 100644
--- a/sim/arm/thumbemu.c
+++ b/sim/arm/thumbemu.c
@@ -209,11 +209,19 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
*ainstr = 0xE12FFF10 /* base */
| ((tinstr & 0x0078) >> 3); /* Rd */
break;
+ case 0xE: /* UNDEFINED */
+ case 0xF: /* UNDEFINED */
+ if (state->is_v5)
+ {
+ /* BLX Rs; BLX Hs */
+ *ainstr = 0xE12FFF30 /* base */
+ | ((tinstr & 0x0078) >> 3); /* Rd */
+ break;
+ }
+ /* Drop through. */
case 0x0: /* UNDEFINED */
case 0x4: /* UNDEFINED */
case 0x8: /* UNDEFINED */
- case 0xE: /* UNDEFINED */
- case 0xF: /* UNDEFINED */
valid = t_undefined;
break;
}
@@ -322,30 +330,48 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
break;
case 22:
case 23:
- if ((tinstr & 0x0F00) == 0x0000)
+ switch (tinstr & 0x0F00)
{
+ case 0x0000:
/* Format 13 */
/* NOTE: The instruction contains a shift left of 2
- equivalent (implemented as ROR #30): */
+ equivalent (implemented as ROR #30): */
*ainstr = ((tinstr & (1 << 7)) /* base */
? 0xE24DDF00 /* SUB */
: 0xE28DDF00) /* ADD */
| (tinstr & 0x007F); /* off7 */
- }
- else if ((tinstr & 0x0F00) == 0x0e00)
- *ainstr = 0xEF000000 | SWI_Breakpoint;
- else
- {
- /* Format 14 */
- ARMword subset[4] = {
- 0xE92D0000, /* STMDB sp!,{rlist} */
- 0xE92D4000, /* STMDB sp!,{rlist,lr} */
- 0xE8BD0000, /* LDMIA sp!,{rlist} */
- 0xE8BD8000 /* LDMIA sp!,{rlist,pc} */
- };
- *ainstr = subset[((tinstr & (1 << 11)) >> 10)
- | ((tinstr & (1 << 8)) >> 8)] /* base */
- | (tinstr & 0x00FF); /* mask8 */
+ break;
+ case 0x0400:
+ /* Format 14 - Push */
+ * ainstr = 0xE92D0000 | (tinstr & 0x00FF);
+ break;
+ case 0x0500:
+ /* Format 14 - Push + LR */
+ * ainstr = 0xE92D4000 | (tinstr & 0x00FF);
+ break;
+ case 0x0c00:
+ /* Format 14 - Pop */
+ * ainstr = 0xE8BD0000 | (tinstr & 0x00FF);
+ break;
+ case 0x0d00:
+ /* Format 14 - Pop + PC */
+ * ainstr = 0xE8BD8000 | (tinstr & 0x00FF);
+ break;
+ case 0x0e00:
+ if (state->is_v5)
+ {
+ /* This is normally an undefined instruction. The v5t architecture
+ defines this particular pattern as a BKPT instruction, for
+ hardware assisted debugging. We map onto the arm BKPT
+ instruction. */
+ * ainstr = 0xE1200070 | ((tinstr & 0xf0) << 4) | (tinstr & 0xf);
+ break;
+ }
+ /* Drop through. */
+ default:
+ /* Everything else is an undefined instruction. */
+ valid = t_undefined;
+ break;
}
break;
case 24: /* STMIA */
@@ -446,6 +472,34 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
valid = t_branch;
break;
case 29: /* UNDEFINED */
+ if (state->is_v5)
+ {
+ if (tinstr & 1)
+ {
+ valid = t_undefined;
+ break;
+ }
+ /* Drop through. */
+
+ do_blx2: /* BLX instruction 2 */
+ /* Format 19 */
+ /* There is no single ARM instruction equivalent for this
+ instruction. Also, it should only ever be matched with the
+ fmt19 "BL/BLX instruction 1" instruction. However, we do
+ allow the simulation of it on its own, with undefined results
+ if r14 is not suitably initialised. */
+ {
+ ARMword tmp = (pc + 2);
+
+ state->Reg[15] = ((state->Reg[14] + ((tinstr & 0x07FF) << 1))
+ & 0xFFFFFFFC);
+ CLEART;
+ state->Reg[14] = (tmp | 1);
+ valid = t_branch;
+ FLUSHPIPE;
+ break;
+ }
+ }
valid = t_undefined;
break;
case 30: /* BL instruction 1 */
@@ -461,7 +515,14 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
valid = t_branch; /* in-case we don't have the 2nd half */
tinstr = next_instr; /* move the instruction down */
if (((tinstr & 0xF800) >> 11) != 31)
- break; /* exit, since not correct instruction */
+ {
+ if (((tinstr & 0xF800) >> 11) == 29)
+ {
+ pc += 2;
+ goto do_blx2;
+ }
+ break; /* exit, since not correct instruction */
+ }
/* else we fall through to process the second half of the BL */
pc += 2; /* point the pc at the 2nd half */
case 31: /* BL instruction 2 */
diff --git a/sim/arm/wrapper.c b/sim/arm/wrapper.c
index b5ecd31..f6c4b05 100644
--- a/sim/arm/wrapper.c
+++ b/sim/arm/wrapper.c
@@ -114,6 +114,8 @@ ARMul_Debug (ARMul_State * state ATTRIBUTE_UNUSED, ARMword pc ATTRIBUTE_UNUSED,
return 0;
}
+int SWI_vector_installed = FALSE;
+
int
sim_write (sd, addr, buffer, size)
SIM_DESC sd ATTRIBUTE_UNUSED;
@@ -125,6 +127,9 @@ sim_write (sd, addr, buffer, size)
init ();
+ if ((addr <= 0x8) && ((addr + size) >= 0x8))
+ SWI_vector_installed = TRUE;
+
for (i = 0; i < size; i++)
ARMul_WriteByte (state, addr + i, buffer[i]);
@@ -216,37 +221,47 @@ sim_create_inferior (sd, abfd, argv, env)
"Unknown machine type; please update sim_create_inferior.\n");
/* fall through */
- case 0: /* arm */
+ case 0:
/* We wouldn't set the machine type with earlier toolchains, so we
- explicitly select a processor capable of supporting all ARM
- 32bit mode. */
- /* fall through */
+ explicitly select a processor capable of supporting all ARMs in
+ 32bit mode. */
+ case bfd_mach_arm_5:
+ case bfd_mach_arm_5T:
+ ARMul_SelectProcessor (state, ARM_v5_Prop);
+ break;
- case 5: /* armv4 */
- case 6: /* armv4t */
- case 7: /* armv5 */
- case 8: /* armv5t */
- if (mach == 7 || mach == 8)
- ARMul_SelectProcessor (state, ARM_v5_Prop);
- else
- ARMul_SelectProcessor (state, ARM_v4_Prop);
- /* Reset mode to ARM. A gdb user may rerun a program that had entered
- THUMB mode from the start and cause the ARM-mode startup code to be
- executed in THUMB mode. */
- ARMul_SetCPSR (state, USER32MODE);
+ case bfd_mach_arm_5TE:
+ ARMul_SelectProcessor (state, ARM_v5_Prop | ARM_v5e_Prop);
+ break;
+
+ case bfd_mach_arm_XScale:
+ ARMul_SelectProcessor (state, ARM_v5_Prop | ARM_v5e_Prop | ARM_XScale_Prop);
break;
- case 3: /* armv3 */
- case 4: /* armv3m */
+ case bfd_mach_arm_4:
+ case bfd_mach_arm_4T:
+ ARMul_SelectProcessor (state, ARM_v4_Prop);
+ break;
+
+ case bfd_mach_arm_3:
+ case bfd_mach_arm_3M:
ARMul_SelectProcessor (state, ARM_Lock_Prop);
break;
- case 1: /* armv2 */
- case 2: /* armv2a */
+ case bfd_mach_arm_2:
+ case bfd_mach_arm_2a:
ARMul_SelectProcessor (state, ARM_Fix26_Prop);
break;
}
+ if (mach > 3)
+ {
+ /* Reset mode to ARM. A gdb user may rerun a program that had entered
+ THUMB mode from the start and cause the ARM-mode startup code to be
+ executed in THUMB mode. */
+ ARMul_SetCPSR (state, USER32MODE);
+ }
+
if (argv != NULL)
{
/*
@@ -354,6 +369,7 @@ sim_store_register (sd, rn, memory, length)
int length ATTRIBUTE_UNUSED;
{
init ();
+
if (rn == 25)
{
state->Cpsr = frommem (state, memory);
@@ -374,6 +390,7 @@ sim_fetch_register (sd, rn, memory, length)
ARMword regval;
init ();
+
if (rn < 16)
regval = ARMul_GetReg (state, state->Mode, rn);
else if (rn == 25) /* FIXME: use PS_REGNUM from gdb/config/arm/tm-arm.h */