Skip to content

Commit

Permalink
Fix sub overflow detection
Browse files Browse the repository at this point in the history
Implement ADEL and ADES exceptions
Fix initial CPU fetch
  • Loading branch information
allkern committed Jun 28, 2023
1 parent 59a2d26 commit baa9e6a
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 35 deletions.
2 changes: 1 addition & 1 deletion frontend/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ int main(int argc, const char* argv[]) {
psx_gpu_set_udata(gpu, 0, screen);

if (cfg->exe) {
while (psx->cpu->pc != 0x80030008) {
while (psx->cpu->pc != 0xBFC06FF0) {
psx_update(psx);
}

Expand Down
75 changes: 51 additions & 24 deletions psx/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void psx_cpu_fetch(psx_cpu_t* cpu) {
cpu->pc += 4;

// Discard fetch cycles
cpu->last_cycles += psx_bus_get_access_cycles(cpu->bus);
psx_bus_get_access_cycles(cpu->bus);
}

void psx_cpu_init(psx_cpu_t* cpu, psx_bus_t* bus) {
Expand Down Expand Up @@ -122,11 +122,14 @@ psx_cpu_instruction_t g_psx_cpu_cop0_table[] = {
};

psx_cpu_instruction_t g_psx_cpu_bxx_table[] = {
psx_cpu_i_bltz , psx_cpu_i_bgez , psx_cpu_i_invalid, psx_cpu_i_invalid,
psx_cpu_i_invalid, psx_cpu_i_invalid, psx_cpu_i_invalid, psx_cpu_i_invalid,
psx_cpu_i_invalid, psx_cpu_i_invalid, psx_cpu_i_invalid, psx_cpu_i_invalid,
psx_cpu_i_invalid, psx_cpu_i_invalid, psx_cpu_i_invalid, psx_cpu_i_invalid,
psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_invalid, psx_cpu_i_invalid
psx_cpu_i_bltz , psx_cpu_i_bgez , psx_cpu_i_bltz , psx_cpu_i_bgez ,
psx_cpu_i_bltz , psx_cpu_i_bgez , psx_cpu_i_bltz , psx_cpu_i_bgez ,
psx_cpu_i_bltz , psx_cpu_i_bgez , psx_cpu_i_bltz , psx_cpu_i_bgez ,
psx_cpu_i_bltz , psx_cpu_i_bgez , psx_cpu_i_bltz , psx_cpu_i_bgez ,
psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltzal , psx_cpu_i_bgezal ,
psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltzal , psx_cpu_i_bgezal ,
psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltzal , psx_cpu_i_bgezal ,
psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltzal , psx_cpu_i_bgezal
};

#define OP ((cpu->buf[1] >> 26) & 0x3f)
Expand Down Expand Up @@ -339,7 +342,7 @@ void psx_cpu_exception(psx_cpu_t* cpu, uint32_t cause) {
// If we're in a delay slot, set delay slot bit
// on CAUSE
if (cpu->delay_slot) {
cpu->cop0_epc = cpu->pc - 4;
cpu->cop0_epc = cpu->pc - 12;
cpu->cop0_cause |= 0x80000000;
} else {
cpu->cop0_epc = cpu->pc - 8;
Expand All @@ -366,9 +369,9 @@ void psx_cpu_irq(psx_cpu_t* cpu, uint32_t irq) {
}

void psx_cpu_i_invalid(psx_cpu_t* cpu) {
log_warn("%08x: Illegal instruction %08x", cpu->pc - 8, cpu->buf[1]);
log_fatal("%08x: Illegal instruction %08x", cpu->pc - 8, cpu->buf[1]);

//psx_cpu_exception(cpu, CAUSE_RI);
psx_cpu_exception(cpu, CAUSE_RI);
}

// Primary
Expand Down Expand Up @@ -649,8 +652,14 @@ void psx_cpu_i_lh(psx_cpu_t* cpu) {

DO_PENDING_LOAD;

cpu->load_d = T;
cpu->load_v = SE16(psx_bus_read16(cpu->bus, s + IMM16S));
uint32_t addr = s + IMM16S;

if (addr & 0x1) {
psx_cpu_exception(cpu, CAUSE_ADEL);
} else {
cpu->load_d = T;
cpu->load_v = SE16(psx_bus_read16(cpu->bus, addr));
}
}

void psx_cpu_i_lwl(psx_cpu_t* cpu) {
Expand All @@ -676,11 +685,16 @@ void psx_cpu_i_lw(psx_cpu_t* cpu) {
TRACE_M("lw");

uint32_t s = cpu->r[S];
uint32_t addr = s + IMM16S;

DO_PENDING_LOAD;

cpu->load_d = T;
cpu->load_v = psx_bus_read32(cpu->bus, s + IMM16S);
if (addr & 0x3) {
psx_cpu_exception(cpu, CAUSE_ADEL);
} else {
cpu->load_d = T;
cpu->load_v = psx_bus_read32(cpu->bus, addr);
}
}

void psx_cpu_i_lbu(psx_cpu_t* cpu) {
Expand All @@ -698,11 +712,16 @@ void psx_cpu_i_lhu(psx_cpu_t* cpu) {
TRACE_M("lhu");

uint32_t s = cpu->r[S];
uint32_t addr = s + IMM16S;

DO_PENDING_LOAD;

cpu->load_d = T;
cpu->load_v = psx_bus_read16(cpu->bus, s + IMM16S);
if (addr & 0x1) {
psx_cpu_exception(cpu, CAUSE_ADEL);
} else {
cpu->load_d = T;
cpu->load_v = psx_bus_read16(cpu->bus, addr);
}
}

void psx_cpu_i_lwr(psx_cpu_t* cpu) {
Expand Down Expand Up @@ -745,6 +764,7 @@ void psx_cpu_i_sh(psx_cpu_t* cpu) {

uint32_t s = cpu->r[S];
uint32_t t = cpu->r[T];
uint32_t addr = s + IMM16S;

DO_PENDING_LOAD;

Expand All @@ -755,7 +775,11 @@ void psx_cpu_i_sh(psx_cpu_t* cpu) {
return;
}

psx_bus_write16(cpu->bus, s + IMM16S, t);
if (addr & 0x1) {
psx_cpu_exception(cpu, CAUSE_ADES);
} else {
psx_bus_write16(cpu->bus, addr, t);
}
}

void psx_cpu_i_swl(psx_cpu_t* cpu) {
Expand Down Expand Up @@ -784,6 +808,7 @@ void psx_cpu_i_sw(psx_cpu_t* cpu) {

uint32_t s = cpu->r[S];
uint32_t t = cpu->r[T];
uint32_t addr = s + IMM16S;

DO_PENDING_LOAD;

Expand All @@ -794,7 +819,11 @@ void psx_cpu_i_sw(psx_cpu_t* cpu) {
return;
}

psx_bus_write32(cpu->bus, s + IMM16S, t);
if (addr & 0x3) {
psx_cpu_exception(cpu, CAUSE_ADES);
} else {
psx_bus_write32(cpu->bus, addr, t);
}
}

void psx_cpu_i_swr(psx_cpu_t* cpu) {
Expand Down Expand Up @@ -1093,18 +1122,16 @@ void psx_cpu_i_sub(psx_cpu_t* cpu) {

int32_t s = (int32_t)cpu->r[S];
int32_t t = (int32_t)cpu->r[T];
int32_t r;

DO_PENDING_LOAD;

int32_t r = s - t;

// To-do: Check SUB overflow check
uint32_t o = (s ^ t) & (t & r);
int o = __builtin_ssub_overflow(s, t, &r);

if (o & 0x80000000) {
if (o) {
psx_cpu_exception(cpu, CAUSE_OV);
} else {
cpu->r[D] = (uint32_t)r;
cpu->r[D] = r;
}
}

Expand Down Expand Up @@ -1249,7 +1276,7 @@ void psx_cpu_i_rfe(psx_cpu_t* cpu) {

DO_PENDING_LOAD;

uint32_t mode = cpu->cop0_sr & 0xf;
uint32_t mode = cpu->cop0_sr & 0x3f;

cpu->cop0_sr &= 0xfffffff0;
cpu->cop0_sr |= mode >> 2;
Expand Down
10 changes: 5 additions & 5 deletions psx/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,11 @@ void psx_cpu_set_b_kcall_hook(psx_cpu_t*, psx_cpu_kcall_hook_t);
#define CAUSE_ADES 0x05
#define CAUSE_IBE 0x06
#define CAUSE_DBE 0x07
#define CAUSE_SYSCALL 0x08
#define CAUSE_BP 0x09
#define CAUSE_RI 0x0a
#define CAUSE_CPU 0x0b
#define CAUSE_OV 0x0c
#define CAUSE_SYSCALL 0x08
#define CAUSE_BP 0x09
#define CAUSE_RI 0x0a
#define CAUSE_CPU 0x0b
#define CAUSE_OV 0x0c

void psx_cpu_i_invalid(psx_cpu_t*);

Expand Down
2 changes: 1 addition & 1 deletion psx/dev/gpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ void psx_gpu_update(psx_gpu_t* gpu, int cyc) {
gpu->line++;

if (gpu->line == GPU_SCANS_PER_FRAME_NTSC) {
psx_ic_irq(gpu->ic, IC_VBLANK);
// psx_ic_irq(gpu->ic, IC_VBLANK);

gpu->line = 0;
} else {
Expand Down
5 changes: 1 addition & 4 deletions psx/psx.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,11 @@ void psx_init(psx_t* psx, const char* bios_path) {
psx_scratchpad_init(psx->scratchpad);
psx_gpu_init(psx->gpu, psx->ic);
psx_spu_init(psx->spu);
psx_cpu_init(psx->cpu, psx->bus);
psx_timer_init(psx->timer);
psx_cdrom_init(psx->cdrom, psx->ic);
psx_pad_init(psx->pad);

psx_bios_load(psx->bios, bios_path);

psx_cpu_fetch(psx->cpu);
psx_cpu_init(psx->cpu, psx->bus);
}

void psx_hard_reset(psx_t* psx) {
Expand Down

0 comments on commit baa9e6a

Please sign in to comment.