shithub: psxe

Download patch

ref: e145a4e8ae7b9e150e6c093b395eb71ab5fe4111
parent: 4055e8901d4fd29cbdd6914ebe9941f5db11bae3
author: allkern <lisandroaalarcon@gmail.com>
date: Sat Jul 20 09:02:03 EDT 2024

Fix report IRQ emulation

Fixes Doom games
Improve read start timings (fixes MMX5/6 MDEC movies)
Fix non-read pause timings (fixes DoA music)
Delay execution when running from BIOS

--- a/psx/cpu.c
+++ b/psx/cpu.c
@@ -291,6 +291,9 @@
 
     cpu->opcode = psx_bus_read32(cpu->bus, cpu->pc);
 
+    cpu->last_cycles = 2;
+    cpu->last_cycles += psx_bus_get_access_cycles(cpu->bus);
+
     cpu->pc = cpu->next_pc;
     cpu->next_pc += 4;
 
@@ -312,7 +315,6 @@
     g_psx_cpu_primary_table[OP](cpu);
 
     // Not even trying to get precise timings here
-    cpu->last_cycles = 2;
     cpu->total_cycles += cpu->last_cycles;
 
     cpu->r[0] = 0;
--- a/psx/dev/cdrom/audio.c
+++ b/psx/dev/cdrom/audio.c
@@ -294,10 +294,11 @@
         cdrom->cdda_remaining_samples = 0;
         cdrom->cdda_sample_index = 0;
         cdrom->state = CD_STATE_IDLE;
+        cdrom->cdda_prev_track = 0;
+        cdrom->cdda_playing = 0;
 
         memset(buf, 0, size);
 
-        // Send autopause IRQ (INT4)
         if (cdrom->mode & MODE_AUTOPAUSE)
             cdrom_send_autopause_irq(cdrom);
 
@@ -304,24 +305,6 @@
         return 0;
     }
 
-    int track = psx_disc_get_track_number(cdrom->disc, cdrom->lba);
-
-    // 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;
-
-        memset(buf, 0, size);
-
-        // 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;
 
@@ -339,8 +322,30 @@
     int track = psx_disc_get_track_number(cdrom->disc, cdrom->lba);
     int track_lba = psx_disc_get_track_lba(cdrom->disc, track);
 
-    int32_t diff = cdrom->lba - track_lba;
+    // 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->cdda_prev_track = 0;
+        cdrom->cdda_playing = 0;
 
+        printf("prev_track=%u track=%u\n", cdrom->cdda_prev_track, track);
+
+        cdrom_send_autopause_irq(cdrom);
+
+        return;
+    } else {
+        cdrom->cdda_prev_track = track;
+    }
+
+    int relative = (cdrom->cdda_sectors_played & 0x10) != 0;
+
+    int32_t diff = cdrom->lba;
+
+    if (relative)
+        diff = cdrom->lba - track_lba;
+
     if (diff < 0)
         diff = -diff;
 
@@ -348,9 +353,10 @@
     int ss = (diff % (60 * 75)) / 75;
     int ff = (diff % (60 * 75)) % 75;
 
