cd: switch to CD controller code from genplus
authornotaz <notasas@gmail.com>
Sat, 5 Oct 2013 01:14:45 +0000 (04:14 +0300)
committernotaz <notasas@gmail.com>
Sun, 6 Oct 2013 21:11:31 +0000 (00:11 +0300)
same license, much cleaner code
using own dma code though..

14 files changed:
pico/cd/LC89510.c [deleted file]
pico/cd/LC89510.h
pico/cd/cd_file.c
pico/cd/cd_sys.c
pico/cd/cdc.c [new file with mode: 0644]
pico/cd/genplus_macros.h
pico/cd/mcd.c
pico/cd/memory.c
pico/cd/memory_arm.s
pico/cd/sek.c
pico/pico_int.h
pico/state.c
platform/base_readme.txt
platform/common/common.mak

diff --git a/pico/cd/LC89510.c b/pico/cd/LC89510.c
deleted file mode 100644 (file)
index 7489476..0000000
+++ /dev/null
@@ -1,637 +0,0 @@
-/***********************************************************\r
- *                                                         *\r
- * This source file was taken from the Gens project        *\r
- * Written by Stéphane Dallongeville                       *\r
- * Copyright (c) 2002 by Stéphane Dallongeville            *\r
- * Modified/adapted for PicoDrive by notaz, 2007           *\r
- *                                                         *\r
- ***********************************************************/\r
-\r
-#include "../pico_int.h"\r
-\r
-#define CDC_DMA_SPEED 256\r
-\r
-\r
-static void CDD_Reset(void)\r
-{\r
-       // Reseting CDD\r
-\r
-       memset(Pico_mcd->s68k_regs+0x34, 0, 2*2); // CDD.Fader, CDD.Control\r
-       Pico_mcd->cdd.Status = 0;\r
-       Pico_mcd->cdd.Minute = 0;\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       // clear receive status and transfer command\r
-       memset(Pico_mcd->s68k_regs+0x38, 0, 20);\r
-       Pico_mcd->s68k_regs[0x38+9] = 0xF;              // Default checksum\r
-}\r
-\r
-\r
-static void CDC_Reset(void)\r
-{\r
-       // Reseting CDC\r
-\r
-       memset(Pico_mcd->cdc.Buffer, 0, sizeof(Pico_mcd->cdc.Buffer));\r
-\r
-       Pico_mcd->cdc.COMIN = 0;\r
-       Pico_mcd->cdc.IFSTAT = 0xFF;\r
-       Pico_mcd->cdc.DAC.N = 0;\r
-       Pico_mcd->cdc.DBC.N = 0;\r
-       Pico_mcd->cdc.HEAD.N = 0x01000000;\r
-       Pico_mcd->cdc.PT.N = 0;\r
-       Pico_mcd->cdc.WA.N = 2352 * 2;\r
-       Pico_mcd->cdc.STAT.N = 0x00000080;\r
-       Pico_mcd->cdc.SBOUT = 0;\r
-       Pico_mcd->cdc.IFCTRL = 0;\r
-       Pico_mcd->cdc.CTRL.N = 0;\r
-\r
-       Pico_mcd->cdc.Decode_Reg_Read = 0;\r
-       Pico_mcd->scd.Status_CDC &= ~0x08;\r
-}\r
-\r
-\r
-PICO_INTERNAL void LC89510_Reset(void)\r
-{\r
-       CDD_Reset();\r
-       CDC_Reset();\r
-\r
-       // clear DMA_Adr & Stop_Watch\r
-       memset(Pico_mcd->s68k_regs + 0xA, 0, 4);\r
-}\r
-\r
-\r
-PICO_INTERNAL void Update_CDC_TRansfer(int which)\r
-{\r
-       unsigned int DMA_Adr, dep, length;\r
-       unsigned short *dest;\r
-       unsigned char  *src;\r
-\r
-       if (1) //Pico_mcd->cdc.DBC.N <= (CDC_DMA_SPEED * 2))\r
-       {\r
-               length = (Pico_mcd->cdc.DBC.N + 1) >> 1;\r
-               Pico_mcd->scd.Status_CDC &= ~0x08;      // Last transfer\r
-               Pico_mcd->s68k_regs[4] |=  0x80;        // End data transfer\r
-               Pico_mcd->s68k_regs[4] &= ~0x40;        // no more data ready\r
-               Pico_mcd->cdc.IFSTAT |= 0x08;           // No more data transfer in progress\r
-\r
-               if (Pico_mcd->cdc.IFCTRL & 0x40)        // DTEIEN = Data Trasnfer End Interrupt Enable ?\r
-               {\r
-                       Pico_mcd->cdc.IFSTAT &= ~0x40;\r
-\r
-                       if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN5)\r
-                       {\r
-                               elprintf(EL_INTS, "cdc DTE irq 5");\r
-                               SekInterruptS68k(5);\r
-                       }\r
-               }\r
-       }\r
-       else length = CDC_DMA_SPEED;\r
-\r
-\r
-       // TODO: dst bounds checking?\r
-       src = Pico_mcd->cdc.Buffer + Pico_mcd->cdc.DAC.N;\r
-       DMA_Adr = (Pico_mcd->s68k_regs[0xA]<<8) | Pico_mcd->s68k_regs[0xB];\r
-\r
-       if (which == 7) // WORD RAM\r
-       {\r
-               if (Pico_mcd->s68k_regs[3] & 4)\r
-               {\r
-                       // test: Final Fight\r
-                       int bank = !(Pico_mcd->s68k_regs[3]&1);\r
-                       dep = ((DMA_Adr & 0x3FFF) << 3);\r
-                       cdprintf("CD DMA # %04x -> word_ram1M # %06x, len=%i",\r
-                                       Pico_mcd->cdc.DAC.N, dep, length);\r
-\r
-                       dest = (unsigned short *) (Pico_mcd->word_ram1M[bank] + dep);\r
-\r
-                       memcpy16bswap(dest, src, length);\r
-\r
-                       /*{ // debug\r
-                               unsigned char *b1 = Pico_mcd->word_ram1M[bank] + dep;\r
-                               unsigned char *b2 = (unsigned char *)(dest+length) - 8;\r
-                               dprintf("%02x %02x %02x %02x .. %02x %02x %02x %02x",\r
-                                       b1[0], b1[1], b1[4], b1[5], b2[0], b2[1], b2[4], b2[5]);\r
-                       }*/\r
-               }\r
-               else\r
-               {\r
-                       dep = ((DMA_Adr & 0x7FFF) << 3);\r
-                       cdprintf("CD DMA # %04x -> word_ram2M # %06x, len=%i",\r
-                                       Pico_mcd->cdc.DAC.N, dep, length);\r
-                       dest = (unsigned short *) (Pico_mcd->word_ram2M + dep);\r
-\r
-                       memcpy16bswap(dest, src, length);\r
-\r
-                       /*{ // debug\r
-                               unsigned char *b1 = Pico_mcd->word_ram2M + dep;\r
-                               unsigned char *b2 = (unsigned char *)(dest+length) - 4;\r
-                               dprintf("%02x %02x %02x %02x .. %02x %02x %02x %02x",\r
-                                       b1[0], b1[1], b1[2], b1[3], b2[0], b2[1], b2[2], b2[3]);\r
-                       }*/\r
-               }\r
-       }\r
-       else if (which == 4) // PCM RAM (check: popful Mail)\r
-       {\r
-               dep = (DMA_Adr & 0x03FF) << 2;\r
-               cdprintf("CD DMA # %04x -> PCM[%i] # %04x, len=%i",\r
-                       Pico_mcd->cdc.DAC.N, Pico_mcd->pcm.bank, dep, length);\r
-               dest = (unsigned short *) (Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank] + dep);\r
-\r
-               if (Pico_mcd->cdc.DAC.N & 1) /* unaligned src? */\r
-                       memcpy(dest, src, length*2);\r
-               else    memcpy16(dest, (unsigned short *) src, length);\r
-       }\r
-       else if (which == 5) // PRG RAM\r
-       {\r
-               dep = DMA_Adr << 3;\r
-               dest = (unsigned short *) (Pico_mcd->prg_ram + dep);\r
-               cdprintf("CD DMA # %04x -> prg_ram # %06x, len=%i",\r
-                               Pico_mcd->cdc.DAC.N, dep, length);\r
-\r
-               memcpy16bswap(dest, src, length);\r
-\r
-               /*{ // debug\r
-                       unsigned char *b1 = Pico_mcd->prg_ram + dep;\r
-                       unsigned char *b2 = (unsigned char *)(dest+length) - 4;\r
-                       dprintf("%02x %02x %02x %02x .. %02x %02x %02x %02x",\r
-                               b1[0], b1[1], b1[2], b1[3], b2[0], b2[1], b2[2], b2[3]);\r
-               }*/\r
-       }\r
-\r
-       length <<= 1;\r
-       Pico_mcd->cdc.DAC.N = (Pico_mcd->cdc.DAC.N + length) & 0xFFFF;\r
-       if (Pico_mcd->scd.Status_CDC & 0x08) Pico_mcd->cdc.DBC.N -= length;\r
-       else Pico_mcd->cdc.DBC.N = 0;\r
-\r
-       // update DMA_Adr\r
-       length >>= 2;\r
-       if (which != 4) length >>= 1;\r
-       DMA_Adr += length;\r
-       Pico_mcd->s68k_regs[0xA] = DMA_Adr >> 8;\r
-       Pico_mcd->s68k_regs[0xB] = DMA_Adr;\r
-}\r
-\r
-\r
-PICO_INTERNAL_ASM unsigned short Read_CDC_Host(int is_sub)\r
-{\r
-       int addr;\r
-\r
-       if (!(Pico_mcd->scd.Status_CDC & 0x08))\r
-       {\r
-               // Transfer data disabled\r
-               cdprintf("Read_CDC_Host FIXME: Transfer data disabled");\r
-               return 0;\r
-       }\r
-\r
-       if ((is_sub && (Pico_mcd->s68k_regs[4] & 7) != 3) ||\r
-               (!is_sub && (Pico_mcd->s68k_regs[4] & 7) != 2))\r
-       {\r
-               // Wrong setting\r
-               cdprintf("Read_CDC_Host FIXME: Wrong setting");\r
-               return 0;\r
-       }\r
-\r
-       Pico_mcd->cdc.DBC.N -= 2;\r
-\r
-       if (Pico_mcd->cdc.DBC.N <= 0)\r
-       {\r
-               Pico_mcd->cdc.DBC.N = 0;\r
-               Pico_mcd->scd.Status_CDC &= ~0x08;              // Last transfer\r
-               Pico_mcd->s68k_regs[4] |=  0x80;                // End data transfer\r
-               Pico_mcd->s68k_regs[4] &= ~0x40;                // no more data ready\r
-               Pico_mcd->cdc.IFSTAT |= 0x08;                   // No more data transfer in progress\r
-\r
-               if (Pico_mcd->cdc.IFCTRL & 0x40)                // DTEIEN = Data Transfer End Interrupt Enable ?\r
-               {\r
-                       Pico_mcd->cdc.IFSTAT &= ~0x40;\r
-\r
-                       if (Pico_mcd->s68k_regs[0x33]&(1<<5)) {\r
-                               elprintf(EL_INTS, "m68k: s68k irq 5");\r
-                               SekInterruptS68k(5);\r
-                       }\r
-\r
-                       cdprintf("CDC - DTE interrupt");\r
-               }\r
-       }\r
-\r
-       addr = Pico_mcd->cdc.DAC.N;\r
-       Pico_mcd->cdc.DAC.N += 2;\r
-\r
-       cdprintf("Read_CDC_Host sub=%i d=%04x dac=%04x dbc=%04x", is_sub,\r
-               (Pico_mcd->cdc.Buffer[addr]<<8) | Pico_mcd->cdc.Buffer[addr+1], Pico_mcd->cdc.DAC.N, Pico_mcd->cdc.DBC.N);\r
-\r
-       return (Pico_mcd->cdc.Buffer[addr]<<8) | Pico_mcd->cdc.Buffer[addr+1];\r
-}\r
-\r
-\r
-PICO_INTERNAL void CDC_Update_Header(void)\r
-{\r
-       if (Pico_mcd->cdc.CTRL.B.B1 & 0x01)             // Sub-Header wanted ?\r
-       {\r
-               Pico_mcd->cdc.HEAD.B.B0 = 0;\r
-               Pico_mcd->cdc.HEAD.B.B1 = 0;\r
-               Pico_mcd->cdc.HEAD.B.B2 = 0;\r
-               Pico_mcd->cdc.HEAD.B.B3 = 0;\r
-       }\r
-       else\r
-       {\r
-               _msf MSF;\r
-\r
-               LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
-\r
-               Pico_mcd->cdc.HEAD.B.B0 = INT_TO_BCDB(MSF.M);\r
-               Pico_mcd->cdc.HEAD.B.B1 = INT_TO_BCDB(MSF.S);\r
-               Pico_mcd->cdc.HEAD.B.B2 = INT_TO_BCDB(MSF.F);\r
-               Pico_mcd->cdc.HEAD.B.B3 = 0x01;\r
-       }\r
-}\r
-\r
-\r
-PICO_INTERNAL unsigned char CDC_Read_Reg(void)\r
-{\r
-       unsigned char ret;\r
-\r
-       switch(Pico_mcd->s68k_regs[5] & 0xF)\r
-       {\r
-               case 0x0: // COMIN\r
-                       cdprintf("CDC read reg 00 = %.2X", Pico_mcd->cdc.COMIN);\r
-\r
-                       Pico_mcd->s68k_regs[5] = 0x1;\r
-                       return Pico_mcd->cdc.COMIN;\r
-\r
-               case 0x1: // IFSTAT\r
-                       cdprintf("CDC read reg 01 = %.2X", Pico_mcd->cdc.IFSTAT);\r
-\r
-                       Pico_mcd->cdc.Decode_Reg_Read |= (1 << 1);              // Reg 1 (decoding)\r
-                       Pico_mcd->s68k_regs[5] = 0x2;\r
-                       return Pico_mcd->cdc.IFSTAT;\r
-\r
-               case 0x2: // DBCL\r
-                       cdprintf("CDC read reg 02 = %.2X", Pico_mcd->cdc.DBC.B.L);\r
-\r
-                       Pico_mcd->s68k_regs[5] = 0x3;\r
-                       return Pico_mcd->cdc.DBC.B.L;\r
-\r
-               case 0x3: // DBCH\r
-                       cdprintf("CDC read reg 03 = %.2X", Pico_mcd->cdc.DBC.B.H);\r
-\r
-                       Pico_mcd->s68k_regs[5] = 0x4;\r
-                       return Pico_mcd->cdc.DBC.B.H;\r
-\r
-               case 0x4: // HEAD0\r
-                       cdprintf("CDC read reg 04 = %.2X", Pico_mcd->cdc.HEAD.B.B0);\r
-\r
-                       Pico_mcd->cdc.Decode_Reg_Read |= (1 << 4);              // Reg 4 (decoding)\r
-                       Pico_mcd->s68k_regs[5] = 0x5;\r
-                       return Pico_mcd->cdc.HEAD.B.B0;\r
-\r
-               case 0x5: // HEAD1\r
-                       cdprintf("CDC read reg 05 = %.2X", Pico_mcd->cdc.HEAD.B.B1);\r
-\r
-                       Pico_mcd->cdc.Decode_Reg_Read |= (1 << 5);              // Reg 5 (decoding)\r
-                       Pico_mcd->s68k_regs[5] = 0x6;\r
-                       return Pico_mcd->cdc.HEAD.B.B1;\r
-\r
-               case 0x6: // HEAD2\r
-                       cdprintf("CDC read reg 06 = %.2X", Pico_mcd->cdc.HEAD.B.B2);\r
-\r
-                       Pico_mcd->cdc.Decode_Reg_Read |= (1 << 6);              // Reg 6 (decoding)\r
-                       Pico_mcd->s68k_regs[5] = 0x7;\r
-                       return Pico_mcd->cdc.HEAD.B.B2;\r
-\r
-               case 0x7: // HEAD3\r
-                       cdprintf("CDC read reg 07 = %.2X", Pico_mcd->cdc.HEAD.B.B3);\r
-\r
-                       Pico_mcd->cdc.Decode_Reg_Read |= (1 << 7);              // Reg 7 (decoding)\r
-                       Pico_mcd->s68k_regs[5] = 0x8;\r
-                       return Pico_mcd->cdc.HEAD.B.B3;\r
-\r
-               case 0x8: // PTL\r
-                       cdprintf("CDC read reg 08 = %.2X", Pico_mcd->cdc.PT.B.L);\r
-\r
-                       Pico_mcd->cdc.Decode_Reg_Read |= (1 << 8);              // Reg 8 (decoding)\r
-                       Pico_mcd->s68k_regs[5] = 0x9;\r
-                       return Pico_mcd->cdc.PT.B.L;\r
-\r
-               case 0x9: // PTH\r
-                       cdprintf("CDC read reg 09 = %.2X", Pico_mcd->cdc.PT.B.H);\r
-\r
-                       Pico_mcd->cdc.Decode_Reg_Read |= (1 << 9);              // Reg 9 (decoding)\r
-                       Pico_mcd->s68k_regs[5] = 0xA;\r
-                       return Pico_mcd->cdc.PT.B.H;\r
-\r
-               case 0xA: // WAL\r
-                       cdprintf("CDC read reg 10 = %.2X", Pico_mcd->cdc.WA.B.L);\r
-\r
-                       Pico_mcd->s68k_regs[5] = 0xB;\r
-                       return Pico_mcd->cdc.WA.B.L;\r
-\r
-               case 0xB: // WAH\r
-                       cdprintf("CDC read reg 11 = %.2X", Pico_mcd->cdc.WA.B.H);\r
-\r
-                       Pico_mcd->s68k_regs[5] = 0xC;\r
-                       return Pico_mcd->cdc.WA.B.H;\r
-\r
-               case 0xC: // STAT0\r
-                       cdprintf("CDC read reg 12 = %.2X", Pico_mcd->cdc.STAT.B.B0);\r
-\r
-                       Pico_mcd->cdc.Decode_Reg_Read |= (1 << 12);             // Reg 12 (decoding)\r
-                       Pico_mcd->s68k_regs[5] = 0xD;\r
-                       return Pico_mcd->cdc.STAT.B.B0;\r
-\r
-               case 0xD: // STAT1\r
-                       cdprintf("CDC read reg 13 = %.2X", Pico_mcd->cdc.STAT.B.B1);\r
-\r
-                       Pico_mcd->cdc.Decode_Reg_Read |= (1 << 13);             // Reg 13 (decoding)\r
-                       Pico_mcd->s68k_regs[5] = 0xE;\r
-                       return Pico_mcd->cdc.STAT.B.B1;\r
-\r
-               case 0xE: // STAT2\r
-                       cdprintf("CDC read reg 14 = %.2X", Pico_mcd->cdc.STAT.B.B2);\r
-\r
-                       Pico_mcd->cdc.Decode_Reg_Read |= (1 << 14);             // Reg 14 (decoding)\r
-                       Pico_mcd->s68k_regs[5] = 0xF;\r
-                       return Pico_mcd->cdc.STAT.B.B2;\r
-\r
-               case 0xF: // STAT3\r
-                       cdprintf("CDC read reg 15 = %.2X", Pico_mcd->cdc.STAT.B.B3);\r
-\r
-                       ret = Pico_mcd->cdc.STAT.B.B3;\r
-                       Pico_mcd->cdc.IFSTAT |= 0x20;                   // decoding interrupt flag cleared\r
-                       if ((Pico_mcd->cdc.CTRL.B.B0 & 0x80) && (Pico_mcd->cdc.IFCTRL & 0x20))\r
-                       {\r
-                               if ((Pico_mcd->cdc.Decode_Reg_Read & 0x73F2) == 0x73F2)\r
-                                       Pico_mcd->cdc.STAT.B.B3 = 0x80;\r
-                       }\r
-                       return ret;\r
-       }\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL void CDC_Write_Reg(unsigned char Data)\r
-{\r
-       cdprintf("CDC write reg%02d = %.2X", Pico_mcd->s68k_regs[5] & 0xF, Data);\r
-\r
-       switch (Pico_mcd->s68k_regs[5] & 0xF)\r
-       {\r
-               case 0x0: // SBOUT\r
-                       Pico_mcd->s68k_regs[5] = 0x1;\r
-                       Pico_mcd->cdc.SBOUT = Data;\r
-\r
-                       break;\r
-\r
-               case 0x1: // IFCTRL\r
-                       Pico_mcd->s68k_regs[5] = 0x2;\r
-                       Pico_mcd->cdc.IFCTRL = Data;\r
-\r
-                       if ((Pico_mcd->cdc.IFCTRL & 0x02) == 0)         // Stop data transfer\r
-                       {\r
-                               Pico_mcd->cdc.DBC.N = 0;\r
-                               Pico_mcd->scd.Status_CDC &= ~0x08;\r
-                               Pico_mcd->cdc.IFSTAT |= 0x08;           // No more data transfer in progress\r
-                       }\r
-                       break;\r
-\r
-               case 0x2: // DBCL\r
-                       Pico_mcd->s68k_regs[5] = 0x3;\r
-                       Pico_mcd->cdc.DBC.B.L = Data;\r
-\r
-                       break;\r
-\r
-               case 0x3: // DBCH\r
-                       Pico_mcd->s68k_regs[5] = 0x4;\r
-                       Pico_mcd->cdc.DBC.B.H = Data;\r
-\r
-                       break;\r
-\r
-               case 0x4: // DACL\r
-                       Pico_mcd->s68k_regs[5] = 0x5;\r
-                       Pico_mcd->cdc.DAC.B.L = Data;\r
-\r
-                       break;\r
-\r
-               case 0x5: // DACH\r
-                       Pico_mcd->s68k_regs[5] = 0x6;\r
-                       Pico_mcd->cdc.DAC.B.H = Data;\r
-\r
-                       break;\r
-\r
-               case 0x6: // DTTRG\r
-                       if (Pico_mcd->cdc.IFCTRL & 0x02)                // Data transfer enable ?\r
-                       {\r
-                               Pico_mcd->cdc.IFSTAT &= ~0x08;          // Data transfer in progress\r
-                               Pico_mcd->scd.Status_CDC |= 0x08;       // Data transfer in progress\r
-                               Pico_mcd->s68k_regs[4] &= 0x7F;         // A data transfer start\r
-\r
-                               cdprintf("************** Starting Data Transfer ***********");\r
-                               cdprintf("RS0 = %.4X  DAC = %.4X  DBC = %.4X  DMA adr = %.4X\n\n", Pico_mcd->s68k_regs[4]<<8,\r
-                                       Pico_mcd->cdc.DAC.N, Pico_mcd->cdc.DBC.N, (Pico_mcd->s68k_regs[0xA]<<8) | Pico_mcd->s68k_regs[0xB]);\r
-\r
-                               // tmp\r
-                               {\r
-                                       int ddx = Pico_mcd->s68k_regs[4] & 7;\r
-                                       if (ddx <  2) break; // invalid\r
-                                       if (ddx <  4) {\r
-                                               Pico_mcd->s68k_regs[4] |= 0x40; // Data set ready in host port\r
-                                               break;\r
-                                       }\r
-                                       if (ddx == 6) break; // invalid\r
-\r
-                                       pcd_event_schedule_s68k(PCD_EVENT_DMA, Pico_mcd->cdc.DBC.N / 2);\r
-                               }\r
-                       }\r
-                       break;\r
-\r
-               case 0x7: // DTACK\r
-                       Pico_mcd->cdc.IFSTAT |= 0x40;                   // end data transfer interrupt flag cleared\r
-                       break;\r
-\r
-               case 0x8: // WAL\r
-                       Pico_mcd->s68k_regs[5] = 0x9;\r
-                       Pico_mcd->cdc.WA.B.L = Data;\r
-\r
-                       break;\r
-\r
-               case 0x9: // WAH\r
-                       Pico_mcd->s68k_regs[5] = 0xA;\r
-                       Pico_mcd->cdc.WA.B.H = Data;\r
-\r
-                       break;\r
-\r
-               case 0xA: // CTRL0\r
-                       Pico_mcd->s68k_regs[5] = 0xB;\r
-                       Pico_mcd->cdc.CTRL.B.B0 = Data;\r
-\r
-                       break;\r
-\r
-               case 0xB: // CTRL1\r
-                       Pico_mcd->s68k_regs[5] = 0xC;\r
-                       Pico_mcd->cdc.CTRL.B.B1 = Data;\r
-\r
-                       break;\r
-\r
-               case 0xC: // PTL\r
-                       Pico_mcd->s68k_regs[5] = 0xD;\r
-                       Pico_mcd->cdc.PT.B.L = Data;\r
-\r
-                       break;\r
-\r
-               case 0xD: // PTH\r
-                       Pico_mcd->s68k_regs[5] = 0xE;\r
-                       Pico_mcd->cdc.PT.B.H = Data;\r
-\r
-                       break;\r
-\r
-               case 0xE: // CTRL2\r
-                       Pico_mcd->cdc.CTRL.B.B2 = Data;\r
-                       break;\r
-\r
-               case 0xF: // RESET\r
-                       CDC_Reset();\r
-                       break;\r
-       }\r
-}\r
-\r
-\r
-static int bswapwrite(int a, unsigned short d)\r
-{\r
-       *(unsigned short *)(Pico_mcd->s68k_regs + a) = (d>>8)|(d<<8);\r
-       return d + (d >> 8);\r
-}\r
-\r
-PICO_INTERNAL void CDD_Export_Status(void)\r
-{\r
-       unsigned int csum;\r
-\r
-       csum  = bswapwrite( 0x38+0, Pico_mcd->cdd.Status);\r
-       csum += bswapwrite( 0x38+2, Pico_mcd->cdd.Minute);\r
-       csum += bswapwrite( 0x38+4, Pico_mcd->cdd.Seconde);\r
-       csum += bswapwrite( 0x38+6, Pico_mcd->cdd.Frame);\r
-       Pico_mcd->s68k_regs[0x38+8] = Pico_mcd->cdd.Ext;\r
-       csum += Pico_mcd->cdd.Ext;\r
-       Pico_mcd->s68k_regs[0x38+9] = ~csum & 0xf;\r
-\r
-       Pico_mcd->s68k_regs[0x37] &= 3; // CDD.Control\r
-\r
-       if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4)\r
-       {\r
-               elprintf(EL_INTS, "cdd export irq 4");\r
-               SekInterruptS68k(4);\r
-       }\r
-\r
-//     cdprintf("CDD exported status\n");\r
-       cdprintf("out:  Status=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X  Checksum=%.4X",\r
-               (Pico_mcd->s68k_regs[0x38+0] << 8) | Pico_mcd->s68k_regs[0x38+1],\r
-               (Pico_mcd->s68k_regs[0x38+2] << 8) | Pico_mcd->s68k_regs[0x38+3],\r
-               (Pico_mcd->s68k_regs[0x38+4] << 8) | Pico_mcd->s68k_regs[0x38+5],\r
-               (Pico_mcd->s68k_regs[0x38+6] << 8) | Pico_mcd->s68k_regs[0x38+7],\r
-               (Pico_mcd->s68k_regs[0x38+8] << 8) | Pico_mcd->s68k_regs[0x38+9]);\r
-}\r
-\r
-\r
-PICO_INTERNAL void CDD_Import_Command(void)\r
-{\r
-//     cdprintf("CDD importing command\n");\r
-       cdprintf("in:  Command=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X  Checksum=%.4X",\r
-               (Pico_mcd->s68k_regs[0x38+10+0] << 8) | Pico_mcd->s68k_regs[0x38+10+1],\r
-               (Pico_mcd->s68k_regs[0x38+10+2] << 8) | Pico_mcd->s68k_regs[0x38+10+3],\r
-               (Pico_mcd->s68k_regs[0x38+10+4] << 8) | Pico_mcd->s68k_regs[0x38+10+5],\r
-               (Pico_mcd->s68k_regs[0x38+10+6] << 8) | Pico_mcd->s68k_regs[0x38+10+7],\r
-               (Pico_mcd->s68k_regs[0x38+10+8] << 8) | Pico_mcd->s68k_regs[0x38+10+9]);\r
-\r
-       switch (Pico_mcd->s68k_regs[0x38+10+0])\r
-       {\r
-               case 0x0:       // STATUS (?)\r
-                       Get_Status_CDD_c0();\r
-                       break;\r
-\r
-               case 0x1:       // STOP ALL (?)\r
-                       Stop_CDD_c1();\r
-                       break;\r
-\r
-               case 0x2:       // GET TOC INFORMATIONS\r
-                       switch(Pico_mcd->s68k_regs[0x38+10+3])\r
-                       {\r
-                               case 0x0:       // get current position (MSF format)\r
-                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00);\r
-                                       Get_Pos_CDD_c20();\r
-                                       break;\r
-\r
-                               case 0x1:       // get elapsed time of current track played/scanned (relative MSF format)\r
-                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 1;\r
-                                       Get_Track_Pos_CDD_c21();\r
-                                       break;\r
-\r
-                               case 0x2:       // get current track in RS2-RS3\r
-                                       Pico_mcd->cdd.Status =  (Pico_mcd->cdd.Status & 0xFF00) | 2;\r
-                                       Get_Current_Track_CDD_c22();\r
-                                       break;\r
-\r
-                               case 0x3:       // get total length (MSF format)\r
-                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 3;\r
-                                       Get_Total_Lenght_CDD_c23();\r
-                                       break;\r
-\r
-                               case 0x4:       // first & last track number\r
-                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 4;\r
-                                       Get_First_Last_Track_CDD_c24();\r
-                                       break;\r
-\r
-                               case 0x5:       // get track addresse (MSF format)\r
-                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 5;\r
-                                       Get_Track_Adr_CDD_c25();\r
-                                       break;\r
-\r
-                               default :       // invalid, then we return status\r
-                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 0xF;\r
-                                       Get_Status_CDD_c0();\r
-                                       break;\r
-                       }\r
-                       break;\r
-\r
-               case 0x3:       // READ\r
-                       Play_CDD_c3();\r
-                       break;\r
-\r
-               case 0x4:       // SEEK\r
-                       Seek_CDD_c4();\r
-                       break;\r
-\r
-               case 0x6:       // PAUSE/STOP\r
-                       Pause_CDD_c6();\r
-                       break;\r
-\r
-               case 0x7:       // RESUME\r
-                       Resume_CDD_c7();\r
-                       break;\r
-\r
-               case 0x8:       // FAST FOWARD\r
-                       Fast_Foward_CDD_c8();\r
-                       break;\r
-\r
-               case 0x9:       // FAST REWIND\r
-                       Fast_Rewind_CDD_c9();\r
-                       break;\r
-\r
-               case 0xA:       // RECOVER INITIAL STATE (?)\r
-                       CDD_cA();\r
-                       break;\r
-\r
-               case 0xC:       // CLOSE TRAY\r
-                       Close_Tray_CDD_cC();\r
-                       break;\r
-\r
-               case 0xD:       // OPEN TRAY\r
-                       Open_Tray_CDD_cD();\r
-                       break;\r
-\r
-               default:        // UNKNOWN\r
-                       CDD_Def();\r
-                       break;\r
-       }\r
-}\r
-\r
index 2b0d382..d641ebb 100644 (file)
 extern "C" {\r
 #endif\r
 \r
-typedef struct\r
-{\r
-       unsigned char Buffer[(32 * 1024 * 2) + 2352];\r
-//     unsigned int Host_Data;         // unused\r
-//     unsigned int DMA_Adr;           // 0A\r
-//     unsigned int Stop_Watch;        // 0C\r
-       unsigned int COMIN;\r
-       unsigned int IFSTAT;\r
-       union\r
-       {\r
-               struct\r
-               {\r
-                       unsigned char L;\r
-                       unsigned char H;\r
-                       unsigned short unused;\r
-               } B;\r
-               int N;\r
-       } DBC;\r
-       union\r
-       {\r
-               struct\r
-               {\r
-                       unsigned char L;\r
-                       unsigned char H;\r
-                       unsigned short unused;\r
-               } B;\r
-               int N;\r
-       } DAC;\r
-       union\r
-       {\r
-               struct\r
-               {\r
-                       unsigned char B0;\r
-                       unsigned char B1;\r
-                       unsigned char B2;\r
-                       unsigned char B3;\r
-               } B;\r
-               unsigned int N;\r
-       } HEAD;\r
-       union\r
-       {\r
-               struct\r
-               {\r
-                       unsigned char L;\r
-                       unsigned char H;\r
-                       unsigned short unused;\r
-               } B;\r
-               int N;\r
-       } PT;\r
-       union\r
-       {\r
-               struct\r
-               {\r
-                       unsigned char L;\r
-                       unsigned char H;\r
-                       unsigned short unused;\r
-               } B;\r
-               int N;\r
-       } WA;\r
-       union\r
-       {\r
-               struct\r
-               {\r
-                       unsigned char B0;\r
-                       unsigned char B1;\r
-                       unsigned char B2;\r
-                       unsigned char B3;\r
-               } B;\r
-               unsigned int N;\r
-       } STAT;\r
-       unsigned int SBOUT;\r
-       unsigned int IFCTRL;\r
-       union\r
-       {\r
-               struct\r
-               {\r
-                       unsigned char B0;\r
-                       unsigned char B1;\r
-                       unsigned char B2;\r
-                       unsigned char B3;\r
-               } B;\r
-               unsigned int N;\r
-       } CTRL;\r
-       unsigned int Decode_Reg_Read;\r
-} CDC;\r
-\r
 typedef struct\r
 {\r
 //     unsigned short Fader;   // 34\r
@@ -116,17 +30,11 @@ typedef struct
 } CDD;\r
 \r
 \r
-PICO_INTERNAL_ASM unsigned short Read_CDC_Host(int is_sub);\r
-PICO_INTERNAL void LC89510_Reset(void);\r
-PICO_INTERNAL void Update_CDC_TRansfer(int which);\r
-PICO_INTERNAL void CDC_Update_Header(void);\r
-\r
-PICO_INTERNAL unsigned char CDC_Read_Reg(void);\r
-PICO_INTERNAL void CDC_Write_Reg(unsigned char Data);\r
-\r
 PICO_INTERNAL void CDD_Export_Status(void);\r
 PICO_INTERNAL void CDD_Import_Command(void);\r
 \r
+void CDD_Reset(void);\r
+\r
 #ifdef __cplusplus\r
 };\r
 #endif\r
