From 60d49b4860162405afdd488ee3dac11fe5e925ab Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Thu, 2 Jun 2016 22:57:08 -0700 Subject: [PATCH] ARM: CP15 improvements --- src/arm/arm.c | 6 +-- src/arm/arm.h | 36 ++++++++++++++++- src/arm/isa-arm.c | 4 +- src/ds/ds.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 137 insertions(+), 8 deletions(-) diff --git a/src/arm/arm.c b/src/arm/arm.c index 5b1a1ac1c..16aaca579 100644 --- a/src/arm/arm.c +++ b/src/arm/arm.c @@ -5,9 +5,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "arm.h" -#include "isa-arm.h" -#include "isa-inlines.h" -#include "isa-thumb.h" +#include "arm/isa-arm.h" +#include "arm/isa-inlines.h" +#include "arm/isa-thumb.h" static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode); diff --git a/src/arm/arm.h b/src/arm/arm.h index f63002641..803581636 100644 --- a/src/arm/arm.h +++ b/src/arm/arm.h @@ -127,6 +127,7 @@ struct ARMInterruptHandler { void (*bkpt16)(struct ARMCore* cpu, int immediate); void (*bkpt32)(struct ARMCore* cpu, int immediate); void (*readCPSR)(struct ARMCore* cpu); + void (*writeCP15)(struct ARMCore*, int crn, int crm, int opcode1, int opcode2, uint32_t value); void (*hitStub)(struct ARMCore* cpu, uint32_t opcode); }; @@ -163,6 +164,25 @@ DECL_BIT(ARMControlReg, L2, 26); DECL_BITFIELD(ARMCoprocessorAccess, uint32_t); +DECL_BITFIELD(ARMCacheability, uint32_t); +DECL_BIT(ARMCacheability, 0, 0); +DECL_BIT(ARMCacheability, 1, 1); +DECL_BIT(ARMCacheability, 2, 2); +DECL_BIT(ARMCacheability, 3, 3); +DECL_BIT(ARMCacheability, 4, 4); +DECL_BIT(ARMCacheability, 5, 5); +DECL_BIT(ARMCacheability, 6, 6); +DECL_BIT(ARMCacheability, 7, 7); + +DECL_BITFIELD(ARMProtection, uint32_t); +DECL_BIT(ARMProtection, Enable, 0); +DECL_BITS(ARMProtection, Size, 1, 5); +DECL_BITS(ARMProtection, Base, 12, 20); + +DECL_BITFIELD(ARMTCMControl, uint32_t); +DECL_BITS(ARMTCMControl, VirtualSize, 1, 5); +DECL_BITS(ARMTCMControl, Base, 12, 20); + struct ARMCP15 { struct { ARMCPUID cpuid; @@ -176,8 +196,20 @@ struct ARMCP15 { uint32_t c1; ARMCoprocessorAccess cpAccess; } r1; - - uint32_t (*write)(struct ARMCore*, int crn, int crm, int opcode1, int opcode2, uint32_t value); + struct { + ARMCacheability d; + ARMCacheability i; + } r2; + struct { + ARMCacheability d; + } r3; + struct { + ARMProtection region[8]; + } r6; + struct { + ARMTCMControl d; + ARMTCMControl i; + } r9; }; struct ARMCore { diff --git a/src/arm/isa-arm.c b/src/arm/isa-arm.c index f1abb3877..99c336c11 100644 --- a/src/arm/isa-arm.c +++ b/src/arm/isa-arm.c @@ -636,8 +636,8 @@ DEFINE_INSTRUCTION_ARM(BX, DEFINE_COPROCESSOR_INSTRUCTION(MRC, ARM_STUB) DEFINE_COPROCESSOR_INSTRUCTION(MCR, - if (cp == 15) { - cpu->cp15.write(cpu, crn, crm, op1, op2, cpu->gprs[rd]); + if (cp == 15 && cpu->irqh.writeCP15) { + cpu->irqh.writeCP15(cpu, crn, crm, op1, op2, cpu->gprs[rd]); } else { ARM_STUB; }) diff --git a/src/ds/ds.c b/src/ds/ds.c index 85756c725..d64d47e8e 100644 --- a/src/ds/ds.c +++ b/src/ds/ds.c @@ -42,9 +42,9 @@ static void DS7InterruptHandlerInit(struct ARMInterruptHandler* irqh); static void DS9Reset(struct ARMCore* cpu); static void DS9TestIRQ(struct ARMCore* cpu); +static void DS9WriteCP15(struct ARMCore* cpu, int crn, int crm, int opcode1, int opcode2, uint32_t value); static void DS9InterruptHandlerInit(struct ARMInterruptHandler* irqh); - static void DSProcessEvents(struct ARMCore* cpu); static void DSHitStub(struct ARMCore* cpu, uint32_t opcode); static void DSIllegal(struct ARMCore* cpu, uint32_t opcode); @@ -108,6 +108,7 @@ void DS7InterruptHandlerInit(struct ARMInterruptHandler* irqh) { irqh->swi32 = NULL; irqh->hitIllegal = DSIllegal; irqh->readCPSR = DS7TestIRQ; + irqh->writeCP15 = NULL; irqh->hitStub = DSHitStub; irqh->bkpt16 = DSBreakpoint; irqh->bkpt32 = DSBreakpoint; @@ -120,6 +121,7 @@ void DS9InterruptHandlerInit(struct ARMInterruptHandler* irqh) { irqh->swi32 = NULL; irqh->hitIllegal = DSIllegal; irqh->readCPSR = DS9TestIRQ; + irqh->writeCP15 = DS9WriteCP15; irqh->hitStub = DSHitStub; irqh->bkpt16 = DSBreakpoint; irqh->bkpt32 = DSBreakpoint; @@ -356,3 +358,98 @@ void DS9TestIRQ(struct ARMCore* cpu) { cpu->nextEvent = cpu->cycles; } } + +static void _writeSysControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) { + mLOG(DS, STUB, "CP15 system control write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value); +} + +static void _writeCacheControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) { + mLOG(DS, STUB, "CP15 cache control control write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value); + switch (opcode2) { + case 0: + cpu->cp15.r2.d = value; + break; + case 1: + cpu->cp15.r2.i = value; + break; + default: + mLOG(DS, GAME_ERROR, "CP15 cache control control bad op2: %i", opcode2); + break; + } +} + +static void _writeWriteBufferControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) { + mLOG(DS, STUB, "CP15 write buffer control write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value); + switch (opcode2) { + case 0: + cpu->cp15.r3.d = value; + break; + default: + mLOG(DS, GAME_ERROR, "CP15 cache control control bad op2: %i", opcode2); + break; + } +} + +static void _writeAccessControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) { + mLOG(DS, STUB, "CP15 access control write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value); +} + +static void _writeRegionConfiguration(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) { + cpu->cp15.r6.region[crm] = value; + uint32_t base = ARMProtectionGetBase(value) << 12; + uint32_t size = 2 << ARMProtectionGetSize(value); + mLOG(DS, STUB, "CP15 region configuration write: Region: %i, Insn: %i, Base: %08X, Size: %08X", crm, opcode2, base, size); +} + +static void _writeCache(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) { + mLOG(DS, STUB, "CP15 cache write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value); +} + +static void _writeTCMControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) { + uint32_t base = ARMTCMControlGetBase(value) << 12; + uint32_t size = 512 << ARMTCMControlGetVirtualSize(value); + mLOG(DS, STUB, "CP15 TCM control write: CRm: %i, Op2: %i, Base: %08X, Size: %08X", crm, opcode2, base, size); + switch (opcode2) { + case 0: + cpu->cp15.r9.d = value; + break; + case 1: + cpu->cp15.r9.i = value; + break; + default: + mLOG(DS, GAME_ERROR, "CP15 TCM control bad op2: %i", opcode2); + break; + } +} + +void DS9WriteCP15(struct ARMCore* cpu, int crn, int crm, int opcode1, int opcode2, uint32_t value) { + switch (crn) { + default: + mLOG(DS, STUB, "CP15 unknown write: CRn: %i, CRm: %i, Op1: %i, Op2: %i, Value: 0x%08X", crn, crm, opcode1, opcode2, value); + break; + case 0: + mLOG(DS, GAME_ERROR, "Attempted to write to read-only cp15 register"); + ARMRaiseUndefined(cpu); + break; + case 1: + _writeSysControl(cpu, crm, opcode2, value); + break; + case 2: + _writeCacheControl(cpu, crm, opcode2, value); + break; + case 3: + _writeWriteBufferControl(cpu, crm, opcode2, value); + break; + case 5: + _writeAccessControl(cpu, crm, opcode2, value); + break; + case 6: + _writeRegionConfiguration(cpu, crm, opcode2, value); + break; + case 7: + _writeCache(cpu, crm, opcode2, value); + break; + case 9: + _writeTCMControl(cpu, crm, opcode2, value); + break; + }}