From c3ae2f98d01baddf23a93ea5c2311701844f8b82 Mon Sep 17 00:00:00 2001 From: Matthew Green Date: Wed, 18 Apr 2001 16:39:37 +0000 Subject: [PATCH] * XScale coprocessor support. 2001-04-18 matthew green * armcopro.c (write_cp15_reg): Set CHANGEMODE if endianness changes. (read_cp15_reg): Make non-static. (XScale_cp15_LDC): Update for write_cp15_reg() change. (XScale_cp15_MCR): Likewise. (XScale_cp15_write_reg): Likewise. (XScale_check_memacc): New function. Check for breakpoints being activated by memory accesses. Does not support the Branch Target Buffer. (XScale_set_fsr_far): New function. Set FSR and FAR for XScale. (XScale_debug_moe): New function. Set the debug Method Of Entry, if configured. (write_cp14_reg): Reset count counter if requested. * armdefs.h (struct ARMul_State): New members `LastTime' and `CP14R0_CCD' used for the timer/counters. (ARMul_CP13_R0_FIQ, ARMul_CP13_R0_IRQ, ARMul_CP13_R8_PMUS, ARMul_CP14_R0_ENABLE, ARMul_CP14_R0_CLKRST, ARMul_CP14_R0_CCD, ARMul_CP14_R0_INTEN0, ARMul_CP14_R0_INTEN1, ARMul_CP14_R0_INTEN2, ARMul_CP14_R0_FLAG0, ARMul_CP14_R0_FLAG1, ARMul_CP14_R0_FLAG2, ARMul_CP14_R10_MOE_IB, ARMul_CP14_R10_MOE_DB, ARMul_CP14_R10_MOE_BT, ARMul_CP15_R1_ENDIAN, ARMul_CP15_R1_ALIGN, ARMul_CP15_R5_X, ARMul_CP15_R5_ST_ALIGN, ARMul_CP15_R5_IMPRE, ARMul_CP15_R5_MMU_EXCPT, ARMul_CP15_DBCON_M, ARMul_CP15_DBCON_E1, ARMul_CP15_DBCON_E0): New defines for XScale registers. (XScale_check_memacc, XScale_set_fsr_far, XScale_debug_moe): Prototype. (ARMul_Emulate32, ARMul_Emulate26): Clean up function definition. (ARMul_Emulate32): Handle the clock counter and hardware instruction breakpoints. Call XScale_set_fsr_far() for software breakpoints and software interrupts. (LoadMult): Call XScale_set_fsr_far() for data aborts. (LoadSMult): Likewise. (StoreMult): Likewise. (StoreSMult): Likewise. * armemu.h (write_cp15_reg): Update prototype. * arminit.c (ARMul_NewState): Initialise CP14R0_CCD and LastTime. (ARMul_Abort): If XScale, check for FIQ and IRQ being enabled in CP13 register 0. * armvirt.c (GetWord): Call XScale_check_memacc(). (PutWord): Likewise. --- sim/arm/ChangeLog | 41 +++++++++++++++++ sim/arm/armcopro.c | 110 +++++++++++++++++++++++++++++++++++++++++++++ sim/arm/armdefs.h | 33 ++++++++++++++ sim/arm/armemu.c | 107 ++++++++++++++++++++++++++++++++++--------- sim/arm/arminit.c | 11 ++++- sim/arm/armvirt.c | 4 ++ 6 files changed, 284 insertions(+), 22 deletions(-) diff --git a/sim/arm/ChangeLog b/sim/arm/ChangeLog index 9f81f545bc..5c031ab276 100644 --- a/sim/arm/ChangeLog +++ b/sim/arm/ChangeLog @@ -1,3 +1,44 @@ +2001-04-18 matthew green + + * armcopro.c (write_cp15_reg): Set CHANGEMODE if endianness changes. + (read_cp15_reg): Make non-static. + (XScale_cp15_LDC): Update for write_cp15_reg() change. + (XScale_cp15_MCR): Likewise. + (XScale_cp15_write_reg): Likewise. + (XScale_check_memacc): New function. Check for breakpoints being + activated by memory accesses. Does not support the Branch Target + Buffer. + (XScale_set_fsr_far): New function. Set FSR and FAR for XScale. + (XScale_debug_moe): New function. Set the debug Method Of Entry, + if configured. + (write_cp14_reg): Reset count counter if requested. + * armdefs.h (struct ARMul_State): New members `LastTime' and + `CP14R0_CCD' used for the timer/counters. + (ARMul_CP13_R0_FIQ, ARMul_CP13_R0_IRQ, ARMul_CP13_R8_PMUS, + ARMul_CP14_R0_ENABLE, ARMul_CP14_R0_CLKRST, ARMul_CP14_R0_CCD, + ARMul_CP14_R0_INTEN0, ARMul_CP14_R0_INTEN1, ARMul_CP14_R0_INTEN2, + ARMul_CP14_R0_FLAG0, ARMul_CP14_R0_FLAG1, ARMul_CP14_R0_FLAG2, + ARMul_CP14_R10_MOE_IB, ARMul_CP14_R10_MOE_DB, ARMul_CP14_R10_MOE_BT, + ARMul_CP15_R1_ENDIAN, ARMul_CP15_R1_ALIGN, ARMul_CP15_R5_X, + ARMul_CP15_R5_ST_ALIGN, ARMul_CP15_R5_IMPRE, ARMul_CP15_R5_MMU_EXCPT, + ARMul_CP15_DBCON_M, ARMul_CP15_DBCON_E1, ARMul_CP15_DBCON_E0): New + defines for XScale registers. + (XScale_check_memacc, XScale_set_fsr_far, XScale_debug_moe): Prototype. + (ARMul_Emulate32, ARMul_Emulate26): Clean up function definition. + (ARMul_Emulate32): Handle the clock counter and hardware instruction + breakpoints. Call XScale_set_fsr_far() for software breakpoints and + software interrupts. + (LoadMult): Call XScale_set_fsr_far() for data aborts. + (LoadSMult): Likewise. + (StoreMult): Likewise. + (StoreSMult): Likewise. + * armemu.h (write_cp15_reg): Update prototype. + * arminit.c (ARMul_NewState): Initialise CP14R0_CCD and LastTime. + (ARMul_Abort): If XScale, check for FIQ and IRQ being enabled in CP13 + register 0. + * armvirt.c (GetWord): Call XScale_check_memacc(). + (PutWord): Likewise. + 2001-03-20 Nick Clifton * armvirt.c (ARMul_ReLoadInstr): Do not enable alignment checking diff --git a/sim/arm/armcopro.c b/sim/arm/armcopro.c index 8605dcfbee..52b22d7b85 100644 --- a/sim/arm/armcopro.c +++ b/sim/arm/armcopro.c @@ -246,6 +246,15 @@ write_cp15_reg (ARMul_State * state, unsigned reg, unsigned opcode_2, unsigned C 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. */ @@ -446,6 +455,103 @@ XScale_cp15_write_reg (ARMul_State * state ATTRIBUTE_UNUSED, 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)) + 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); + } + } +} + +/***************************************************************************\ +* Check set +\***************************************************************************/ +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. */ /* There are two sets of registers for copro 13. @@ -735,6 +841,10 @@ write_cp14_reg (unsigned reg, ARMword value) 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: diff --git a/sim/arm/armdefs.h b/sim/arm/armdefs.h index 4ad5c5f07a..fde3125163 100644 --- a/sim/arm/armdefs.h +++ b/sim/arm/armdefs.h @@ -102,6 +102,9 @@ struct ARMul_State ARMul_CPWrites *CPWrite[16]; /* Write CP register */ unsigned char *CPData[16]; /* Coprocessor data */ unsigned char const *CPRegWords[16]; /* map of coprocessor register sizes */ + unsigned long LastTime; /* Value of last call to ARMul_Time() */ + ARMword CP14R0_CCD; /* used to count 64 clock cycles with CP14 R0 bit + 3 set */ unsigned EventSet; /* the number of events in the queue */ unsigned long Now; /* time to the nearest cycle */ @@ -342,6 +345,32 @@ extern ARMword ARMul_MemAccess (ARMul_State * state, ARMword, ARMword, #define ARMul_CANT 1 #define ARMul_INC 3 +#define ARMul_CP13_R0_FIQ 0x1 +#define ARMul_CP13_R0_IRQ 0x2 +#define ARMul_CP13_R8_PMUS 0x1 + +#define ARMul_CP14_R0_ENABLE 0x0001 +#define ARMul_CP14_R0_CLKRST 0x0004 +#define ARMul_CP14_R0_CCD 0x0008 +#define ARMul_CP14_R0_INTEN0 0x0010 +#define ARMul_CP14_R0_INTEN1 0x0020 +#define ARMul_CP14_R0_INTEN2 0x0040 +#define ARMul_CP14_R0_FLAG0 0x0100 +#define ARMul_CP14_R0_FLAG1 0x0200 +#define ARMul_CP14_R0_FLAG2 0x0400 +#define ARMul_CP14_R10_MOE_IB 0x0004 +#define ARMul_CP14_R10_MOE_DB 0x0008 +#define ARMul_CP14_R10_MOE_BT 0x000c +#define ARMul_CP15_R1_ENDIAN 0x0080 +#define ARMul_CP15_R1_ALIGN 0x0002 +#define ARMul_CP15_R5_X 0x0400 +#define ARMul_CP15_R5_ST_ALIGN 0x0001 +#define ARMul_CP15_R5_IMPRE 0x0406 +#define ARMul_CP15_R5_MMU_EXCPT 0x0400 +#define ARMul_CP15_DBCON_M 0x0100 +#define ARMul_CP15_DBCON_E1 0x000c +#define ARMul_CP15_DBCON_E0 0x0003 + extern unsigned ARMul_CoProInit (ARMul_State * state); extern void ARMul_CoProExit (ARMul_State * state); extern void ARMul_CoProAttach (ARMul_State * state, unsigned number, @@ -351,6 +380,10 @@ extern void ARMul_CoProAttach (ARMul_State * state, unsigned number, ARMul_CDPs * cdp, ARMul_CPReads * read, ARMul_CPWrites * write); extern void ARMul_CoProDetach (ARMul_State * state, unsigned number); +extern void XScale_check_memacc (ARMul_State * state, ARMword * address, + int store); +extern void XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword far); +extern int XScale_debug_moe (ARMul_State * state, int moe); /***************************************************************************\ * Definitons of things in the host environment * diff --git a/sim/arm/armemu.c b/sim/arm/armemu.c index dcc505fa3b..0947470abb 100644 --- a/sim/arm/armemu.c +++ b/sim/arm/armemu.c @@ -529,6 +529,79 @@ ARMul_Emulate26 (register ARMul_State * state) break; } /* cc check */ + /* Handle the Clock counter here. */ + if (state->is_XScale) + { + ARMword cp14r0 = state->CPRead[14] (state, 0, 0); + + if (cp14r0 && ARMul_CP14_R0_ENABLE) + { + unsigned long newcycles, nowtime = ARMul_Time(state); + + newcycles = nowtime - state->LastTime; + state->LastTime = nowtime; + if (cp14r0 && ARMul_CP14_R0_CCD) + { + if (state->CP14R0_CCD == -1) + state->CP14R0_CCD = newcycles; + else + state->CP14R0_CCD += newcycles; + if (state->CP14R0_CCD >= 64) + { + newcycles = 0; + while (state->CP14R0_CCD >= 64) + state->CP14R0_CCD -= 64, newcycles++; + goto check_PMUintr; + } + } + else + { + ARMword cp14r1; + int do_int = 0; + + state->CP14R0_CCD = -1; +check_PMUintr: + cp14r0 |= ARMul_CP14_R0_FLAG2; + (void) state->CPWrite[14] (state, 0, cp14r0); + + cp14r1 = state->CPRead[14] (state, 1, 0); + + /* coded like this for portability */ + while (newcycles) + { + if (cp14r1 == 0xffffffff) + { + cp14r1 = 0; + do_int = 1; + } + else + cp14r1++; + newcycles--; + } + (void) state->CPWrite[14] (state, 1, cp14r1); + if (do_int && (cp14r0 & ARMul_CP14_R0_INTEN2)) + { + if (state->CPRead[13] (state, 8, 0) + && ARMul_CP13_R8_PMUS) + ARMul_Abort (state, ARMul_FIQV); + else + ARMul_Abort (state, ARMul_IRQV); + } + } + } + } + + /* Handle hardware instructions breakpoints here. */ + if (state->is_XScale) + { + if ((pc | 3) == (read_cp15_reg (14, 0, 8) | 2) + || (pc | 3) == (read_cp15_reg (14, 0, 9) | 2)) + { + if (XScale_debug_moe (state, ARMul_CP14_R10_MOE_IB)) + ARMul_OSHandleSWI (state, SWI_Breakpoint); + } + } + /***************************************************************************\ * Actual execution of instructions begins here * \***************************************************************************/ @@ -1355,26 +1428,11 @@ ARMul_Emulate26 (register ARMul_State * state) 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 (state, 5, 0, 0, 0x200); /* Set FSR. */ - write_cp15_reg (state, 6, 0, 0, pc); /* Set FAR. */ - } - else - break; - } + /* BKPT - normally this will cause an abort, but on the + XScale we must check the DCSR. */ + XScale_set_fsr_far (state, ARMul_CP15_R5_MMU_EXCPT, pc); + if (!XScale_debug_moe (state, ARMul_CP14_R10_MOE_BT)) + break; } /* Force the next instruction to be refetched. */ @@ -3425,6 +3483,7 @@ ARMul_Emulate26 (register ARMul_State * state) if (instr == ARMul_ABORTWORD && state->AbortAddr == pc) { /* A prefetch abort. */ + XScale_set_fsr_far (state, ARMul_CP15_R5_MMU_EXCPT, pc); ARMul_Abort (state, ARMul_PrefetchAbortV); break; } @@ -4295,6 +4354,7 @@ LoadMult (ARMul_State * state, ARMword instr, ARMword address, ARMword WBBase) state->Reg[temp++] = dest; else if (!state->Aborted) { + XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address); state->Aborted = ARMul_DataAbortV; } @@ -4307,6 +4367,7 @@ LoadMult (ARMul_State * state, ARMword instr, ARMword address, ARMword WBBase) state->Reg[temp] = dest; else if (!state->Aborted) { + XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address); state->Aborted = ARMul_DataAbortV; } } @@ -4373,6 +4434,7 @@ LoadSMult (ARMul_State * state, state->Reg[temp++] = dest; else if (!state->Aborted) { + XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address); state->Aborted = ARMul_DataAbortV; } @@ -4388,6 +4450,7 @@ LoadSMult (ARMul_State * state, state->Reg[temp] = dest; else if (!state->Aborted) { + XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address); state->Aborted = ARMul_DataAbortV; } } @@ -4489,6 +4552,7 @@ StoreMult (ARMul_State * state, ARMword instr, if (state->abortSig && !state->Aborted) { + XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address); state->Aborted = ARMul_DataAbortV; } @@ -4504,6 +4568,7 @@ StoreMult (ARMul_State * state, ARMword instr, if (state->abortSig && !state->Aborted) { + XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address); state->Aborted = ARMul_DataAbortV; } } @@ -4585,6 +4650,7 @@ StoreSMult (ARMul_State * state, if (state->abortSig && !state->Aborted) { + XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address); state->Aborted = ARMul_DataAbortV; } @@ -4599,6 +4665,7 @@ StoreSMult (ARMul_State * state, if (state->abortSig && !state->Aborted) { + XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address); state->Aborted = ARMul_DataAbortV; } } diff --git a/sim/arm/arminit.c b/sim/arm/arminit.c index 2f6e73df3c..bdbb2c7777 100644 --- a/sim/arm/arminit.c +++ b/sim/arm/arminit.c @@ -106,6 +106,9 @@ ARMul_NewState (void) state->OSptr = NULL; state->CommandLine = NULL; + state->CP14R0_CCD = -1; + state->LastTime = 0; + state->EventSet = 0; state->Now = 0; state->EventPtr = (struct EventNode **) malloc ((unsigned) EVENTLISTSIZE * @@ -299,10 +302,14 @@ ARMul_Abort (ARMul_State * state, ARMword vector) SETABORT (IBIT, SVC26MODE, isize); break; case ARMul_IRQV: /* IRQ */ - SETABORT (IBIT, state->prog32Sig ? IRQ32MODE : IRQ26MODE, esize); + if (!state->is_XScale + || (state->CPRead[13](state, 0, 0) & ARMul_CP13_R0_IRQ)) + SETABORT (IBIT, state->prog32Sig ? IRQ32MODE : IRQ26MODE, esize); break; case ARMul_FIQV: /* FIQ */ - SETABORT (INTBITS, state->prog32Sig ? FIQ32MODE : FIQ26MODE, esize); + if (!state->is_XScale + || (state->CPRead[13](state, 0, 0) & ARMul_CP13_R0_FIQ)) + SETABORT (INTBITS, state->prog32Sig ? FIQ32MODE : FIQ26MODE, esize); break; } if (ARMul_MODE32BIT) diff --git a/sim/arm/armvirt.c b/sim/arm/armvirt.c index 15f2cb6850..ce1e77d8c4 100644 --- a/sim/arm/armvirt.c +++ b/sim/arm/armvirt.c @@ -64,6 +64,8 @@ GetWord (ARMul_State * state, ARMword address, int check) ARMword **pagetable; ARMword *pageptr; + XScale_check_memacc (state, &address, 0); + page = address >> PAGEBITS; offset = (address & OFFSETBITS) >> 2; pagetable = (ARMword **) state->MemDataPtr; @@ -97,6 +99,8 @@ PutWord (ARMul_State * state, ARMword address, ARMword data, int check) ARMword **pagetable; ARMword *pageptr; + XScale_check_memacc (state, &address, 1); + page = address >> PAGEBITS; offset = (address & OFFSETBITS) >> 2; pagetable = (ARMword **) state->MemDataPtr;