physical cdrom readahead
authornotaz <notasas@gmail.com>
Wed, 20 Mar 2024 23:14:56 +0000 (01:14 +0200)
committernotaz <notasas@gmail.com>
Fri, 22 Mar 2024 19:12:48 +0000 (21:12 +0200)
much more messy than I hoped
notaz/pcsx_rearmed#335

Makefile
frontend/libretro-cdrom.c [new file with mode: 0644]
frontend/libretro-cdrom.h [new file with mode: 0644]
frontend/libretro.c
frontend/libretro_core_options.h
frontend/plugin.c
frontend/plugin.h
libpcsxcore/cdriso.c
libpcsxcore/cdrom.c
libpcsxcore/plugins.c
libpcsxcore/plugins.h

index 7079ecd..8b2b87d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -249,8 +249,10 @@ OBJS += deps/libretro-common/string/stdstring.o
 OBJS += deps/libretro-common/vfs/vfs_implementation.o
 endif
 ifeq "$(HAVE_PHYSICAL_CDROM)" "1"
-OBJS += deps/libretro-common/cdrom/cdrom.o
+OBJS += frontend/libretro-cdrom.o
+OBJS += deps/libretro-common/lists/string_list.o
 OBJS += deps/libretro-common/memmap/memalign.o
+OBJS += deps/libretro-common/rthreads/rthreads.o
 OBJS += deps/libretro-common/vfs/vfs_implementation_cdrom.o
 CFLAGS += -DHAVE_CDROM
 endif
diff --git a/frontend/libretro-cdrom.c b/frontend/libretro-cdrom.c
new file mode 100644 (file)
index 0000000..654de1c
--- /dev/null
@@ -0,0 +1,70 @@
+#include "libretro-cdrom.h"
+#include "../deps/libretro-common/cdrom/cdrom.c"
+#if defined(__linux__) && !defined(ANDROID)
+//#include <linux/cdrom.h>
+#endif
+
+static int cdrom_send_command_dummy(const libretro_vfs_implementation_file *stream,
+      CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len,
+      unsigned char *sense, size_t sense_len)
+{
+   return 1;
+}
+
+static int cdrom_send_command_once(const libretro_vfs_implementation_file *stream,
+      CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len)
+{
+   unsigned char sense[CDROM_MAX_SENSE_BYTES] = {0};
+   int ret =
+#if defined(__linux__) && !defined(ANDROID)
+      cdrom_send_command_linux
+#elif defined(_WIN32) && !defined(_XBOX)
+      cdrom_send_command_win32
+#else
+      cdrom_send_command_dummy
+#endif
+         (stream, dir, buf, len, cmd, cmd_len, sense, sizeof(sense));
+#ifdef CDROM_DEBUG
+   if (ret && sense[2])
+      cdrom_print_sense_data(sense, sizeof(sense));
+#endif
+   (void)cdrom_send_command_dummy;
+   return ret;
+}
+
+// "extensions" to libretro-common
+int cdrom_set_read_speed_x(libretro_vfs_implementation_file *stream, unsigned speed)
+{
+   // SET CD-ROM SPEED, DA is newer?
+   unsigned char cmd1[] = {0xDA, 0, speed - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+   unsigned char cmd2[] = {0xBB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+   int ret;
+   ret = cdrom_send_command_once(stream, DIRECTION_NONE, NULL, 0, cmd1, sizeof(cmd1));
+   if (ret) {
+      printf("DA failed\n");
+#if defined(__linux__) && !defined(ANDROID)
+      // doesn't work, too late?
+      //ret = ioctl(fileno(stream->fp), CDROM_SELECT_SPEED, &speed);
+#endif
+   }
+   if (ret) {
+      speed = speed * 2352 * 75 / 1024;
+      cmd2[2] = speed >> 8;
+      cmd2[3] = speed;
+      ret = cdrom_send_command_once(stream, DIRECTION_NONE, NULL, 0, cmd2, sizeof(cmd2));
+   }
+   return ret;
+}
+
+int cdrom_read_sector(libretro_vfs_implementation_file *stream,
+      unsigned int lba, void *b)
+{
+   unsigned char cmd[] = {0xBE, 0, 0, 0, 0, 0, 0, 0, 1, 0xF8, 0, 0};
+   cmd[2] = lba >> 24;
+   cmd[3] = lba >> 16;
+   cmd[4] = lba >> 8;
+   cmd[5] = lba;
+   return cdrom_send_command_once(stream, DIRECTION_IN, b, 2352, cmd, sizeof(cmd));
+}
+
+// vim:sw=3:ts=3:expandtab
diff --git a/frontend/libretro-cdrom.h b/frontend/libretro-cdrom.h
new file mode 100644 (file)
index 0000000..a09f773
--- /dev/null
@@ -0,0 +1,5 @@
+#include "cdrom/cdrom.h"
+
+int cdrom_set_read_speed_x(libretro_vfs_implementation_file *stream, unsigned speed);
+int cdrom_read_sector(libretro_vfs_implementation_file *stream,
+      unsigned int lba, void *b);
index a3c3610..5cd0aee 100644 (file)
@@ -15,6 +15,7 @@
 #include <sys/syscall.h>
 #endif
 
+#include "retro_miscellaneous.h"
 #ifdef SWITCH
 #include <switch.h>
 #endif
@@ -1237,12 +1238,25 @@ static void disk_init(void)
    }
 }
 