index 0f19b71..43bbb5d 100644 (file)
@@ -282,6 +282,7 @@ PICO_INTERNAL void Unload_ISO(void)
        memset(Pico_mcd->TOC.Tracks, 0, sizeof(Pico_mcd->TOC.Tracks));
 }
 
+#if 1*0
 
 PICO_INTERNAL int FILE_Read_One_LBA_CDC(void)
 {
@@ -398,3 +399,4 @@ PICO_INTERNAL int FILE_Read_One_LBA_CDC(void)
        return 0;
 }
 
+#endif
index 1c19057..f7cd7b5 100644 (file)
 #define FAST_REV       0x10300         // FAST REVERSE track CDD status\r
 #define PLAYING                0x0100          // PLAYING audio track CDD status\r
 \r
+//#undef cdprintf\r
+//#define cdprintf(x, ...) elprintf(EL_STATUS, x, ##__VA_ARGS__)\r
+\r
+#define CDC_Update_Header()\r
 \r
 static int CD_Present = 0;\r
 \r
@@ -139,15 +143,32 @@ PICO_INTERNAL void Check_CD_Command(void)
                cdprintf("Got a read command");\r
 \r
                // DATA ?\r
-               if (Pico_mcd->scd.Cur_Track == 1)\r
+               if (Pico_mcd->scd.Cur_Track == 1) {\r
                     Pico_mcd->s68k_regs[0x36] |=  0x01;\r
-               else Pico_mcd->s68k_regs[0x36] &= ~0x01;                        // AUDIO\r
 \r
-               if (Pico_mcd->scd.File_Add_Delay == 0)\r
-               {\r
-                       FILE_Read_One_LBA_CDC();\r
+                 if (Pico_mcd->scd.File_Add_Delay == 0)\r
+                 {\r
+                       unsigned char header[4];\r
+                       _msf MSF;\r
+\r
+                       LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
+\r
+                       header[0] = INT_TO_BCDB(MSF.M);\r
+                       header[1] = INT_TO_BCDB(MSF.S);\r
+                       header[2] = INT_TO_BCDB(MSF.F);\r
+                       header[3] = 0x01;\r
+\r
+                       //FILE_Read_One_LBA_CDC();\r
+                       Pico_mcd->scd.Cur_LBA +=\r
+                         cdc_decoder_update(header);\r
+                 }\r
+                 else Pico_mcd->scd.File_Add_Delay--;\r
+               }\r
+               else {\r
+                       Pico_mcd->s68k_regs[0x36] &= ~0x01;                     // AUDIO\r
+                       unsigned char header[4] = { 0, };\r
+                       cdc_decoder_update(header);\r
                }\r
-               else Pico_mcd->scd.File_Add_Delay--;\r
        }\r
 \r
        // Check CDD\r