-    printf("report: track %u %02u:%02u:%02u\n",
+    printf("report: track %u %02u:%02u:%02u relative=%d\n",
         track,
-        mm, ss, ff
+        mm, ss, ff,
+        relative
     );
 
     queue_push(cdrom->response, cdrom_get_stat(cdrom));
@@ -357,7 +363,7 @@
     queue_push(cdrom->response, ITOB(track));
     queue_push(cdrom->response, 1);
     queue_push(cdrom->response, ITOB(mm));
-    queue_push(cdrom->response, ITOB(ss) | 0x80);
+    queue_push(cdrom->response, ITOB(ss) | (relative ? 0x80 : 0));
     queue_push(cdrom->response, ITOB(ff));
     queue_push(cdrom->response, 0);
     queue_push(cdrom->response, 0);
@@ -393,10 +399,10 @@
 
             ++cdrom->cdda_sectors_played;
 
-            if (cdrom->cdda_sectors_played == 75) {
+            if ((cdrom->cdda_sectors_played & 0xf) == 0) {
                 cdrom_send_report_irq(cdrom);
 
-                cdrom->cdda_sectors_played = 0;
+                cdrom->cdda_sectors_played &= 0x3f;
             }
         }
 
--- a/psx/dev/cdrom/cdrom.c
+++ b/psx/dev/cdrom/cdrom.c
@@ -205,9 +205,7 @@
 }
 
 int cdrom_get_seek_delay(psx_cdrom_t* cdrom, int ts) {
-    int delay = CD_DELAY_FR;
-
-    delay += cdrom->pending_speed_switch_delay;
+    int delay = cdrom->pending_speed_switch_delay;
 
     cdrom->pending_speed_switch_delay = 0;
 
--- a/psx/dev/cdrom/cdrom.h
+++ b/psx/dev/cdrom/cdrom.h
@@ -34,7 +34,7 @@
 #define CD_DELAY_STOP_DS 25845878
 #define CD_DELAY_READ_SS (33868800 / 75)
 #define CD_DELAY_READ_DS (33868800 / (2*75))
-#define CD_DELAY_START_READ (cdrom_get_read_delay(cdrom))
+#define CD_DELAY_START_READ (cdrom_get_read_delay(cdrom) + cdrom_get_seek_delay(cdrom, ts))
 #define CD_DELAY_ONGOING_READ (cdrom_get_read_delay(cdrom) + (CD_DELAY_1MS * 4))
 
 #define XA_STEREO_SAMPLES 2016 // Samples per sector
--- a/psx/dev/cdrom/impl.c
+++ b/psx/dev/cdrom/impl.c
@@ -162,6 +162,8 @@
 
     queue_push(cdrom->response, cdrom_get_stat(cdrom));
 
+    cdrom_process_setloc(cdrom);
+
     int track = -1;
 
     if (!queue_is_empty(cdrom->parameters)) {
@@ -168,13 +170,11 @@
         int track = BTOI(queue_pop(cdrom->parameters));
 
         if (track)
-            cdrom->pending_lba = psx_disc_get_track_lba(cdrom->disc, track);
+            cdrom->lba = psx_disc_get_track_lba(cdrom->disc, track);
     } else {
-        track = psx_disc_get_track_number(cdrom->disc, cdrom->pending_lba);
+        track = psx_disc_get_track_number(cdrom->disc, cdrom->lba);
     }
 
-    cdrom_process_setloc(cdrom);
-
     int mm = cdrom->lba / (60 * 75);
     int ss = (cdrom->lba % (60 * 75)) / 75;
     int ff = (cdrom->lba % (60 * 75)) % 75;
@@ -234,7 +234,7 @@
 
     cdrom->state = CD_STATE_READ;
     cdrom->prev_state = CD_STATE_READ;
-    cdrom->delay = cdrom_get_seek_delay(cdrom, ts);
+    cdrom->delay = CD_DELAY_START_READ;
     cdrom->read_ongoing = 1;
 }
 
@@ -274,13 +274,7 @@
 
         cdrom_process_setloc(cdrom);
 
-        cdrom->prev_state = CD_STATE_IDLE;
-        cdrom->state = CD_STATE_IDLE;
-        cdrom->pending_command = 0;
-        cdrom->busy = 0;
-        cdrom->cdda_playing = 0;
-        cdrom->xa_playing = 0;
-        cdrom->read_ongoing = 0;
+        cdrom_pause(cdrom);
     }
 }
 
@@ -291,14 +285,8 @@
         queue_push(cdrom->response, cdrom_get_stat(cdrom));
 
         // Pausing at 1x takes 70ms, 2x takes 35ms
-        if (!cdrom->read_ongoing) {
-            cdrom->delay = 7000;
-        } else {
-            cdrom->delay = cdrom_get_pause_delay(cdrom);
-        }
-
+        cdrom->delay = cdrom_get_pause_delay(cdrom);
         cdrom->state = CD_STATE_TX_RESP2;
-        cdrom->busy = 1;
     } else {
         cdrom_set_int(cdrom, 2);
 
@@ -492,7 +480,7 @@
 
     int tn = psx_disc_get_track_count(cdrom->disc);
 
-    printf("tn=%u (%02x)\n", tn, ITOB(tn));
+    printf("getstat=%02x\n", cdrom_get_stat(cdrom));
 
     queue_push(cdrom->response, cdrom_get_stat(cdrom));
     queue_push(cdrom->response, 1);
@@ -718,7 +706,7 @@
 
     cdrom->state = CD_STATE_READ;
     cdrom->prev_state = CD_STATE_READ;
-    cdrom->delay = cdrom_get_seek_delay(cdrom, ts);
+    cdrom->delay = CD_DELAY_START_READ;
     cdrom->read_ongoing = 1;
 }
 
--