ref: 4055e8901d4fd29cbdd6914ebe9941f5db11bae3
parent: b215143e21d7428dd424bdeae2d08d5be38cfb0f
author: allkern <lisandroaalarcon@gmail.com>
date: Fri Jul 19 12:24:15 EDT 2024
Implement autopause IRQ, timing adjustments
--- a/psx/dev/cdrom/audio.c
+++ b/psx/dev/cdrom/audio.c
@@ -278,7 +278,15 @@
return 1;
}
-void cdrom_reload_cdda_buffer(psx_cdrom_t* cdrom, void* buf, size_t size) {+void cdrom_send_autopause_irq(psx_cdrom_t* cdrom) {+ cdrom_set_int(cdrom, 4);
+
+ queue_push(cdrom->response, cdrom_get_stat(cdrom));
+
+ psx_ic_irq(cdrom->ic, IC_CDROM);
+}
+
+int cdrom_reload_cdda_buffer(psx_cdrom_t* cdrom, void* buf, size_t size) {int ts = psx_disc_read(cdrom->disc, cdrom->lba, cdrom->cdda_buf);
// We hit the end of the disc
@@ -285,30 +293,41 @@
if (ts == TS_FAR) {cdrom->cdda_remaining_samples = 0;
cdrom->cdda_sample_index = 0;
+ cdrom->state = CD_STATE_IDLE;
memset(buf, 0, size);
- cdrom->state = CD_STATE_IDLE;
+ // Send autopause IRQ (INT4)
+ if (cdrom->mode & MODE_AUTOPAUSE)
+ cdrom_send_autopause_irq(cdrom);
- return;
+ return 0;
}
- // We hit pregap (end of previous track)
- // if ((ts == TS_PREGAP) && (cdrom->mode & MODE_AUTOPAUSE)) {- // cdrom->cdda_remaining_samples = 0;
- // cdrom->cdda_sample_index = 0;
+ int track = psx_disc_get_track_number(cdrom->disc, cdrom->lba);
- // memset(buf, 0, size);
+ // Sense a track change
+ if ((track != cdrom->cdda_prev_track) && (cdrom->mode & MODE_AUTOPAUSE)) {+ cdrom->cdda_remaining_samples = 0;
+ cdrom->cdda_sample_index = 0;
+ cdrom->state = CD_STATE_IDLE;
- // cdrom->state = CD_STATE_IDLE;
+ memset(buf, 0, size);
- // return;
- // }
+ // Send autopause IRQ (INT4)
+ cdrom_send_autopause_irq(cdrom);
+ return 0;
+ } else {+ cdrom->cdda_prev_track = track;
+ }
+
cdrom->cdda_remaining_samples = CD_SECTOR_SIZE >> 1;
cdrom->cdda_sample_index = 0;
cdrom->pending_lba = ++cdrom->lba;
+
+ return 1;
}
void cdrom_send_report_irq(psx_cdrom_t* cdrom) {@@ -369,7 +388,8 @@
for (int i = 0; i < (size >> 1);) { if (!cdrom->cdda_remaining_samples) {- cdrom_reload_cdda_buffer(cdrom, buf, size);
+ if (!cdrom_reload_cdda_buffer(cdrom, buf, size))
+ return;
++cdrom->cdda_sectors_played;
--- a/psx/dev/cdrom/cdrom.c
+++ b/psx/dev/cdrom/cdrom.c
@@ -198,16 +198,17 @@
}
int cdrom_get_pause_delay(psx_cdrom_t* cdrom) {- return (cdrom->mode & MODE_SPEED) ?
- (CD_DELAY_1MS * (70/2)) : (CD_DELAY_1MS * 70);
+ if (!cdrom->read_ongoing)
+ return 7000;
+
+ return CD_DELAY_1MS * ((cdrom->mode & MODE_SPEED) ? 35 : 70);
}
int cdrom_get_seek_delay(psx_cdrom_t* cdrom, int ts) {int delay = CD_DELAY_FR;
- return delay;
-
delay += cdrom->pending_speed_switch_delay;
+
cdrom->pending_speed_switch_delay = 0;
// Ridiculous delays for seeking to an audio sector
@@ -214,6 +215,7 @@
// or out of the disk
if (ts == TS_FAR) delay = 650 * CD_DELAY_1MS;
if (ts == TS_AUDIO) delay = 4000 * CD_DELAY_1MS;
+ // if (ts == TS_PREGAP) delay = 4000 * CD_DELAY_1MS;
return delay;
}
@@ -434,8 +436,6 @@
int ts = psx_disc_query(cdrom->disc, cdrom->lba);
- // printf("ts=%u ", ts);-
if (ts == TS_FAR) {cdrom_error(cdrom,
CD_STAT_SPINDLE | CD_STAT_SEEKERROR,
@@ -445,6 +445,7 @@
return;
}
+ //if (ts == TS_AUDIO || ts == TS_PREGAP) { if (ts == TS_AUDIO) {cdrom_error(cdrom,
CD_STAT_SPINDLE | CD_STAT_SEEKERROR,
@@ -497,6 +498,13 @@
if (cdrom->state == CD_STATE_PLAY)
return;
+ // Hold IRQ until IFR is acknowledged
+ if (cdrom->ifr & 0x1f) {+ cdrom->delay = 2;
+
+ return;
+ }
+
psx_ic_irq(cdrom->ic, IC_CDROM);
if (cdrom->state == CD_STATE_TX_RESP1) {@@ -663,11 +671,13 @@
if (data & 0x40)
queue_clear(cdrom->parameters);
+ // uint8_t prev_ifr = cdrom->ifr & 0x1f;
+
cdrom->ifr &= ~(data & 0x1f);
// If an INT is acknowledged, then the response
// FIFO is cleared
- // if ((cdrom->ifr & 0x1f) == 0)
+ // if (((cdrom->ifr & 0x1f) == 0) && (prev_ifr != 0))
// queue_clear(cdrom->response);
}
--- a/psx/dev/cdrom/cdrom.h
+++ b/psx/dev/cdrom/cdrom.h
@@ -245,6 +245,7 @@
uint32_t cdda_sample_index;
uint32_t cdda_sectors_played;
int cdda_playing;
+ int cdda_prev_track;
int read_ongoing;
uint8_t xa_buf[CD_SECTOR_SIZE];
int16_t xa_left_buf[XA_STEREO_SAMPLES];
--- a/psx/dev/cdrom/impl.c
+++ b/psx/dev/cdrom/impl.c
@@ -169,6 +169,8 @@
if (track)
cdrom->pending_lba = psx_disc_get_track_lba(cdrom->disc, track);
+ } else {+ track = psx_disc_get_track_number(cdrom->disc, cdrom->pending_lba);
}
cdrom_process_setloc(cdrom);
@@ -185,6 +187,7 @@
cdrom->cdda_playing = 1;
cdrom->cdda_remaining_samples = 0;
cdrom->cdda_sample_index = 0;
+ cdrom->cdda_prev_track = track;
cdrom_restore_state(cdrom);
}
@@ -231,7 +234,7 @@
cdrom->state = CD_STATE_READ;
cdrom->prev_state = CD_STATE_READ;
- cdrom->delay = cdrom_get_read_delay(cdrom);
+ cdrom->delay = cdrom_get_seek_delay(cdrom, ts);
cdrom->read_ongoing = 1;
}
@@ -285,12 +288,17 @@
if (cdrom->state == CD_STATE_TX_RESP1) {cdrom_set_int(cdrom, 3);
- queue_push(cdrom->response, CD_STAT_READ | CD_STAT_SPINDLE);
+ queue_push(cdrom->response, cdrom_get_stat(cdrom));
// Pausing at 1x takes 70ms, 2x takes 35ms
- // but setting delays that high breaks games
- cdrom->delay = CD_DELAY_1MS * ((cdrom->mode & MODE_SPEED) ? 70 : 35);
+ if (!cdrom->read_ongoing) {+ cdrom->delay = 7000;
+ } else {+ cdrom->delay = cdrom_get_pause_delay(cdrom);
+ }
+
cdrom->state = CD_STATE_TX_RESP2;
+ cdrom->busy = 1;
} else {cdrom_set_int(cdrom, 2);
@@ -309,7 +317,7 @@
queue_push(cdrom->response, cdrom_get_stat(cdrom));
- cdrom->delay = CD_DELAY_FR;
+ cdrom->delay = CD_DELAY_1MS;
cdrom->state = CD_STATE_TX_RESP2;
} else {cdrom_set_int(cdrom, 2);
@@ -345,9 +353,6 @@
queue_push(cdrom->response, cdrom_get_stat(cdrom));
- // 0x0d byte has to be sent (and ignored) for some reason
- // queue_pop(cdrom->parameters);
-
cdrom->xa_file = queue_pop(cdrom->parameters);
cdrom->xa_channel = queue_pop(cdrom->parameters);
@@ -365,10 +370,9 @@
// Big speed switch delay
if (prev_speed != (cdrom->mode & MODE_SPEED))
- cdrom->pending_speed_switch_delay = CD_DELAY_1MS;
+ cdrom->pending_speed_switch_delay = 650 * CD_DELAY_1MS;
cdrom_pause(cdrom);
- // cdrom_restore_state(cdrom);
}
void cdrom_cmd_getparam(psx_cdrom_t* cdrom) {@@ -488,6 +492,8 @@
int tn = psx_disc_get_track_count(cdrom->disc);
+ printf("tn=%u (%02x)\n", tn, ITOB(tn));+
queue_push(cdrom->response, cdrom_get_stat(cdrom));
queue_push(cdrom->response, 1);
queue_push(cdrom->response, ITOB(tn));
@@ -712,7 +718,7 @@
cdrom->state = CD_STATE_READ;
cdrom->prev_state = CD_STATE_READ;
- cdrom->delay = CD_DELAY_START_READ;
+ cdrom->delay = cdrom_get_seek_delay(cdrom, ts);
cdrom->read_ongoing = 1;
}
@@ -729,9 +735,8 @@
cdrom_set_int(cdrom, 3);
queue_push(cdrom->response, cdrom_get_stat(cdrom));
- cdrom->delay = CD_DELAY_1MS * 10;
+ cdrom->delay = PSX_CPU_CPS / 2;
cdrom->state = CD_STATE_TX_RESP2;
- // cdrom->busy = 1;
} else {cdrom_set_int(cdrom, 2);
queue_push(cdrom->response, cdrom_get_stat(cdrom));
--
⑨