@@ -755,3 +776,158 @@ PICO_INTERNAL int CDD_Def(void)
 }\r
 \r
 \r
+static int bswapwrite(int a, unsigned short d)\r
+{\r
+       *(unsigned short *)(Pico_mcd->s68k_regs + a) = (d>>8)|(d<<8);\r
+       return d + (d >> 8);\r
+}\r
+\r
+PICO_INTERNAL void CDD_Export_Status(void)\r
+{\r
+       unsigned int csum;\r
+\r
+       csum  = bswapwrite( 0x38+0, Pico_mcd->cdd.Status);\r
+       csum += bswapwrite( 0x38+2, Pico_mcd->cdd.Minute);\r
+       csum += bswapwrite( 0x38+4, Pico_mcd->cdd.Seconde);\r
+       csum += bswapwrite( 0x38+6, Pico_mcd->cdd.Frame);\r
+       Pico_mcd->s68k_regs[0x38+8] = Pico_mcd->cdd.Ext;\r
+       csum += Pico_mcd->cdd.Ext;\r
+       Pico_mcd->s68k_regs[0x38+9] = ~csum & 0xf;\r
+\r
+       Pico_mcd->s68k_regs[0x37] &= 3; // CDD.Control\r
+\r
+       if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4)\r
+       {\r
+               elprintf(EL_INTS, "cdd export irq 4");\r
+               SekInterruptS68k(4);\r
+       }\r
+\r
+//     cdprintf("CDD exported status\n");\r
+       cdprintf("out:  Status=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X  Checksum=%.4X",\r
+               (Pico_mcd->s68k_regs[0x38+0] << 8) | Pico_mcd->s68k_regs[0x38+1],\r
+               (Pico_mcd->s68k_regs[0x38+2] << 8) | Pico_mcd->s68k_regs[0x38+3],\r
+               (Pico_mcd->s68k_regs[0x38+4] << 8) | Pico_mcd->s68k_regs[0x38+5],\r
+               (Pico_mcd->s68k_regs[0x38+6] << 8) | Pico_mcd->s68k_regs[0x38+7],\r
+               (Pico_mcd->s68k_regs[0x38+8] << 8) | Pico_mcd->s68k_regs[0x38+9]);\r
+}\r
+\r
+\r
+PICO_INTERNAL void CDD_Import_Command(void)\r
+{\r
+//     cdprintf("CDD importing command\n");\r
+       cdprintf("in:  Command=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X  Checksum=%.4X",\r
+               (Pico_mcd->s68k_regs[0x38+10+0] << 8) | Pico_mcd->s68k_regs[0x38+10+1],\r
+               (Pico_mcd->s68k_regs[0x38+10+2] << 8) | Pico_mcd->s68k_regs[0x38+10+3],\r
+               (Pico_mcd->s68k_regs[0x38+10+4] << 8) | Pico_mcd->s68k_regs[0x38+10+5],\r
+               (Pico_mcd->s68k_regs[0x38+10+6] << 8) | Pico_mcd->s68k_regs[0x38+10+7],\r
+               (Pico_mcd->s68k_regs[0x38+10+8] << 8) | Pico_mcd->s68k_regs[0x38+10+9]);\r
+\r
+       switch (Pico_mcd->s68k_regs[0x38+10+0])\r
+       {\r
+               case 0x0:       // STATUS (?)\r
+                       Get_Status_CDD_c0();\r
+                       break;\r
+\r
+               case 0x1:       // STOP ALL (?)\r
+                       Stop_CDD_c1();\r
+                       break;\r
+\r
+               case 0x2:       // GET TOC INFORMATIONS\r
+                       switch(Pico_mcd->s68k_regs[0x38+10+3])\r
+                       {\r
+                               case 0x0:       // get current position (MSF format)\r
+                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00);\r
+                                       Get_Pos_CDD_c20();\r
+                                       break;\r
+\r
+                               case 0x1:       // get elapsed time of current track played/scanned (relative MSF format)\r
+                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 1;\r
+                                       Get_Track_Pos_CDD_c21();\r
+                                       break;\r
+\r
+                               case 0x2:       // get current track in RS2-RS3\r
+                                       Pico_mcd->cdd.Status =  (Pico_mcd->cdd.Status & 0xFF00) | 2;\r
+                                       Get_Current_Track_CDD_c22();\r
+                                       break;\r
+\r
+                               case 0x3:       // get total length (MSF format)\r
+                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 3;\r
+                                       Get_Total_Lenght_CDD_c23();\r
+                                       break;\r
+\r
+                               case 0x4:       // first & last track number\r
+                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 4;\r
+                                       Get_First_Last_Track_CDD_c24();\r
+                                       break;\r
+\r
+                               case 0x5:       // get track addresse (MSF format)\r
+                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 5;\r
+                                       Get_Track_Adr_CDD_c25();\r
+                                       break;\r
+\r
+                               default :       // invalid, then we return status\r
+                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 0xF;\r
+                                       Get_Status_CDD_c0();\r
+                                       break;\r
+                       }\r
+                       break;\r
+\r
+               case 0x3:       // READ\r
+                       Play_CDD_c3();\r
+                       break;\r
+\r
+               case 0x4:       // SEEK\r
+                       Seek_CDD_c4();\r
+                       break;\r
+\r
+               case 0x6:       // PAUSE/STOP\r
+                       Pause_CDD_c6();\r
+                       break;\r
+\r
+               case 0x7:       // RESUME\r
+                       Resume_CDD_c7();\r
+                       break;\r
+\r
+               case 0x8:       // FAST FOWARD\r
+                       Fast_Foward_CDD_c8();\r
+                       break;\r
+\r
+               case 0x9:       // FAST REWIND\r
+                       Fast_Rewind_CDD_c9();\r
+                       break;\r
+\r
+               case 0xA:       // RECOVER INITIAL STATE (?)\r
+                       CDD_cA();\r
+                       break;\r
+\r
+               case 0xC:       // CLOSE TRAY\r
+                       Close_Tray_CDD_cC();\r
+                       break;\r
+\r
+               case 0xD:       // OPEN TRAY\r
+                       Open_Tray_CDD_cD();\r
+                       break;\r
+\r
+               default:        // UNKNOWN\r
+                       CDD_Def();\r
+                       break;\r
+       }\r
+}\r
+\r
+void CDD_Reset(void)\r
+{\r
+       // Reseting CDD\r
+\r
+       memset(Pico_mcd->s68k_regs+0x34, 0, 2*2); // CDD.Fader, CDD.Control\r
+       Pico_mcd->cdd.Status = 0;\r
+       Pico_mcd->cdd.Minute = 0;\r
+       Pico_mcd->cdd.Seconde = 0;\r
+       Pico_mcd->cdd.Frame = 0;\r
+       Pico_mcd->cdd.Ext = 0;\r
+\r
+       // clear receive status and transfer command\r
+       memset(Pico_mcd->s68k_regs+0x38, 0, 20);\r
+       Pico_mcd->s68k_regs[0x38+9] = 0xF;              // Default checksum\r
+}\r
+\r
+\r
diff --git a/pico/cd/cdc.c b/pico/cd/cdc.c
new file mode 100644 (file)
index 0000000..aa1ded9
--- /dev/null
@@ -0,0 +1,851 @@
+/***************************************************************************************
+ *  Genesis Plus
+ *  CD data controller (LC89510 compatible)
+ *
+ *  Copyright (C) 2012  Eke-Eke (Genesis Plus GX)
+ *
+ *  Redistribution and use of this code or any derivative works are permitted
+ *  provided that the following conditions are met:
+ *
+ *   - Redistributions may not be sold, nor may they be used in a commercial
+ *     product or activity.
+ *
+ *   - Redistributions that are modified from the original source must include the
+ *     complete source code, including the source code for all components used by a
+ *     binary built from the modified sources. However, as a special exception, the
+ *     source code distributed need not include anything that is normally distributed
+ *     (in either source or binary form) with the major components (compiler, kernel,
+ *     and so on) of the operating system on which the executable runs, unless that
+ *     component itself accompanies the executable.
+ *
+ *   - Redistributions must reproduce the above copyright notice, this list of
+ *     conditions and the following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************************/
+
+#include "../pico_int.h"
+#include "genplus_macros.h"
+
+/* IFSTAT register bitmasks */
+#define BIT_DTEI  0x40
+#define BIT_DECI  0x20
+#define BIT_DTBSY 0x08
+#define BIT_DTEN  0x02
+
+/* IFCTRL register bitmasks */
+#define BIT_DTEIEN  0x40
+#define BIT_DECIEN  0x20
+#define BIT_DOUTEN  0x02
+
+/* CTRL0 register bitmasks */
+#define BIT_DECEN   0x80
+#define BIT_E01RQ   0x20
+#define BIT_AUTORQ  0x10
+#define BIT_WRRQ    0x04
+
+/* CTRL1 register bitmasks */
+#define BIT_MODRQ   0x08
+#define BIT_FORMRQ  0x04
+#define BIT_SHDREN  0x01
+
+/* CTRL2 register bitmask */
+#define BIT_VALST   0x80
+
+/* PicoDrive: doing DMA at once, not using callbacks */
+//#define DMA_BYTES_PER_LINE 512
+
+enum dma_type {
+  word_ram_0_dma_w = 1,
+  word_ram_1_dma_w = 2,
+  word_ram_2M_dma_w = 3,
+  pcm_ram_dma_w = 4,
+  prg_ram_dma_w = 5,
+};
+
+/* CDC hardware */
+typedef struct
+{
+  uint8 ifstat;
+  uint8 ifctrl;
+  reg16_t dbc;
+  reg16_t dac;
+  reg16_t pt;
+  reg16_t wa;
+  uint8 ctrl[2];
+  uint8 head[2][4];
+  uint8 stat[4];
+  int cycles;
+  //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; 
+
+static cdc_t cdc;
+
+void cdc_init(void)
+{
+  memset(&cdc, 0, sizeof(cdc_t));
+}
+
+void cdc_reset(void)
+{
+  /* reset CDC register index */
+  Pico_mcd->regs[0x04>>1].byte.l = 0x00;
+
+  /* reset CDC registers */
+  cdc.ifstat  = 0xff;
+  cdc.ifctrl  = 0x00;
+  cdc.ctrl[0] = 0x00;
+  cdc.ctrl[1] = 0x00;
+  cdc.stat[0] = 0x00;
+  cdc.stat[1] = 0x00;
+  cdc.stat[2] = 0x00;
+  cdc.stat[3] = 0x80;
+  cdc.head[0][0] = 0x00;
+  cdc.head[0][1] = 0x00;
+  cdc.head[0][2] = 0x00;
+  cdc.head[0][3] = 0x01;
+  cdc.head[1][0] = 0x00;
+  cdc.head[1][1] = 0x00;
+  cdc.head[1][2] = 0x00;
+  cdc.head[1][3] = 0x00;
+
+  /* reset CDC cycle counter */
+  cdc.cycles = 0;
+
+  /* DMA transfer disabled */
+  cdc.dma_w = 0;
+}
+
+int cdc_context_save(uint8 *state)
+{
+  uint8 tmp8;
+  int bufferptr = 0;
+
+  if (cdc.dma_w == pcm_ram_dma_w)
+  {
+    tmp8 = 1;
+  }
+  else if (cdc.dma_w == prg_ram_dma_w)
+  {
+    tmp8 = 2;
+  }
+  else if (cdc.dma_w == word_ram_0_dma_w)
+  {
+    tmp8 = 3;
+  }
+  else if (cdc.dma_w == word_ram_1_dma_w)
+  {
+    tmp8 = 4;
+  }
+  else if (cdc.dma_w == word_ram_2M_dma_w)
+  {
+    tmp8 = 5;
+  }
+  else
+  {
+    tmp8 = 0;
+  }
+
+  save_param(&cdc, sizeof(cdc));
+  save_param(&tmp8, 1);
+
+  return bufferptr;
+}
+
+int cdc_context_load(uint8 *state)
+{
+  uint8 tmp8;
+  int bufferptr = 0;
+
+  load_param(&cdc, sizeof(cdc));
+  load_param(&tmp8, 1);
+
+  switch (tmp8)
+  {
+    case 1:
+      cdc.dma_w = pcm_ram_dma_w;
+      break;
+    case 2:
+      cdc.dma_w = prg_ram_dma_w;
+      break;
+    case 3:
+      cdc.dma_w = word_ram_0_dma_w;
+      break;
+    case 4:
+      cdc.dma_w = word_ram_1_dma_w;
+      break;
+    case 5:
+      cdc.dma_w = word_ram_2M_dma_w;
+      break;
+    default:
+      cdc.dma_w = 0;
+      break;
+  }
+
+  return bufferptr;
+}
+
+int cdc_context_load_old(uint8 *state)
+{
+#define old_load(v, ofs) \
+  memcpy(&cdc.v, state + ofs, sizeof(cdc.v))
+
+  memcpy(cdc.ram, state, 0x4000);
+  old_load(ifstat, 67892);
+  old_load(ifctrl, 67924);
+  old_load(dbc, 67896);
+  old_load(dac, 67900);
+  old_load(pt, 67908);
+  old_load(wa, 67912);
+  old_load(ctrl, 67928);
+  old_load(head[0], 67904);
+  old_load(stat, 67916);
+
+  cdc.dma_w = 0;
+  switch (Pico_mcd->regs[0x04>>1].byte.h & 0x07)
+  {
+    case 4: /* PCM RAM DMA */
+      cdc.dma_w = pcm_ram_dma_w;
+      break;
+    case 5: /* PRG-RAM DMA */
+      cdc.dma_w = prg_ram_dma_w;
+      break;
+    case 7: /* WORD-RAM DMA */
+      if (Pico_mcd->regs[0x02 >> 1].byte.l & 0x04)
+      {
+        if (Pico_mcd->regs[0x02 >> 1].byte.l & 0x01)
+          cdc.dma_w = word_ram_0_dma_w;
+        else
+          cdc.dma_w = word_ram_1_dma_w;
+      }
+      else
+      {
+        if (Pico_mcd->regs[0x02 >> 1].byte.l & 0x02)
+          cdc.dma_w = word_ram_2M_dma_w;
+      }
+      break;
+  }
+
+  return 0x10960; // sizeof(old_cdc)
+#undef old_load
+}
+
+static void do_dma(enum dma_type type, int words_in)
+{
+       int dma_addr = (Pico_mcd->s68k_regs[0x0a] << 8) | Pico_mcd->s68k_regs[0x0b];
+  int src_addr = cdc.dac.w & 0x3ffe;
+  int dst_addr = dma_addr;
+  int words = words_in;
+  int dst_limit = 0;
+  uint8 *dst;
+  int len;
+
+  elprintf(EL_CD, "dma %d %04x->%04x %x",
+    type, cdc.dac.w, dst_addr, words_in);
+
+  switch (type)
+  {
+    case pcm_ram_dma_w:
+      dst_addr = (dst_addr << 2) & 0xffc;
+      if (dst_addr + words * 2 > 0x1000) {
+        elprintf(EL_ANOMALY, "pcm dma oflow: %x %x", dst_addr, words);
+        words = (0x1000 - dst_addr) / 2;
+      }
+      dst = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank];
+      dst = dst + dst_addr;
+      while (words > 0)
+      {
+        if (src_addr + words * 2 > 0x4000) {
+          len = 0x4000 - src_addr;
+          memcpy(dst, cdc.ram + src_addr, len);
+          dst += len;
+          src_addr = 0;
+          words -= len / 2;
+          continue;
+        }
+        memcpy(dst, cdc.ram + src_addr, words * 2);
+        break;
+      }
+      goto update_dma;
+
+    case prg_ram_dma_w:
+      dst_addr <<= 3;
+                 dst = Pico_mcd->prg_ram + dst_addr;
+      dst_limit = 0x80000;
+      break;
+
+    case word_ram_0_dma_w:
+      dst_addr = (dst_addr << 3) & 0x1fffe;
+                       dst = Pico_mcd->word_ram1M[0] + dst_addr;
+      dst_limit = 0x20000;
+      break;
+
+    case word_ram_1_dma_w:
+      dst_addr = (dst_addr << 3) & 0x1fffe;
+                       dst = Pico_mcd->word_ram1M[1] + dst_addr;
+      dst_limit = 0x20000;
+      break;
+
+    case word_ram_2M_dma_w:
+      dst_addr = (dst_addr << 3) & 0x3fffe;
+                       dst = Pico_mcd->word_ram2M + dst_addr;
+      dst_limit = 0x40000;
+      break;
+
+    default:
+      elprintf(EL_ANOMALY, "invalid dma: %d", type);
+      goto update_dma;
+  }
+
+  if (dst_addr + words * 2 > dst_limit) {
+    elprintf(EL_ANOMALY, "cd dma %d oflow: %x %x", type, dst_addr, words);
+    words = (dst_limit - dst_addr) / 2;
+  }
+  while (words > 0)
+  {
+    if (src_addr + words * 2 > 0x4000) {
+      len = 0x4000 - src_addr;
+      memcpy16bswap((void *)dst, cdc.ram + src_addr, len / 2);
+      dst += len;
+      src_addr = 0;
+      words -= len / 2;
+      continue;
+    }
+    memcpy16bswap((void *)dst, cdc.ram + src_addr, words);
+    break;
+  }
+
+update_dma:
+  /* update DMA addresses */
+  cdc.dac.w += words_in * 2;
+  if (type == pcm_ram_dma_w)
+    dma_addr += words_in >> 1;
+  else
+    dma_addr += words_in >> 2;
+
+  Pico_mcd->s68k_regs[0x0a] = dma_addr >> 8;
+  Pico_mcd->s68k_regs[0x0b] = dma_addr;
+}
+
+// tmp
+static void cdd_read_data(uint8 *dst)
+{
+  int lba = Pico_mcd->scd.Cur_LBA;
+
+  /* only read DATA track sectors */
+  if (0 <= lba && lba < Pico_mcd->TOC.Tracks[0].Length)
+  {
+    /* read sector data (Mode 1 = 2048 bytes) */
+    PicoCDBufferRead(dst, lba);
+  }
+}
+
+void cdc_dma_update(void)
+{
+  /* end of DMA transfer ? */
+  //if (cdc.dbc.w < DMA_BYTES_PER_LINE)
+  {
+    /* transfer remaining words using 16-bit DMA */
+    //cdc.dma_w((cdc.dbc.w + 1) >> 1);
+    do_dma(cdc.dma_w, (cdc.dbc.w + 1) >> 1);
+
+    /* reset data byte counter (DBCH bits 4-7 should be set to 1) */
+    cdc.dbc.w = 0xf000;
+
+    /* clear !DTEN and !DTBSY */
+    cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
+
+    /* pending Data Transfer End interrupt */
+    cdc.ifstat &= ~BIT_DTEI;
+
+    /* Data Transfer End interrupt enabled ? */
+    if (cdc.ifctrl & BIT_DTEIEN)
+    {
+      /* level 5 interrupt enabled ? */
+      if (Pico_mcd->regs[0x32>>1].byte.l & PCDS_IEN5)
+      {
+        /* update IRQ level */
+        elprintf(EL_INTS, "cdc DTE irq 5");
+        SekInterruptS68k(5);
+      }
+    }
+
+    /* clear DSR bit & set EDT bit (SCD register $04) */
+    Pico_mcd->regs[0x04>>1].byte.h = (Pico_mcd->regs[0x04>>1].byte.h & 0x07) | 0x80;
+
+    /* disable DMA transfer */
+    cdc.dma_w = 0;
+  }
+#if 0
+  else
+  {
+    /* transfer all words using 16-bit DMA */
+    cdc.dma_w(DMA_BYTES_PER_LINE >> 1);
+
+    /* decrement data byte counter */
+    cdc.dbc.w -= length;
+  }
+#endif
+}
+
+int cdc_decoder_update(uint8 header[4])
+{
+  /* data decoding enabled ? */
+  if (cdc.ctrl[0] & BIT_DECEN)
+  {
+    /* update HEAD registers */
+    memcpy(cdc.head[0], header, sizeof(cdc.head[0]));
+
+    /* set !VALST */
+    cdc.stat[3] = 0x00;
+
+    /* pending decoder interrupt */
+    cdc.ifstat &= ~BIT_DECI;
+
+    /* decoder interrupt enabled ? */
+    if (cdc.ifctrl & BIT_DECIEN)
+    {
+      /* level 5 interrupt enabled ? */
+      if (Pico_mcd->regs[0x32>>1].byte.l & PCDS_IEN5)
+      {
+        /* update IRQ level */
+        elprintf(EL_INTS, "cdc DEC irq 5");
+        SekInterruptS68k(5);
+      }
+    }
+
+    /* buffer RAM write enabled ? */
+    if (cdc.ctrl[0] & BIT_WRRQ)
+    {
+      uint16 offset;
+
+      /* increment block pointer  */
+      cdc.pt.w += 2352;
+
+      /* increment write address */
+      cdc.wa.w += 2352;
+
+      /* CDC buffer address */
+      offset = cdc.pt.w & 0x3fff;
+
+      /* write CDD block header (4 bytes) */
+      memcpy(cdc.ram + offset, header, 4);
+
+      /* write CDD block data (2048 bytes) */
+      cdd_read_data(cdc.ram + 4 + offset);
+
+      /* take care of buffer overrun */
+      if (offset > (0x4000 - 2048 - 4))
+      {
+        /* data should be written at the start of buffer */
+        memcpy(cdc.ram, cdc.ram + 0x4000, offset + 2048 + 4 - 0x4000);
+      }
+
+      /* read next data block */
+      return 1;
+    }
+  }
+  
+  /* keep decoding same data block if Buffer Write is disabled */
+  return 0;
+}
+
+void cdc_reg_w(unsigned char data)
+{
+#ifdef LOG_CDC
+  elprintf(EL_STATUS, "CDC register %X write 0x%04x", Pico_mcd->regs[0x04>>1].byte.l & 0x0F, data);
+#endif
+  switch (Pico_mcd->regs[0x04>>1].byte.l & 0x0F)
+  {
+    case 0x01:  /* IFCTRL */
+    {
+      /* pending interrupts ? */
+      if (((data & BIT_DTEIEN) && !(cdc.ifstat & BIT_DTEI)) ||
+          ((data & BIT_DECIEN) && !(cdc.ifstat & BIT_DECI)))
+      {
+        /* level 5 interrupt enabled ? */
+        if (Pico_mcd->regs[0x32>>1].byte.l & PCDS_IEN5)
+        {
+          /* update IRQ level */
+          elprintf(EL_INTS, "cdc pending irq 5");
+          SekInterruptS68k(5);
+        }
+      }
+      else // if (scd.pending & (1 << 5))
+      {
+        /* clear pending level 5 interrupts */
+        SekInterruptClearS68k(5);
+      }
+
+      /* abort any data transfer if data output is disabled */
+      if (!(data & BIT_DOUTEN))
+      {
+        /* clear !DTBSY and !DTEN */
+        cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
+      }
+
+      cdc.ifctrl = data;
+      Pico_mcd->regs[0x04>>1].byte.l = 0x02;
+      break;
+    }
+
+    case 0x02:  /* DBCL */
+      cdc.dbc.byte.l = data;
+      Pico_mcd->regs[0x04>>1].byte.l = 0x03;
+      break;
+
+    case 0x03:  /* DBCH */
+      cdc.dbc.byte.h = data;
+      Pico_mcd->regs[0x04>>1].byte.l = 0x04;
+      break;
+
+    case 0x04:  /* DACL */
+      cdc.dac.byte.l = data;
+      Pico_mcd->regs[0x04>>1].byte.l = 0x05;
+      break;
+
+    case 0x05:  /* DACH */
+      cdc.dac.byte.h = data;
+      Pico_mcd->regs[0x04>>1].byte.l = 0x06;
+      break;
+
+    case 0x06:  /* DTRG */
+    {
+      /* start data transfer if data output is enabled */
+      if (cdc.ifctrl & BIT_DOUTEN)
+      {
+        /* set !DTBSY */
+        cdc.ifstat &= ~BIT_DTBSY;
+
+        /* clear DBCH bits 4-7 */
+        cdc.dbc.byte.h &= 0x0f;
+
+        /* clear EDT & DSR bits (SCD register $04) */
+        Pico_mcd->regs[0x04>>1].byte.h &= 0x07;
+
+        cdc.dma_w = 0;
+
+        /* setup data transfer destination */
+        switch (Pico_mcd->regs[0x04>>1].byte.h & 0x07)
+        {
+          case 2: /* MAIN-CPU host read */
+          case 3: /* SUB-CPU host read */
+          {
+            /* set !DTEN */
+            cdc.ifstat &= ~BIT_DTEN;
+
+            /* set DSR bit (register $04) */
+            Pico_mcd->regs[0x04>>1].byte.h |= 0x40;
+            break;
+          }
+
+          case 4: /* PCM RAM DMA */
+          {
+            cdc.dma_w = pcm_ram_dma_w;
+            break;
+          }
+
+          case 5: /* PRG-RAM DMA */
+          {
+            cdc.dma_w = prg_ram_dma_w;
+            break;
+          }
+
+          case 7: /* WORD-RAM DMA */
+          {
+            /* check memory mode */
+            if (Pico_mcd->regs[0x02 >> 1].byte.l & 0x04)
+            {
+              /* 1M mode */
+              if (Pico_mcd->regs[0x02 >> 1].byte.l & 0x01)
+              {
+                /* Word-RAM bank 0 is assigned to SUB-CPU */
+                cdc.dma_w = word_ram_0_dma_w;
+              }
+              else
+              {
+                /* Word-RAM bank 1 is assigned to SUB-CPU */
+                cdc.dma_w = word_ram_1_dma_w;
+              }
+            }
+            else
+            {
+              /* 2M mode */
+              if (Pico_mcd->regs[0x02 >> 1].byte.l & 0x02)
+              {
+                /* only process DMA if Word-RAM is assigned to SUB-CPU */
+                cdc.dma_w = word_ram_2M_dma_w;
+              }
+            }
+            break;
+          }
+
+          default: /* invalid */
+          {
+            elprintf(EL_ANOMALY, "invalid CDC tranfer destination (%d)",
+              Pico_mcd->regs[0x04>>1].byte.h & 0x07);
+            break;
+          }
+        }
+
+        if (cdc.dma_w)
+          pcd_event_schedule_s68k(PCD_EVENT_DMA, cdc.dbc.w / 2);
+      }
+
+      Pico_mcd->regs[0x04>>1].byte.l = 0x07;
+      break;
+    }
+
+    case 0x07:  /* DTACK */
+    {
+      /* clear pending data transfer end interrupt */
+      cdc.ifstat |= BIT_DTEI;
+
+      /* clear DBCH bits 4-7 */
+      cdc.dbc.byte.h &= 0x0f;
+
+#if 0
+      /* no pending decoder interrupt ? */
+      if ((cdc.ifstat | BIT_DECI) || !(cdc.ifctrl & BIT_DECIEN))
+      {
+        /* clear pending level 5 interrupt */
+        SekInterruptClearS68k(5);
+      }
+#endif
+      Pico_mcd->regs[0x04>>1].byte.l = 0x08;
+      break;
+    }
+
+    case 0x08:  /* WAL */
+      cdc.wa.byte.l = data;
+      Pico_mcd->regs[0x04>>1].byte.l = 0x09;
+      break;
+
+    case 0x09:  /* WAH */
+      cdc.wa.byte.h = data;
+      Pico_mcd->regs[0x04>>1].byte.l = 0x0a;
+      break;
+
+    case 0x0a:  /* CTRL0 */
+    {
+      /* set CRCOK bit only if decoding is enabled */
+      cdc.stat[0] = data & BIT_DECEN;
+
+      /* 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 
+      {
+        /* set MODE & FORM bits according to CTRL1 register */
+        cdc.stat[2] = cdc.ctrl[1] & (BIT_MODRQ | BIT_FORMRQ);
+      }
+
+      cdc.ctrl[0] = data;
+      Pico_mcd->regs[0x04>>1].byte.l = 0x0b;
+      break;
+    }
+
+    case 0x0b:  /* CTRL1 */
+    {
+      /* update decoding mode */
+      if (cdc.ctrl[0] & BIT_AUTORQ)
+      {
+        /* set MODE bit according to CTRL1 register & clear FORM bit */
+        cdc.stat[2] = data & BIT_MODRQ;
+      }
+      else 
+      {
+        /* set MODE & FORM bits according to CTRL1 register */
+        cdc.stat[2] = data & (BIT_MODRQ | BIT_FORMRQ);
+      }
+
+      cdc.ctrl[1] = data;
+      Pico_mcd->regs[0x04>>1].byte.l = 0x0c;
+      break;
+    }
+
+    case 0x0c:  /* PTL */
+      cdc.pt.byte.l = data;
+      Pico_mcd->regs[0x04>>1].byte.l = 0x0d;
+      break;
+  
+    case 0x0d:  /* PTH */
+      cdc.pt.byte.h = data;
+      Pico_mcd->regs[0x04>>1].byte.l = 0x0e;
+      break;
+
+    case 0x0e:  /* CTRL2 (unused) */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x0f;
+      break;
+
+    case 0x0f:  /* RESET */
+      cdc_reset();
+      break;
+
+    default:  /* by default, SBOUT is not used */
+      break;
+  }
+}
+
+unsigned char cdc_reg_r(void)
+{
+  switch (Pico_mcd->regs[0x04>>1].byte.l & 0x0F)
+  {
+    case 0x01:  /* IFSTAT */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x02;
+      return cdc.ifstat;
+
+    case 0x02:  /* DBCL */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x03;
+      return cdc.dbc.byte.l;
+
+    case 0x03:  /* DBCH */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x04;
+      return cdc.dbc.byte.h;
+
+    case 0x04:  /* HEAD0 */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x05;
+      return cdc.head[cdc.ctrl[1] & BIT_SHDREN][0];
+
+    case 0x05:  /* HEAD1 */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x06;
+      return cdc.head[cdc.ctrl[1] & BIT_SHDREN][1];
+
+    case 0x06:  /* HEAD2 */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x07;
+      return cdc.head[cdc.ctrl[1] & BIT_SHDREN][2];
+
+    case 0x07:  /* HEAD3 */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x08;
+      return cdc.head[cdc.ctrl[1] & BIT_SHDREN][3];
+
+    case 0x08:  /* PTL */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x09;
+      return cdc.pt.byte.l;
+
+    case 0x09:  /* PTH */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x0a;
+      return cdc.pt.byte.h;
+
+    case 0x0a:  /* WAL */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x0b;
+      return cdc.wa.byte.l;
+
+    case 0x0b:  /* WAH */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x0c;
+      return cdc.wa.byte.h;
+
+    case 0x0c: /* STAT0 */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x0d;
+      return cdc.stat[0];
+
+    case 0x0d: /* STAT1 (always return 0) */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x0e;
+      return 0x00;
+
+    case 0x0e:  /* STAT2 */
+      Pico_mcd->regs[0x04>>1].byte.l = 0x0f;
+      return cdc.stat[2];
+
+    case 0x0f:  /* STAT3 */
+    {
+      uint8 data = cdc.stat[3];
+
+      /* clear !VALST (note: this is not 100% correct but BIOS do not seem to care) */
+      cdc.stat[3] = BIT_VALST;
+
+      /* 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))
+      {
+        /* clear pending level 5 interrupt */
+        SekInterruptClearS68k(5);
+      }
+#endif
+
+      Pico_mcd->regs[0x04>>1].byte.l = 0x00;
+      return data;
+    }
+
+    default:  /* by default, COMIN is always empty */
+      return 0xff;
+  }
+}
+
+unsigned short cdc_host_r(void)
+{
+  /* check if data is available */
+  if (!(cdc.ifstat & BIT_DTEN))
+  {
+    /* read data word from CDC RAM buffer */
+    uint8 *datap = cdc.ram + (cdc.dac.w & 0x3ffe);
+    uint16 data = (datap[0] << 8) | datap[1];
+
+#ifdef LOG_CDC
+    error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac.w, data, cdc.dbc.w, s68k.pc);
+#endif
+    /* increment data address counter */
+    cdc.dac.w += 2;
+
+    /* decrement data byte counter */
+    cdc.dbc.w -= 2;
+
+    /* end of transfer ? */
+    if ((int16)cdc.dbc.w <= 0)
+    {
+      /* reset data byte counter (DBCH bits 4-7 should be set to 1) */
+      cdc.dbc.w = 0xf000;
+
+      /* clear !DTEN and !DTBSY */
+      cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
+
+      /* pending Data Transfer End interrupt */
+      cdc.ifstat &= ~BIT_DTEI;
+
+      /* Data Transfer End interrupt enabled ? */
+      if (cdc.ifctrl & BIT_DTEIEN)
+      {
+        /* level 5 interrupt enabled ? */
+        if (Pico_mcd->regs[0x32>>1].byte.l & PCDS_IEN5)
+        {
+          /* update IRQ level */
+          elprintf(EL_INTS, "cdc DTE irq 5");
+          SekInterruptS68k(5);
+        }
+      }
+
+      /* clear DSR bit & set EDT bit (SCD register $04) */
+      Pico_mcd->regs[0x04>>1].byte.h = (Pico_mcd->regs[0x04>>1].byte.h & 0x07) | 0x80;
+    }
+
+    return data;
+  }
+
+#ifdef LOG_CDC
+  error("error reading CDC host (data transfer disabled)\n");
+#endif
+  return 0xffff;
+}
+
+// vim:shiftwidth=2:ts=2:expandtab
index 8ac5d35..04c381a 100644 (file)
 #define int16 signed short\r
 #define int32 signed int\r
 \r
