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