shithub: psxe

Download patch

ref: 61c23fa9b7efb4506b39cef21187ea5a39ab50d0
parent: a034f22be3a4d33dc1daaf4c8d20534363eba259
author: allkern <lisandroaalarcon@gmail.com>
date: Tue Jul 4 16:37:14 EDT 2023

Rework pipelining implementation

The shell is finally booting!

--- a/psx/cpu.c
+++ b/psx/cpu.c
@@ -84,15 +84,15 @@
     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)
-#define D ((cpu->buf[1] >> 11) & 0x1f)
-#define IMM5 ((cpu->buf[1] >> 6) & 0x1f)
-#define CMT ((cpu->buf[1] >> 6) & 0xfffff)
-#define SOP (cpu->buf[1] & 0x3f)
-#define IMM26 (cpu->buf[1] & 0x3ffffff)
-#define IMM16 (cpu->buf[1] & 0xffff)
+#define OP ((cpu->opcode >> 26) & 0x3f)
+#define S ((cpu->opcode >> 21) & 0x1f)
+#define T ((cpu->opcode >> 16) & 0x1f)
+#define D ((cpu->opcode >> 11) & 0x1f)
+#define IMM5 ((cpu->opcode >> 6) & 0x1f)
+#define CMT ((cpu->opcode >> 6) & 0xfffff)
+#define SOP (cpu->opcode & 0x3f)
+#define IMM26 (cpu->opcode & 0x3ffffff)
+#define IMM16 (cpu->opcode & 0xffff)
 #define IMM16S ((int32_t)((int16_t)IMM16))
 
 #define R_R0 (cpu->r[0])
@@ -128,7 +128,7 @@
 #define R_FP (cpu->r[30])
 #define R_RA (cpu->r[31])
 
-// #define CPU_TRACE
+#define CPU_TRACE
 
 #ifdef CPU_TRACE
 #define TRACE_M(m) \
@@ -210,6 +210,12 @@
 #define SE8(v) ((int32_t)((int8_t)v))
 #define SE16(v) ((int32_t)((int16_t)v))
 
+#define BRANCH(offset) \
+    cpu->next_pc = cpu->next_pc + (offset); \
+    cpu->next_pc = cpu->next_pc - 4; \
+    cpu->branch = 1; \
+    cpu->branch_taken = 1;
+
 const char* g_mips_cop0_register_names[] = {
     "cop0_r0",
     "cop0_r1",
@@ -288,28 +294,13 @@
 void cpu_b_kcall_hook(psx_cpu_t*);
 
 void psx_cpu_fetch(psx_cpu_t* cpu) {
-    cpu->buf[0] = psx_bus_read32(cpu->bus, cpu->pc);
-    cpu->pc += 4;
+    //cpu->buf[0] = psx_bus_read32(cpu->bus, cpu->pc);
+    //cpu->pc += 4;
 
     // Discard fetch cycles
     psx_bus_get_access_cycles(cpu->bus);
 }
 
-void psx_cpu_init(psx_cpu_t* cpu, psx_bus_t* bus) {
-    memset(cpu, 0, sizeof(psx_cpu_t));
-
-    psx_cpu_set_a_kcall_hook(cpu, cpu_a_kcall_hook);
-    psx_cpu_set_b_kcall_hook(cpu, cpu_b_kcall_hook);
-
-    cpu->bus = bus;
-    cpu->pc = 0xbfc00000;
-
-    cpu->cop0_r[COP0_SR] = 0x10900000;
-    cpu->cop0_r[COP0_PRID] = 0x00000002;
-
-    psx_cpu_fetch(cpu);
-}
-
 void psx_cpu_destroy(psx_cpu_t* cpu) {
     free(cpu);
 }
@@ -330,29 +321,44 @@
     fread((char*)cpu, sizeof(*cpu) - sizeof(psx_bus_t*), 1, file);
 }
 