+typedef union\r
+{\r
+    uint16 w;\r
+    struct\r
+    {\r
+#if 1\r
+        uint8 l;\r
+        uint8 h;\r
+#else\r
+        uint8 h;\r
+        uint8 l;\r
+#endif\r
+    } byte;\r
+\r
+} reg16_t;\r
+\r
 #define READ_BYTE(BASE, ADDR) (BASE)[(ADDR)^1]\r
 #define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[(ADDR)^1] = (VAL)\r
 \r
index 24e99e4..3355361 100644 (file)
@@ -46,6 +46,7 @@ PICO_INTERNAL void PicoPowerMCD(void)
   memset(&Pico_mcd->pcm, 0, sizeof(Pico_mcd->pcm));
   memset(&Pico_mcd->m, 0, sizeof(Pico_mcd->m));
 
+  cdc_init();
   Reset_CD();
 
   // cold reset state (tested)
@@ -59,7 +60,9 @@ void pcd_soft_reset(void)
 {
   // Reset_CD(); // breaks Fahrenheit CD swap
 
-  LC89510_Reset();
+  Pico_mcd->m.s68k_pend_ints = 0;
+  cdc_reset();
+  CDD_Reset();
 #ifdef _ASM_CD_MEMORY_C
   //PicoMemResetCDdecode(1); // don't have to call this in 2M mode
 #endif
@@ -150,8 +153,7 @@ static void pcd_int3_timer_event(unsigned int now)
 
 static void pcd_dma_event(unsigned int now)
 {
-  int ddx = Pico_mcd->s68k_regs[4] & 7;
-       Update_CDC_TRansfer(ddx);
+  cdc_dma_update();
 }
 
 typedef void (event_cb)(unsigned int now);
@@ -355,9 +357,6 @@ void pcd_state_loaded(void)
     if (Pico_mcd->s68k_regs[0x31])
       pcd_event_schedule(SekCycleAimS68k, PCD_EVENT_TIMER3,
         Pico_mcd->s68k_regs[0x31] * 384);
-
-    if (Pico_mcd->scd.Status_CDC & 0x08)
-           Update_CDC_TRansfer(Pico_mcd->s68k_regs[4] & 7);
   }
 
   diff = cycles - Pico_mcd->pcm.update_cycles;