+#ifdef HAVE_CDROM
+static long CALLBACK rcdrom_open(void);
+static long CALLBACK rcdrom_close(void);
+#endif
+
 static bool disk_set_eject_state(bool ejected)
 {
    // weird PCSX API..
    SetCdOpenCaseTime(ejected ? -1 : (time(NULL) + 2));
    LidInterrupt();
 
+#ifdef HAVE_CDROM
+   if (CDR_open == rcdrom_open) {
+      // likely the real cd was also changed - rescan
+      rcdrom_close();
+      if (!ejected)
+         rcdrom_open();
+   }
+#endif
    disk_ejected = ejected;
    return true;
 }
@@ -1295,8 +1309,7 @@ static bool disk_set_image_index(unsigned int index)
 
    if (!disk_ejected)
    {
-      SetCdOpenCaseTime(time(NULL) + 2);
-      LidInterrupt();
+      disk_set_eject_state(disk_ejected);
    }
 
    disk_current_index = index;
@@ -1501,23 +1514,176 @@ static void extract_directory(char *buf, const char *path, size_t size)
 #ifdef HAVE_CDROM
 #include "vfs/vfs_implementation.h"
 #include "vfs/vfs_implementation_cdrom.h"
-#include "cdrom/cdrom.h"
-static libretro_vfs_implementation_file *rcdrom_h;
+#include "libretro-cdrom.h"
+#include "rthreads/rthreads.h"
+#include "retro_timers.h"
+struct cached_buf {
+   unsigned char buf[2352];
+   unsigned int lba;
+};
+static struct {
+   libretro_vfs_implementation_file *h;
+   sthread_t *thread;
+   slock_t *read_lock;
+   slock_t *buf_lock;
+   scond_t *cond;
+   struct cached_buf *buf;
+   unsigned int buf_cnt, thread_exit, do_prefetch;
+   unsigned int total_lba, prefetch_lba;
+} rcdrom;
+
+static void lbacache_do(unsigned int lba)
+{
+   unsigned char m, s, f, buf[2352];
+   unsigned int i = lba % rcdrom.buf_cnt;
+   int ret;
+
+   cdrom_lba_to_msf(lba + 150, &m, &s, &f);
+   slock_lock(rcdrom.read_lock);
+   ret = cdrom_read_sector(rcdrom.h, lba, buf);
+   slock_lock(rcdrom.buf_lock);
+   slock_unlock(rcdrom.read_lock);
+   //printf("%d:%02d:%02d m%d f%d\n", m, s, f, buf[12+3], ((buf[12+4+2] >> 5) & 1) + 1);
+   if (ret) {
+      rcdrom.do_prefetch = 0;
+      slock_unlock(rcdrom.buf_lock);
+      LogErr("cdrom_read_sector failed for lba %d\n", ret, lba);
+      return;
+   }
+
+   if (lba != rcdrom.buf[i].lba) {
+      memcpy(rcdrom.buf[i].buf, buf, sizeof(rcdrom.buf[i].buf));
+      rcdrom.buf[i].lba = lba;
+   }
+   slock_unlock(rcdrom.buf_lock);
+   retro_sleep(0); // why does the main thread stall without this?
+}
+
+static int lbacache_get(unsigned int lba, void *buf)
+{
+   unsigned int i;
+   int ret = 0;
+
+   i = lba % rcdrom.buf_cnt;
+   slock_lock(rcdrom.buf_lock);
+   if (lba == rcdrom.buf[i].lba) {
+      memcpy(buf, rcdrom.buf[i].buf, 2352);
+      ret = 1;
+   }
+   slock_unlock(rcdrom.buf_lock);
+   return ret;
+}
+
+static void rcdrom_prefetch_thread(void *unused)
+{
+   unsigned int buf_cnt, lba, lba_to;
+
+   slock_lock(rcdrom.buf_lock);
+   while (!rcdrom.thread_exit)
+   {
+#ifdef __GNUC__
+      __asm__ __volatile__("":::"memory"); // barrier
+#endif
+      if (!rcdrom.do_prefetch)
+         scond_wait(rcdrom.cond, rcdrom.buf_lock);
+      if (!rcdrom.do_prefetch || !rcdrom.h || rcdrom.thread_exit)
+         continue;
+
+      buf_cnt = rcdrom.buf_cnt;
+      lba = rcdrom.prefetch_lba;
+      lba_to = lba + buf_cnt;
+      if (lba_to > rcdrom.total_lba)
+         lba_to = rcdrom.total_lba;
+      for (; lba < lba_to; lba++) {
+         if (lba != rcdrom.buf[lba % buf_cnt].lba)
+            break;
+      }
+      if (lba == lba_to) {
+         // caching complete
+         rcdrom.do_prefetch = 0;
+         continue;
+      }
+
+      slock_unlock(rcdrom.buf_lock);
+      lbacache_do(lba);
+      slock_lock(rcdrom.buf_lock);
+   }
+   slock_unlock(rcdrom.buf_lock);
+}
+
+static void rcdrom_stop_thread(void)
+{
+   rcdrom.thread_exit = 1;
+   if (rcdrom.buf_lock) {
+      slock_lock(rcdrom.buf_lock);
+      rcdrom.do_prefetch = 0;
+      if (rcdrom.cond)
+         scond_signal(rcdrom.cond);
+      slock_unlock(rcdrom.buf_lock);
+   }
+   if (rcdrom.thread) {
+      sthread_join(rcdrom.thread);
+      rcdrom.thread = NULL;
+   }
+   if (rcdrom.cond) { scond_free(rcdrom.cond); rcdrom.cond = NULL; }
+   if (rcdrom.buf_lock) { slock_free(rcdrom.buf_lock); rcdrom.buf_lock = NULL; }
+   if (rcdrom.read_lock) { slock_free(rcdrom.read_lock); rcdrom.read_lock = NULL; }
+   free(rcdrom.buf);
+   rcdrom.buf = NULL;
+}
+
+// the thread is optional, if anything fails we can do direct reads
+static void rcdrom_start_thread(void)
+{
+   rcdrom_stop_thread();
+   rcdrom.thread_exit = rcdrom.prefetch_lba = rcdrom.do_prefetch = 0;
+   if (rcdrom.buf_cnt == 0)
+      return;
+   rcdrom.buf = calloc(rcdrom.buf_cnt, sizeof(rcdrom.buf[0]));
+   rcdrom.buf_lock = slock_new();
+   rcdrom.read_lock = slock_new();
+   rcdrom.cond = scond_new();
+   if (rcdrom.buf && rcdrom.buf_lock && rcdrom.read_lock && rcdrom.cond) {
+      rcdrom.thread = sthread_create(rcdrom_prefetch_thread, NULL);
+      rcdrom.buf[0].lba = ~0;
+   }
+   if (!rcdrom.thread) {
+      LogErr("cdrom precache thread init failed.\n");
+      rcdrom_stop_thread();
+   }
+}
 
 static long CALLBACK rcdrom_open(void)
 {
-   //printf("%s %s\n", __func__, GetIsoFile());
-   rcdrom_h = retro_vfs_file_open_impl(GetIsoFile(), RETRO_VFS_FILE_ACCESS_READ,
+   const char *name = GetIsoFile();
+   //printf("%s %s\n", __func__, name);
+   rcdrom.h = retro_vfs_file_open_impl(name, RETRO_VFS_FILE_ACCESS_READ,
       RETRO_VFS_FILE_ACCESS_HINT_NONE);
-   return rcdrom_h ? 0 : -1;
+   if (rcdrom.h) {
+      int ret = cdrom_set_read_speed_x(rcdrom.h, 4);
+      if (ret) LogErr("CD speed set failed\n");
+      const cdrom_toc_t *toc = retro_vfs_file_get_cdrom_toc();
+      const cdrom_track_t *last = &toc->track[toc->num_tracks - 1];
+      unsigned int lba = cdrom_msf_to_lba(last->min, last->sec, last->frame) - 150;
+      rcdrom.total_lba = lba + last->track_size;
+      //cdrom_get_current_config_random_readable(rcdrom.h);
+      //cdrom_get_current_config_multiread(rcdrom.h);
+      //cdrom_get_current_config_cdread(rcdrom.h);
+      //cdrom_get_current_config_profiles(rcdrom.h);
+      rcdrom_start_thread();
+      return 0;
+   }
+   LogErr("retro_vfs_file_open failed for '%s'\n", name);
+   return -1;
 }
 
 static long CALLBACK rcdrom_close(void)
 {
    //printf("%s\n", __func__);
-   if (rcdrom_h) {
-      retro_vfs_file_close_impl(rcdrom_h);
-      rcdrom_h = NULL;
+   if (rcdrom.h) {
+      rcdrom_stop_thread();
+      retro_vfs_file_close_impl(rcdrom.h);
+      rcdrom.h = NULL;
    }
    return 0;
 }
@@ -1536,10 +1702,7 @@ static long CALLBACK rcdrom_getTD(unsigned char track, unsigned char *rt)
    const cdrom_toc_t *toc = retro_vfs_file_get_cdrom_toc();
    rt[0] = 0, rt[1] = 2, rt[2] = 0;
    if (track == 0) {
-      const cdrom_track_t *last = &toc->track[toc->num_tracks - 1];
-      unsigned lba = cdrom_msf_to_lba(last->min, last->sec, last->frame);
-      lba += last->track_size;
-      cdrom_lba_to_msf(lba, &rt[2], &rt[1], &rt[0]);
+      cdrom_lba_to_msf(rcdrom.total_lba + 150, &rt[2], &rt[1], &rt[0]);
    }
    else if (track <= toc->num_tracks) {
       int i = track - 1;
@@ -1551,15 +1714,63 @@ static long CALLBACK rcdrom_getTD(unsigned char track, unsigned char *rt)
    return 0;
 }
 
+static long CALLBACK rcdrom_prefetch(unsigned char m, unsigned char s, unsigned char f)
+{
+   unsigned int lba = cdrom_msf_to_lba(m, s, f) - 150;
+   if (rcdrom.cond && rcdrom.h) {
+      rcdrom.prefetch_lba = lba;
+      rcdrom.do_prefetch = 1;
+      scond_signal(rcdrom.cond);
+   }
+   if (rcdrom.buf) {
+     unsigned int c = rcdrom.buf_cnt;
+     if (c)
+        return rcdrom.buf[lba % c].lba == lba;
+   }
+   return 1;
+}
+
+static int rcdrom_read_msf(unsigned char m, unsigned char s, unsigned char f,
+      void *buf, const char *func)
+{
+   unsigned int lba = cdrom_msf_to_lba(m, s, f) - 150;
+   int hit = 0, ret = -1;
+   if (rcdrom.buf_lock)
+      hit = lbacache_get(lba, buf);
+   if (!hit && rcdrom.read_lock) {
+      // maybe still prefetching
+      slock_lock(rcdrom.read_lock);
+      slock_unlock(rcdrom.read_lock);
+      hit = lbacache_get(lba, buf);
+      if (hit)
+         hit = 2;
+   }
+   if (!hit) {
+      slock_t *lock = rcdrom.read_lock;
+      rcdrom.do_prefetch = 0;
+      if (lock)
+         slock_lock(lock);
+      if (rcdrom.h)
+         ret = cdrom_read_sector(rcdrom.h, lba, buf);
+      if (lock)
+         slock_unlock(lock);
+   }
+   else
+      ret = 0;
+   //printf("%s %d:%02d:%02d -> %d hit %d\n", func, m, s, f, ret, hit);
+   return ret;
+}
+
 static boolean CALLBACK rcdrom_readTrack(unsigned char *time)
 {
-   void *buf = ISOgetBuffer();
-   int ret = -1;
-   if (rcdrom_h)
-      ret = cdrom_read(rcdrom_h, NULL,
-           btoi(time[0]), btoi(time[1]), btoi(time[2]), buf, 2340, 12);
-   //printf("%s %x:%02x:%02x -> %d\n", __func__, time[0], time[1], time[2], ret);
-   return !ret;
+   unsigned char m = btoi(time[0]), s = btoi(time[1]), f = btoi(time[2]);
+   return !rcdrom_read_msf(m, s, f, ISOgetBuffer() - 12, __func__);
+}
+
+static long CALLBACK rcdrom_readCDDA(unsigned char m, unsigned char s, unsigned char f,
+      unsigned char *buffer)
+{
+   return rcdrom_read_msf(m, s, f, buffer, __func__);
 }
 
 static unsigned char * CALLBACK rcdrom_getBuffer(void)
@@ -1582,16 +1793,6 @@ static long CALLBACK rcdrom_getStatus(struct CdrStat *stat)
    stat->Type = toc->track[0].audio ? 2 : 1;
    return 0;
 }
-
-static long CALLBACK rcdrom_readCDDA(unsigned char m, unsigned char s, unsigned char f,
-      unsigned char *buffer)
-{
-   int ret = -1;
-   if (rcdrom_h)
-      ret = cdrom_read(rcdrom_h, NULL, m, s, f, buffer, 2352, 0);
-   //printf("%s %d:%02d:%02d -> %d\n", __func__, m, s, f, ret);
-   return ret;
-}
 #endif // HAVE_CDROM
 
 #if defined(__QNX__) || defined(_WIN32)
@@ -1851,7 +2052,8 @@ bool retro_load_game(const struct retro_game_info *info)
       CDR_getBufferSub = rcdrom_getBufferSub;
       CDR_getStatus = rcdrom_getStatus;
       CDR_readCDDA = rcdrom_readCDDA;
-#else
+      CDR_prefetch = rcdrom_prefetch;
+#elif !defined(USE_LIBRETRO_VFS)
       ReleasePlugins();
       LogErr("%s\n", "Physical CD-ROM support is not compiled in.");
       show_notification("Physical CD-ROM support is not compiled in.", 6000, 3);
@@ -2246,6 +2448,26 @@ static void update_variables(bool in_flight)
          display_internal_fps = true;
    }
 
