Rework pipelining implementation

The shell is finally booting!
This commit is contained in:
allkern
2023-07-04 20:37:14 -03:00
parent a034f22be3
commit 61c23fa9b7
11 changed files with 129 additions and 116 deletions
+78 -91
View File
@@ -84,15 +84,15 @@ uint32_t g_psx_cpu_cop0_write_mask_table[] = {
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 @@ uint32_t g_psx_cpu_cop0_write_mask_table[] = {
#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 @@ uint32_t g_psx_cpu_cop0_write_mask_table[] = {
#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_a_kcall_hook(psx_cpu_t*);
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 @@ void psx_cpu_load_state(psx_cpu_t* cpu, FILE* file) {
fread((char*)cpu, sizeof(*cpu) - sizeof(psx_bus_t*), 1, file);
}
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) == 0x000000a4)
if (cpu->a_function_hook) cpu->a_function_hook(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);
}
cpu->opcode = psx_bus_read32(cpu->bus, cpu->pc);
cpu->pc = cpu->next_pc;
cpu->next_pc += 4;
if (psx_cpu_check_irq(cpu)) {
psx_cpu_exception(cpu, CAUSE_INT);
return;
}
if (psx_cpu_check_irq(cpu))
return;
psx_cpu_fetch(cpu);
cpu->delay_slot = cpu->branch;
cpu->branch = 0;
g_psx_cpu_primary_table[OP](cpu);
cpu->last_cycles = 2;
@@ -362,33 +368,25 @@ void psx_cpu_cycle(psx_cpu_t* cpu) {
}
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
@@ -399,21 +397,15 @@ void psx_cpu_exception(psx_cpu_t* cpu, uint32_t cause) {
// 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_special(psx_cpu_t* cpu) {
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 @@ void psx_cpu_i_bltz(psx_cpu_t* cpu) {
DO_PENDING_LOAD;
if ((int32_t)s < (int32_t)0) {
cpu->pc -= 4;
cpu->pc += (IMM16S << 2);
BRANCH(IMM16S << 2);
}
}
@@ -451,8 +443,7 @@ void psx_cpu_i_bgez(psx_cpu_t* cpu) {
DO_PENDING_LOAD;
if ((int32_t)s >= (int32_t)0) {
cpu->pc -= 4;
cpu->pc += (IMM16S << 2);
BRANCH(IMM16S << 2);
}
}
@@ -463,11 +454,10 @@ void psx_cpu_i_bltzal(psx_cpu_t* cpu) {
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 @@ void psx_cpu_i_bgezal(psx_cpu_t* cpu) {
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 @@ void psx_cpu_i_j(psx_cpu_t* cpu) {
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 @@ void psx_cpu_i_jal(psx_cpu_t* cpu) {
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 @@ void psx_cpu_i_beq(psx_cpu_t* cpu) {
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 @@ void psx_cpu_i_bne(psx_cpu_t* cpu) {
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 @@ void psx_cpu_i_blez(psx_cpu_t* cpu) {
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 @@ void psx_cpu_i_bgtz(psx_cpu_t* cpu) {
DO_PENDING_LOAD;
if ((int32_t)s > (int32_t)0) {
cpu->pc -= 4;
cpu->pc += (IMM16S << 2);
BRANCH(IMM16S << 2);
}
}
@@ -1002,7 +991,7 @@ void psx_cpu_i_jr(psx_cpu_t* cpu) {
DO_PENDING_LOAD;
cpu->pc = s;
cpu->next_pc = s;
}
void psx_cpu_i_jalr(psx_cpu_t* cpu) {
@@ -1014,15 +1003,13 @@ void psx_cpu_i_jalr(psx_cpu_t* cpu) {
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;
+3 -3
View File
@@ -66,13 +66,13 @@ typedef void (*psx_cpu_kcall_hook_t)(psx_cpu_t*);
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];
+32 -3
View File
@@ -22,13 +22,14 @@ const psx_dma_do_fn_t g_psx_dma_do_table[] = {
#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;
dma->io_size = PSX_DMAR_SIZE;
dma->bus = bus;
dma->ic = ic;
dma->dpcr = 0x07654321;
dma->otc.chcr = 0x00000002;
@@ -109,6 +110,12 @@ void psx_dma_write32(psx_dma_t* dma, uint32_t offset, uint32_t value) {
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_fn_t g_psx_dma_gpu_table[] = {
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,7 +231,17 @@ void psx_dma_do_gpu(psx_dma_t* dma) {
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);
@@ -266,7 +285,17 @@ void psx_dma_do_otc(psx_dma_t* dma) {
//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) {
+6 -1
View File
@@ -8,6 +8,7 @@
#define PSX_DMAR_END 0x1f8010ff
#include "../bus.h"
#include "ic.h"
typedef struct {
uint32_t madr;
@@ -19,6 +20,7 @@ typedef struct {
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 @@ typedef struct {
} 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*);
@@ -100,4 +102,7 @@ typedef void (*psx_dma_do_fn_t)(psx_dma_t*);
#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
+1 -13
View File
@@ -796,9 +796,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;
}
@@ -807,16 +805,6 @@ void gpu_scanline_event(psx_gpu_t* gpu) {
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;
+1 -1
View File
@@ -87,7 +87,7 @@ void psx_ic_write8(psx_ic_t* ic, uint32_t offset, uint8_t value) {
}
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);
}
+1 -1
View File
@@ -28,7 +28,7 @@ enum {
IC_VBLANK = 0x001,
IC_GPU = 0x002,
IC_CDROM = 0x004,
IC_DM = 0x008,
IC_DMA = 0x008,
IC_TMR0 = 0x010,
IC_TMR1 = 0x020,
IC_TMR2 = 0x040,
+1 -1
View File
@@ -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 0x05;
case 4: return 0x07;
// case 8: return pad->mode;
case 10: return pad->ctrl;
// case 14: return pad->baud;
+4
View File
@@ -17,6 +17,10 @@ void psx_timer_init(psx_timer_t* timer) {
}
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;
+1
View File
@@ -27,6 +27,7 @@ void psx_exe_load(psx_cpu_t* cpu, const char* path) {
// 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];
+1 -2
View File
@@ -28,7 +28,6 @@ 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);
}
void psx_run_frame(psx_t* psx) {
@@ -102,7 +101,7 @@ void psx_init(psx_t* psx, const char* bios_path) {
// 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);