mcd, fixes and improvements for mcd-verificator
authorkub <derkub@gmail.com>
Tue, 17 Sep 2024 22:17:45 +0000 (00:17 +0200)
committerkub <derkub@gmail.com>
Tue, 17 Sep 2024 22:37:50 +0000 (00:37 +0200)
pico/cd/cdc.c
pico/cd/cdd.c
pico/cd/mcd.c
pico/cd/memory.c
pico/pico_int.h

index 1163cb2..be5a9c5 100644 (file)
@@ -92,7 +92,7 @@ typedef struct
   //void (*dma_w)(unsigned int words);
   int dma_w;
   uint8 ram[0x4000 + 2352]; /* 16K external RAM (with one block overhead to handle buffer overrun) */
-} cdc_t; 
+} cdc_t;
 
 static cdc_t cdc;
 
@@ -125,7 +125,7 @@ void cdc_reset(void)
   cdc.head[1][3] = 0x00;
 
   /* reset CDC cycle counter */
-  cdc.cycles = 0;
+  cdc.cycles = SekCyclesDoneS68k();
 
   /* DMA transfer disabled */
   cdc.dma_w = 0;
@@ -245,6 +245,16 @@ int cdc_context_load_old(uint8 *state)
 #undef old_load
 }
 
+static int check_decoder_irq_pending(void)
+{
+  /* As per mcd-verificator, DECI is active for a phase of 49:72 per sector */
+  /* 12500000/75 * 49/(49+72) = ~67500, but it sometimes fails with that */
+  if (CYCLES_GE(SekCyclesDoneS68k(), cdc.cycles + 67250))
+    cdc.ifstat |= BIT_DECI;
+
+  return !(cdc.ifstat & BIT_DECI) && (cdc.ifctrl & BIT_DECIEN);
+}
+
 static void do_dma(enum dma_type type, int bytes_in)
 {
   int dma_addr = (Pico_mcd->s68k_regs[0x0a] << 8) | Pico_mcd->s68k_regs[0x0b];
@@ -368,7 +378,7 @@ void cdc_dma_update(void)
       cdc.ifstat &= ~BIT_DTEI;
 
       /* Data Transfer End interrupt enabled ? */
-      if (cdc.ifctrl & BIT_DTEIEN)
+      if (!check_decoder_irq_pending() && (cdc.ifctrl & BIT_DTEIEN))
       {
         /* level 5 interrupt enabled ? */
         if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
@@ -411,9 +421,10 @@ int cdc_decoder_update(uint8 header[4])
 
     /* pending decoder interrupt */
     cdc.ifstat &= ~BIT_DECI;
+    cdc.cycles = SekCyclesDoneS68k();
 
     /* decoder interrupt enabled ? */
-    if (cdc.ifctrl & BIT_DECIEN)
+    if (((cdc.ifstat & BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN)) && (cdc.ifctrl & BIT_DECIEN))
     {
       /* level 5 interrupt enabled ? */
       if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
@@ -455,7 +466,7 @@ int cdc_decoder_update(uint8 header[4])
       return 1;
     }
   }
-  
+
   /* keep decoding same data block if Buffer Write is disabled */
   return 0;
 }