+#ifdef HAVE_CDROM
+   var.value = NULL;
+   var.key = "pcsx_rearmed_phys_cd_readahead";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      long newval = strtol(var.value, NULL, 10);
+      bool changed = rcdrom.buf_cnt != newval;
+      if (rcdrom.h && changed)
+         rcdrom_stop_thread();
+      rcdrom.buf_cnt = newval;
+      if (rcdrom.h && changed) {
+         rcdrom_start_thread();
+         if (rcdrom.cond && rcdrom.prefetch_lba) {
+            rcdrom.do_prefetch = 1;
+            scond_signal(rcdrom.cond);
+         }
+      }
+   }
+#endif
+
    //
    // CPU emulation related config
 #ifndef DRC_DISABLE
index 3c5614e..be9e8ab 100644 (file)
@@ -182,6 +182,25 @@ struct retro_core_option_v2_definition option_defs_us[] = {
       "sync",
    },
 #endif
+#ifdef HAVE_CDROM
+#define V(x) { #x, NULL }
+   {
+      "pcsx_rearmed_phys_cd_readahead",
+      "Physical CD read-ahead",
+      NULL,
+      "(Hardware CD-ROM only) Reads the specified amount of sectors ahead of time to try to avoid later stalls. 333000 will try to read the complete disk (requires an additional 750MB of RAM).",
+      NULL,
+      "system",
+      {
+         V(0),  V(1),  V(2),  V(3),  V(4),  V(5),  V(6),  V(7),
+         V(8),  V(9),  V(10), V(11), V(12), V(13), V(14), V(15),
+         V(16), V(32), V(64), V(128), V(256), V(512), V(1024), V(333000),
+         { NULL, NULL},
+      },
+      "12",
+   },
+#undef V
+#endif
 #ifndef DRC_DISABLE
    {
       "pcsx_rearmed_drc",
index c400165..b3ad3bd 100644 (file)
@@ -41,6 +41,7 @@ static long CALLBACK CDRgetStatus(struct CdrStat *_) { return 0; }
 static char * CALLBACK CDRgetDriveLetter(void) { return NULL; }
 static long CALLBACK CDRreadCDDA(unsigned char _, unsigned char __, unsigned char ___, unsigned char *____) { return 0; }
 static long CALLBACK CDRgetTE(unsigned char _, unsigned char *__, unsigned char *___, unsigned char *____) { return 0; }
+static long CALLBACK CDRprefetch(unsigned char m, unsigned char s, unsigned char f) { return 1; }
 
 /* GPU */
 static void CALLBACK GPUdisplayText(char *_) { return; }
@@ -163,6 +164,7 @@ static const struct {
        DIRECT_CDR(CDRsetfilename),
        DIRECT_CDR(CDRreadCDDA),
        DIRECT_CDR(CDRgetTE),
+       DIRECT_CDR(CDRprefetch),
        /* SPU */
        DIRECT_SPU(SPUinit),
        DIRECT_SPU(SPUshutdown),
index 5e12f90..a96d609 100644 (file)
@@ -1,7 +1,9 @@
 #ifndef __PLUGIN_H__
 #define __PLUGIN_H__
 
+#ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#endif
 
 #define PLUGIN_DL_BASE 0xfbad0000
 
index 7924bb3..cd2d202 100644 (file)
@@ -100,6 +100,7 @@ long CALLBACK CDR__configure(void);
 long CALLBACK CDR__test(void);
 void CALLBACK CDR__about(void);
 long CALLBACK CDR__setfilename(char *filename);
+long CALLBACK CDR__prefetch(u8 m, u8 s, u8 f);
 
 static void DecodeRawSubData(void);
 
@@ -1738,6 +1739,7 @@ void cdrIsoInit(void) {
        CDR_test = CDR__test;
        CDR_about = CDR__about;
        CDR_setfilename = CDR__setfilename;
+       CDR_prefetch = CDR__prefetch;
 
        numtracks = 0;
 }
index 872cc0c..5da24c8 100644 (file)
@@ -68,7 +68,7 @@ static struct {
        } subq;
        unsigned char TrackChanged;
        unsigned char ReportDelay;
-       unsigned char unused3;
+       unsigned char PhysCdPropagations;
        unsigned short sectorsRead;
        unsigned int  freeze_ver;
 
@@ -660,6 +660,14 @@ static void msfiSub(u8 *msfi, u32 count)
 
 void cdrPlayReadInterrupt(void)
 {
+       int hit = CDR_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]);
+       if (!hit && cdr.PhysCdPropagations++ < 222) {
+               // this propagates real cdrom delays to the emulated game
+               CDRPLAYREAD_INT(cdReadTime / 2, 0);
+               return;
+       }
+       cdr.PhysCdPropagations = 0;
+
        cdr.LastReadSeekCycles = psxRegs.cycle;
 
        if (cdr.Reading) {
@@ -694,6 +702,7 @@ void cdrPlayReadInterrupt(void)
        }
 
        msfiAdd(cdr.SetSectorPlay, 1);
+       CDR_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]);
 
        // update for CdlGetlocP/autopause
        generate_subq(cdr.SetSectorPlay);
