X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=sim%2Farm%2Farmcopro.c;h=4c5da245e091fb64abe16aee46e269f73d451382;hb=00923338dec84505addaf9cdeca2e9c844757824;hp=579446c1959437779ffc83277900d75a5c68b88b;hpb=6d358e869b1efe22fa6697a8aa4191ddacbacef0;p=deliverable%2Fbinutils-gdb.git diff --git a/sim/arm/armcopro.c b/sim/arm/armcopro.c index 579446c195..4c5da245e0 100644 --- a/sim/arm/armcopro.c +++ b/sim/arm/armcopro.c @@ -3,7 +3,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -12,43 +12,987 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + along with this program; if not, see . */ #include "armdefs.h" +#include "armos.h" +#include "armemu.h" #include "ansidecl.h" +#include "iwmmxt.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; +} + +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; +} + +/* The XScale Co-processors. */ + +/* Coprocessor 15: System Control. */ +static void write_cp14_reg (unsigned, ARMword); +static ARMword read_cp14_reg (unsigned); + +/* 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; + + return TRUE; +} + +/* 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. */ + +static void +write_cp15_reg (ARMul_State * state, + 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; + + /* Change the endianness if necessary. */ + if ((value & ARMul_CP15_R1_ENDIAN) != + (XScale_cp15_opcode_2_is_0_Regs [reg] & ARMul_CP15_R1_ENDIAN)) + { + state->bigendSig = value & ARMul_CP15_R1_ENDIAN; + /* Force ARMulator to notice these now. */ + state->Emulate = CHANGEMODE; + } + 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 cp15 register. */ + +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_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 (state, 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 (state, reg, 0, 0, value); + + return TRUE; +} + +/* Check for special XScale memory access features. */ + +void +XScale_check_memacc (ARMul_State * state, ARMword * address, int store) +{ + ARMword dbcon, r0, r1; + int e1, e0; + + if (!state->is_XScale) + return; + + /* Check for PID-ification. + XXX BTB access support will require this test failing. */ + r0 = (read_cp15_reg (13, 0, 0) & 0xfe000000); + if (r0 && (* address & 0xfe000000) == 0) + * address |= r0; + + /* Check alignment fault enable/disable. */ + if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN) && (* address & 3)) + { + /* Set the FSR and FAR. + Do not use XScale_set_fsr_far as this checks the DCSR register. */ + write_cp15_reg (state, 5, 0, 0, ARMul_CP15_R5_MMU_EXCPT); + write_cp15_reg (state, 6, 0, 0, * address); + + ARMul_Abort (state, ARMul_DataAbortV); + } + + if (XScale_debug_moe (state, -1)) + return; + + /* Check the data breakpoint registers. */ + dbcon = read_cp15_reg (14, 0, 4); + r0 = read_cp15_reg (14, 0, 0); + r1 = read_cp15_reg (14, 0, 3); + e0 = dbcon & ARMul_CP15_DBCON_E0; + + if (dbcon & ARMul_CP15_DBCON_M) + { + /* r1 is a inverse mask. */ + if (e0 != 0 && ((store && e0 != 3) || (!store && e0 != 1)) + && ((* address & ~r1) == (r0 & ~r1))) + { + XScale_debug_moe (state, ARMul_CP14_R10_MOE_DB); + ARMul_OSHandleSWI (state, SWI_Breakpoint); + } + } + else + { + if (e0 != 0 && ((store && e0 != 3) || (!store && e0 != 1)) + && ((* address & ~3) == (r0 & ~3))) + { + XScale_debug_moe (state, ARMul_CP14_R10_MOE_DB); + ARMul_OSHandleSWI (state, SWI_Breakpoint); + } + + e1 = (dbcon & ARMul_CP15_DBCON_E1) >> 2; + if (e1 != 0 && ((store && e1 != 3) || (!store && e1 != 1)) + && ((* address & ~3) == (r1 & ~3))) + { + XScale_debug_moe (state, ARMul_CP14_R10_MOE_DB); + ARMul_OSHandleSWI (state, SWI_Breakpoint); + } + } +} + +/* Set the XScale FSR and FAR registers. */ + +void +XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword far) +{ + if (!state->is_XScale || (read_cp14_reg (10) & (1UL << 31)) == 0) + return; + + write_cp15_reg (state, 5, 0, 0, fsr); + write_cp15_reg (state, 6, 0, 0, far); +} + +/* Set the XScale debug `method of entry' if it is enabled. */ + +int +XScale_debug_moe (ARMul_State * state, int moe) +{ + ARMword value; + + if (!state->is_XScale) + return 1; + + value = read_cp14_reg (10); + if (value & (1UL << 31)) + { + if (moe != -1) + { + value &= ~0x1c; + value |= moe; + + write_cp14_reg (10, value); + } + return 1; + } + return 0; +} + +/* Coprocessor 13: Interrupt Controller and Bus Controller. */ -/***************************************************************************\ -* Dummy Co-processors * -\***************************************************************************/ +/* 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 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 *); +static ARMword XScale_cp13_CR0_Regs[16]; +static ARMword XScale_cp13_CR1_Regs[16]; -/***************************************************************************\ -* Define Co-Processor instruction handlers here * -\***************************************************************************/ +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; + } + + return TRUE; +} + +/* 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 registers 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 (! CP_ACCESS_ALLOWED (state, 13)) + return ARMul_CANT; + + /* Registers 0, 4 and 8 are defined when CRm == 0. + Registers 0, 1, 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 == 1 || (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 1: /* BCUMOD */ + /* Only bit 0 is accecssible. */ + value &= 1; + value |= XScale_cp13_CR1_Regs[1] & ~ 1; + 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; + + return TRUE; +} + +/* 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. */ + +static 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; + + /* Reset the clock counter if necessary. */ + if (value & ARMul_CP14_R0_CLKRST) + XScale_cp14_Regs [1] = 0; + 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]; @@ -57,12 +1001,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; @@ -70,26 +1019,44 @@ 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) { - state->prog32Sig = value >> 4 & 1; - state->data32Sig = value >> 5 & 1; + ARMword p,d,l,b; + + p = state->prog32Sig; + d = state->data32Sig; + l = state->lateabtSig; + b = state->bigendSig; + + state->prog32Sig = value >> 4 & 1; + state->data32Sig = value >> 5 & 1; state->lateabtSig = value >> 6 & 1; - state->bigendSig = value >> 7 & 1; - state->Emulate = TRUE; /* force ARMulator to notice these now ! */ + state->bigendSig = value >> 7 & 1; + + if ( p != state->prog32Sig + || d != state->data32Sig + || l != state->lateabtSig + || b != state->bigendSig) + /* Force ARMulator to notice these now. */ + state->Emulate = CHANGEMODE; } - return (ARMul_DONE); -} + return ARMul_DONE; +} static unsigned MMURead (ARMul_State * state ATTRIBUTE_UNUSED, unsigned reg, ARMword * value) @@ -98,7 +1065,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 @@ -106,121 +1074,142 @@ MMUWrite (ARMul_State * state, unsigned reg, ARMword value) { if (reg < 8) MMUReg[reg] = value; + if (reg == 1) { - state->prog32Sig = value >> 4 & 1; - state->data32Sig = value >> 5 & 1; + ARMword p,d,l,b; + + p = state->prog32Sig; + d = state->data32Sig; + l = state->lateabtSig; + b = state->bigendSig; + + state->prog32Sig = value >> 4 & 1; + state->data32Sig = value >> 5 & 1; state->lateabtSig = value >> 6 & 1; - state->bigendSig = value >> 7 & 1; - state->Emulate = TRUE; /* force ARMulator to notice these now ! */ + state->bigendSig = value >> 7 & 1; + + if ( p != state->prog32Sig + || d != state->data32Sig + || l != state->lateabtSig + || b != state->bigendSig) + /* Force ARMulator to notice these now. */ + state->Emulate = CHANGEMODE; } - return (TRUE); + + 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; } - return (ARMul_CANT); + else if (type == ARMul_BUSY) + { + if (ARMul_Time (state) >= finish) + return ARMul_DONE; + else + return ARMul_BUSY; + } + + return ARMul_CANT; } static unsigned @@ -228,7 +1217,7 @@ DoAFIQ (ARMul_State * state) { state->NfiqSig = LOW; state->Exception++; - return (0); + return 0; } static unsigned @@ -236,7 +1225,7 @@ DoAIRQ (ARMul_State * state) { state->NirqSig = LOW; state->Exception++; - return (0); + return 0; } static unsigned @@ -246,92 +1235,134 @@ 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; } -/***************************************************************************\ -* Install co-processor instruction handlers in this routine * -\***************************************************************************/ +/* Install co-processor instruction handlers in this routine. */ 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). */ + if (state->is_ep9312) + { + ARMul_CoProAttach (state, 4, NULL, NULL, DSPLDC4, DSPSTC4, + DSPMRC4, DSPMCR4, DSPCDP4, NULL, NULL); + ARMul_CoProAttach (state, 5, NULL, NULL, DSPLDC5, DSPSTC5, + DSPMRC5, DSPMCR5, DSPCDP5, NULL, NULL); + ARMul_CoProAttach (state, 6, NULL, NULL, NULL, NULL, + DSPMRC6, DSPMCR6, DSPCDP6, NULL, NULL); + } + else + { + ARMul_CoProAttach (state, 4, NULL, NULL, ValLDC, ValSTC, + ValMRC, ValMCR, ValCDP, NULL, NULL); - ARMul_CoProAttach (state, 4, NULL, NULL, - ValLDC, ValSTC, ValMRC, ValMCR, ValCDP, NULL, NULL); + ARMul_CoProAttach (state, 5, NULL, NULL, NULL, NULL, + ValMRC, ValMCR, IntCDP, NULL, NULL); + } - ARMul_CoProAttach (state, 5, NULL, NULL, - NULL, NULL, ValMRC, ValMCR, IntCDP, NULL, NULL); + if (state->is_XScale) + { + 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, 15, MMUInit, NULL, - NULL, NULL, MMUMRC, MMUMCR, NULL, MMURead, MMUWrite); + 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); + } + else + { + ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL, + MMUMRC, MMUMCR, NULL, MMURead, MMUWrite); + } + + if (state->is_iWMMXt) + { + ARMul_CoProAttach (state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC, + NULL, NULL, IwmmxtCDP, NULL, NULL); + + ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL, + IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL, NULL); + } - /* 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; } -/***************************************************************************\ -* Install co-processor finalisation routines in this routine * -\***************************************************************************/ +/* Install co-processor finalisation routines in this routine. */ void ARMul_CoProExit (ARMul_State * state) @@ -341,20 +1372,25 @@ 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); } -/***************************************************************************\ -* Routines to hook Co-processors into ARMulator * -\***************************************************************************/ +/* Routines to hook Co-processors into ARMulator. */ 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; @@ -382,40 +1418,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); -}