-void psx_cpu_cycle(psx_cpu_t* cpu) {
-    if ((cpu->pc & 0x3fffffff) == 0x000000a4)
-        if (cpu->a_function_hook) cpu->a_function_hook(cpu);
+void psx_cpu_init(psx_cpu_t* cpu, psx_bus_t* bus) {
+    memset(cpu, 0, sizeof(psx_cpu_t));
 
+    psx_cpu_set_a_kcall_hook(cpu, cpu_a_kcall_hook);
+    psx_cpu_set_b_kcall_hook(cpu, cpu_b_kcall_hook);
+
+    cpu->bus = bus;
+    cpu->pc = 0xbfc00000;
+    cpu->next_pc = cpu->pc + 4;
+
+    cpu->cop0_r[COP0_SR] = 0x10900000;
+    cpu->cop0_r[COP0_PRID] = 0x00000002;
+}
+
+void psx_cpu_cycle(psx_cpu_t* cpu) {
     if ((cpu->pc & 0x3fffffff) == 0x000000b4)
-        if (cpu->a_function_hook) cpu->b_function_hook(cpu);
+        if (cpu->b_function_hook) cpu->b_function_hook(cpu);
 
-    cpu->buf[1] = cpu->buf[0];
+    cpu->saved_pc = cpu->pc;
+    cpu->delay_slot = cpu->branch;
+    cpu->branch = 0;
+    cpu->branch_taken = 0;
 
-    if (cpu->pc & 0x3) {
+    if (cpu->saved_pc & 3) {
         psx_cpu_exception(cpu, CAUSE_ADEL);
-
-        return;
     }
 
-    if (psx_cpu_check_irq(cpu))
-        return;
+    cpu->opcode = psx_bus_read32(cpu->bus, cpu->pc);
 
-    psx_cpu_fetch(cpu);
+    cpu->pc = cpu->next_pc;
+    cpu->next_pc += 4;
 
-    cpu->delay_slot = cpu->branch;
-    cpu->branch = 0;
+    if (psx_cpu_check_irq(cpu)) {
+        psx_cpu_exception(cpu, CAUSE_INT);
 
+        return;
+    }
+
     g_psx_cpu_primary_table[OP](cpu);
 
     cpu->last_cycles = 2;
@@ -362,35 +368,27 @@
 }
 
 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;
+    return (cpu->cop0_r[COP0_SR] & SR_IEC) && (cpu->cop0_r[COP0_SR] & cpu->cop0_r[COP0_CAUSE] & 0x00000700);
 }
 
 void psx_cpu_exception(psx_cpu_t* cpu, uint32_t cause) {
+    cpu->cop0_r[COP0_CAUSE] &= 0x0000ff00;
+
     // Set excode and clear 3 LSBs
     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;
-    }
+    cpu->cop0_r[COP0_EPC] = cpu->saved_pc;
 
-    // If we're in a delay slot, set delay slot bit
-    // on CAUSE
     if (cpu->delay_slot) {
         cpu->cop0_r[COP0_EPC] -= 4;
         cpu->cop0_r[COP0_CAUSE] |= 0x80000000;
-    } else {
-        cpu->cop0_r[COP0_CAUSE] &= 0x7fffffff;
     }
 
+    if ((cause == CAUSE_INT) && (cpu->cop0_r[COP0_EPC] & 0xfe000000) == 0x4a000000) {
+        cpu->cop0_r[COP0_EPC] += 4;
+    }
+
     // Do exception stack push
     uint32_t mode = cpu->cop0_r[COP0_SR] & 0x3f;
 
@@ -399,21 +397,15 @@
 
     // Set PC to the vector selected on BEV
     cpu->pc = (cpu->cop0_r[COP0_SR] & SR_BEV) ? 0xbfc00180 : 0x80000080;
-
-    // Simulate pipeline flush
-    psx_cpu_fetch(cpu);
-
-    cpu->buf[1] = cpu->buf[0];
+    cpu->next_pc = cpu->pc + 4;
 }
 
 void psx_cpu_irq(psx_cpu_t* cpu, uint32_t irq) {
-    // Set interrupt pending field
-    cpu->cop0_r[COP0_CAUSE] &= ~SR_IM2;
     cpu->cop0_r[COP0_CAUSE] |= irq ? SR_IM2 : 0;
 }
 
 void psx_cpu_i_invalid(psx_cpu_t* cpu) {
-    log_fatal("%08x: Illegal instruction %08x", cpu->pc - 8, cpu->buf[1]);
+    log_fatal("%08x: Illegal instruction %08x", cpu->pc - 8, cpu->opcode);
 
     psx_cpu_exception(cpu, CAUSE_RI);
 }
@@ -425,6 +417,7 @@
 
 void psx_cpu_i_bxx(psx_cpu_t* cpu) {
     cpu->branch = 1;
+    cpu->branch_taken = 0;
 
     g_psx_cpu_bxx_table[T](cpu);
 }
@@ -438,8 +431,7 @@
     DO_PENDING_LOAD;
 
     if ((int32_t)s < (int32_t)0) {
-        cpu->pc -= 4;
-        cpu->pc += (IMM16S << 2);
+        BRANCH(IMM16S << 2);
     }
 }
 
