more realistic exception handling

This commit is contained in:
zeromus 2010-04-23 03:31:55 +00:00
parent 4069c5a517
commit a9b186acb3
8 changed files with 177 additions and 81 deletions

View File

@ -586,8 +586,11 @@ inline void SetupMMU(BOOL debugConsole) {
}
FORCEINLINE void CheckMemoryDebugEvent(const EDEBUG_EVENT event, const MMU_ACCESS_TYPE type, const u32 procnum, const u32 addr, const u32 size, const u32 val)
FORCEINLINE void CheckMemoryDebugEvent(EDEBUG_EVENT event, const MMU_ACCESS_TYPE type, const u32 procnum, const u32 addr, const u32 size, const u32 val)
{
//TODO - ugh work out a better prefetch event system
if(type == MMU_AT_CODE && event == DEBUG_EVENT_READ)
event = DEBUG_EVENT_EXECUTE;
if(CheckDebugEvent(event))
{
DebugEventData.memAccessType = type;
@ -596,11 +599,6 @@ FORCEINLINE void CheckMemoryDebugEvent(const EDEBUG_EVENT event, const MMU_ACCES
DebugEventData.size = size;
DebugEventData.val = val;
HandleDebugEvent(event);
if(type == MMU_AT_CODE && event == DEBUG_EVENT_READ)
{
HandleDebugEvent(DEBUG_EVENT_EXECUTE);
}
}
}
@ -704,6 +702,12 @@ FORCEINLINE u32 _MMU_read32(const int PROCNUM, const MMU_ACCESS_TYPE AT, const u
if(addr<0x02000000)
return T1ReadLong_guaranteedAligned(MMU.ARM9_ITCM, addr&0x7FFC);
//what happens when we execute from DTCM? nocash makes it look like we get 0xFFFFFFFF but i can't seem to verify it
//historically, desmume would fall through to its old memory map struct
//which would return unused memory (0)
//it seems the hardware returns 0 or something benign because in actuality 0xFFFFFFFF is an undefined opcode
//and we know our handling for that is solid
goto dunno;
}

View File

@ -45,7 +45,7 @@
//#define LOG_ARM9
//#define LOG_ARM7
bool dolog = true;
//bool dolog = true;
//#define LOG_TO_FILE
//#define LOG_TO_FILE_REGS
@ -2127,25 +2127,67 @@ void NDS_Reset()
{
NDS_ARM9.swi_tab = ARM9_swi_tab;
T1WriteLong(MMU.ARM9_BIOS, 0x0000, 0xEAFFFFFE); // loop for Reset !!!
T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEAFFFFFE); // loop for Undef instr expection
T1WriteLong(MMU.ARM9_BIOS, 0x0008, 0xEA00009C); // SWI
T1WriteLong(MMU.ARM9_BIOS, 0x000C, 0xEAFFFFFE); // loop for Prefetch Abort
T1WriteLong(MMU.ARM9_BIOS, 0x0010, 0xEAFFFFFE); // loop for Data Abort
//bios chains data abort to fast irq
//exception vectors:
T1WriteLong(MMU.ARM9_BIOS, 0x0000, 0xEAFFFFFE); // (infinite loop for) Reset !!!
//T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEAFFFFFE); // (infinite loop for) Undefined instruction
T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEA000004); // Undefined instruction -> Fast IRQ (just guessing)
T1WriteLong(MMU.ARM9_BIOS, 0x0008, 0xEA00009C); // SWI -> ?????
T1WriteLong(MMU.ARM9_BIOS, 0x000C, 0xEAFFFFFE); // (infinite loop for) Prefetch Abort
T1WriteLong(MMU.ARM9_BIOS, 0x0010, 0xEA000001); // Data Abort -> Fast IRQ
T1WriteLong(MMU.ARM9_BIOS, 0x0014, 0x00000000); // Reserved
T1WriteLong(MMU.ARM9_BIOS, 0x0018, 0xEA000095); // Normal IRQ
T1WriteLong(MMU.ARM9_BIOS, 0x001C, 0x00000000); // Fast IRQ
for (int t = 0; t < 156; t++) // logo
T1WriteLong(MMU.ARM9_BIOS, 0x0018, 0xEA000095); // Normal IRQ -> 0x0274
T1WriteLong(MMU.ARM9_BIOS, 0x001C, 0xEA00009D); // Fast IRQ -> 0x0298
// logo (do some games fail to boot without this? example?)
for (int t = 0; t < 0x9C; t++)
MMU.ARM9_BIOS[t + 0x20] = logo_data[t];
T1WriteLong(MMU.ARM9_BIOS, 0x0274, 0xE92D500F);
T1WriteLong(MMU.ARM9_BIOS, 0x0278, 0xEE190F11);
T1WriteLong(MMU.ARM9_BIOS, 0x027C, 0xE1A00620);
T1WriteLong(MMU.ARM9_BIOS, 0x0280, 0xE1A00600);
T1WriteLong(MMU.ARM9_BIOS, 0x0284, 0xE2800C40);
T1WriteLong(MMU.ARM9_BIOS, 0x0288, 0xE28FE000);
T1WriteLong(MMU.ARM9_BIOS, 0x028C, 0xE510F004);
T1WriteLong(MMU.ARM9_BIOS, 0x0290, 0xE8BD500F);
T1WriteLong(MMU.ARM9_BIOS, 0x0294, 0xE25EF004);
//...0xBC:
//(now what goes in this gap??)
//IRQ handler: get dtcm address and jump to a vector in it
T1WriteLong(MMU.ARM9_BIOS, 0x0274, 0xE92D500F); //STMDB SP!, {R0-R3,R12,LR}
T1WriteLong(MMU.ARM9_BIOS, 0x0278, 0xEE190F11); //MRC CP15, 0, R0, CR9, CR1, 0
T1WriteLong(MMU.ARM9_BIOS, 0x027C, 0xE1A00620); //MOV R0, R0, LSR #C
T1WriteLong(MMU.ARM9_BIOS, 0x0280, 0xE1A00600); //MOV R0, R0, LSL #C
T1WriteLong(MMU.ARM9_BIOS, 0x0284, 0xE2800C40); //ADD R0, R0, #4000
T1WriteLong(MMU.ARM9_BIOS, 0x0288, 0xE28FE000); //ADD LR, PC, #0
T1WriteLong(MMU.ARM9_BIOS, 0x028C, 0xE510F004); //LDR PC, [R0, -#4]
//????
T1WriteLong(MMU.ARM9_BIOS, 0x0290, 0xE8BD500F); //LDMIA SP!, {R0-R3,R12,LR}
T1WriteLong(MMU.ARM9_BIOS, 0x0294, 0xE25EF004); //SUBS PC, LR, #4
//-------
//FIQ and abort exception handler
//TODO - this code is copied from the bios. refactor it
//friendly reminder: to calculate an immediate offset: encoded = (desired_address-cur_address-8)
T1WriteLong(MMU.ARM9_BIOS, 0x0298, 0xE10FD000); //MRS SP, CPSR
T1WriteLong(MMU.ARM9_BIOS, 0x029C, 0xE38DD0C0); //ORR SP, SP, #C0
T1WriteLong(MMU.ARM9_BIOS, 0x02A0, 0xE12FF00D); //MSR CPSR_fsxc, SP
T1WriteLong(MMU.ARM9_BIOS, 0x02A4, 0xE59FD000 | (0x2D4-0x2A4-8)); //LDR SP, [FFFF02D4]
T1WriteLong(MMU.ARM9_BIOS, 0x02A8, 0xE28DD001); //ADD SP, SP, #1
T1WriteLong(MMU.ARM9_BIOS, 0x02AC, 0xE92D5000); //STMDB SP!, {R12,LR}
T1WriteLong(MMU.ARM9_BIOS, 0x02B0, 0xE14FE000); //MRS LR, SPSR
T1WriteLong(MMU.ARM9_BIOS, 0x02B4, 0xEE11CF10); //MRC CP15, 0, R12, CR1, CR0, 0
T1WriteLong(MMU.ARM9_BIOS, 0x02B8, 0xE92D5000); //STMDB SP!, {R12,LR}
T1WriteLong(MMU.ARM9_BIOS, 0x02BC, 0xE3CCC001); //BIC R12, R12, #1
T1WriteLong(MMU.ARM9_BIOS, 0x02C0, 0xEE01CF10); //MCR CP15, 0, R12, CR1, CR0, 0
T1WriteLong(MMU.ARM9_BIOS, 0x02C4, 0xE3CDC001); //BIC R12, SP, #1
T1WriteLong(MMU.ARM9_BIOS, 0x02C8, 0xE59CC010); //LDR R12, [R12, #10]
T1WriteLong(MMU.ARM9_BIOS, 0x02CC, 0xE35C0000); //CMP R12, #0
T1WriteLong(MMU.ARM9_BIOS, 0x02D0, 0x112FFF3C); //BLXNE R12
T1WriteLong(MMU.ARM9_BIOS, 0x02D4, 0x027FFD9C); //0x027FFD9C
//---------
}
#ifdef LOG_ARM7
@ -2247,6 +2289,9 @@ void NDS_Reset()
NDS_ARM9.R13_svc = 0x00803FC0;
NDS_ARM9.R13_irq = 0x00803FA0;
NDS_ARM9.R13_usr = 0x00803EC0;
NDS_ARM9.R13_abt = NDS_ARM9.R13_usr; //?????
//I think it is wrong to take gbatek's "SYS" and put it in USR--maybe USR doesnt matter.
//i think SYS is all the misc modes. please verify by setting nonsensical stack values for USR here
NDS_ARM9.R[13] = NDS_ARM9.R13_usr;
//n.b.: im not sure about all these, I dont know enough about arm9 svc/irq/etc modes
//and how theyre named in desmume to match them up correctly. i just guessed.