@@ -1109,6 +1118,8 @@ void cdrInterrupt(void) {
                        seekTime = cdrSeekTime(cdr.SetSector);
                        memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
                        cdr.DriveState = DRIVESTATE_SEEK;
+                       CDR_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1],
+                                       cdr.SetSectorPlay[2]);
                        /*
                        Crusaders of Might and Magic = 0.5x-4x
                        - fix cutscene speech start
@@ -1246,6 +1257,8 @@ void cdrInterrupt(void) {
                        cdr.SubqForwardSectors = 1;
                        cdr.sectorsRead = 0;
                        cdr.DriveState = DRIVESTATE_SEEK;
+                       CDR_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1],
+                                       cdr.SetSectorPlay[2]);
 
                        cycles = (cdr.Mode & MODE_SPEED) ? cdReadTime : cdReadTime * 2;
                        cycles += seekTime;
@@ -1423,6 +1436,7 @@ static void cdrReadInterrupt(void)
                cdrReadInterruptSetResult(cdr.StatP);
 
        msfiAdd(cdr.SetSectorPlay, 1);
+       CDR_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]);
 
        CDRPLAYREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime, 0);
 }
index 9a39982..369ea97 100644 (file)
@@ -68,6 +68,7 @@ CDRabout              CDR_about;
 CDRsetfilename        CDR_setfilename;
 CDRreadCDDA           CDR_readCDDA;
 CDRgetTE              CDR_getTE;
+CDRprefetch           CDR_prefetch;
 
 SPUinit               SPU_init;
 SPUshutdown           SPU_shutdown;
@@ -257,6 +258,7 @@ long CALLBACK CDR__configure(void) { return 0; }
 long CALLBACK CDR__test(void) { return 0; }
 void CALLBACK CDR__about(void) {}
 long CALLBACK CDR__setfilename(char*filename) { return 0; }
+long CALLBACK CDR__prefetch(u8 m, u8 s, u8 f) { return 1; }
 
 #define LoadCdrSym1(dest, name) \
        LoadSym(CDR_##dest, CDR##dest, name, TRUE);
@@ -301,6 +303,7 @@ static int LoadCDRplugin(const char *CDRdll) {
        LoadCdrSym0(setfilename, "CDRsetfilename");
        LoadCdrSymN(readCDDA, "CDRreadCDDA");
        LoadCdrSymN(getTE, "CDRgetTE");
+       LoadCdrSym0(prefetch, "CDRprefetch");
 
        return 0;
 }
index df8ed87..4054bf6 100644 (file)
@@ -133,6 +133,7 @@ struct SubQ {
 };\r
 typedef long (CALLBACK* CDRreadCDDA)(unsigned char, unsigned char, unsigned char, unsigned char *);\r
 typedef long (CALLBACK* CDRgetTE)(unsigned char, unsigned char *, unsigned char *, unsigned char *);\r
+typedef long (CALLBACK* CDRprefetch)(unsigned char, unsigned char, unsigned char);\r
 \r
 // CD-ROM function pointers\r
 extern CDRinit               CDR_init;\r
@@ -154,6 +155,7 @@ extern CDRabout              CDR_about;
 extern CDRsetfilename        CDR_setfilename;\r
 extern CDRreadCDDA           CDR_readCDDA;\r
 extern CDRgetTE              CDR_getTE;\r
+extern CDRprefetch           CDR_prefetch;\r
 \r
 long CALLBACK CDR__getStatus(struct CdrStat *stat);\r
 \r