From 3f23709ef37c5b3511c1445cbed7b447b56a37e0 Mon Sep 17 00:00:00 2001 From: notaz Date: Sat, 5 Oct 2013 04:14:45 +0300 Subject: [PATCH] cd: switch to CD controller code from genplus same license, much cleaner code using own dma code though.. --- pico/cd/LC89510.c | 637 --------------------------- pico/cd/LC89510.h | 96 +---- pico/cd/cd_file.c | 2 + pico/cd/cd_sys.c | 188 +++++++- pico/cd/cdc.c | 851 +++++++++++++++++++++++++++++++++++++ pico/cd/genplus_macros.h | 16 + pico/cd/mcd.c | 11 +- pico/cd/memory.c | 8 +- pico/cd/memory_arm.s | 10 +- pico/cd/sek.c | 14 + pico/pico_int.h | 83 ++-- pico/state.c | 94 +++- platform/base_readme.txt | 7 +- platform/common/common.mak | 2 +- 14 files changed, 1212 insertions(+), 807 deletions(-) delete mode 100644 pico/cd/LC89510.c create mode 100644 pico/cd/cdc.c diff --git a/pico/cd/LC89510.c b/pico/cd/LC89510.c deleted file mode 100644 index 74894760..00000000 --- a/pico/cd/LC89510.c +++ /dev/null @@ -1,637 +0,0 @@ -/*********************************************************** - * * - * This source file was taken from the Gens project * - * Written by Stéphane Dallongeville * - * Copyright (c) 2002 by Stéphane Dallongeville * - * Modified/adapted for PicoDrive by notaz, 2007 * - * * - ***********************************************************/ - -#include "../pico_int.h" - -#define CDC_DMA_SPEED 256 - - -static void CDD_Reset(void) -{ - // Reseting CDD - - memset(Pico_mcd->s68k_regs+0x34, 0, 2*2); // CDD.Fader, CDD.Control - Pico_mcd->cdd.Status = 0; - Pico_mcd->cdd.Minute = 0; - Pico_mcd->cdd.Seconde = 0; - Pico_mcd->cdd.Frame = 0; - Pico_mcd->cdd.Ext = 0; - - // clear receive status and transfer command - memset(Pico_mcd->s68k_regs+0x38, 0, 20); - Pico_mcd->s68k_regs[0x38+9] = 0xF; // Default checksum -} - - -static void CDC_Reset(void) -{ - // Reseting CDC - - memset(Pico_mcd->cdc.Buffer, 0, sizeof(Pico_mcd->cdc.Buffer)); - - Pico_mcd->cdc.COMIN = 0; - Pico_mcd->cdc.IFSTAT = 0xFF; - Pico_mcd->cdc.DAC.N = 0; - Pico_mcd->cdc.DBC.N = 0; - Pico_mcd->cdc.HEAD.N = 0x01000000; - Pico_mcd->cdc.PT.N = 0; - Pico_mcd->cdc.WA.N = 2352 * 2; - Pico_mcd->cdc.STAT.N = 0x00000080; - Pico_mcd->cdc.SBOUT = 0; - Pico_mcd->cdc.IFCTRL = 0; - Pico_mcd->cdc.CTRL.N = 0; - - Pico_mcd->cdc.Decode_Reg_Read = 0; - Pico_mcd->scd.Status_CDC &= ~0x08; -} - - -PICO_INTERNAL void LC89510_Reset(void) -{ - CDD_Reset(); - CDC_Reset(); - - // clear DMA_Adr & Stop_Watch - memset(Pico_mcd->s68k_regs + 0xA, 0, 4); -} - - -PICO_INTERNAL void Update_CDC_TRansfer(int which) -{ - unsigned int DMA_Adr, dep, length; - unsigned short *dest; - unsigned char *src; - - if (1) //Pico_mcd->cdc.DBC.N <= (CDC_DMA_SPEED * 2)) - { - length = (Pico_mcd->cdc.DBC.N + 1) >> 1; - Pico_mcd->scd.Status_CDC &= ~0x08; // Last transfer - Pico_mcd->s68k_regs[4] |= 0x80; // End data transfer - Pico_mcd->s68k_regs[4] &= ~0x40; // no more data ready - Pico_mcd->cdc.IFSTAT |= 0x08; // No more data transfer in progress - - if (Pico_mcd->cdc.IFCTRL & 0x40) // DTEIEN = Data Trasnfer End Interrupt Enable ? - { - Pico_mcd->cdc.IFSTAT &= ~0x40; - - if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN5) - { - elprintf(EL_INTS, "cdc DTE irq 5"); - SekInterruptS68k(5); - } - } - } - else length = CDC_DMA_SPEED; - - - // TODO: dst bounds checking? - src = Pico_mcd->cdc.Buffer + Pico_mcd->cdc.DAC.N; - DMA_Adr = (Pico_mcd->s68k_regs[0xA]<<8) | Pico_mcd->s68k_regs[0xB]; - - if (which == 7) // WORD RAM - { - if (Pico_mcd->s68k_regs[3] & 4) - { - // test: Final Fight - int bank = !(Pico_mcd->s68k_regs[3]&1); - dep = ((DMA_Adr & 0x3FFF) << 3); - cdprintf("CD DMA # %04x -> word_ram1M # %06x, len=%i", - Pico_mcd->cdc.DAC.N, dep, length); - - dest = (unsigned short *) (Pico_mcd->word_ram1M[bank] + dep); - - memcpy16bswap(dest, src, length); - - /*{ // debug - unsigned char *b1 = Pico_mcd->word_ram1M[bank] + dep; - unsigned char *b2 = (unsigned char *)(dest+length) - 8; - dprintf("%02x %02x %02x %02x .. %02x %02x %02x %02x", - b1[0], b1[1], b1[4], b1[5], b2[0], b2[1], b2[4], b2[5]); - }*/ - } - else - { - dep = ((DMA_Adr & 0x7FFF) << 3); - cdprintf("CD DMA # %04x -> word_ram2M # %06x, len=%i", - Pico_mcd->cdc.DAC.N, dep, length); - dest = (unsigned short *) (Pico_mcd->word_ram2M + dep); - - memcpy16bswap(dest, src, length); - - /*{ // debug - unsigned char *b1 = Pico_mcd->word_ram2M + dep; - unsigned char *b2 = (unsigned char *)(dest+length) - 4; - dprintf("%02x %02x %02x %02x .. %02x %02x %02x %02x", - b1[0], b1[1], b1[2], b1[3], b2[0], b2[1], b2[2], b2[3]); - }*/ - } - } - else if (which == 4) // PCM RAM (check: popful Mail) - { - dep = (DMA_Adr & 0x03FF) << 2; - cdprintf("CD DMA # %04x -> PCM[%i] # %04x, len=%i", - Pico_mcd->cdc.DAC.N, Pico_mcd->pcm.bank, dep, length); - dest = (unsigned short *) (Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank] + dep); - - if (Pico_mcd->cdc.DAC.N & 1) /* unaligned src? */ - memcpy(dest, src, length*2); - else memcpy16(dest, (unsigned short *) src, length); - } - else if (which == 5) // PRG RAM - { - dep = DMA_Adr << 3; - dest = (unsigned short *) (Pico_mcd->prg_ram + dep); - cdprintf("CD DMA # %04x -> prg_ram # %06x, len=%i", - Pico_mcd->cdc.DAC.N, dep, length); - - memcpy16bswap(dest, src, length); - - /*{ // debug - unsigned char *b1 = Pico_mcd->prg_ram + dep; - unsigned char *b2 = (unsigned char *)(dest+length) - 4; - dprintf("%02x %02x %02x %02x .. %02x %02x %02x %02x", - b1[0], b1[1], b1[2], b1[3], b2[0], b2[1], b2[2], b2[3]); - }*/ - } - - length <<= 1; - Pico_mcd->cdc.DAC.N = (Pico_mcd->cdc.DAC.N + length) & 0xFFFF; - if (Pico_mcd->scd.Status_CDC & 0x08) Pico_mcd->cdc.DBC.N -= length; - else Pico_mcd->cdc.DBC.N = 0; - - // update DMA_Adr - length >>= 2; - if (which != 4) length >>= 1; - DMA_Adr += length; - Pico_mcd->s68k_regs[0xA] = DMA_Adr >> 8; - Pico_mcd->s68k_regs[0xB] = DMA_Adr; -} - - -PICO_INTERNAL_ASM unsigned short Read_CDC_Host(int is_sub) -{ - int addr; - - if (!(Pico_mcd->scd.Status_CDC & 0x08)) - { - // Transfer data disabled - cdprintf("Read_CDC_Host FIXME: Transfer data disabled"); - return 0; - } - - if ((is_sub && (Pico_mcd->s68k_regs[4] & 7) != 3) || - (!is_sub && (Pico_mcd->s68k_regs[4] & 7) != 2)) - { - // Wrong setting - cdprintf("Read_CDC_Host FIXME: Wrong setting"); - return 0; - } - - Pico_mcd->cdc.DBC.N -= 2; - - if (Pico_mcd->cdc.DBC.N <= 0) - { - Pico_mcd->cdc.DBC.N = 0; - Pico_mcd->scd.Status_CDC &= ~0x08; // Last transfer - Pico_mcd->s68k_regs[4] |= 0x80; // End data transfer - Pico_mcd->s68k_regs[4] &= ~0x40; // no more data ready - Pico_mcd->cdc.IFSTAT |= 0x08; // No more data transfer in progress - - if (Pico_mcd->cdc.IFCTRL & 0x40) // DTEIEN = Data Transfer End Interrupt Enable ? - { - Pico_mcd->cdc.IFSTAT &= ~0x40; - - if (Pico_mcd->s68k_regs[0x33]&(1<<5)) { - elprintf(EL_INTS, "m68k: s68k irq 5"); - SekInterruptS68k(5); - } - - cdprintf("CDC - DTE interrupt"); - } - } - - addr = Pico_mcd->cdc.DAC.N; - Pico_mcd->cdc.DAC.N += 2; - - cdprintf("Read_CDC_Host sub=%i d=%04x dac=%04x dbc=%04x", is_sub, - (Pico_mcd->cdc.Buffer[addr]<<8) | Pico_mcd->cdc.Buffer[addr+1], Pico_mcd->cdc.DAC.N, Pico_mcd->cdc.DBC.N); - - return (Pico_mcd->cdc.Buffer[addr]<<8) | Pico_mcd->cdc.Buffer[addr+1]; -} - - -PICO_INTERNAL void CDC_Update_Header(void) -{ - if (Pico_mcd->cdc.CTRL.B.B1 & 0x01) // Sub-Header wanted ? - { - Pico_mcd->cdc.HEAD.B.B0 = 0; - Pico_mcd->cdc.HEAD.B.B1 = 0; - Pico_mcd->cdc.HEAD.B.B2 = 0; - Pico_mcd->cdc.HEAD.B.B3 = 0; - } - else - { - _msf MSF; - - LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF); - - Pico_mcd->cdc.HEAD.B.B0 = INT_TO_BCDB(MSF.M); - Pico_mcd->cdc.HEAD.B.B1 = INT_TO_BCDB(MSF.S); - Pico_mcd->cdc.HEAD.B.B2 = INT_TO_BCDB(MSF.F); - Pico_mcd->cdc.HEAD.B.B3 = 0x01; - } -} - - -PICO_INTERNAL unsigned char CDC_Read_Reg(void) -{ - unsigned char ret; - - switch(Pico_mcd->s68k_regs[5] & 0xF) - { - case 0x0: // COMIN - cdprintf("CDC read reg 00 = %.2X", Pico_mcd->cdc.COMIN); - - Pico_mcd->s68k_regs[5] = 0x1; - return Pico_mcd->cdc.COMIN; - - case 0x1: // IFSTAT - cdprintf("CDC read reg 01 = %.2X", Pico_mcd->cdc.IFSTAT); - - Pico_mcd->cdc.Decode_Reg_Read |= (1 << 1); // Reg 1 (decoding) - Pico_mcd->s68k_regs[5] = 0x2; - return Pico_mcd->cdc.IFSTAT; - - case 0x2: // DBCL - cdprintf("CDC read reg 02 = %.2X", Pico_mcd->cdc.DBC.B.L); - - Pico_mcd->s68k_regs[5] = 0x3; - return Pico_mcd->cdc.DBC.B.L; - - case 0x3: // DBCH - cdprintf("CDC read reg 03 = %.2X", Pico_mcd->cdc.DBC.B.H); - - Pico_mcd->s68k_regs[5] = 0x4; - return Pico_mcd->cdc.DBC.B.H; - - case 0x4: // HEAD0 - cdprintf("CDC read reg 04 = %.2X", Pico_mcd->cdc.HEAD.B.B0); - - Pico_mcd->cdc.Decode_Reg_Read |= (1 << 4); // Reg 4 (decoding) - Pico_mcd->s68k_regs[5] = 0x5; - return Pico_mcd->cdc.HEAD.B.B0; - - case 0x5: // HEAD1 - cdprintf("CDC read reg 05 = %.2X", Pico_mcd->cdc.HEAD.B.B1); - - Pico_mcd->cdc.Decode_Reg_Read |= (1 << 5); // Reg 5 (decoding) - Pico_mcd->s68k_regs[5] = 0x6; - return Pico_mcd->cdc.HEAD.B.B1; - - case 0x6: // HEAD2 - cdprintf("CDC read reg 06 = %.2X", Pico_mcd->cdc.HEAD.B.B2); - - Pico_mcd->cdc.Decode_Reg_Read |= (1 << 6); // Reg 6 (decoding) - Pico_mcd->s68k_regs[5] = 0x7; - return Pico_mcd->cdc.HEAD.B.B2; - - case 0x7: // HEAD3 - cdprintf("CDC read reg 07 = %.2X", Pico_mcd->cdc.HEAD.B.B3); - - Pico_mcd->cdc.Decode_Reg_Read |= (1 << 7); // Reg 7 (decoding) - Pico_mcd->s68k_regs[5] = 0x8; - return Pico_mcd->cdc.HEAD.B.B3; - - case 0x8: // PTL - cdprintf("CDC read reg 08 = %.2X", Pico_mcd->cdc.PT.B.L); - - Pico_mcd->cdc.Decode_Reg_Read |= (1 << 8); // Reg 8 (decoding) - Pico_mcd->s68k_regs[5] = 0x9; - return Pico_mcd->cdc.PT.B.L; - - case 0x9: // PTH - cdprintf("CDC read reg 09 = %.2X", Pico_mcd->cdc.PT.B.H); - - Pico_mcd->cdc.Decode_Reg_Read |= (1 << 9); // Reg 9 (decoding) - Pico_mcd->s68k_regs[5] = 0xA; - return Pico_mcd->cdc.PT.B.H; - - case 0xA: // WAL - cdprintf("CDC read reg 10 = %.2X", Pico_mcd->cdc.WA.B.L); - - Pico_mcd->s68k_regs[5] = 0xB; - return Pico_mcd->cdc.WA.B.L; - - case 0xB: // WAH - cdprintf("CDC read reg 11 = %.2X", Pico_mcd->cdc.WA.B.H); - - Pico_mcd->s68k_regs[5] = 0xC; - return Pico_mcd->cdc.WA.B.H; - - case 0xC: // STAT0 - cdprintf("CDC read reg 12 = %.2X", Pico_mcd->cdc.STAT.B.B0); - - Pico_mcd->cdc.Decode_Reg_Read |= (1 << 12); // Reg 12 (decoding) - Pico_mcd->s68k_regs[5] = 0xD; - return Pico_mcd->cdc.STAT.B.B0; - - case 0xD: // STAT1 - cdprintf("CDC read reg 13 = %.2X", Pico_mcd->cdc.STAT.B.B1); - - Pico_mcd->cdc.Decode_Reg_Read |= (1 << 13); // Reg 13 (decoding) - Pico_mcd->s68k_regs[5] = 0xE; - return Pico_mcd->cdc.STAT.B.B1; - - case 0xE: // STAT2 - cdprintf("CDC read reg 14 = %.2X", Pico_mcd->cdc.STAT.B.B2); - - Pico_mcd->cdc.Decode_Reg_Read |= (1 << 14); // Reg 14 (decoding) - Pico_mcd->s68k_regs[5] = 0xF; - return Pico_mcd->cdc.STAT.B.B2; - - case 0xF: // STAT3 - cdprintf("CDC read reg 15 = %.2X", Pico_mcd->cdc.STAT.B.B3); - - ret = Pico_mcd->cdc.STAT.B.B3; - Pico_mcd->cdc.IFSTAT |= 0x20; // decoding interrupt flag cleared - if ((Pico_mcd->cdc.CTRL.B.B0 & 0x80) && (Pico_mcd->cdc.IFCTRL & 0x20)) - { - if ((Pico_mcd->cdc.Decode_Reg_Read & 0x73F2) == 0x73F2) - Pico_mcd->cdc.STAT.B.B3 = 0x80; - } - return ret; - } - - return 0; -} - - -PICO_INTERNAL void CDC_Write_Reg(unsigned char Data) -{ - cdprintf("CDC write reg%02d = %.2X", Pico_mcd->s68k_regs[5] & 0xF, Data); - - switch (Pico_mcd->s68k_regs[5] & 0xF) - { - case 0x0: // SBOUT - Pico_mcd->s68k_regs[5] = 0x1; - Pico_mcd->cdc.SBOUT = Data; - - break; - - case 0x1: // IFCTRL - Pico_mcd->s68k_regs[5] = 0x2; - Pico_mcd->cdc.IFCTRL = Data; - - if ((Pico_mcd->cdc.IFCTRL & 0x02) == 0) // Stop data transfer - { - Pico_mcd->cdc.DBC.N = 0; - Pico_mcd->scd.Status_CDC &= ~0x08; - Pico_mcd->cdc.IFSTAT |= 0x08; // No more data transfer in progress - } - break; - - case 0x2: // DBCL - Pico_mcd->s68k_regs[5] = 0x3; - Pico_mcd->cdc.DBC.B.L = Data; - - break; - - case 0x3: // DBCH - Pico_mcd->s68k_regs[5] = 0x4; - Pico_mcd->cdc.DBC.B.H = Data; - - break; - - case 0x4: // DACL - Pico_mcd->s68k_regs[5] = 0x5; - Pico_mcd->cdc.DAC.B.L = Data; - - break; - - case 0x5: // DACH - Pico_mcd->s68k_regs[5] = 0x6; - Pico_mcd->cdc.DAC.B.H = Data; - - break; - - case 0x6: // DTTRG - if (Pico_mcd->cdc.IFCTRL & 0x02) // Data transfer enable ? - { - Pico_mcd->cdc.IFSTAT &= ~0x08; // Data transfer in progress - Pico_mcd->scd.Status_CDC |= 0x08; // Data transfer in progress - Pico_mcd->s68k_regs[4] &= 0x7F; // A data transfer start - - cdprintf("************** Starting Data Transfer ***********"); - cdprintf("RS0 = %.4X DAC = %.4X DBC = %.4X DMA adr = %.4X\n\n", Pico_mcd->s68k_regs[4]<<8, - Pico_mcd->cdc.DAC.N, Pico_mcd->cdc.DBC.N, (Pico_mcd->s68k_regs[0xA]<<8) | Pico_mcd->s68k_regs[0xB]); - - // tmp - { - int ddx = Pico_mcd->s68k_regs[4] & 7; - if (ddx < 2) break; // invalid - if (ddx < 4) { - Pico_mcd->s68k_regs[4] |= 0x40; // Data set ready in host port - break; - } - if (ddx == 6) break; // invalid - - pcd_event_schedule_s68k(PCD_EVENT_DMA, Pico_mcd->cdc.DBC.N / 2); - } - } - break; - - case 0x7: // DTACK - Pico_mcd->cdc.IFSTAT |= 0x40; // end data transfer interrupt flag cleared - break; - - case 0x8: // WAL - Pico_mcd->s68k_regs[5] = 0x9; - Pico_mcd->cdc.WA.B.L = Data; - - break; - - case 0x9: // WAH - Pico_mcd->s68k_regs[5] = 0xA; - Pico_mcd->cdc.WA.B.H = Data; - - break; - - case 0xA: // CTRL0 - Pico_mcd->s68k_regs[5] = 0xB; - Pico_mcd->cdc.CTRL.B.B0 = Data; - - break; - - case 0xB: // CTRL1 - Pico_mcd->s68k_regs[5] = 0xC; - Pico_mcd->cdc.CTRL.B.B1 = Data; - - break; - - case 0xC: // PTL - Pico_mcd->s68k_regs[5] = 0xD; - Pico_mcd->cdc.PT.B.L = Data; - - break; - - case 0xD: // PTH - Pico_mcd->s68k_regs[5] = 0xE; - Pico_mcd->cdc.PT.B.H = Data; - - break; - - case 0xE: // CTRL2 - Pico_mcd->cdc.CTRL.B.B2 = Data; - break; - - case 0xF: // RESET - CDC_Reset(); - break; - } -} - - -static int bswapwrite(int a, unsigned short d) -{ - *(unsigned short *)(Pico_mcd->s68k_regs + a) = (d>>8)|(d<<8); - return d + (d >> 8); -} - -PICO_INTERNAL void CDD_Export_Status(void) -{ - unsigned int csum; - - csum = bswapwrite( 0x38+0, Pico_mcd->cdd.Status); - csum += bswapwrite( 0x38+2, Pico_mcd->cdd.Minute); - csum += bswapwrite( 0x38+4, Pico_mcd->cdd.Seconde); - csum += bswapwrite( 0x38+6, Pico_mcd->cdd.Frame); - Pico_mcd->s68k_regs[0x38+8] = Pico_mcd->cdd.Ext; - csum += Pico_mcd->cdd.Ext; - Pico_mcd->s68k_regs[0x38+9] = ~csum & 0xf; - - Pico_mcd->s68k_regs[0x37] &= 3; // CDD.Control - - if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) - { - elprintf(EL_INTS, "cdd export irq 4"); - SekInterruptS68k(4); - } - -// cdprintf("CDD exported status\n"); - cdprintf("out: Status=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X Checksum=%.4X", - (Pico_mcd->s68k_regs[0x38+0] << 8) | Pico_mcd->s68k_regs[0x38+1], - (Pico_mcd->s68k_regs[0x38+2] << 8) | Pico_mcd->s68k_regs[0x38+3], - (Pico_mcd->s68k_regs[0x38+4] << 8) | Pico_mcd->s68k_regs[0x38+5], - (Pico_mcd->s68k_regs[0x38+6] << 8) | Pico_mcd->s68k_regs[0x38+7], - (Pico_mcd->s68k_regs[0x38+8] << 8) | Pico_mcd->s68k_regs[0x38+9]); -} - - -PICO_INTERNAL void CDD_Import_Command(void) -{ -// cdprintf("CDD importing command\n"); - cdprintf("in: Command=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X Checksum=%.4X", - (Pico_mcd->s68k_regs[0x38+10+0] << 8) | Pico_mcd->s68k_regs[0x38+10+1], - (Pico_mcd->s68k_regs[0x38+10+2] << 8) | Pico_mcd->s68k_regs[0x38+10+3], - (Pico_mcd->s68k_regs[0x38+10+4] << 8) | Pico_mcd->s68k_regs[0x38+10+5], - (Pico_mcd->s68k_regs[0x38+10+6] << 8) | Pico_mcd->s68k_regs[0x38+10+7], - (Pico_mcd->s68k_regs[0x38+10+8] << 8) | Pico_mcd->s68k_regs[0x38+10+9]); - - switch (Pico_mcd->s68k_regs[0x38+10+0]) - { - case 0x0: // STATUS (?) - Get_Status_CDD_c0(); - break; - - case 0x1: // STOP ALL (?) - Stop_CDD_c1(); - break; - - case 0x2: // GET TOC INFORMATIONS - switch(Pico_mcd->s68k_regs[0x38+10+3]) - { - case 0x0: // get current position (MSF format) - Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00); - Get_Pos_CDD_c20(); - break; - - case 0x1: // get elapsed time of current track played/scanned (relative MSF format) - Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 1; - Get_Track_Pos_CDD_c21(); - break; - - case 0x2: // get current track in RS2-RS3 - Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 2; - Get_Current_Track_CDD_c22(); - break; - - case 0x3: // get total length (MSF format) - Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 3; - Get_Total_Lenght_CDD_c23(); - break; - - case 0x4: // first & last track number - Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 4; - Get_First_Last_Track_CDD_c24(); - break; - - case 0x5: // get track addresse (MSF format) - Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 5; - Get_Track_Adr_CDD_c25(); - break; - - default : // invalid, then we return status - Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 0xF; - Get_Status_CDD_c0(); - break; - } - break; - - case 0x3: // READ - Play_CDD_c3(); - break; - - case 0x4: // SEEK - Seek_CDD_c4(); - break; - - case 0x6: // PAUSE/STOP - Pause_CDD_c6(); - break; - - case 0x7: // RESUME - Resume_CDD_c7(); - break; - - case 0x8: // FAST FOWARD - Fast_Foward_CDD_c8(); - break; - - case 0x9: // FAST REWIND - Fast_Rewind_CDD_c9(); - break; - - case 0xA: // RECOVER INITIAL STATE (?) - CDD_cA(); - break; - - case 0xC: // CLOSE TRAY - Close_Tray_CDD_cC(); - break; - - case 0xD: // OPEN TRAY - Open_Tray_CDD_cD(); - break; - - default: // UNKNOWN - CDD_Def(); - break; - } -} - diff --git a/pico/cd/LC89510.h b/pico/cd/LC89510.h index 2b0d3826..d641ebb3 100644 --- a/pico/cd/LC89510.h +++ b/pico/cd/LC89510.h @@ -14,92 +14,6 @@ extern "C" { #endif -typedef struct -{ - unsigned char Buffer[(32 * 1024 * 2) + 2352]; -// unsigned int Host_Data; // unused -// unsigned int DMA_Adr; // 0A -// unsigned int Stop_Watch; // 0C - unsigned int COMIN; - unsigned int IFSTAT; - union - { - struct - { - unsigned char L; - unsigned char H; - unsigned short unused; - } B; - int N; - } DBC; - union - { - struct - { - unsigned char L; - unsigned char H; - unsigned short unused; - } B; - int N; - } DAC; - union - { - struct - { - unsigned char B0; - unsigned char B1; - unsigned char B2; - unsigned char B3; - } B; - unsigned int N; - } HEAD; - union - { - struct - { - unsigned char L; - unsigned char H; - unsigned short unused; - } B; - int N; - } PT; - union - { - struct - { - unsigned char L; - unsigned char H; - unsigned short unused; - } B; - int N; - } WA; - union - { - struct - { - unsigned char B0; - unsigned char B1; - unsigned char B2; - unsigned char B3; - } B; - unsigned int N; - } STAT; - unsigned int SBOUT; - unsigned int IFCTRL; - union - { - struct - { - unsigned char B0; - unsigned char B1; - unsigned char B2; - unsigned char B3; - } B; - unsigned int N; - } CTRL; - unsigned int Decode_Reg_Read; -} CDC; - typedef struct { // unsigned short Fader; // 34 @@ -116,17 +30,11 @@ typedef struct } CDD; -PICO_INTERNAL_ASM unsigned short Read_CDC_Host(int is_sub); -PICO_INTERNAL void LC89510_Reset(void); -PICO_INTERNAL void Update_CDC_TRansfer(int which); -PICO_INTERNAL void CDC_Update_Header(void); - -PICO_INTERNAL unsigned char CDC_Read_Reg(void); -PICO_INTERNAL void CDC_Write_Reg(unsigned char Data); - PICO_INTERNAL void CDD_Export_Status(void); PICO_INTERNAL void CDD_Import_Command(void); +void CDD_Reset(void); + #ifdef __cplusplus }; #endif diff --git a/pico/cd/cd_file.c b/pico/cd/cd_file.c index 0f19b71d..43bbb5d8 100644 --- a/pico/cd/cd_file.c +++ b/pico/cd/cd_file.c @@ -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 diff --git a/pico/cd/cd_sys.c b/pico/cd/cd_sys.c index 1c19057f..f7cd7b5e 100644 --- a/pico/cd/cd_sys.c +++ b/pico/cd/cd_sys.c @@ -23,6 +23,10 @@ #define FAST_REV 0x10300 // FAST REVERSE track CDD status #define PLAYING 0x0100 // PLAYING audio track CDD status +//#undef cdprintf +//#define cdprintf(x, ...) elprintf(EL_STATUS, x, ##__VA_ARGS__) + +#define CDC_Update_Header() static int CD_Present = 0; @@ -139,15 +143,32 @@ PICO_INTERNAL void Check_CD_Command(void) cdprintf("Got a read command"); // DATA ? - if (Pico_mcd->scd.Cur_Track == 1) + if (Pico_mcd->scd.Cur_Track == 1) { Pico_mcd->s68k_regs[0x36] |= 0x01; - else Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO - if (Pico_mcd->scd.File_Add_Delay == 0) - { - FILE_Read_One_LBA_CDC(); + if (Pico_mcd->scd.File_Add_Delay == 0) + { + unsigned char header[4]; + _msf MSF; + + LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF); + + header[0] = INT_TO_BCDB(MSF.M); + header[1] = INT_TO_BCDB(MSF.S); + header[2] = INT_TO_BCDB(MSF.F); + header[3] = 0x01; + + //FILE_Read_One_LBA_CDC(); + Pico_mcd->scd.Cur_LBA += + cdc_decoder_update(header); + } + else Pico_mcd->scd.File_Add_Delay--; + } + else { + Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO + unsigned char header[4] = { 0, }; + cdc_decoder_update(header); } - else Pico_mcd->scd.File_Add_Delay--; } // Check CDD @@ -755,3 +776,158 @@ PICO_INTERNAL int CDD_Def(void) } +static int bswapwrite(int a, unsigned short d) +{ + *(unsigned short *)(Pico_mcd->s68k_regs + a) = (d>>8)|(d<<8); + return d + (d >> 8); +} + +PICO_INTERNAL void CDD_Export_Status(void) +{ + unsigned int csum; + + csum = bswapwrite( 0x38+0, Pico_mcd->cdd.Status); + csum += bswapwrite( 0x38+2, Pico_mcd->cdd.Minute); + csum += bswapwrite( 0x38+4, Pico_mcd->cdd.Seconde); + csum += bswapwrite( 0x38+6, Pico_mcd->cdd.Frame); + Pico_mcd->s68k_regs[0x38+8] = Pico_mcd->cdd.Ext; + csum += Pico_mcd->cdd.Ext; + Pico_mcd->s68k_regs[0x38+9] = ~csum & 0xf; + + Pico_mcd->s68k_regs[0x37] &= 3; // CDD.Control + + if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) + { + elprintf(EL_INTS, "cdd export irq 4"); + SekInterruptS68k(4); + } + +// cdprintf("CDD exported status\n"); + cdprintf("out: Status=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X Checksum=%.4X", + (Pico_mcd->s68k_regs[0x38+0] << 8) | Pico_mcd->s68k_regs[0x38+1], + (Pico_mcd->s68k_regs[0x38+2] << 8) | Pico_mcd->s68k_regs[0x38+3], + (Pico_mcd->s68k_regs[0x38+4] << 8) | Pico_mcd->s68k_regs[0x38+5], + (Pico_mcd->s68k_regs[0x38+6] << 8) | Pico_mcd->s68k_regs[0x38+7], + (Pico_mcd->s68k_regs[0x38+8] << 8) | Pico_mcd->s68k_regs[0x38+9]); +} + + +PICO_INTERNAL void CDD_Import_Command(void) +{ +// cdprintf("CDD importing command\n"); + cdprintf("in: Command=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X Checksum=%.4X", + (Pico_mcd->s68k_regs[0x38+10+0] << 8) | Pico_mcd->s68k_regs[0x38+10+1], + (Pico_mcd->s68k_regs[0x38+10+2] << 8) | Pico_mcd->s68k_regs[0x38+10+3], + (Pico_mcd->s68k_regs[0x38+10+4] << 8) | Pico_mcd->s68k_regs[0x38+10+5], + (Pico_mcd->s68k_regs[0x38+10+6] << 8) | Pico_mcd->s68k_regs[0x38+10+7], + (Pico_mcd->s68k_regs[0x38+10+8] << 8) | Pico_mcd->s68k_regs[0x38+10+9]); + + switch (Pico_mcd->s68k_regs[0x38+10+0]) + { + case 0x0: // STATUS (?) + Get_Status_CDD_c0(); + break; + + case 0x1: // STOP ALL (?) + Stop_CDD_c1(); + break; + + case 0x2: // GET TOC INFORMATIONS + switch(Pico_mcd->s68k_regs[0x38+10+3]) + { + case 0x0: // get current position (MSF format) + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00); + Get_Pos_CDD_c20(); + break; + + case 0x1: // get elapsed time of current track played/scanned (relative MSF format) + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 1; + Get_Track_Pos_CDD_c21(); + break; + + case 0x2: // get current track in RS2-RS3 + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 2; + Get_Current_Track_CDD_c22(); + break; + + case 0x3: // get total length (MSF format) + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 3; + Get_Total_Lenght_CDD_c23(); + break; + + case 0x4: // first & last track number + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 4; + Get_First_Last_Track_CDD_c24(); + break; + + case 0x5: // get track addresse (MSF format) + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 5; + Get_Track_Adr_CDD_c25(); + break; + + default : // invalid, then we return status + Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 0xF; + Get_Status_CDD_c0(); + break; + } + break; + + case 0x3: // READ + Play_CDD_c3(); + break; + + case 0x4: // SEEK + Seek_CDD_c4(); + break; + + case 0x6: // PAUSE/STOP + Pause_CDD_c6(); + break; + + case 0x7: // RESUME + Resume_CDD_c7(); + break; + + case 0x8: // FAST FOWARD + Fast_Foward_CDD_c8(); + break; + + case 0x9: // FAST REWIND + Fast_Rewind_CDD_c9(); + break; + + case 0xA: // RECOVER INITIAL STATE (?) + CDD_cA(); + break; + + case 0xC: // CLOSE TRAY + Close_Tray_CDD_cC(); + break; + + case 0xD: // OPEN TRAY + Open_Tray_CDD_cD(); + break; + + default: // UNKNOWN + CDD_Def(); + break; + } +} + +void CDD_Reset(void) +{ + // Reseting CDD + + memset(Pico_mcd->s68k_regs+0x34, 0, 2*2); // CDD.Fader, CDD.Control + Pico_mcd->cdd.Status = 0; + Pico_mcd->cdd.Minute = 0; + Pico_mcd->cdd.Seconde = 0; + Pico_mcd->cdd.Frame = 0; + Pico_mcd->cdd.Ext = 0; + + // clear receive status and transfer command + memset(Pico_mcd->s68k_regs+0x38, 0, 20); + Pico_mcd->s68k_regs[0x38+9] = 0xF; // Default checksum +} + + diff --git a/pico/cd/cdc.c b/pico/cd/cdc.c new file mode 100644 index 00000000..aa1ded97 --- /dev/null +++ b/pico/cd/cdc.c @@ -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 diff --git a/pico/cd/genplus_macros.h b/pico/cd/genplus_macros.h index 8ac5d35b..04c381a7 100644 --- a/pico/cd/genplus_macros.h +++ b/pico/cd/genplus_macros.h @@ -12,6 +12,22 @@ #define int16 signed short #define int32 signed int +typedef union +{ + uint16 w; + struct + { +#if 1 + uint8 l; + uint8 h; +#else + uint8 h; + uint8 l; +#endif + } byte; + +} reg16_t; + #define READ_BYTE(BASE, ADDR) (BASE)[(ADDR)^1] #define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[(ADDR)^1] = (VAL) diff --git a/pico/cd/mcd.c b/pico/cd/mcd.c index 24e99e44..33553613 100644 --- a/pico/cd/mcd.c +++ b/pico/cd/mcd.c @@ -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; diff --git a/pico/cd/memory.c b/pico/cd/memory.c index b0f5e4a8..d3a2927e 100644 --- a/pico/cd/memory.c +++ b/pico/cd/memory.c @@ -100,7 +100,7 @@ static u32 m68k_reg_read16(u32 a) d = *(u16 *)(Pico_mcd->bios + 0x72); goto end; case 8: - d = Read_CDC_Host(0); + d = cdc_host_r(); goto end; case 0xA: elprintf(EL_UIO, "m68k FIXME: reserved read"); @@ -286,9 +286,9 @@ u32 s68k_reg_read16(u32 a) elprintf(EL_CDREG3, "s68k_regs r3: %02x @%06x", (u8)d, SekPcS68k); return s68k_poll_detect(a, d); case 6: - return CDC_Read_Reg(); + return cdc_reg_r(); case 8: - return Read_CDC_Host(1); // Gens returns 0 here on byte reads + return cdc_host_r(); case 0xC: d = SekCyclesDoneS68k() - Pico_mcd->m.stopwatch_base_c; d /= 384; @@ -379,7 +379,7 @@ void s68k_reg_write8(u32 a, u32 d) //dprintf("s68k CDC reg addr: %x", d&0xf); break; case 7: - CDC_Write_Reg(d); + cdc_reg_w(d); return; case 0xa: elprintf(EL_CDREGS, "s68k set CDC dma addr"); diff --git a/pico/cd/memory_arm.s b/pico/cd/memory_arm.s index e19c5613..f3a1372a 100644 --- a/pico/cd/memory_arm.s +++ b/pico/cd/memory_arm.s @@ -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 @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ diff --git a/pico/cd/sek.c b/pico/cd/sek.c index 8d838628..d4914901 100644 --- a/pico/cd/sek.c +++ b/pico/cd/sek.c @@ -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 +} diff --git a/pico/pico_int.h b/pico/pico_int.h index a8bf7ee4..d4d6d7de 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -417,38 +417,44 @@ struct mcd_misc typedef struct { - unsigned char bios[0x20000]; // 000000: 128K - union { // 020000: 512K - unsigned char prg_ram[0x80000]; - unsigned char prg_ram_b[4][0x20000]; - }; - union { // 0a0000: 256K - struct { - unsigned char word_ram2M[0x40000]; - unsigned char unused0[0x20000]; - }; - struct { - unsigned char unused1[0x20000]; - unsigned char word_ram1M[2][0x20000]; - }; - }; - union { // 100000: 64K - unsigned char pcm_ram[0x10000]; - unsigned char pcm_ram_b[0x10][0x1000]; - }; - // FIXME: should be short - unsigned char s68k_regs[0x200]; // 110000: GA, not CPU regs - unsigned char bram[0x2000]; // 110200: 8K - struct mcd_misc m; // 112200: misc - struct mcd_pcm pcm; // 112240: - _scd_toc TOC; // not to be saved - CDD cdd; - CDC cdc; - _scd scd; - int pcm_mixbuf[PCM_MIXBUF_LEN * 2]; - int pcm_mixpos; - char pcm_mixbuf_dirty; - char pcm_regs_dirty; + unsigned char bios[0x20000]; // 000000: 128K + union { // 020000: 512K + unsigned char prg_ram[0x80000]; + unsigned char prg_ram_b[4][0x20000]; + }; + union { // 0a0000: 256K + struct { + unsigned char word_ram2M[0x40000]; + unsigned char unused0[0x20000]; + }; + struct { + unsigned char unused1[0x20000]; + unsigned char word_ram1M[2][0x20000]; + }; + }; + union { // 100000: 64K + unsigned char pcm_ram[0x10000]; + unsigned char pcm_ram_b[0x10][0x1000]; + }; + union { + unsigned char s68k_regs[0x200]; // 110000: GA, not CPU regs + union { + struct { + unsigned char h; + unsigned char l; + } byte; + } regs[0x200/2]; + }; + unsigned char bram[0x2000]; // 110200: 8K + struct mcd_misc m; // 112200: misc + struct mcd_pcm pcm; // 112240: + _scd_toc TOC; // not to be saved + CDD cdd; + _scd scd; + int pcm_mixbuf[PCM_MIXBUF_LEN * 2]; + int pcm_mixpos; + char pcm_mixbuf_dirty; + char pcm_regs_dirty; } mcd_state; // XXX: this will need to be reworked for cart+cd support. @@ -610,6 +616,18 @@ void PicoWrite16_io(unsigned int a, unsigned int d); // pico/memory.c PICO_INTERNAL void PicoMemSetupPico(void); +// cd/cdc.c +void cdc_init(void); +void cdc_reset(void); +int cdc_context_save(unsigned char *state); +int cdc_context_load(unsigned char *state); +int cdc_context_load_old(unsigned char *state); +void cdc_dma_update(void); +int cdc_decoder_update(unsigned char header[4]); +void cdc_reg_w(unsigned char data); +unsigned char cdc_reg_r(void); +unsigned short cdc_host_r(void); + // cd/gfx.c void gfx_init(void); void gfx_start(unsigned int base); @@ -706,6 +724,7 @@ void SekTrace(int is_s68k); PICO_INTERNAL void SekInitS68k(void); PICO_INTERNAL int SekResetS68k(void); PICO_INTERNAL int SekInterruptS68k(int irq); +void SekInterruptClearS68k(int irq); // sound/sound.c PICO_INTERNAL void cdda_start_play(); diff --git a/pico/state.c b/pico/state.c index a1ceac2c..94cefade 100644 --- a/pico/state.c +++ b/pico/state.c @@ -148,10 +148,10 @@ typedef enum { CHUNK_BRAM, CHUNK_GA_REGS, CHUNK_PCM, - CHUNK_CDC, + CHUNK_CDC, // old CHUNK_CDD, // 20 CHUNK_SCD, - CHUNK_RC, + CHUNK_RC, // old CHUNK_MISC_CD, // CHUNK_IOPORTS, // versions < 1.70 did not save that.. @@ -176,6 +176,7 @@ typedef enum { // add new stuff here CHUNK_CD_EVT = 50, CHUNK_CD_GFX, + CHUNK_CD_CDC, // CHUNK_DEFAULT_COUNT, CHUNK_CARTHW_ = CHUNK_CARTHW, // 64 (defined in PicoInt) @@ -237,12 +238,17 @@ static int write_chunk(chunk_name_e name, int len, void *data, void *file) return (bwritten == len + 4 + 1); } +#define CHUNK_LIMIT_W 18772 // sizeof(cdc) + #define CHECKED_WRITE(name,len,data) { \ if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT && chunk_names[name]) { \ strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \ PicoStateProgressCB(sbuff); \ } \ - if (!write_chunk(name, len, data, file)) return 1; \ + if (data == buf2 && len > CHUNK_LIMIT_W) \ + goto out; \ + if (!write_chunk(name, len, data, file)) \ + goto out; \ } #define CHECKED_WRITE_BUFF(name,buff) { \ @@ -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); \ PicoStateProgressCB(sbuff); \ } \ - if (!write_chunk(name, sizeof(buff), &buff, file)) return 1; \ + if (!write_chunk(name, sizeof(buff), &buff, file)) \ + goto out; \ } static int state_save(void *file) @@ -258,7 +265,9 @@ static int state_save(void *file) char sbuff[32] = "Saving.. "; unsigned char buff[0x60], buff_z80[Z80_STATE_SIZE]; void *ym2612_regs = YM2612GetRegs(); - int ver = 0x0170; // not really used.. + void *buf2 = NULL; + int ver = 0x0191; // not really used.. + int retval = -1; int len; areaWrite("PicoSEXT", 1, 8, file); @@ -290,6 +299,10 @@ static int state_save(void *file) if (PicoAHW & PAHW_MCD) { + buf2 = malloc(CHUNK_LIMIT_W); + if (buf2 == NULL) + return -1; + memset(buff, 0, sizeof(buff)); SekPackCpu(buff, 1); if (Pico_mcd->s68k_regs[3] & 4) // 1M mode? @@ -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 CHECKED_WRITE_BUFF(CHUNK_PCM, Pico_mcd->pcm); CHECKED_WRITE_BUFF(CHUNK_CDD, Pico_mcd->cdd); - CHECKED_WRITE_BUFF(CHUNK_CDC, Pico_mcd->cdc); CHECKED_WRITE_BUFF(CHUNK_SCD, Pico_mcd->scd); CHECKED_WRITE_BUFF(CHUNK_MISC_CD, Pico_mcd->m); memset(buff, 0, 0x40); memcpy(buff, pcd_event_times, sizeof(pcd_event_times)); CHECKED_WRITE(CHUNK_CD_EVT, 0x40, buff); - len = gfx_context_save(buff); - CHECKED_WRITE(CHUNK_CD_GFX, len, buff); + + len = gfx_context_save(buf2); + CHECKED_WRITE(CHUNK_CD_GFX, len, buf2); + len = cdc_context_save(buf2); + CHECKED_WRITE(CHUNK_CD_CDC, len, buf2); if (Pico_mcd->s68k_regs[3] & 4) // convert back wram_2M_to_1M(Pico_mcd->word_ram2M); @@ -358,7 +373,12 @@ static int state_save(void *file) CHECKED_WRITE(chwc->chunk, chwc->size, chwc->ptr); } - return 0; + retval = 0; + +out: + if (buf2 != NULL) + free(buf2); + return retval; } static int g_read_offs = 0; @@ -366,7 +386,7 @@ static int g_read_offs = 0; #define R_ERROR_RETURN(error) \ { \ elprintf(EL_STATUS, "load_state @ %x: " error, g_read_offs); \ - return 1; \ + goto out; \ } // when is eof really set? @@ -374,7 +394,6 @@ static int g_read_offs = 0; if (areaRead(data, 1, len, file) != len) { \ if (len == 1 && areaEof(file)) goto readend; \ R_ERROR_RETURN("areaRead: premature EOF\n"); \ - return 1; \ } \ g_read_offs += len; \ } @@ -390,14 +409,24 @@ static int g_read_offs = 0; #define CHECKED_READ_BUFF(buff) CHECKED_READ2(sizeof(buff), &buff); +#define CHUNK_LIMIT_R 0x10960 // sizeof(old_cdc) + +#define CHECKED_READ_LIM(data) { \ + if (len > CHUNK_LIMIT_R) \ + R_ERROR_RETURN("chunk size over limit."); \ + CHECKED_READ(len, data); \ +} + static int state_load(void *file) { unsigned char buff_m68k[0x60], buff_s68k[0x60]; unsigned char buff_z80[Z80_STATE_SIZE]; unsigned char buff_sh2[SH2_STATE_SIZE]; - unsigned char buff[0x40]; + unsigned char *buf = NULL; unsigned char chunk; void *ym2612_regs; + int len_check; + int retval = -1; char header[8]; int ver, len; @@ -405,6 +434,10 @@ static int state_load(void *file) memset(buff_s68k, 0, sizeof(buff_s68k)); memset(buff_z80, 0, sizeof(buff_z80)); + buf = malloc(CHUNK_LIMIT_R); + if (buf == NULL) + return -1; + g_read_offs = 0; CHECKED_READ(8, header); if (strncmp(header, "PicoSMCD", 8) && strncmp(header, "PicoSEXT", 8)) @@ -416,6 +449,7 @@ static int state_load(void *file) while (!areaEof(file)) { + len_check = 0; CHECKED_READ(1, &chunk); CHECKED_READ(4, &len); if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length"); @@ -465,18 +499,28 @@ static int state_load(void *file) case CHUNK_GA_REGS: CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break; case CHUNK_PCM: CHECKED_READ_BUFF(Pico_mcd->pcm); break; case CHUNK_CDD: CHECKED_READ_BUFF(Pico_mcd->cdd); break; - case CHUNK_CDC: CHECKED_READ_BUFF(Pico_mcd->cdc); break; case CHUNK_SCD: CHECKED_READ_BUFF(Pico_mcd->scd); break; case CHUNK_MISC_CD: CHECKED_READ_BUFF(Pico_mcd->m); break; case CHUNK_CD_EVT: - CHECKED_READ_BUFF(buff); - memcpy(pcd_event_times, buff, sizeof(pcd_event_times)); + CHECKED_READ2(0x40, buf); + memcpy(pcd_event_times, buf, sizeof(pcd_event_times)); break; case CHUNK_CD_GFX: - CHECKED_READ2(0x18, buff); - gfx_context_load(buff); + CHECKED_READ_LIM(buf); + len_check = gfx_context_load(buf); + break; + + case CHUNK_CD_CDC: + CHECKED_READ_LIM(buf); + len_check = cdc_context_load(buf); + break; + + // old, to be removed: + case CHUNK_CDC: + CHECKED_READ_LIM(buf); + cdc_context_load_old(buf); break; // 32x stuff @@ -504,8 +548,8 @@ static int state_load(void *file) case CHUNK_32XPAL: CHECKED_READ_BUFF(Pico32xMem->pal); break; case CHUNK_32X_EVT: - CHECKED_READ_BUFF(buff); - memcpy(p32x_event_times, buff, sizeof(p32x_event_times)); + CHECKED_READ2(0x40, buf); + memcpy(p32x_event_times, buf, sizeof(p32x_event_times)); break; #endif default: @@ -523,7 +567,10 @@ static int state_load(void *file) areaSeek(file, len, SEEK_CUR); break; } -breakswitch:; +breakswitch: + if (len_check != 0 && len_check != len) + elprintf(EL_STATUS, "load_state: chunk %d has bad len %d/%d", + len, len_check); } readend: @@ -554,7 +601,11 @@ readend: cdda_start_play(); } - return 0; + retval = 0; + +out: + free(buf); + return retval; } static int state_load_gfx(void *file) @@ -608,6 +659,7 @@ static int state_load_gfx(void *file) } } +out: readend: return 0; } diff --git a/platform/base_readme.txt b/platform/base_readme.txt index 31d3b71b..175bcc1b 100644 --- a/platform/base_readme.txt +++ b/platform/base_readme.txt @@ -519,7 +519,7 @@ Texas Instruments SN76489 / SN76496 programmable tone/noise generator Homepage: http://www.mame.net/ Eke -CD graphics processor implementation (from Genesis Plus GX) +CD graphics processor and CD controller implementation (from Genesis Plus GX) Stephane Dallongeville Gens, MD/Mega CD/32X emulator. Some Sega CD code is based on this emu. @@ -565,6 +565,11 @@ Additional thanks Changelog --------- +1.91 (2013-10-) + + Switched to CD controller code from Eke's Genesis Plus GX. + * Fixed overflow issue where cd emulation would break after + ~10 minutes of gameplay + 1.90 (2013-09-24) + 32X+CD emulation has been implemented. + CD graphics processor code has been replaced with much cleaner Eke's diff --git a/platform/common/common.mak b/platform/common/common.mak index 3a836e15..c651bcad 100644 --- a/platform/common/common.mak +++ b/platform/common/common.mak @@ -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 -- 2.39.5