@@ -451,8 +443,7 @@
     DO_PENDING_LOAD;
 
     if ((int32_t)s >= (int32_t)0) {
-        cpu->pc -= 4;
-        cpu->pc += (IMM16S << 2);
+        BRANCH(IMM16S << 2);
     }
 }
 
@@ -463,11 +454,10 @@
 
     DO_PENDING_LOAD;
 
-    R_RA = cpu->pc;
+    R_RA = cpu->next_pc;
 
     if ((int32_t)s < (int32_t)0) {
-        cpu->pc -= 4;
-        cpu->pc += (IMM16S << 2);
+        BRANCH(IMM16S << 2);
     }
 }
 
@@ -478,11 +468,10 @@
 
     DO_PENDING_LOAD;
 
-    R_RA = cpu->pc;
+    R_RA = cpu->next_pc;
 
     if ((int32_t)s >= (int32_t)0) {
-        cpu->pc -= 4;
-        cpu->pc += (IMM16S << 2);
+        BRANCH(IMM16S << 2);
     }
 }
 
@@ -493,7 +482,7 @@
 
     DO_PENDING_LOAD;
 
-    cpu->pc = (cpu->pc & 0xf0000000) | (IMM26 << 2);
+    cpu->next_pc = (cpu->next_pc & 0xf0000000) | (IMM26 << 2);
 }
 
 void psx_cpu_i_jal(psx_cpu_t* cpu) {
@@ -503,13 +492,14 @@
 
     DO_PENDING_LOAD;
 
-    cpu->r[31] = cpu->pc;
+    R_RA = cpu->next_pc;
 
-    cpu->pc = (cpu->pc & 0xf0000000) | (IMM26 << 2);
+    cpu->next_pc = (cpu->next_pc & 0xf0000000) | (IMM26 << 2);
 }
 
 void psx_cpu_i_beq(psx_cpu_t* cpu) {
     cpu->branch = 1;
+    cpu->branch_taken = 0;
 
     TRACE_B("beq");
 
@@ -519,13 +509,13 @@
     DO_PENDING_LOAD;
 
     if (s == t) {
-        cpu->pc -= 4;
-        cpu->pc += (IMM16S << 2);
+        BRANCH(IMM16S << 2);
     }
 }
 
 void psx_cpu_i_bne(psx_cpu_t* cpu) {
     cpu->branch = 1;
+    cpu->branch_taken = 0;
 
     TRACE_B("bne");
 
@@ -535,13 +525,13 @@
     DO_PENDING_LOAD;
 
     if (s != t) {
-        cpu->pc -= 4;
-        cpu->pc += (IMM16S << 2);
+        BRANCH(IMM16S << 2);
     }
 }
 
 void psx_cpu_i_blez(psx_cpu_t* cpu) {
     cpu->branch = 1;
+    cpu->branch_taken = 0;
 
     TRACE_B("blez");
 
@@ -550,13 +540,13 @@
     DO_PENDING_LOAD;
 
     if ((int32_t)s <= (int32_t)0) {
-        cpu->pc -= 4;
-        cpu->pc += (IMM16S << 2);
+        BRANCH(IMM16S << 2);
     }
 }
 
 void psx_cpu_i_bgtz(psx_cpu_t* cpu) {
     cpu->branch = 1;
+    cpu->branch_taken = 0;
 
     TRACE_B("bgtz");
 
@@ -565,8 +555,7 @@
     DO_PENDING_LOAD;
 
     if ((int32_t)s > (int32_t)0) {
-        cpu->pc -= 4;
-        cpu->pc += (IMM16S << 2);
+        BRANCH(IMM16S << 2);
     }
 }
 
@@ -1002,7 +991,7 @@
 
     DO_PENDING_LOAD;
 