index b0f5e4a..d3a2927 100644 (file)
@@ -100,7 +100,7 @@ static u32 m68k_reg_read16(u32 a)
       d = *(u16 *)(Pico_mcd->bios + 0x72);\r
       goto end;\r
     case 8:\r
-      d = Read_CDC_Host(0);\r
+      d = cdc_host_r();\r
       goto end;\r
     case 0xA:\r
       elprintf(EL_UIO, "m68k FIXME: reserved read");\r
@@ -286,9 +286,9 @@ u32 s68k_reg_read16(u32 a)
       elprintf(EL_CDREG3, "s68k_regs r3: %02x @%06x", (u8)d, SekPcS68k);\r
       return s68k_poll_detect(a, d);\r
     case 6:\r
-      return CDC_Read_Reg();\r
+      return cdc_reg_r();\r
     case 8:\r
-      return Read_CDC_Host(1); // Gens returns 0 here on byte reads\r
+      return cdc_host_r();\r
     case 0xC:\r
       d = SekCyclesDoneS68k() - Pico_mcd->m.stopwatch_base_c;\r
       d /= 384;\r
@@ -379,7 +379,7 @@ void s68k_reg_write8(u32 a, u32 d)
       //dprintf("s68k CDC reg addr: %x", d&0xf);\r
       break;\r
     case 7:\r
