From f1129fb8ff9938330168992fb23ed35e37d82d61 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 30 Nov 2000 01:55:12 +0000 Subject: [PATCH] Add support for ARM's v5TE architecture and Intel's XScale extenstions --- sim/arm/ChangeLog | 28 +- sim/arm/armcopro.c | 1208 ++++++++++++++++++++++++++++++++++++++++++++-------- sim/arm/armdefs.h | 9 + sim/arm/armemu.c | 496 ++++++++++++++++++++- sim/arm/armemu.h | 23 +- sim/arm/arminit.c | 22 +- sim/arm/armos.c | 67 ++- sim/arm/armsupp.c | 2 + sim/arm/thumbemu.c | 101 ++++- sim/arm/wrapper.c | 57 ++- sim/configure | 4 + sim/configure.in | 4 + 12 files changed, 1771 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 + + * 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 * 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 * configure: Regenerated to track ../common/aclocal.m4 changes. - 1999-05-08 Felix Lee * 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 */ diff --git a/sim/configure b/sim/configure index 49452c3..8d324ad 100755 --- a/sim/configure +++ b/sim/configure @@ -1415,6 +1415,10 @@ case "${target}" in sim_target=arm extra_subdirs="${extra_subdirs} testsuite" ;; + xscale-*-*) + sim_target=arm + extra_subdirs="${extra_subdirs} testsuite" + ;; d10v-*-*) sim_target=d10v ;; d30v-*-*) sim_target=d30v diff --git a/sim/configure.in b/sim/configure.in index b0fa140..e472f88 100644 --- a/sim/configure.in +++ b/sim/configure.in @@ -54,6 +54,10 @@ case "${target}" in sim_target=arm extra_subdirs="${extra_subdirs} testsuite" ;; + xscale-*-*) + sim_target=arm + extra_subdirs="${extra_subdirs} testsuite" + ;; d10v-*-*) sim_target=d10v ;; d30v-*-*) sim_target=d30v -- 2.7.4