ref: e0b3a93fa7bfd40bec62acb4e74bed9f69464a0f
parent: dd3b848162f118070b1d669c7983eb83b712ad53
author: allkern <lisandroaalarcon@gmail.com>
date: Wed Jul 19 17:43:31 EDT 2023
Reimplement most CDROM commands
--- a/psx/cpu.c
+++ b/psx/cpu.c
@@ -450,8 +450,8 @@
cpu->next_pc = cpu->pc + 4;
}
-void psx_cpu_irq(psx_cpu_t* cpu, uint32_t irq) {- cpu->cop0_r[COP0_CAUSE] |= irq ? SR_IM2 : 0;
+void psx_cpu_set_irq_pending(psx_cpu_t* cpu) {+ cpu->cop0_r[COP0_CAUSE] |= SR_IM2;
}
void psx_cpu_i_invalid(psx_cpu_t* cpu) {@@ -1509,7 +1509,7 @@
}
void psx_gte_i_ncds(psx_cpu_t* cpu) {- log_fatal("ncds: Unimplemented GTE instruction");+ // log_fatal("ncds: Unimplemented GTE instruction");}
void psx_gte_i_cdp(psx_cpu_t* cpu) {--- a/psx/cpu.h
+++ b/psx/cpu.h
@@ -185,7 +185,7 @@
void psx_cpu_destroy(psx_cpu_t*);
void psx_cpu_cycle(psx_cpu_t*);
void psx_cpu_exception(psx_cpu_t*, uint32_t);
-void psx_cpu_irq(psx_cpu_t*, uint32_t);
+void psx_cpu_set_irq_pending(psx_cpu_t*);
void psx_cpu_load_state(psx_cpu_t*, FILE*);
void psx_cpu_save_state(psx_cpu_t*, FILE*);
void psx_cpu_fetch(psx_cpu_t*);
--- a/psx/dev/cdrom.c
+++ b/psx/dev/cdrom.c
@@ -9,14 +9,18 @@
cdrom->rfifo[cdrom->rfifo_index++] = data; \
SET_BITS(status, STAT_RSLRRDY_MASK, STAT_RSLRRDY_MASK);
-#define SEND_INT1(delay) SET_BITS(ifr, IFR_INT, IFR_INT1) cdrom->irq_delay = delay;
-#define SEND_INT2(delay) SET_BITS(ifr, IFR_INT, IFR_INT2) cdrom->irq_delay = delay;
-#define SEND_INT3(delay) SET_BITS(ifr, IFR_INT, IFR_INT3) cdrom->irq_delay = delay;
-#define SEND_INT4(delay) SET_BITS(ifr, IFR_INT, IFR_INT4) cdrom->irq_delay = delay;
-#define SEND_INT5(delay) SET_BITS(ifr, IFR_INT, IFR_INT5) cdrom->irq_delay = delay;
-#define SEND_INT6(delay) SET_BITS(ifr, IFR_INT, IFR_INT6) cdrom->irq_delay = delay;
-#define SEND_INT7(delay) SET_BITS(ifr, IFR_INT, IFR_INT7) cdrom->irq_delay = delay;
+#define SEND_INT1(delay) cdrom->int_number = IFR_INT1; cdrom->irq_delay = delay;
+#define SEND_INT2(delay) cdrom->int_number = IFR_INT2; cdrom->irq_delay = delay;
+#define SEND_INT3(delay) cdrom->int_number = IFR_INT3; cdrom->irq_delay = delay;
+#define SEND_INT4(delay) cdrom->int_number = IFR_INT4; cdrom->irq_delay = delay;
+#define SEND_INT5(delay) cdrom->int_number = IFR_INT5; cdrom->irq_delay = delay;
+#define SEND_INT6(delay) cdrom->int_number = IFR_INT6; cdrom->irq_delay = delay;
+#define SEND_INT7(delay) cdrom->int_number = IFR_INT7; cdrom->irq_delay = delay;
+uint8_t cdrom_btoi(uint8_t b) {+ return ((b >> 4) * 10) + (b & 0xf);
+}
+
static const uint8_t g_psx_cdrom_btoi_table[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
@@ -53,15 +57,107 @@
};
void cdrom_cmd_unimplemented(psx_cdrom_t* cdrom) {}-void cdrom_cmd_getstat(psx_cdrom_t* cdrom) {}-void cdrom_cmd_setloc(psx_cdrom_t* cdrom) {}-void cdrom_cmd_readn(psx_cdrom_t* cdrom) {}+void cdrom_cmd_getstat(psx_cdrom_t* cdrom) {+ if (!cdrom->tray_open) {+ SET_BITS(stat, GETSTAT_TRAYOPEN, 0);
+ }
+
+ if (!cdrom->disc) {+ SET_BITS(stat, GETSTAT_TRAYOPEN, 0xff);
+ }
+
+ RESP_PUSH(cdrom->stat);
+ SEND_INT3(DELAY_1MS);
+
+ cdrom->delayed_response_command = 0;
+}
+void cdrom_cmd_setloc(psx_cdrom_t* cdrom) {+ if (cdrom->pfifo_index != 3) {+ log_fatal("setloc: Expected exactly 3 parameters, got %u instead", cdrom->pfifo_index);+
+ return;
+ }
+
+ cdrom->seek_sect = g_psx_cdrom_btoi_table[cdrom->pfifo[--cdrom->pfifo_index]];
+ cdrom->seek_ss = g_psx_cdrom_btoi_table[cdrom->pfifo[--cdrom->pfifo_index]];
+ cdrom->seek_mm = g_psx_cdrom_btoi_table[cdrom->pfifo[--cdrom->pfifo_index]];
+
+ // Account for 2 second gap
+ uint32_t seconds = (cdrom->seek_mm * 60) + cdrom->seek_ss - 2;
+ uint32_t sectors = (seconds * CD_SECTORS_PER_SECOND) + cdrom->seek_sect;
+
+ cdrom->seek_offset = sectors * CD_SECTOR_SIZE;
+
+ log_fatal("setloc: %02u:%02u:%02u (%08x)",+ cdrom->seek_mm,
+ cdrom->seek_ss,
+ cdrom->seek_sect,
+ cdrom->seek_offset
+ );
+
+ RESP_PUSH(cdrom->stat);
+ SEND_INT3(DELAY_1MS);
+}
+void cdrom_cmd_readn(psx_cdrom_t* cdrom) {+ if (!cdrom->delayed_response_command) {+ RESP_PUSH(cdrom->stat);
+ SEND_INT3(DELAY_1MS);
+
+ cdrom->stat |= GETSTAT_READ;
+
+ log_fatal("Reading data from disc. offset=%02x:%02x:%02x (%08x)",+ cdrom->seek_mm, cdrom->seek_ss, cdrom->seek_sect,
+ cdrom->seek_offset
+ );
+
+ fread(cdrom->read_buf, 1, CD_SECTOR_SIZE, cdrom->disc);
+
+ cdrom->delayed_response_command = 0x06;
+ } else {+ //fseek(cdrom->disc, cdrom->seek_offset, 0);
+
+ // for (int y = 0; y < 8; y++) {+ // for (int x = 0; x < 0x10; x++) {+ // printf("%02x ", cdrom->read_buf[x + (y * 0x10)]);+ // }
+
+ // printf("\n");+ // }
+
+ // exit(1);
+
+ int double_speed = cdrom->mode & MODE_SPEED;
+
+ RESP_PUSH(cdrom->stat);
+ SEND_INT1(double_speed ? READ_DOUBLE_DELAY : READ_SINGLE_DELAY);
+
+ SET_BITS(status, STAT_DRQSTS_MASK, STAT_DRQSTS_MASK);
+
+ cdrom->dfifo_full = 1;
+ cdrom->stat &= ~GETSTAT_READ;
+
+ // Repeat until pause
+ cdrom->delayed_response_command = 0x06;
+ }
+}
void cdrom_cmd_stop(psx_cdrom_t* cdrom) {}-void cdrom_cmd_pause(psx_cdrom_t* cdrom) {}-void cdrom_cmd_init(psx_cdrom_t* cdrom) {- log_fatal("CdlInit");+void cdrom_cmd_pause(psx_cdrom_t* cdrom) {+ if (!cdrom->delayed_response_command) {+ RESP_PUSH(cdrom->stat);
+ SEND_INT3(DELAY_1MS);
+ cdrom->delayed_response_command = 0x09;
+ } else {+ RESP_PUSH(cdrom->stat);
+ SEND_INT2(DELAY_1MS);
+
+ cdrom->delayed_response_command = 0;
+ }
+}
+void cdrom_cmd_init(psx_cdrom_t* cdrom) { if (!cdrom->delayed_response_command) {+ cdrom->stat = 0x20;
+
SEND_INT3(DELAY_1MS);
RESP_PUSH(cdrom->stat);
@@ -70,26 +166,135 @@
SEND_INT2(DELAY_1MS);
RESP_PUSH(cdrom->stat);
- cdrom->delayed_response_command = 0x00;
+ cdrom->delayed_response_command = 0;
}
}
void cdrom_cmd_unmute(psx_cdrom_t* cdrom) {} void cdrom_cmd_setfilter(psx_cdrom_t* cdrom) {}-void cdrom_cmd_setmode(psx_cdrom_t* cdrom) {}+void cdrom_cmd_setmode(psx_cdrom_t* cdrom) {+ if (cdrom->pfifo_index != 1) {+ log_fatal("CdlSetmode: Expected exactly 1 parameter");+
+ return;
+ }
+
+ cdrom->mode = cdrom->pfifo[--cdrom->pfifo_index];
+
+ RESP_PUSH(cdrom->stat);
+ SEND_INT3(DELAY_1MS);
+
+ cdrom->delayed_response_command = 0;
+}
void cdrom_cmd_getlocl(psx_cdrom_t* cdrom) {} void cdrom_cmd_getlocp(psx_cdrom_t* cdrom) {} void cdrom_cmd_gettn(psx_cdrom_t* cdrom) {} void cdrom_cmd_gettd(psx_cdrom_t* cdrom) {}-void cdrom_cmd_seekl(psx_cdrom_t* cdrom) {}+void cdrom_cmd_seekl(psx_cdrom_t* cdrom) {+ if (!cdrom->delayed_response_command) {+ RESP_PUSH(cdrom->stat);
+ SEND_INT3(DELAY_1MS);
+
+ log_fatal("seekl: Seeking to address %08x", cdrom->seek_offset);+
+ fseek(cdrom->disc, cdrom->seek_offset, 0);
+
+ cdrom->delayed_response_command = 0x15;
+ } else {+ RESP_PUSH(cdrom->stat);
+ SEND_INT2(DELAY_1MS);
+
+ cdrom->delayed_response_command = 0;
+ }
+}
void cdrom_cmd_seekp(psx_cdrom_t* cdrom) {}-void cdrom_cmd_test(psx_cdrom_t* cdrom) {}-void cdrom_cmd_getid(psx_cdrom_t* cdrom) {}+void cdrom_cmd_test(psx_cdrom_t* cdrom) {+ if (cdrom->pfifo_index != 1) {+ log_fatal("test: Expected exactly 1 parameter");+ }
+
+ switch (cdrom->pfifo[--cdrom->pfifo_index]) {+ case 0x20: {+ RESP_PUSH(0x01);
+ RESP_PUSH(0x95);
+ RESP_PUSH(0x13);
+ RESP_PUSH(0x03);
+ SEND_INT3(DELAY_1MS);
+ } break;
+ }
+
+ cdrom->delayed_response_command = 0;
+}
+void cdrom_cmd_getid(psx_cdrom_t* cdrom) {+ if (!cdrom->delayed_response_command) {+ RESP_PUSH(cdrom->stat);
+ SEND_INT3(DELAY_1MS);
+
+ cdrom->delayed_response_command = 0x1a;
+ } else {+ if (!cdrom->disc) {+ RESP_PUSH(0x00);
+ RESP_PUSH(0x00);
+ RESP_PUSH(0x00);
+ RESP_PUSH(0x00);
+ RESP_PUSH(0x00);
+ RESP_PUSH(0x00);
+ RESP_PUSH(0x40);
+ } else {+ RESP_PUSH('A');+ RESP_PUSH('A');+ RESP_PUSH('A');+ RESP_PUSH('A');+ RESP_PUSH('A');+ RESP_PUSH('A');+ RESP_PUSH('A');+ }
+
+ SEND_INT2(DELAY_1MS);
+
+ cdrom->delayed_response_command = 0;
+ }
+}
void cdrom_cmd_reads(psx_cdrom_t* cdrom) {} void cdrom_cmd_readtoc(psx_cdrom_t* cdrom) {}typedef void (*cdrom_cmd_t)(psx_cdrom_t*);
+const char* g_psx_cdrom_command_names[] = {+ "CdlUnimplemented",
+ "CdlGetstat",
+ "CdlSetloc",
+ "CdlUnimplemented",
+ "CdlUnimplemented",
+ "CdlUnimplemented",
+ "CdlReadn",
+ "CdlUnimplemented",
+ "CdlStop",
+ "CdlPause",
+ "CdlInit",
+ "CdlUnimplemented",
+ "CdlUnmute",
+ "CdlSetfilter",
+ "CdlSetmode",
+ "CdlUnimplemented",
+ "CdlGetlocl",
+ "CdlGetlocp",
+ "CdlUnimplemented",
+ "CdlGettn",
+ "CdlGettd",
+ "CdlSeekl",
+ "CdlSeekp",
+ "CdlUnimplemented",
+ "CdlUnimplemented",
+ "CdlTest",
+ "CdlGetid",
+ "CdlReads",
+ "CdlUnimplemented",
+ "CdlUnimplemented",
+ "CdlReadtoc",
+ "CdlUnimplemented"
+};
+
cdrom_cmd_t g_psx_cdrom_command_table[] = {cdrom_cmd_unimplemented,
cdrom_cmd_getstat,
@@ -148,7 +353,7 @@
uint8_t cdrom_read_dfifo(psx_cdrom_t* cdrom) {if (!cdrom->dfifo_full)
- return 0x00;
+ return 0;
int sector_size_bit = cdrom->mode & MODE_SECTOR_SIZE;
@@ -158,6 +363,8 @@
if (cdrom->dfifo_index != read_sector_size) {return cdrom->dfifo[offset + (cdrom->dfifo_index++)];
} else {+ SET_BITS(status, STAT_DRQSTS_MASK, 0);
+
cdrom->dfifo_full = 0;
}
@@ -177,18 +384,19 @@
}
void cdrom_write_cmd(psx_cdrom_t* cdrom, uint8_t value) {- cdrom->delayed_response_command = 0;
- cdrom->command = value;
-
- log_fatal(" Command %02x (pfifo=%02x, %02x, %02x, %02x), pfifo_index=%u",+ log_fatal("%s(%02x) params=[%02x, %02x, %02x, %02x, %02x, %02x]",+ g_psx_cdrom_command_names[value],
value,
cdrom->pfifo[0],
cdrom->pfifo[1],
cdrom->pfifo[2],
cdrom->pfifo[3],
- cdrom->pfifo_index
+ cdrom->pfifo[4],
+ cdrom->pfifo[5]
);
+ cdrom->delayed_response_command = 0;
+
g_psx_cdrom_command_table[value](cdrom);
}
@@ -224,6 +432,7 @@
void cdrom_write_ifr(psx_cdrom_t* cdrom, uint8_t value) {cdrom->ifr &= ~(value & 0x7);
+ // Clear Parameter FIFO
if (value & 0x40) {cdrom->pfifo_index = 0;
@@ -233,6 +442,13 @@
(STAT_PRMEMPT_MASK | STAT_PRMWRDY_MASK)
);
}
+
+ // Clear Response FIFO
+ // if (value & 0x7) {+ // cdrom->rfifo_index = 0;
+
+ // SET_BITS(status, STAT_RSLRRDY_MASK, 0);
+ // }
}
void cdrom_write_sminfo(psx_cdrom_t* cdrom, uint8_t value) {@@ -314,9 +530,11 @@
}
uint8_t psx_cdrom_read8(psx_cdrom_t* cdrom, uint32_t offset) {- log_fatal("CDROM read -> %s", g_psx_cdrom_read_names_table[(STAT_INDEX << 2) | offset]);+ uint8_t data = g_psx_cdrom_read_table[(STAT_INDEX << 2) | offset](cdrom);
- return g_psx_cdrom_read_table[(STAT_INDEX << 2) | offset](cdrom);
+ // log_fatal("%s (read %02x)", g_psx_cdrom_read_names_table[(STAT_INDEX << 2) | offset], data);+
+ return data;
}
void psx_cdrom_write32(psx_cdrom_t* cdrom, uint32_t offset, uint32_t value) {@@ -328,7 +546,7 @@
}
void psx_cdrom_write8(psx_cdrom_t* cdrom, uint32_t offset, uint8_t value) {- log_fatal("CDROM write -> %s (%02x)", g_psx_cdrom_write_names_table[(STAT_INDEX << 2) | offset], value);+ // log_fatal("%s (write %02x)", g_psx_cdrom_write_names_table[(STAT_INDEX << 2) | offset], value);g_psx_cdrom_write_table[(STAT_INDEX << 2) | offset](cdrom, value);
}
@@ -338,6 +556,13 @@
cdrom->irq_delay -= 2;
if (cdrom->irq_delay <= 0) {+ if (cdrom->int_number) {+ SET_BITS(ifr, IFR_INT, cdrom->int_number);
+
+ cdrom->int_number = 0;
+ }
+
+ log_fatal("CDROM INT%u", cdrom->ifr & 0x7);psx_ic_irq(cdrom->ic, IC_CDROM);
cdrom->irq_delay = 0;
--- a/psx/dev/cdrom.h
+++ b/psx/dev/cdrom.h
@@ -117,6 +117,7 @@
int irq_delay;
uint8_t command;
uint8_t delayed_response_command;
+ uint8_t int_number;
int delayed_response;
const char* path;
--- a/psx/dev/ic.c
+++ b/psx/dev/ic.c
@@ -89,7 +89,8 @@
void psx_ic_irq(psx_ic_t* ic, int id) {ic->stat |= id;
- psx_cpu_irq(ic->cpu, ic->mask & ic->stat);
+ if (ic->mask & ic->stat)
+ psx_cpu_set_irq_pending(ic->cpu);
}
void psx_ic_destroy(psx_ic_t* ic) {--- a/psx/dev/timer.c
+++ b/psx/dev/timer.c
@@ -49,7 +49,7 @@
int index = offset >> 4;
int reg = offset & 0xf;
- log_fatal("Timer %u %s read32", index, g_psx_timer_reg_names[reg]);+ //log_fatal("Timer %u %s read32", index, g_psx_timer_reg_names[reg]); switch (reg) {case 0: return timer->timer[index].counter;
@@ -70,7 +70,7 @@
int index = offset >> 4;
int reg = offset & 0xf;
- log_fatal("Timer %u %s read16", index, g_psx_timer_reg_names[reg]);+ //log_fatal("Timer %u %s read16 %04x", index, g_psx_timer_reg_names[reg], timer->timer[index].counter); switch (reg) {case 0: return timer->timer[index].counter;
@@ -97,12 +97,11 @@
int index = offset >> 4;
int reg = offset & 0xf;
- log_fatal("Timer %u %s write32 %08x", index, g_psx_timer_reg_names[reg], value);+ //log_fatal("Timer %u %s write32 %08x", index, g_psx_timer_reg_names[reg], value); switch (reg) { case 0: {timer->timer[index].counter = value;
- timer->f_counter[index] = value;
} return;
case 4: {timer->timer[index].mode = value;
@@ -124,7 +123,6 @@
switch (reg) { case 0: {timer->timer[index].counter = value;
- timer->f_counter[index] = value;
} return;
case 4: {timer->timer[index].mode = value;
@@ -131,7 +129,9 @@
timer->timer[index].mode |= 0x400;
timer->timer[index].irq_fired = 0;
} return;
- case 8: timer->timer[index].target = value; return;
+ case 8: {+ timer->timer[index].target = value;
+ } return;
}
log_fatal("Unhandled 16-bit TIMER write at offset %08x (%02x)", offset, value);@@ -142,7 +142,8 @@
}
void timer_update_timer0(psx_timer_t* timer, int cyc) {- T0_PREV = T0_COUNTER;
+ int reached_target = ((uint32_t)T0_COUNTER + cyc) >= T0_TARGET;
+ int reached_max = ((uint32_t)T0_COUNTER + cyc) >= 0xffff;
// Dotclock unsupported
// if (T0_MODE & 0x100)
@@ -152,9 +153,6 @@
int can_fire_irq = (T0_MODE & MODE_IRQRMD) || !T0_IRQ_FIRED;
- int reached_target = (T0_PREV <= T0_TARGET) && (T0_COUNTER >= T0_TARGET);
- int reached_max = (T0_PREV <= 0xffff) && (T0_COUNTER >= 0xffff);
-
int target_irq = reached_target && (T0_MODE & MODE_TGTIRQ);
int max_irq = reached_max && (T0_MODE & MODE_MAXIRQ);
@@ -185,17 +183,21 @@
}
void timer_update_timer1(psx_timer_t* timer, int cyc) {- T1_PREV = T1_COUNTER;
+ int reached_target, reached_max;
- // Hblank increment is done in handler
- if ((!T1_PAUSED) && !(T1_MODE & 0x100))
- T1_COUNTER += cyc;
+ if (T1_MODE & 0x100) {+ reached_target = T1_COUNTER == T1_TARGET;
+ reached_max = T1_COUNTER == 0xffff;
+ } else {+ reached_target = ((uint32_t)T1_COUNTER + cyc) >= T1_TARGET;
+ reached_max = ((uint32_t)T1_COUNTER + cyc) >= 0xffff;
+ if (!T1_PAUSED)
+ T1_COUNTER += cyc;
+ }
+
int can_fire_irq = (T1_MODE & MODE_IRQRMD) || !T1_IRQ_FIRED;
- int reached_target = (T1_PREV <= T1_TARGET) && (T1_COUNTER >= T1_TARGET);
- int reached_max = (T1_PREV <= 0xffff) && (T1_COUNTER >= 0xffff);
-
int target_irq = reached_target && (T1_MODE & MODE_TGTIRQ);
int max_irq = reached_max && (T1_MODE & MODE_MAXIRQ);
@@ -214,14 +216,12 @@
timer->timer[0].irq_fired = 1;
- psx_ic_irq(timer->ic, IC_TIMER0);
+ psx_ic_irq(timer->ic, IC_TIMER1);
}
if (T1_MODE & MODE_RESETC) {if (reached_target)
T1_COUNTER -= T1_TARGET;
- } else {- T1_COUNTER -= 0xffff;
}
}
--- a/psx/dev/timer.h
+++ b/psx/dev/timer.h
@@ -63,15 +63,13 @@
psx_ic_t* ic;
struct {- int32_t prev_counter;
- int32_t counter;
+ uint16_t prev_counter;
+ uint16_t counter;
uint32_t mode;
uint32_t target;
int paused;
int irq_fired;
} timer[3];
-
- float f_counter[3];
} psx_timer_t;
psx_timer_t* psx_timer_create();
--
⑨