-      CDC_Write_Reg(d);\r
+      cdc_reg_w(d);\r
       return;\r
     case 0xa:\r
       elprintf(EL_CDREGS, "s68k set CDC dma addr");\r
index e19c561..f3a1372 100644 (file)
@@ -49,7 +49,7 @@
 
 @ externs, just for reference
 .extern Pico
-.extern Read_CDC_Host
+.extern cdc_host_r
 .extern m68k_reg_write8
 .extern s68k_reg_read16
 .extern s68k_reg_write8
@@ -195,12 +195,12 @@ m_m68k_read8_r07:
     bx      lr
 m_m68k_read8_r08:
     mov     r0, #0
-    bl      Read_CDC_Host             @ TODO: make it local
+    bl      cdc_host_r
     mov     r0, r0, lsr #8
     bx      lr
 m_m68k_read8_r09:
     mov     r0, #0
-    b       Read_CDC_Host
+    b       cdc_host_r
 m_m68k_read8_r0c:
     add     r1, r1, #0x110000
     add     r1, r1, #0x002200
@@ -292,7 +292,7 @@ m_m68k_read16_r06:
     bx      lr
 m_m68k_read16_r08:
     mov     r0, #0
-    b       Read_CDC_Host
+    b       cdc_host_r
 m_m68k_read16_r0c:
     add     r1, r1, #0x110000
     add     r1, r1, #0x002200