@@ -473,6 +484,7 @@ void cdc_reg_w(unsigned char data)
     case 0x01:  /* IFCTRL */
     {
       /* pending interrupts ? */
+      check_decoder_irq_pending();
       if (((data & BIT_DTEIEN) && !(cdc.ifstat & BIT_DTEI)) ||
           ((data & BIT_DECIEN) && !(cdc.ifstat & BIT_DECI)))
       {
@@ -621,14 +633,13 @@ void cdc_reg_w(unsigned char data)
       /* clear DBCH bits 4-7 */
       cdc.dbc &= 0x0fff;
 
-#if 0
       /* no pending decoder interrupt ? */
-      if ((cdc.ifstat | BIT_DECI) || !(cdc.ifctrl & BIT_DECIEN))
+      if (!check_decoder_irq_pending())
       {
         /* clear pending level 5 interrupt */
         pcd_irq_s68k(5, 0);
       }
-#endif
+
       Pico_mcd->s68k_regs[0x04+1] = 0x08;
       break;
     }
@@ -648,16 +659,23 @@ void cdc_reg_w(unsigned char data)
     case 0x0a:  /* CTRL0 */
     {
       /* reset DECI if decoder turned off */
-      if (!(data & BIT_DECEN))
+      if (!(data & BIT_DECEN)) {
         cdc.ifstat |= BIT_DECI;
 
+        if ((cdc.ifstat & BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN))
+        {
+          /* clear pending level 5 interrupt */
+          pcd_irq_s68k(5, 0);
+        }
+      }
+
       /* update decoding mode */
       if (data & BIT_AUTORQ)
       {
         /* set MODE bit according to CTRL1 register & clear FORM bit */
         cdc.stat[2] = cdc.ctrl[1] & BIT_MODRQ;
       }
-      else 
+      else
       {
         /* set MODE & FORM bits according to CTRL1 register */
         cdc.stat[2] = cdc.ctrl[1] & (BIT_MODRQ | BIT_FORMRQ);
@@ -676,7 +694,7 @@ void cdc_reg_w(unsigned char data)
         /* set MODE bit according to CTRL1 register & clear FORM bit */
         cdc.stat[2] = data & BIT_MODRQ;
       }
-      else 
+      else
       {
         /* set MODE & FORM bits according to CTRL1 register */
         cdc.stat[2] = data & (BIT_MODRQ | BIT_FORMRQ);
@@ -692,7 +710,7 @@ void cdc_reg_w(unsigned char data)
       cdc.pt |= data;
       Pico_mcd->s68k_regs[0x04+1] = 0x0d;
       break;
-  
+
     case 0x0d:  /* PTH */
       cdc.pt &= 0x00ff;
       cdc.pt |= data << 8;
@@ -722,6 +740,7 @@ unsigned char cdc_reg_r(void)
 
     case 0x01:  /* IFSTAT */
       Pico_mcd->s68k_regs[0x04+1] = 0x02;
+      check_decoder_irq_pending();
       return cdc.ifstat;
 
     case 0x02:  /* DBCL */
@@ -785,15 +804,13 @@ unsigned char cdc_reg_r(void)
 
       /* clear pending decoder interrupt */
       cdc.ifstat |= BIT_DECI;
-      
-#if 0
+
       /* no pending data transfer end interrupt */
-      if ((cdc.ifstat | BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN))
+      if ((cdc.ifstat & BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN))
       {
         /* clear pending level 5 interrupt */
         pcd_irq_s68k(5, 0);
       }
-#endif
 
       Pico_mcd->s68k_regs[0x04+1] = 0x10;
       return data;
@@ -805,8 +822,14 @@ unsigned char cdc_reg_r(void)
   }
 }
 
-unsigned short cdc_host_r(void)
+unsigned short cdc_host_r(int sub)
 {
+  int dir = Pico_mcd->s68k_regs[0x04+0] & 0x07;
+
+  /* sync sub cpu if DSR bit not there (yet?) on main cpu */
+  if (!(Pico_mcd->s68k_regs[0x04+0] & 0x40))
+    if (!sub) pcd_sync_s68k(SekCyclesDone()+8, 0); /* HACK, mcd-verificator */
+
   /* check if data is available */
   if (!(cdc.ifstat & BIT_DTEN))
   {
@@ -817,7 +840,11 @@ unsigned short cdc_host_r(void)
 #ifdef LOG_CDC
     error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac, data, cdc.dbc, s68k.pc);
 #endif
+
+    /* only the configured cpu access advances the DMA */
+    if ((sub && dir != 3) || (!sub && dir != 2))
+      return data;
+
     /* increment data address counter */
     cdc.dac += 2;
 
@@ -843,7 +870,7 @@ unsigned short cdc_host_r(void)
         cdc.ifstat &= ~BIT_DTEI;
 
         /* Data Transfer End interrupt enabled ? */
-        if (cdc.ifctrl & BIT_DTEIEN)
+        if (!check_decoder_irq_pending() && (cdc.ifctrl & BIT_DTEIEN))
         {
           /* level 5 interrupt enabled ? */
           if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
index 89ca183..6f121f4 100644 (file)
@@ -720,6 +720,28 @@ void cdd_update(void)
   error("LBA = %d (track n°%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
 #endif
   
+  /* update decoder, depending on track type */
+  if (cdd.status == CD_PLAY && !is_audio(cdd.index))
+  {
+    /* DATA sector header (CD-ROM Mode 1) */
+    uint8 header[4];
+    uint32 msf = cdd.lba + 150;
+    header[0] = lut_BCD_8[(msf / 75) / 60];
+    header[1] = lut_BCD_8[(msf / 75) % 60];
+    header[2] = lut_BCD_8[(msf % 75)];
+    header[3] = 0x01;
+
+    /* data track sector read is controlled by CDC */
+    cdc_decoder_update(header);
+  }
+  else
+  {
+    uint8 header[4] = { 0, };
+
+    /* audio blocks are still sent to CDC as well as CD DAC/Fader */
+    cdc_decoder_update(header);
+  }
+
   /* drive latency */
   if (cdd.latency > 0)
   {
@@ -737,33 +759,11 @@ void cdd_update(void)
       return;
     }
 
-    /* track type */
-    if (!is_audio(cdd.index))
+    /* check against audio track start index */
+    if (is_audio(cdd.index) && cdd.lba >= cdd.toc.tracks[cdd.index].start)
     {
-      /* DATA sector header (CD-ROM Mode 1) */
-      uint8 header[4];
-      uint32 msf = cdd.lba + 150;
-      header[0] = lut_BCD_8[(msf / 75) / 60];
-      header[1] = lut_BCD_8[(msf / 75) % 60];
-      header[2] = lut_BCD_8[(msf % 75)];
-      header[3] = 0x01;
-
-      /* data track sector read is controlled by CDC */
-      cdc_decoder_update(header);
-    }
-    else
-    {
-      uint8 header[4] = { 0, };
-
-      /* check against audio track start index */
-      if (cdd.lba >= cdd.toc.tracks[cdd.index].start)
-      {
-        /* audio track playing */
-        Pico_mcd->s68k_regs[0x36+0] = 0x00;
-      }
-
-      /* audio blocks are still sent to CDC as well as CD DAC/Fader */
-      cdc_decoder_update(header);
+      /* audio track playing */
+      Pico_mcd->s68k_regs[0x36+0] = 0x00;
     }
  
     /* next block is automatically read */
@@ -1005,8 +1005,15 @@ void cdd_process(void)
                  (Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1])) * 75 +
                  (Pico_mcd->s68k_regs[0x48+0] * 10 + Pico_mcd->s68k_regs[0x48+1]) - 150;
 
-      /* if drive is currently reading, another block or 2 are decoded before the seek starts */
-      if (cdd.status == CD_PLAY && !(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) {
+      /* return track index in RS2-RS3 */
+      set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
+      set_reg16(0x3a, 0x0000);
+      set_reg16(0x3c, 0x0000);
+      set_reg16(0x3e, 0x0000);
+      set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f);
+
+      /* seek delayed by max 2 blocks before the seek starts */
+      if (!(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) {
         Pico_mcd->m.state_flags |= PCD_ST_CDD_CMD;
         return;
       }
@@ -1051,12 +1058,6 @@ void cdd_process(void)
       /* update status */
       cdd.status = CD_PLAY;
 
-      /* return track index in RS2-RS3 */
-      set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
-      set_reg16(0x3a, 0x0000);
-      set_reg16(0x3c, 0x0000);
-      set_reg16(0x3e, 0x0000);
-      set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f);
       return;
     }
 
@@ -1070,8 +1071,15 @@ void cdd_process(void)
                  (Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1])) * 75 +
                  (Pico_mcd->s68k_regs[0x48+0] * 10 + Pico_mcd->s68k_regs[0x48+1]) - 150;
 
