shithub: psxe

Download patch

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