@@ -501,7 +501,7 @@ m_s68k_read16_regs:
     cmp     r0, #8
     bne     s68k_reg_read16
     mov     r0, #1
-    b       Read_CDC_Host
+    b       cdc_host_r
 
 
 @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
index 8d83862..d491490 100644 (file)
@@ -189,3 +189,17 @@ PICO_INTERNAL int SekInterruptS68k(int irq)
   return 0;
 }
 
+void SekInterruptClearS68k(int irq)
+{
+  int level_new = new_irq_level(irq);
+
+#ifdef EMU_C68K
+  PicoCpuCS68k.irq = level_new;
+#endif
+#ifdef EMU_M68K
+  CPU_INT_LEVEL = level_new << 8;
+#endif
+#ifdef EMU_F68K
+  PicoCpuFS68k.interrupts[0] = level_new;
+#endif
+}
index a8bf7ee..d4d6d7d 100644 (file)
@@ -417,38 +417,44 @@ struct mcd_misc
 \r
 typedef struct\r
 {\r
-       unsigned char bios[0x20000];                    // 000000: 128K\r
-       union {                                         // 020000: 512K\r
-               unsigned char prg_ram[0x80000];\r
-               unsigned char prg_ram_b[4][0x20000];\r
-       };\r
-       union {                                         // 0a0000: 256K\r
-               struct {\r
-                       unsigned char word_ram2M[0x40000];\r
-                       unsigned char unused0[0x20000];\r
-               };\r
-               struct {\r
-                       unsigned char unused1[0x20000];\r
-                       unsigned char word_ram1M[2][0x20000];\r
-               };\r
-       };\r
-       union {                                         // 100000: 64K\r
-               unsigned char pcm_ram[0x10000];\r
-               unsigned char pcm_ram_b[0x10][0x1000];\r
-       };\r
-       // FIXME: should be short\r
-       unsigned char s68k_regs[0x200];                 // 110000: GA, not CPU regs\r
-       unsigned char bram[0x2000];                     // 110200: 8K\r
-       struct mcd_misc m;                              // 112200: misc\r
-       struct mcd_pcm pcm;                             // 112240:\r
-       _scd_toc TOC;                                   // not to be saved\r
-       CDD  cdd;\r
-       CDC  cdc;\r
-       _scd scd;\r
-       int pcm_mixbuf[PCM_MIXBUF_LEN * 2];\r
-       int pcm_mixpos;\r
-       char pcm_mixbuf_dirty;\r
-       char pcm_regs_dirty;\r
+  unsigned char bios[0x20000];                 // 000000: 128K\r
+  union {                                      // 020000: 512K\r
+    unsigned char prg_ram[0x80000];\r
+    unsigned char prg_ram_b[4][0x20000];\r
+  };\r
+  union {                                      // 0a0000: 256K\r
+    struct {\r
+      unsigned char word_ram2M[0x40000];\r
+      unsigned char unused0[0x20000];\r
+    };\r
+    struct {\r
+      unsigned char unused1[0x20000];\r
+      unsigned char word_ram1M[2][0x20000];\r
+    };\r
+  };\r
+  union {                                      // 100000: 64K\r
+    unsigned char pcm_ram[0x10000];\r
+    unsigned char pcm_ram_b[0x10][0x1000];\r
+  };\r
+  union {\r
+    unsigned char s68k_regs[0x200];            // 110000: GA, not CPU regs\r
+    union {\r
+      struct {\r
+        unsigned char h;\r
+        unsigned char l;\r
+      } byte;\r
+    } regs[0x200/2];\r
+  };\r
+  unsigned char bram[0x2000];                  // 110200: 8K\r
+  struct mcd_misc m;                           // 112200: misc\r
+  struct mcd_pcm pcm;                          // 112240:\r
+  _scd_toc TOC;                                        // not to be saved\r
+  CDD  cdd;\r
+  _scd scd;\r
+  int pcm_mixbuf[PCM_MIXBUF_LEN * 2];\r
+  int pcm_mixpos;\r
+  char pcm_mixbuf_dirty;\r
+  char pcm_regs_dirty;\r
 } mcd_state;\r
 \r
 // XXX: this will need to be reworked for cart+cd support.\r
@@ -610,6 +616,18 @@ void PicoWrite16_io(unsigned int a, unsigned int d);
 // pico/memory.c\r
 PICO_INTERNAL void PicoMemSetupPico(void);\r
 \r
+// cd/cdc.c\r
+void cdc_init(void);\r
+void cdc_reset(void);\r
+int  cdc_context_save(unsigned char *state);\r
+int  cdc_context_load(unsigned char *state);\r
+int  cdc_context_load_old(unsigned char *state);\r
+void cdc_dma_update(void);\r
+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
+\r
 // cd/gfx.c\r
 void gfx_init(void);\r
 void gfx_start(unsigned int base);\r
@@ -706,6 +724,7 @@ void SekTrace(int is_s68k);
 PICO_INTERNAL void SekInitS68k(void);\r
 PICO_INTERNAL int  SekResetS68k(void);\r
 PICO_INTERNAL int  SekInterruptS68k(int irq);\r
+void SekInterruptClearS68k(int irq);\r
 \r
 // sound/sound.c\r
 PICO_INTERNAL void cdda_start_play();\r
index a1ceac2..94cefad 100644 (file)
@@ -148,10 +148,10 @@ typedef enum {
   CHUNK_BRAM,\r
   CHUNK_GA_REGS,\r
   CHUNK_PCM,\r
-  CHUNK_CDC,\r
+  CHUNK_CDC,     // old\r
   CHUNK_CDD,     // 20\r
   CHUNK_SCD,\r
-  CHUNK_RC,\r
+  CHUNK_RC,      // old\r
   CHUNK_MISC_CD,\r
   //\r
   CHUNK_IOPORTS, // versions < 1.70 did not save that..\r
@@ -176,6 +176,7 @@ typedef enum {
   // add new stuff here\r
   CHUNK_CD_EVT = 50,\r
   CHUNK_CD_GFX,\r
+  CHUNK_CD_CDC,\r
   //\r
   CHUNK_DEFAULT_COUNT,\r
   CHUNK_CARTHW_ = CHUNK_CARTHW,  // 64 (defined in PicoInt)\r
@@ -237,12 +238,17 @@ static int write_chunk(chunk_name_e name, int len, void *data, void *file)
   return (bwritten == len + 4 + 1);\r
 }\r
 \r
+#define CHUNK_LIMIT_W 18772 // sizeof(cdc)\r
+\r
 #define CHECKED_WRITE(name,len,data) { \\r
   if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT && chunk_names[name]) { \\r
     strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \\r
     PicoStateProgressCB(sbuff); \\r
   } \\r