View File

@ -261,28 +261,6 @@ TEMPLATE static u32 FASTCALL OP_UND(const u32 i)
return 1;
}
#define TRAPUNDEF() \
LOG("Undefined instruction: %#08X PC = %#08X \n", cpu->instruction, cpu->instruct_adr); \
\
if (((cpu->intVector != 0) ^ (PROCNUM == ARMCPU_ARM9))) \
{ \
Status_Reg tmp = cpu->CPSR; \
armcpu_switchMode(cpu, UND); /* enter und mode */ \
cpu->R[14] = cpu->R[15] - 4; /* jump to und Vector */ \
cpu->SPSR = tmp; /* save old CPSR as new SPSR */ \
cpu->CPSR.bits.T = 0; /* handle as ARM32 code */ \
cpu->CPSR.bits.I = cpu->SPSR.bits.I; /* keep int disable flag */ \
cpu->changeCPSR(); \
cpu->R[15] = cpu->intVector + 0x04; \
cpu->next_instruction = cpu->R[15]; \
return 4; \
} \
else \
{ \
emu_halt(); \
return 4; \
} \
//-----------------------------------------------------------------------------
// AND / ANDS
// Timing: OK
@ -3176,6 +3154,8 @@ TEMPLATE static u32 FASTCALL OP_BX(const u32 i)
u32 tmp = cpu->R[REG_POS(cpu->instruction, 0)];
cpu->CPSR.bits.T = BIT0(tmp);
//zeromus has a little concern about these. shouldnt they be 0xFFFFFFFC?
//can someone refute this or prove it?
cpu->R[15] = tmp & 0xFFFFFFFE;
cpu->next_instruction = cpu->R[15];
return 3;
@ -3187,6 +3167,8 @@ TEMPLATE static u32 FASTCALL OP_BLX_REG(const u32 i)
cpu->R[14] = cpu->next_instruction;
cpu->CPSR.bits.T = BIT0(tmp);
//zeromus has a little concern about these. shouldnt they be 0xFFFFFFFC?
//can someone refute this or prove it?
cpu->R[15] = tmp & 0xFFFFFFFE;
cpu->next_instruction = cpu->R[15];
return 3;
@ -6732,37 +6714,37 @@ TEMPLATE static u32 FASTCALL OP_LDRD_STRD_OFFSET_PRE_INDEX(const u32 i)
TEMPLATE static u32 FASTCALL OP_STC_P_IMM_OFF(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
TEMPLATE static u32 FASTCALL OP_STC_M_IMM_OFF(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
TEMPLATE static u32 FASTCALL OP_STC_P_PREIND(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
TEMPLATE static u32 FASTCALL OP_STC_M_PREIND(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
TEMPLATE static u32 FASTCALL OP_STC_P_POSTIND(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
TEMPLATE static u32 FASTCALL OP_STC_M_POSTIND(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
TEMPLATE static u32 FASTCALL OP_STC_OPTION(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
//-----------------------------------------------------------------------------
@ -6772,38 +6754,37 @@ TEMPLATE static u32 FASTCALL OP_STC_OPTION(const u32 i)
TEMPLATE static u32 FASTCALL OP_LDC_P_IMM_OFF(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
TEMPLATE static u32 FASTCALL OP_LDC_M_IMM_OFF(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
TEMPLATE static u32 FASTCALL OP_LDC_P_PREIND(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
TEMPLATE static u32 FASTCALL OP_LDC_M_PREIND(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
TEMPLATE static u32 FASTCALL OP_LDC_P_POSTIND(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
TEMPLATE static u32 FASTCALL OP_LDC_M_POSTIND(const u32 i)
{
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
TEMPLATE static u32 FASTCALL OP_LDC_OPTION(const u32 i)
{
TRAPUNDEF();
return 2;
return TRAPUNDEF(cpu);
}
//-----------------------------------------------------------------------------
@ -6813,7 +6794,7 @@ TEMPLATE static u32 FASTCALL OP_LDC_OPTION(const u32 i)
TEMPLATE static u32 FASTCALL OP_MCR(const u32 i)
{
u32 cpnum = REG_POS(i, 8);
if(!cpu->coproc[cpnum])
{
emu_halt();
@ -6911,7 +6892,7 @@ TEMPLATE static u32 FASTCALL OP_BKPT(const u32 i)
TEMPLATE static u32 FASTCALL OP_CDP(const u32 i)
{
LOG("Stopped (OP_CDP) \n");
TRAPUNDEF();
return TRAPUNDEF(cpu);
}
//-----------------------------------------------------------------------------

View File

@ -397,7 +397,7 @@ FORCEINLINE static u32 armcpu_prefetch()
armcpu->R[15] = armcpu->next_instruction + 4;
}
#else
curInstruction &= 0x0FFFFFFC;
curInstruction &= 0xFFFFFFFC; //please don't change this to 0x0FFFFFFC -- the NDS will happily run on 0xF******* addresses all day long
armcpu->instruction = _MMU_read32<PROCNUM, MMU_AT_CODE>(curInstruction);
armcpu->instruct_adr = curInstruction;
armcpu->next_instruction = curInstruction + 4;
@ -419,7 +419,7 @@ FORCEINLINE static u32 armcpu_prefetch()
armcpu->R[15] = armcpu->next_instruction + 2;
}
#else
curInstruction &= 0x0FFFFFFE;
curInstruction &= 0xFFFFFFFE; //please don't change this to 0x0FFFFFFE -- the NDS will happily run on 0xF******* addresses all day long
armcpu->instruction = _MMU_read16<PROCNUM, MMU_AT_CODE>(curInstruction);
armcpu->instruct_adr = curInstruction;
armcpu->next_instruction = curInstruction + 2;
@ -469,6 +469,37 @@ static BOOL (FASTCALL* test_conditions[])(Status_Reg CPSR)= {
(cond<15&&test_conditions[cond](CPSR))
#endif
//TODO - merge with armcpu_irqException?
//http://www.ethernut.de/en/documents/arm-exceptions.html
//http://docs.google.com/viewer?a=v&q=cache:V4ht1YkxprMJ:www.cs.nctu.edu.tw/~wjtsai/EmbeddedSystemDesign/Ch3-1.pdf+arm+exception+handling&hl=en&gl=us&pid=bl&srcid=ADGEEShx9VTHbUhWdDOrTVRzLkcCsVfJiijncNDkkgkrlJkLa7D0LCpO8fQ_hhU3DTcgZh9rcZWWQq4TYhhCovJ625h41M0ZUX3WGasyzWQFxYzDCB-VS6bsUmpoJnRxAc-bdkD0qmsu&sig=AHIEtbR9VHvDOCRmZFQDUVwy53iJDjoSPQ
void armcpu_exception(armcpu_t *cpu, u32 number)
{
Mode cpumode = USR;
switch(number)
{
case EXCEPTION_RESET: cpumode = SVC; break;
case EXCEPTION_UNDEFINED_INSTRUCTION: cpumode = UND; break;
case EXCEPTION_SWI: cpumode = SVC; break;
case EXCEPTION_PREFETCH_ABORT: cpumode = ABT; break;
case EXCEPTION_DATA_ABORT: cpumode = ABT; break;
case EXCEPTION_RESERVED_0x14: emu_halt(); break;
case EXCEPTION_IRQ: cpumode = IRQ; break;
case EXCEPTION_FAST_IRQ: cpumode = FIQ; break;
}
Status_Reg tmp = cpu->CPSR;
armcpu_switchMode(cpu, cpumode); //enter new mode
cpu->R[14] = cpu->next_instruction;
cpu->SPSR = tmp; //save old CPSR as new SPSR
cpu->CPSR.bits.T = 0; //handle as ARM32 code
cpu->CPSR.bits.I = 1;
cpu->changeCPSR();
cpu->R[15] = cpu->intVector + number;
cpu->next_instruction = cpu->R[15];
printf("armcpu_exception!\n");
//extern bool dolog;
//dolog=true;
}
BOOL armcpu_irqException(armcpu_t *armcpu)
{
@ -502,6 +533,21 @@ BOOL armcpu_irqException(armcpu_t *armcpu)
return TRUE;
}
u32 TRAPUNDEF(armcpu_t* cpu)
{
LOG("Undefined instruction: %#08X PC = %#08X \n", cpu->instruction, cpu->instruct_adr);
if (((cpu->intVector != 0) ^ (cpu->proc_ID == ARMCPU_ARM9)))
{
armcpu_exception(&NDS_ARM9,0x04);
return 4;
}
else
{
emu_halt();
return 4;
}
}
//BOOL
//armcpu_flagIrq( armcpu_t *armcpu) {
// if(armcpu->CPSR.bits.I) return FALSE;
@ -524,6 +570,11 @@ u32 armcpu_exec()
u32 cFetch = 0;
u32 cExecute = 0;
if(NDS_ARM9.instruct_adr == 0x0201125C)
{
int zzz=9;
}
//this assert is annoying. but sometimes it is handy.
//assert(ARMPROC.instruct_adr!=0x00000000);
#ifdef DEVELOPER
@ -538,18 +589,18 @@ u32 armcpu_exec()
break;
case 0x00000004:
printf("BIOS%c: Undefined instruction\n", PROCNUM?'7':'9');
emu_halt();
//emu_halt();
break;
case 0x00000008:
//printf("BIOS%c: SWI\n", PROCNUM?'7':'9');
break;
case 0x0000000C:
printf("BIOS%c: Prefetch Abort!!!\n", PROCNUM?'7':'9');
emu_halt();
//emu_halt();
break;
case 0x00000010:
printf("BIOS%c: Data Abort!!!\n", PROCNUM?'7':'9');
emu_halt();
//printf("BIOS%c: Data Abort!!!\n", PROCNUM?'7':'9');
//emu_halt();
break;
case 0x00000014:
printf("BIOS%c: Reserved!!!\n", PROCNUM?'7':'9');

View File

@ -29,6 +29,15 @@
#define OPCODE(i) (((i)>>21)&0xF)
#define SIGNEBIT(i) BIT_N(i,20)
#define EXCEPTION_RESET 0x00
#define EXCEPTION_UNDEFINED_INSTRUCTION 0x04
#define EXCEPTION_SWI 0x08
#define EXCEPTION_PREFETCH_ABORT 0x0C
#define EXCEPTION_DATA_ABORT 0x10
#define EXCEPTION_RESERVED_0x14 0x14
#define EXCEPTION_IRQ 0x18
#define EXCEPTION_FAST_IRQ 0x1C
#define INSTRUCTION_INDEX(i) ((((i)>>16)&0xFF0)|(((i)>>4)&0xF))
inline u32 ROR(u32 i, u32 j) { return ((((u32)(i))>>(j)) | (((u32)(i))<<(32-(j)))); }
@ -216,6 +225,8 @@ template<int PROCNUM> u32 armcpu_exec();
BOOL armcpu_irqException(armcpu_t *armcpu);
BOOL armcpu_flagIrq( armcpu_t *armcpu);
void armcpu_exception(armcpu_t *cpu, u32 number);
u32 TRAPUNDEF(armcpu_t* cpu);
extern armcpu_t NDS_ARM7;
extern armcpu_t NDS_ARM9;

View File

@ -36,6 +36,8 @@
#include "lua-engine.h"
#endif
armcpu_t* TDebugEventData::cpu() { return procnum==0?&NDS_ARM9:&NDS_ARM7; }
TDebugEventData DebugEventData;
u32 debugFlag;
@ -43,25 +45,25 @@ u32 debugFlag;
const bool debug_acl = false;
static bool acl_check_access(u32 adr, u32 access) {
//tweak the access value with the execution mode.
//user code is USR and every other mode is SYS.
//this is weird logic, but I didn't want to change..
access |= 1;
if ((NDS_ARM9.CPSR.val & 0x1F) == 0x10) {
// is user mode access
access ^= 1;
}
//non-user modes get separate access handling, so check that here
if(NDS_ARM9.CPSR.bits.mode != USR)
access |= 1;
if (armcp15_isAccessAllowed((armcp15_t *)NDS_ARM9.coproc[15],adr,access)==FALSE) {
HandleDebugEvent(DEBUG_EVENT_ACL_EXCEPTION);
}
return true;
}
void armcpu_exception(armcpu_t *cpu, u32 number);
void HandleDebugEvent_ACL_Exception()
{
printf("ACL EXCEPTION!\n");
emu_halt();
if(DebugEventData.memAccessType == MMU_AT_CODE)
armcpu_exception(DebugEventData.cpu(),EXCEPTION_PREFETCH_ABORT);
else if(DebugEventData.memAccessType == MMU_AT_DATA)
armcpu_exception(DebugEventData.cpu(),EXCEPTION_DATA_ABORT);
}
void HandleDebugEvent_Read()

View File

@ -169,12 +169,14 @@ private:
};
extern DebugNotify DEBUG_Notify;
struct armcpu_t;
//information about a debug event will be stuffed into here by the generator
struct TDebugEventData
{
MMU_ACCESS_TYPE memAccessType;
u32 procnum, addr, size, val;
armcpu_t* cpu();
};
extern TDebugEventData DebugEventData;

View File

@ -69,8 +69,8 @@ static bool OverflowFromSUB(s32 alu_out, s32 left, s32 right)
TEMPLATE static u32 FASTCALL OP_UND_THUMB(const u32 i)
{
INFO("THUMB%c: Undefined instruction: 0x%08X PC=0x%08X. Stopped!!!\n", cpu->proc_ID?'7':'9', cpu->instruction, cpu->instruct_adr);
emu_halt();
INFO("THUMB%c: Undefined instruction: 0x%08X PC=0x%08X.\n", cpu->proc_ID?'7':'9', cpu->instruction, cpu->instruct_adr);
TRAPUNDEF(cpu);
return 1;
}