From 35e060d44959b30447b51c5a3ef2100124b61725 Mon Sep 17 00:00:00 2001 From: allkern Date: Sun, 2 Jul 2023 23:31:18 -0300 Subject: [PATCH] Improve IRQ handling --- psx/cpu.c | 61 ++++++++++++++++++++++++++++++------------------- psx/cpu.h | 2 +- psx/dev/gpu.c | 4 ++-- psx/dev/pad.c | 2 +- psx/dev/timer.c | 18 +++++++-------- psx/psx.c | 2 +- 6 files changed, 52 insertions(+), 37 deletions(-) diff --git a/psx/cpu.c b/psx/cpu.c index a3ff619..02dbfdb 100644 --- a/psx/cpu.c +++ b/psx/cpu.c @@ -65,6 +65,25 @@ psx_cpu_instruction_t g_psx_cpu_bxx_table[] = { psx_cpu_i_bltz , psx_cpu_i_bgez , psx_cpu_i_bltz , psx_cpu_i_bgez }; +uint32_t g_psx_cpu_cop0_write_mask_table[] = { + 0x00000000, // cop0r0-r2 - N/A + 0x00000000, // cop0r0-r2 - N/A + 0x00000000, // cop0r0-r2 - N/A + 0xffffffff, // cop0r3 - BPC - Breakpoint on execute (R/W) + 0x00000000, // cop0r4 - N/A + 0xffffffff, // cop0r5 - BDA - Breakpoint on data access (R/W) + 0x00000000, // cop0r6 - JUMPDEST - Randomly memorized jump address (R) + 0xffc0f03f, // cop0r7 - DCIC - Breakpoint control (R/W) + 0x00000000, // cop0r8 - BadVaddr - Bad Virtual Address (R) + 0xffffffff, // cop0r9 - BDAM - Data Access breakpoint mask (R/W) + 0x00000000, // cop0r10 - N/A + 0xffffffff, // cop0r11 - BPCM - Execute breakpoint mask (R/W) + 0xffffffff, // cop0r12 - SR - System status register (R/W) + 0x00000300, // cop0r13 - CAUSE - (R) Describes the most recently recognised exception + 0x00000000, // cop0r14 - EPC - Return Address from Trap (R) + 0x00000000 // cop0r15 - PRID - Processor ID (R) +}; + #define OP ((cpu->buf[1] >> 26) & 0x3f) #define S ((cpu->buf[1] >> 21) & 0x1f) #define T ((cpu->buf[1] >> 16) & 0x1f) @@ -326,6 +345,9 @@ void psx_cpu_cycle(psx_cpu_t* cpu) { return; } + if (psx_cpu_check_irq(cpu)) + return; + psx_cpu_fetch(cpu); cpu->delay_slot = cpu->branch; @@ -333,32 +355,20 @@ void psx_cpu_cycle(psx_cpu_t* cpu) { g_psx_cpu_primary_table[OP](cpu); - if ((cpu->cop0_r[COP0_SR] & SR_IEC) && (cpu->cop0_r[COP0_CAUSE] & cpu->cop0_r[COP0_SR] & SR_IM2)) { - psx_cpu_exception(cpu, CAUSE_INT); - } - - cpu->last_cycles = 2 + psx_bus_get_access_cycles(cpu->bus); + cpu->last_cycles = 2; + cpu->total_cycles += cpu->last_cycles; cpu->r[0] = 0; } -void psx_cpu_check_irq(psx_cpu_t* cpu) { - if ((cpu->cop0_r[COP0_SR] & SR_IEC) && (cpu->cop0_r[COP0_CAUSE] & cpu->cop0_r[COP0_SR] & SR_IM2)) { - // log_fatal("(before) IRQ pc=%08x, epc=%08x, cause=%08x, sr=%08x, tc=%u (%08x), istat=%08x, imask=%08x, [0]=%08x, [1]=%08x", - // cpu->pc, - // cpu->cop0_r[COP0_EPC], - // cpu->cop0_r[COP0_CAUSE], - // cpu->cop0_r[COP0_SR], - // cpu->total_cycles, - // cpu->total_cycles, - // psx_bus_read32(cpu->bus, 0x1F801070), - // psx_bus_read32(cpu->bus, 0x1F801074), - // cpu->buf[0], - // cpu->buf[1] - // ); - +int psx_cpu_check_irq(psx_cpu_t* cpu) { + if ((cpu->cop0_r[COP0_SR] & SR_IEC) && (cpu->cop0_r[COP0_SR] & cpu->cop0_r[COP0_CAUSE] & 0x00000700)) { psx_cpu_exception(cpu, CAUSE_INT); + + return 1; } + + return 0; } void psx_cpu_exception(psx_cpu_t* cpu, uint32_t cause) { @@ -366,13 +376,18 @@ void psx_cpu_exception(psx_cpu_t* cpu, uint32_t cause) { cpu->cop0_r[COP0_CAUSE] &= 0xffffff80; cpu->cop0_r[COP0_CAUSE] |= cause; + if (cause == CAUSE_INT) { + cpu->cop0_r[COP0_EPC] = cpu->pc - 4; + } else { + cpu->cop0_r[COP0_EPC] = cpu->pc - 8; + } + // If we're in a delay slot, set delay slot bit // on CAUSE if (cpu->delay_slot) { - cpu->cop0_r[COP0_EPC] = cpu->pc - 12; + cpu->cop0_r[COP0_EPC] -= 4; cpu->cop0_r[COP0_CAUSE] |= 0x80000000; } else { - cpu->cop0_r[COP0_EPC] = cpu->pc - 8; cpu->cop0_r[COP0_CAUSE] &= 0x7fffffff; } @@ -1266,7 +1281,7 @@ void psx_cpu_i_mtc0(psx_cpu_t* cpu) { DO_PENDING_LOAD; - cpu->cop0_r[D] = t; + cpu->cop0_r[D] = t & g_psx_cpu_cop0_write_mask_table[D]; } void psx_cpu_i_ctc0(psx_cpu_t* cpu) { diff --git a/psx/cpu.h b/psx/cpu.h index 954c790..85e4c18 100644 --- a/psx/cpu.h +++ b/psx/cpu.h @@ -161,7 +161,7 @@ void psx_cpu_save_state(psx_cpu_t*, FILE*); void psx_cpu_fetch(psx_cpu_t*); void psx_cpu_set_a_kcall_hook(psx_cpu_t*, psx_cpu_kcall_hook_t); void psx_cpu_set_b_kcall_hook(psx_cpu_t*, psx_cpu_kcall_hook_t); -void psx_cpu_check_irq(psx_cpu_t*); +int psx_cpu_check_irq(psx_cpu_t*); /* 00h INT Interrupt diff --git a/psx/dev/gpu.c b/psx/dev/gpu.c index d93468e..c8d71d5 100644 --- a/psx/dev/gpu.c +++ b/psx/dev/gpu.c @@ -759,7 +759,7 @@ void gpu_scanline_event(psx_gpu_t* gpu) { if (gpu->line == GPU_SCANS_PER_VDRAW_NTSC) { // Disable Vblank for now // log_fatal("Vblank"); - // psx_ic_irq(gpu->ic, IC_VBLANK); + psx_ic_irq(gpu->ic, IC_VBLANK); } else if (gpu->line == GPU_SCANS_PER_FRAME_NTSC) { gpu->line = 0; } @@ -780,7 +780,7 @@ void psx_gpu_update(psx_gpu_t* gpu, int cyc) { // Tick Hblank timer if (gpu->cycles >= (float)GPU_CYCLES_PER_SCANL_NTSC) { - gpu->cycles = 0; + gpu->cycles -= (float)GPU_CYCLES_PER_SCANL_NTSC; gpu_scanline_event(gpu); } diff --git a/psx/dev/pad.c b/psx/dev/pad.c index cdb035c..a76bcaf 100644 --- a/psx/dev/pad.c +++ b/psx/dev/pad.c @@ -42,7 +42,7 @@ uint32_t psx_pad_read32(psx_pad_t* pad, uint32_t offset) { uint16_t psx_pad_read16(psx_pad_t* pad, uint32_t offset) { switch (offset) { // case 0: return 0x00; - // case 4: return 0x03; + case 4: return 0x05; // case 8: return pad->mode; case 10: return pad->ctrl; // case 14: return pad->baud; diff --git a/psx/dev/timer.c b/psx/dev/timer.c index c00bc3d..cc61d15 100644 --- a/psx/dev/timer.c +++ b/psx/dev/timer.c @@ -38,16 +38,16 @@ uint16_t psx_timer_read16(psx_timer_t* timer, uint32_t offset) { return 0x000016b0; } - // int t = (offset >> 4) & 0x3; - // int r = offset & 0xf; + int t = (offset >> 4) & 0x3; + int r = offset & 0xf; - // if (r == 0) { - // switch (t) { - // case 0: return timer->t0_stub++; - // case 1: return timer->t1_stub++; - // case 2: return timer->t2_stub++; - // } - // } + if (r == 0) { + switch (t) { + case 0: return timer->t0_stub++; + case 1: return timer->t1_stub++; + case 2: return timer->t2_stub++; + } + } log_fatal("Unhandled 16-bit TIMER read at offset %08x", offset); diff --git a/psx/psx.c b/psx/psx.c index 6de63f3..772bf76 100644 --- a/psx/psx.c +++ b/psx/psx.c @@ -28,7 +28,7 @@ void psx_update(psx_t* psx) { psx_cpu_cycle(psx->cpu); psx_cdrom_update(psx->cdrom); psx_gpu_update(psx->gpu, psx->cpu->last_cycles); - psx_cpu_check_irq(psx->cpu); + //psx_cpu_check_irq(psx->cpu); } void psx_run_frame(psx_t* psx) {