all repos — mgba @ 60d49b4860162405afdd488ee3dac11fe5e925ab

mGBA Game Boy Advance Emulator

ARM: CP15 improvements
Jeffrey Pfau jeffrey@endrift.com
Thu, 02 Jun 2016 22:57:08 -0700
commit

60d49b4860162405afdd488ee3dac11fe5e925ab

parent

8bfad3f7beb823a9560e017fff526cf18d04b5d4

4 files changed, 137 insertions(+), 8 deletions(-)

jump to
M src/arm/arm.csrc/arm/arm.c

@@ -5,9 +5,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this

* 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);
M src/arm/arm.hsrc/arm/arm.h

@@ -127,6 +127,7 @@ void (*hitIllegal)(struct ARMCore* cpu, uint32_t opcode);

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 @@ ARMControlReg c0;

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 {
M src/arm/isa-arm.csrc/arm/isa-arm.c

@@ -636,8 +636,8 @@

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; })
M src/ds/ds.csrc/ds/ds.c

@@ -42,8 +42,8 @@ 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);

@@ -108,6 +108,7 @@ irqh->swi16 = NULL;

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 @@ irqh->swi16 = NULL;

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 @@ ds->springIRQ9 = 1;

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; + }}