diff options
Diffstat (limited to 'sim/arm/armcopro.c')
-rw-r--r-- | sim/arm/armcopro.c | 1208 |
1 files changed, 1033 insertions, 175 deletions
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); -} |