-  if (!write_chunk(name, len, data, file)) return 1; \\r
+  if (data == buf2 && len > CHUNK_LIMIT_W) \\r
+    goto out; \\r
+  if (!write_chunk(name, len, data, file)) \\r
+    goto out; \\r
 }\r
 \r
 #define CHECKED_WRITE_BUFF(name,buff) { \\r
@@ -250,7 +256,8 @@ static int write_chunk(chunk_name_e name, int len, void *data, void *file)
     strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \\r
     PicoStateProgressCB(sbuff); \\r
   } \\r
-  if (!write_chunk(name, sizeof(buff), &buff, file)) return 1; \\r
+  if (!write_chunk(name, sizeof(buff), &buff, file)) \\r
+    goto out; \\r
 }\r
 \r
 static int state_save(void *file)\r
@@ -258,7 +265,9 @@ static int state_save(void *file)
   char sbuff[32] = "Saving.. ";\r
   unsigned char buff[0x60], buff_z80[Z80_STATE_SIZE];\r
   void *ym2612_regs = YM2612GetRegs();\r
-  int ver = 0x0170; // not really used..\r
+  void *buf2 = NULL;\r
+  int ver = 0x0191; // not really used..\r
+  int retval = -1;\r
   int len;\r
 \r
   areaWrite("PicoSEXT", 1, 8, file);\r
@@ -290,6 +299,10 @@ static int state_save(void *file)
 \r
   if (PicoAHW & PAHW_MCD)\r
   {\r
+    buf2 = malloc(CHUNK_LIMIT_W);\r
+    if (buf2 == NULL)\r
+      return -1;\r
+\r
     memset(buff, 0, sizeof(buff));\r
     SekPackCpu(buff, 1);\r
     if (Pico_mcd->s68k_regs[3] & 4) // 1M mode?\r
@@ -305,14 +318,16 @@ static int state_save(void *file)
     CHECKED_WRITE_BUFF(CHUNK_GA_REGS,  Pico_mcd->s68k_regs); // GA regs, not CPU regs\r
     CHECKED_WRITE_BUFF(CHUNK_PCM,      Pico_mcd->pcm);\r
     CHECKED_WRITE_BUFF(CHUNK_CDD,      Pico_mcd->cdd);\r
-    CHECKED_WRITE_BUFF(CHUNK_CDC,      Pico_mcd->cdc);\r
     CHECKED_WRITE_BUFF(CHUNK_SCD,      Pico_mcd->scd);\r
     CHECKED_WRITE_BUFF(CHUNK_MISC_CD,  Pico_mcd->m);\r
     memset(buff, 0, 0x40);\r
     memcpy(buff, pcd_event_times, sizeof(pcd_event_times));\r
     CHECKED_WRITE(CHUNK_CD_EVT, 0x40, buff);\r
-    len = gfx_context_save(buff);\r
-    CHECKED_WRITE(CHUNK_CD_GFX, len, buff);\r
+\r
+    len = gfx_context_save(buf2);\r
+    CHECKED_WRITE(CHUNK_CD_GFX, len, buf2);\r
+    len = cdc_context_save(buf2);\r
+    CHECKED_WRITE(CHUNK_CD_CDC, len, buf2);\r
 \r
     if (Pico_mcd->s68k_regs[3] & 4) // convert back\r
       wram_2M_to_1M(Pico_mcd->word_ram2M);\r
@@ -358,7 +373,12 @@ static int state_save(void *file)
       CHECKED_WRITE(chwc->chunk, chwc->size, chwc->ptr);\r
   }\r
 \r
-  return 0;\r
+  retval = 0;\r
+\r
+out:\r
+  if (buf2 != NULL)\r
+    free(buf2);\r
+  return retval;\r
 }\r
 \r
 static int g_read_offs = 0;\r
@@ -366,7 +386,7 @@ static int g_read_offs = 0;
 #define R_ERROR_RETURN(error) \\r
 { \\r
   elprintf(EL_STATUS, "load_state @ %x: " error, g_read_offs); \\r
-  return 1; \\r
+  goto out; \\r
 }\r
 \r
 // when is eof really set?\r
@@ -374,7 +394,6 @@ static int g_read_offs = 0;
   if (areaRead(data, 1, len, file) != len) { \\r
     if (len == 1 && areaEof(file)) goto readend; \\r
     R_ERROR_RETURN("areaRead: premature EOF\n"); \\r
-    return 1; \\r
   } \\r
   g_read_offs += len; \\r
 }\r
@@ -390,14 +409,24 @@ static int g_read_offs = 0;
 \r
 #define CHECKED_READ_BUFF(buff) CHECKED_READ2(sizeof(buff), &buff);\r
 \r
+#define CHUNK_LIMIT_R 0x10960 // sizeof(old_cdc)\r
+\r
+#define CHECKED_READ_LIM(data) { \\r
+  if (len > CHUNK_LIMIT_R) \\r
+    R_ERROR_RETURN("chunk size over limit."); \\r
+  CHECKED_READ(len, data); \\r
+}\r
+\r
 static int state_load(void *file)\r
 {\r
   unsigned char buff_m68k[0x60], buff_s68k[0x60];\r
   unsigned char buff_z80[Z80_STATE_SIZE];\r
   unsigned char buff_sh2[SH2_STATE_SIZE];\r
-  unsigned char buff[0x40];\r
+  unsigned char *buf = NULL;\r
   unsigned char chunk;\r
   void *ym2612_regs;\r
+  int len_check;\r
+  int retval = -1;\r
   char header[8];\r
   int ver, len;\r
 \r
@@ -405,6 +434,10 @@ static int state_load(void *file)
   memset(buff_s68k, 0, sizeof(buff_s68k));\r
   memset(buff_z80, 0, sizeof(buff_z80));\r
 \r
+  buf = malloc(CHUNK_LIMIT_R);\r
+  if (buf == NULL)\r
+    return -1;\r
+\r
   g_read_offs = 0;\r
   CHECKED_READ(8, header);\r
   if (strncmp(header, "PicoSMCD", 8) && strncmp(header, "PicoSEXT", 8))\r
@@ -416,6 +449,7 @@ static int state_load(void *file)
 \r
   while (!areaEof(file))\r
   {\r
+    len_check = 0;\r
     CHECKED_READ(1, &chunk);\r
     CHECKED_READ(4, &len);\r
     if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r
@@ -465,18 +499,28 @@ static int state_load(void *file)
       case CHUNK_GA_REGS:  CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;\r
       case CHUNK_PCM:      CHECKED_READ_BUFF(Pico_mcd->pcm); break;\r
       case CHUNK_CDD:      CHECKED_READ_BUFF(Pico_mcd->cdd); break;\r
-      case CHUNK_CDC:      CHECKED_READ_BUFF(Pico_mcd->cdc); break;\r
       case CHUNK_SCD:      CHECKED_READ_BUFF(Pico_mcd->scd); break;\r
       case CHUNK_MISC_CD:  CHECKED_READ_BUFF(Pico_mcd->m); break;\r
 \r
       case CHUNK_CD_EVT:\r
-        CHECKED_READ_BUFF(buff);\r
-        memcpy(pcd_event_times, buff, sizeof(pcd_event_times));\r
+        CHECKED_READ2(0x40, buf);\r
+        memcpy(pcd_event_times, buf, sizeof(pcd_event_times));\r
         break;\r
 \r
       case CHUNK_CD_GFX:\r
-        CHECKED_READ2(0x18, buff);\r
-        gfx_context_load(buff);\r
+        CHECKED_READ_LIM(buf);\r
+        len_check = gfx_context_load(buf);\r
+        break;\r
+\r
+      case CHUNK_CD_CDC:\r
+        CHECKED_READ_LIM(buf);\r
+        len_check = cdc_context_load(buf);\r
+        break;\r
+\r
+      // old, to be removed:\r
+      case CHUNK_CDC:\r
+        CHECKED_READ_LIM(buf);\r
+        cdc_context_load_old(buf);\r
         break;\r
 \r
       // 32x stuff\r
@@ -504,8 +548,8 @@ static int state_load(void *file)
       case CHUNK_32XPAL:      CHECKED_READ_BUFF(Pico32xMem->pal); break;\r
 \r
       case CHUNK_32X_EVT:\r
-        CHECKED_READ_BUFF(buff);\r
-        memcpy(p32x_event_times, buff, sizeof(p32x_event_times));\r
+        CHECKED_READ2(0x40, buf);\r
+        memcpy(p32x_event_times, buf, sizeof(p32x_event_times));\r
         break;\r
 #endif\r
       default:\r
@@ -523,7 +567,10 @@ static int state_load(void *file)
         areaSeek(file, len, SEEK_CUR);\r
         break;\r
     }\r
-breakswitch:;\r
+breakswitch:\r
+    if (len_check != 0 && len_check != len)\r
+      elprintf(EL_STATUS, "load_state: chunk %d has bad len %d/%d",\r
+        len, len_check);\r
   }\r
 \r
 readend:\r
@@ -554,7 +601,11 @@ readend:
       cdda_start_play();\r
   }\r
 \r
-  return 0;\r
+  retval = 0;\r
+\r
+out:\r
+  free(buf);\r
+  return retval;\r
 }\r
 \r
 static int state_load_gfx(void *file)\r
@@ -608,6 +659,7 @@ static int state_load_gfx(void *file)
     }\r
   }\r
 \r
+out:\r
 readend:\r
   return 0;\r
 }\r
index 31d3b71..175bcc1 100644 (file)
@@ -519,7 +519,7 @@ Texas Instruments SN76489 / SN76496 programmable tone/noise generator
 Homepage: http://www.mame.net/\r
 \r
 Eke\r
-CD graphics processor implementation (from Genesis Plus GX)\r
+CD graphics processor and CD controller implementation (from Genesis Plus GX)\r
 \r
 Stephane Dallongeville\r
 Gens, MD/Mega CD/32X emulator. Some Sega CD code is based on this emu.\r
@@ -565,6 +565,11 @@ Additional thanks
 \r
 Changelog\r
 ---------\r
+1.91 (2013-10-)\r
+  + Switched to CD controller code from Eke's Genesis Plus GX.\r
+  * Fixed overflow issue where cd emulation would break after\r
+    ~10 minutes of gameplay\r
+\r
 1.90 (2013-09-24)\r
   + 32X+CD emulation has been implemented.\r
   + CD graphics processor code has been replaced with much cleaner Eke's\r
index 3a836e1..c651bca 100644 (file)
@@ -93,7 +93,7 @@ DEFINES += NO_SMS
 endif
 # CD
 SRCS_COMMON += $(R)pico/cd/mcd.c $(R)pico/cd/memory.c $(R)pico/cd/sek.c \
-       $(R)pico/cd/LC89510.c $(R)pico/cd/cd_sys.c $(R)pico/cd/cd_file.c \
+       $(R)pico/cd/cdc.c $(R)pico/cd/cd_sys.c $(R)pico/cd/cd_file.c \
        $(R)pico/cd/cue.c $(R)pico/cd/gfx.c $(R)pico/cd/gfx_dma.c \
        $(R)pico/cd/misc.c $(R)pico/cd/pcm.c $(R)pico/cd/buffering.c
 # 32X