ARM: CP15 improvements

This commit is contained in:
Jeffrey Pfau 2016-06-02 22:57:08 -07:00
parent 8bfad3f7be
commit 60d49b4860
4 changed files with 137 additions and 8 deletions

View File

@ -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);

View File

@ -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 {

View File

@ -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;
})

View File

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