-    cpu->pc = s;
+    cpu->next_pc = s;
 }
 
 void psx_cpu_i_jalr(psx_cpu_t* cpu) {
@@ -1014,15 +1003,13 @@
 
     DO_PENDING_LOAD;
 
-    cpu->r[D] = cpu->pc;
+    cpu->r[D] = cpu->next_pc;
 
-    cpu->pc = s;
+    cpu->next_pc = s;
 }
 
 void psx_cpu_i_syscall(psx_cpu_t* cpu) {
     TRACE_I20("syscall");
-
-    //log_info("SYS(%02xh): %s()", cpu->r[4], g_psx_cpu_syscall_function_symbol_table[cpu->r[4]]);
     
     DO_PENDING_LOAD;
 
--- a/psx/cpu.h
+++ b/psx/cpu.h
@@ -66,13 +66,13 @@
 
 struct psx_cpu_t {
     uint32_t r[32];
-    uint32_t buf[2];
-    uint32_t pc;
+    uint32_t opcode;
+    uint32_t pc, next_pc, saved_pc;
     uint32_t hi, lo;
     uint32_t load_d, load_v;
     uint32_t last_cycles;
     uint32_t total_cycles;
-    int branch, delay_slot;
+    int branch, delay_slot, branch_taken;
 
     uint32_t cop0_r[16];
 
--- a/psx/dev/dma.c
+++ b/psx/dev/dma.c
@@ -22,7 +22,7 @@
 
 #define CR(c, r) *((&dma->mdec_in.madr) + (c * 3) + r)
 
-void psx_dma_init(psx_dma_t* dma, psx_bus_t* bus) {
+void psx_dma_init(psx_dma_t* dma, psx_bus_t* bus, psx_ic_t* ic) {
     memset(dma, 0, sizeof(psx_dma_t));
 
     dma->io_base = PSX_DMAR_BEGIN;
@@ -29,6 +29,7 @@
     dma->io_size = PSX_DMAR_SIZE;
 
     dma->bus = bus;
+    dma->ic = ic;
 
     dma->dpcr = 0x07654321;
     dma->otc.chcr = 0x00000002;
@@ -109,7 +110,13 @@
                 irqf &= 0x7f;
 
                 dma->dicr |= irqf << 24;
-                
+
+                if (dma->dicr & 0x00008000) {
+                    dma->dicr |= 0x80000000;
+
+                    psx_ic_irq(dma->ic, IC_DMA);
+                }
+                
                 log_error("DMA irqc    write %08x irqfr=%08x", value, irqfr);
             } break;
 
@@ -208,6 +215,8 @@
     psx_dma_do_gpu_linked
 };
 
+#define TEST_SET_IRQ_FLAG()
+
 void psx_dma_do_gpu(psx_dma_t* dma) {
     if (!CHCR_BUSY(gpu))
         return;
@@ -222,8 +231,18 @@
 
     g_psx_dma_gpu_table[CHCR_SYNC(gpu)](dma);
 
-    dma->dicr |= 0x04000000;
+    if (dma->dicr & 0x00040000) {
+        dma->dicr |= 0x04000000;
 
+        if ((dma->dicr & 0x8000) || ((dma->dicr & 0x800000) && (dma->dicr & 0x7f000000))) {
+            dma->dicr |= 0x80000000;
+
+            psx_ic_irq(dma->ic, IC_DMA);
+        } else {
+            dma->dicr &= 0x7fffffff;
+        }
+    }
+
     // Clear BCR and CHCR trigger and busy bits
     dma->gpu.chcr &= ~(CHCR_BUSY_MASK | CHCR_TRIG_MASK);
     dma->gpu.bcr = 0;
@@ -266,7 +285,17 @@
     //dma->otc.chcr &= ~(CHCR_BUSY_MASK | CHCR_TRIG_MASK);
     dma->otc.bcr = 0;
 
-    dma->dicr |= 0x40000000;
+    if (dma->dicr & 0x00400000) {
+        dma->dicr |= 0x40000000;
+
+        if ((dma->dicr & 0x8000) || ((dma->dicr & 0x800000) && (dma->dicr & 0x7f000000))) {
+            dma->dicr |= 0x80000000;
+
+            psx_ic_irq(dma->ic, IC_DMA);
+        } else {
+            dma->dicr &= 0x7fffffff;
+        }
+    }
 }
 
 void psx_dma_destroy(psx_dma_t* dma) {
--- a/psx/dev/dma.h
+++ b/psx/dev/dma.h
@@ -8,6 +8,7 @@
 #define PSX_DMAR_END   0x1f8010ff
 
 #include "../bus.h"
+#include "ic.h"
 
 typedef struct {
     uint32_t madr;
@@ -19,6 +20,7 @@
     uint32_t io_base, io_size;
 
     psx_bus_t* bus;
+    psx_ic_t* ic;
 
     dma_channel_t mdec_in;
     dma_channel_t mdec_out;
@@ -33,7 +35,7 @@
 } psx_dma_t;
 
 psx_dma_t* psx_dma_create();
-void psx_dma_init(psx_dma_t*, psx_bus_t*);
+void psx_dma_init(psx_dma_t*, psx_bus_t*, psx_ic_t*);
 void psx_dma_do_mdec_in(psx_dma_t*);
 void psx_dma_do_mdec_out(psx_dma_t*);
 void psx_dma_do_gpu(psx_dma_t*);
@@ -99,5 +101,8 @@
 
 #define BCR_SIZE(c) (dma->c.bcr & 0xffff)
 #define BCR_BCNT(c) ((dma->c.bcr >> 16) & 0xffff)
+
+#define DICR_FIRQ 0x00008000
+#define DICR_IRQE 0x00000000
 
 #endif
\ No newline at end of file
--- a/psx/dev/gpu.c
+++ b/psx/dev/gpu.c
@@ -796,9 +796,7 @@
     }
 
     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;
     }
@@ -807,16 +805,6 @@
 void psx_gpu_update(psx_gpu_t* gpu, int cyc) {
     // Convert CPU (~33.8 MHz) cycles to GPU (~53.7 MHz) cycles
     gpu->cycles += (float)cyc * (PSX_GPU_CLOCK_FREQ_NTSC / PSX_CPU_CLOCK_FREQ);
-    //gpu->cycles += (float)cyc;
-
-    // if (gpu->cycles >= ((float)PSX_CPU_CLOCK / 60.0f)) {
-    //     psx_ic_irq(gpu->ic, IC_VBLANK);
-
-    //     gpu->cycles -= (float)PSX_CPU_CLOCK / 60.0f;
-    // }
-
-    // if (gpu->cycles >= (float)GPU_CYCLES_PER_HDRAW_NTSC) {
-    //     Tick Hblank timer
 
     if (gpu->cycles >= (float)GPU_CYCLES_PER_SCANL_NTSC) {
         gpu->cycles -= (float)GPU_CYCLES_PER_SCANL_NTSC;
--- a/psx/dev/ic.c
+++ b/psx/dev/ic.c
@@ -87,7 +87,7 @@
 }
 
 void psx_ic_irq(psx_ic_t* ic, int id) {
-    ic->stat = id;
+    ic->stat |= id;
 
     psx_cpu_irq(ic->cpu, ic->mask & ic->stat);
 }
--- a/psx/dev/ic.h
+++ b/psx/dev/ic.h
@@ -28,7 +28,7 @@
     IC_VBLANK       = 0x001,
     IC_GPU          = 0x002,
     IC_CDROM        = 0x004,
-    IC_DM           = 0x008,
+    IC_DMA          = 0x008,
     IC_TMR0         = 0x010,
     IC_TMR1         = 0x020,
     IC_TMR2         = 0x040,
--- a/psx/dev/pad.c
+++ b/psx/dev/pad.c
@@ -42,7 +42,7 @@
 uint16_t psx_pad_read16(psx_pad_t* pad, uint32_t offset) {
     switch (offset) {
         // case 0: return 0x00;
-        case 4: return 0x05;
+        case 4: return 0x07;
         // case 8: return pad->mode;
         case 10: return pad->ctrl;
         // case 14: return pad->baud;
--- a/psx/dev/timer.c
+++ b/psx/dev/timer.c
@@ -17,6 +17,10 @@
 }
 
 uint32_t psx_timer_read32(psx_timer_t* timer, uint32_t offset) {
+    if (offset == 0x20) {
+        return 0x000016b0;
+    }
+
     int t = (offset >> 4) & 0x3;
     int r = offset & 0xf;
 
--- a/psx/exe.c
+++ b/psx/exe.c
@@ -27,6 +27,7 @@
 
     // Load initial register values
     cpu->pc = hdr.ipc;
+    cpu->next_pc = cpu->pc + 4;
     cpu->r[28] = hdr.igp;
     cpu->r[29] = hdr.ispb + hdr.ispoff;
     cpu->r[30] = cpu->r[29];
--- a/psx/psx.c
+++ b/psx/psx.c
@@ -28,7 +28,6 @@
     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);
 }
 
 void psx_run_frame(psx_t* psx) {
@@ -102,7 +101,7 @@
     // Init devices
     psx_bios_init(psx->bios);
     psx_ram_init(psx->ram, psx->mc2);
-    psx_dma_init(psx->dma, psx->bus);
+    psx_dma_init(psx->dma, psx->bus, psx->ic);
     psx_exp1_init(psx->exp1, psx->mc1);
     psx_mc1_init(psx->mc1);
     psx_mc2_init(psx->mc2);
--