-      /* if drive is currently reading, another block or 2 are decoded before the seek starts */
-      if (cdd.status == CD_PLAY && !(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) {
+      /* unknown RS1-RS8 values (returning 0xF in RS1 invalidates track infos in RS2-RS8 and fixes Final Fight CD intro when seek time is emulated) */
+      set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
+      set_reg16(0x3a, 0x0000);
+      set_reg16(0x3c, 0x0000);
+      set_reg16(0x3e, 0x0000);
+      set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f);
+
+      /* seek delayed by max 2 blocks before the seek starts */
+      if (!(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) {
         Pico_mcd->m.state_flags |= PCD_ST_CDD_CMD;
         return;
       }
@@ -1101,19 +1109,16 @@ void cdd_process(void)
       /* update status */
       cdd.status = CD_READY;
 
-      /* unknown RS1-RS8 values (returning 0xF in RS1 invalidates track infos in RS2-RS8 and fixes Final Fight CD intro when seek time is emulated) */
-      set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
-      set_reg16(0x3a, 0x0000);
-      set_reg16(0x3c, 0x0000);
-      set_reg16(0x3e, 0x0000);
-      set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f);
       return;
     }
 
     case 0x06:  /* Pause */
     {
-      /* if drive is currently reading, another block or 2 are decoded before the seek starts */
-      if (cdd.status == CD_PLAY && !(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) {
+      /* update status (RS1-RS8 unchanged) */
+      cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_READY;
+
+      /* seek delayed by max 2 blocks before the seek starts */
+      if (!(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) {
         Pico_mcd->m.state_flags |= PCD_ST_CDD_CMD;
         return;
       }
@@ -1121,8 +1126,6 @@ void cdd_process(void)
       /* no audio track playing */
       Pico_mcd->s68k_regs[0x36+0] = 0x01;
 
-      /* update status (RS1-RS8 unchanged) */
-      cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_READY;
       break;
     }
 
index ca94aab..7086a17 100644 (file)
@@ -58,7 +58,7 @@ PICO_INTERNAL void PicoPowerMCD(void)
   Pico_mcd->m.state_flags = PCD_ST_S68K_RST;
   Pico_mcd->m.busreq = 2;     // busreq on, s68k in reset
   Pico_mcd->s68k_regs[3] = 1; // 2M word RAM mode, m68k access
-  if (Pico.romsize <= 0x20000) // hack to detect BIOS, no GA HINT vector for MSU
+  if (Pico.romsize == 0x20000) // hack to detect BIOS, no GA HINT vector for MSU
     memset(Pico.rom + 0x70, 0xff, 4);
 }
 
@@ -149,11 +149,11 @@ static void pcd_cdc_event(unsigned int now)
   {
     /* reset CDD command wait flag */
     Pico_mcd->s68k_regs[0x4b] = 0xf0;
+  }
 
-    if ((Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) && (Pico_mcd->s68k_regs[0x37] & 4)) {
-      elprintf(EL_INTS|EL_CD, "s68k: cdd irq 4");
-      pcd_irq_s68k(4, 1);
-    }
+  if ((Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) && (Pico_mcd->s68k_regs[0x37] & 4)) {
+    elprintf(EL_INTS|EL_CD, "s68k: cdd irq 4");
+    pcd_irq_s68k(4, 1);
   }
 
   pcd_event_schedule(now, PCD_EVENT_CDC, 12500000/75);
@@ -312,8 +312,7 @@ static int SekSyncM68k(int once);
 
 void pcd_run_cpus_normal(int m68k_cycles)
 {
-  // TODO this is suspicious. ~1 cycle refresh delay every 256 cycles?
-  SekAimM68k(m68k_cycles, 0x42); // Fhey area
+  SekAimM68k(m68k_cycles, 0x108);
 
   while (CYCLES_GT(Pico.t.m68c_aim, Pico.t.m68c_cnt)) {
     if (SekShouldInterrupt()) {
index 99c6610..461dc0d 100644 (file)
@@ -68,7 +68,7 @@ static void remap_word_ram(u32 r3);
 \r
 // poller detection\r
 #define POLL_LIMIT 16\r
-#define POLL_CYCLES 64\r
+#define POLL_CYCLES 52\r
 \r
 void m68k_comm_check(u32 a)\r
 {\r
@@ -122,18 +122,20 @@ static u32 m68k_reg_read16(u32 a)
       elprintf(EL_CDREG3, "m68k_regs r3: %02x @%06x", (u8)d, SekPc);\r
       goto end;\r
     case 4:\r
+      pcd_sync_s68k(SekCyclesDone(), 0);\r
       d = Pico_mcd->s68k_regs[4]<<8;\r
       goto end;\r
     case 6:\r
       d = *(u16 *)(Pico.rom + 0x72);\r
       goto end;\r
     case 8:\r
-      d = cdc_host_r();\r
+      d = cdc_host_r(0);\r
       goto end;\r
     case 0xa:\r
       elprintf(EL_UIO, "m68k FIXME: reserved read");\r
       goto end;\r
     case 0xc: // 384 cycle stopwatch timer\r
+      pcd_sync_s68k(SekCyclesDone(), 0);\r
       d = pcd_stopwatch_read(0);\r
       elprintf(EL_CDREGS, "m68k stopwatch timer read (%04x)", d);\r
       goto end;\r
@@ -238,7 +240,7 @@ void m68k_reg_write8(u32 a, u32 d)
         ((u16 *)Pico.rom)[0x70/2], ((u16 *)Pico.rom)[0x72/2]);\r
       return;\r
     case 8:\r
-      (void) cdc_host_r(); // acts same as reading\r
+      (void) cdc_host_r(0); // acts same as reading\r
       return;\r
     case 0x0f:\r
       a = 0x0e;\r
@@ -338,7 +340,7 @@ u32 s68k_reg_read16(u32 a)
       d = cdc_reg_r();\r
       goto end;\r
     case 8:\r
-      d = cdc_host_r();\r
+      d = cdc_host_r(1);\r
       goto end;\r
     case 0xc:\r
       d = pcd_stopwatch_read(1);\r
@@ -557,7 +559,7 @@ void s68k_reg_write16(u32 a, u32 d)
       // these are only byte registers, LDS/UDS ignored\r
       return s68k_reg_write8(a + 1, d);\r
     case 0x08:\r
-      return (void) cdc_host_r(); // acts same as reading\r
+      return (void) cdc_host_r(1); // acts same as reading\r
     case 0x0a: // DMA address\r
       r[0xa] = d >> 8;\r
       r[0xb] = d;\r
@@ -1232,13 +1234,13 @@ PICO_INTERNAL void PicoMemSetupCD(void)
     Pico_mcd = plat_mmap(0x05000000, sizeof(mcd_state), 0, 0);\r
     memset(Pico_mcd, 0, sizeof(mcd_state));\r
   }\r
-  pcd_base_address = (Pico.romsize > 0x20000 ? 0x400000 : 0x000000);\r
+  pcd_base_address = (Pico.romsize != 0x20000 ? 0x400000 : 0x000000);\r
 \r
   // setup default main68k map\r
   PicoMemSetup();\r
 \r
   // main68k map (BIOS or MSU mapped by PicoMemSetup()):\r
-  if (Pico.romsize > 0x20000) {\r
+  if (pcd_base_address != 0) {\r
     // MSU cartridge. Fake BIOS detection\r
     cpu68k_map_set(m68k_read8_map,   0x400000, 0x41ffff, PicoReadM68k8_bios, 1);\r
     cpu68k_map_set(m68k_read16_map,  0x400000, 0x41ffff, PicoReadM68k16_bios, 1);\r
index 7875b8a..546e5ec 100644 (file)
@@ -763,7 +763,7 @@ void cdc_dma_update(void);
 int  cdc_decoder_update(unsigned char header[4]);\r
 void cdc_reg_w(unsigned char data);\r
 unsigned char  cdc_reg_r(void);\r
-unsigned short cdc_host_r(void);\r
+unsigned short cdc_host_r(int sub);\r
 \r
 // cd/cdd.c\r
 void cdd_reset(void);\r