kolibrios-gitea/contrib/other/uarm/cp15.c

187 lines
4.6 KiB
C
Raw Normal View History

#include "cp15.h"
#define CPUID_PXA255 0x69052D06UL //spepping A0
#define CPUID_PXA270 0x69054114UL //stepping C0
static Boolean cp15prvCoprocRegXferFunc(struct ArmCpu* cpu, void* userData, Boolean two, Boolean read, UInt8 op1, UInt8 Rx, UInt8 CRn, UInt8 CRm, UInt8 op2){
ArmCP15* cp15 = userData;
UInt32 val = 0, tmp;
if(!read) val = cpuGetRegExternal(cpu, Rx);
if(op1 != 0 || two) goto fail; //CP15 only accessed with MCR/MRC with op1 == 0
switch(CRn){
case 0: //ID codes
if(!read) goto fail; //cannot write to ID codes register
if(CRm != 0) goto fail; //CRm must be zero for this read
if(op2 == 0){ //main ID register
val = CPUID_PXA255;
goto success;
}
else if(op2 == 1){ //cahce type register - we lie here
val = 0x0B16A16AUL;
goto success;
}
break;
case 1: //control register
if(op2 == 0){
if(read){
val = cp15->control;
}
else{
tmp = val ^ cp15->control; //see what changed and mask off then chack for what we support changing of
if(tmp & 0x84F0UL){
err_str("cp15: unknown bits changed 0x");
err_hex(cp15->control);
err_str("->0x");
err_hex(val);
err_str(", halting\r\n");
while(true);
}
if(tmp & 0x00002000UL){ // V bit
cpuSetVectorAddr(cp15->cpu, (val & 0x00002000UL) ? 0xFFFF0000UL : 0x00000000UL);
cp15->control ^= 0x00002000UL;
}
if(tmp & 0x00000200UL){ // R bit
mmuSetR(cp15->mmu, (val & 0x00000200UL) != 0);
cp15->control ^= 0x00000200UL;
}
if(tmp & 0x00000100UL){ // S bit
mmuSetS(cp15->mmu, (val & 0x00000100UL) != 0);
cp15->control ^= 0x00000100UL;
}
if(tmp & 0x00000001UL){ // M bit
mmuSetTTP(cp15->mmu, (val & 0x00000001UL) ? cp15->ttb : MMU_DISABLED_TTP);
mmuTlbFlush(cp15->mmu);
cp15->control ^= 0x00000001UL;
}
}
}
else if(op2 == 1){ //PXA-specific thing
if(read) val = cp15->ACP;
else cp15->ACP = val;
}
else break;
goto success;
case 2: //translation tabler base
if(read) val = cp15->ttb;
else{
if(cp15->control & 0x00000001UL){ //mmu is on
mmuSetTTP(cp15->mmu, val);
mmuTlbFlush(cp15->mmu);
}
cp15->ttb = val;
}
goto success;
case 3: //domain access control
if(read) val = mmuGetDomainCfg(cp15->mmu);
else mmuSetDomainCfg(cp15->mmu, val);
goto success;
case 5: //FSR
if(read) val = cp15->FSR;
else cp15->FSR = val;
goto success;
case 6: //FAR
if(read) val = cp15->FAR;
else cp15->FAR = val;
goto success;
case 7: //cache ops
if((CRm == 5 || CRm == 7)&& op2 == 0) cpuIcacheInval(cp15->cpu); //invalidate entire {icache(5) or both i and dcache(7)}
if((CRm == 5 || CRm == 7) && op2 == 1) cpuIcacheInvalAddr(cp15->cpu, val); //invalidate {icache(5) or both i and dcache(7)} line, given VA
if((CRm == 5 || CRm == 7) && op2 == 2) cpuIcacheInval(cp15->cpu); //invalidate {icache(5) or both i and dcache(7)} line, given set/index. i dont know how to do this, so flush thee whole thing
goto success;
case 8: //TLB ops
mmuTlbFlush(cp15->mmu);
goto success;
case 9: //cache lockdown
if(CRm == 1 && op2 == 0){
err_str("Attempt to lock 0x");
err_hex(val);
err_str("+32 in icache\r\n");
}
else if(CRm == 2 && op2 == 0){
err_str("Dcache now ");
err_str(val ? "in" : "out of");
err_str(" lock mode\r\n");
}
goto success;
case 10: //TLB lockdown
goto success;
case 13: //FCSE
err_str("FCSE not supported\n");
break;
case 15:
if(op2 == 0 && CRm == 1){ //CPAR
if(read) val = cpuGetCPAR(cp15->cpu);
else cpuSetCPAR(cp15->cpu, val & 0x3FFF);
goto success;
}
break;
}
fail:
//TODO: cause invalid instruction trap in cpu
return false;
success:
if(read) cpuSetReg(cpu, Rx, val);
return true;
}
void cp15Init(ArmCP15* cp15, ArmCpu* cpu, ArmMmu* mmu){
ArmCoprocessor cp;
cp.regXfer = cp15prvCoprocRegXferFunc;
cp.dataProcessing = NULL;
cp.memAccess = NULL;
cp.twoRegF = NULL;
cp.userData = cp15;
__mem_zero(cp15, sizeof(ArmCP15));
cp15->cpu = cpu;
cp15->mmu = mmu;
cp15->control = 0x00004072UL;
cpuCoprocessorRegister(cpu, 15, &cp);
}
void cp15Deinit(ArmCP15* cp15){
cpuCoprocessorUnregister(cp15->cpu, 15);
}
void cp15SetFaultStatus(ArmCP15* cp15, UInt32 addr, UInt8 faultStatus){
cp15->FAR = addr;
cp15->FSR = faultStatus;
}