mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 15:27:46 -04:00
lowercasing filenames, part3
git-svn-id: file:///home/notaz/opt/svn/PicoDrive@576 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
parent
d158df697d
commit
1cfc5cc4ce
71 changed files with 0 additions and 0 deletions
624
pico/cd/LC89510.c
Normal file
624
pico/cd/LC89510.c
Normal file
|
@ -0,0 +1,624 @@
|
|||
/***********************************************************
|
||||
* *
|
||||
* 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 (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] & (1<<5))
|
||||
{
|
||||
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]);
|
||||
}
|
||||
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] & (1<<4))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
135
pico/cd/LC89510.h
Normal file
135
pico/cd/LC89510.h
Normal file
|
@ -0,0 +1,135 @@
|
|||
/***********************************************************
|
||||
* *
|
||||
* This source 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 *
|
||||
* *
|
||||
***********************************************************/
|
||||
|
||||
#ifndef _LC89510_H
|
||||
#define _LC89510_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
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
|
||||
// unsigned short Control; // 36
|
||||
// unsigned short Cur_Comm;// unused
|
||||
|
||||
// "Receive status"
|
||||
unsigned short Status;
|
||||
unsigned short Minute;
|
||||
unsigned short Seconde;
|
||||
unsigned short Frame;
|
||||
unsigned char Ext;
|
||||
unsigned char pad[3];
|
||||
} 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
332
pico/cd/area.c
Normal file
332
pico/cd/area.c
Normal file
|
@ -0,0 +1,332 @@
|
|||
// Savestate handling for emulated Sega/Mega CD machine.
|
||||
// (c) Copyright 2007, Grazvydas "notaz" Ignotas
|
||||
|
||||
|
||||
#include "../pico_int.h"
|
||||
|
||||
// ym2612
|
||||
#include "../sound/ym2612.h"
|
||||
|
||||
// sn76496
|
||||
extern int *sn76496_regs;
|
||||
|
||||
carthw_state_chunk *carthw_chunks;
|
||||
void (*PicoStateProgressCB)(const char *str) = 0;
|
||||
|
||||
|
||||
typedef enum {
|
||||
CHUNK_M68K = 1,
|
||||
CHUNK_RAM,
|
||||
CHUNK_VRAM,
|
||||
CHUNK_ZRAM,
|
||||
CHUNK_CRAM, // 5
|
||||
CHUNK_VSRAM,
|
||||
CHUNK_MISC,
|
||||
CHUNK_VIDEO,
|
||||
CHUNK_Z80,
|
||||
CHUNK_PSG, // 10
|
||||
CHUNK_FM,
|
||||
// CD stuff
|
||||
CHUNK_S68K,
|
||||
CHUNK_PRG_RAM,
|
||||
CHUNK_WORD_RAM,
|
||||
CHUNK_PCM_RAM, // 15
|
||||
CHUNK_BRAM,
|
||||
CHUNK_GA_REGS,
|
||||
CHUNK_PCM,
|
||||
CHUNK_CDC,
|
||||
CHUNK_CDD, // 20
|
||||
CHUNK_SCD,
|
||||
CHUNK_RC,
|
||||
CHUNK_MISC_CD,
|
||||
CHUNK_DEFAULT_COUNT
|
||||
// CHUNK_CARTHW = 64, // defined in PicoInt
|
||||
} chunk_name_e;
|
||||
|
||||
|
||||
static char *chunk_names[] = {
|
||||
"INVALID!",
|
||||
"Saving.. M68K state",
|
||||
"Saving.. RAM",
|
||||
"Saving.. VRAM",
|
||||
"Saving.. ZRAM",
|
||||
"Saving.. CRAM", // 5
|
||||
"Saving.. VSRAM",
|
||||
"Saving.. emu state",
|
||||
"Saving.. VIDEO",
|
||||
"Saving.. Z80 state",
|
||||
"Saving.. PSG", // 10
|
||||
"Saving.. FM",
|
||||
// CD stuff
|
||||
"Saving.. S68K state",
|
||||
"Saving.. PRG_RAM",
|
||||
"Saving.. WORD_RAM",
|
||||
"Saving.. PCM_RAM", // 15
|
||||
"Saving.. BRAM",
|
||||
"Saving.. GATE ARRAY regs",
|
||||
"Saving.. PCM state",
|
||||
"Saving.. CDC",
|
||||
"Saving.. CDD", // 20
|
||||
"Saving.. SCD",
|
||||
"Saving.. GFX chip",
|
||||
"Saving.. MCD state",
|
||||
};
|
||||
|
||||
|
||||
static int write_chunk(chunk_name_e name, int len, void *data, void *file)
|
||||
{
|
||||
size_t bwritten = 0;
|
||||
bwritten += areaWrite(&name, 1, 1, file);
|
||||
bwritten += areaWrite(&len, 1, 4, file);
|
||||
bwritten += areaWrite(data, 1, len, file);
|
||||
|
||||
return (bwritten == len + 4 + 1);
|
||||
}
|
||||
|
||||
|
||||
#define CHECKED_WRITE(name,len,data) { \
|
||||
if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT) \
|
||||
PicoStateProgressCB(chunk_names[name]); \
|
||||
if (!write_chunk(name, len, data, file)) return 1; \
|
||||
}
|
||||
|
||||
#define CHECKED_WRITE_BUFF(name,buff) { \
|
||||
if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT) \
|
||||
PicoStateProgressCB(chunk_names[name]); \
|
||||
if (!write_chunk(name, sizeof(buff), &buff, file)) return 1; \
|
||||
}
|
||||
|
||||
PICO_INTERNAL int PicoCdSaveState(void *file)
|
||||
{
|
||||
unsigned char buff[0x60];
|
||||
void *ym2612_regs = YM2612GetRegs();
|
||||
|
||||
areaWrite("PicoSEXT", 1, 8, file);
|
||||
areaWrite(&PicoVer, 1, 4, file);
|
||||
|
||||
memset(buff, 0, sizeof(buff));
|
||||
PicoAreaPackCpu(buff, 0);
|
||||
CHECKED_WRITE_BUFF(CHUNK_M68K, buff);
|
||||
CHECKED_WRITE_BUFF(CHUNK_RAM, Pico.ram);
|
||||
CHECKED_WRITE_BUFF(CHUNK_VRAM, Pico.vram);
|
||||
CHECKED_WRITE_BUFF(CHUNK_ZRAM, Pico.zram);
|
||||
CHECKED_WRITE_BUFF(CHUNK_CRAM, Pico.cram);
|
||||
CHECKED_WRITE_BUFF(CHUNK_VSRAM, Pico.vsram);
|
||||
CHECKED_WRITE_BUFF(CHUNK_MISC, Pico.m);
|
||||
CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video);
|
||||
if (PicoOpt&7) {
|
||||
memset(buff, 0, sizeof(buff));
|
||||
z80_pack(buff);
|
||||
CHECKED_WRITE_BUFF(CHUNK_Z80, buff);
|
||||
}
|
||||
if (PicoOpt&3)
|
||||
CHECKED_WRITE(CHUNK_PSG, 28*4, sn76496_regs);
|
||||
if (PicoOpt&1) {
|
||||
ym2612_pack_state();
|
||||
CHECKED_WRITE(CHUNK_FM, 0x200+4, ym2612_regs);
|
||||
}
|
||||
|
||||
if (PicoAHW & PAHW_MCD)
|
||||
{
|
||||
memset(buff, 0, sizeof(buff));
|
||||
PicoAreaPackCpu(buff, 1);
|
||||
if (Pico_mcd->s68k_regs[3]&4) // 1M mode?
|
||||
wram_1M_to_2M(Pico_mcd->word_ram2M);
|
||||
Pico_mcd->m.hint_vector = *(unsigned short *)(Pico_mcd->bios + 0x72);
|
||||
|
||||
CHECKED_WRITE_BUFF(CHUNK_S68K, buff);
|
||||
CHECKED_WRITE_BUFF(CHUNK_PRG_RAM, Pico_mcd->prg_ram);
|
||||
CHECKED_WRITE_BUFF(CHUNK_WORD_RAM, Pico_mcd->word_ram2M); // in 2M format
|
||||
CHECKED_WRITE_BUFF(CHUNK_PCM_RAM, Pico_mcd->pcm_ram);
|
||||
CHECKED_WRITE_BUFF(CHUNK_BRAM, Pico_mcd->bram);
|
||||
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_RC, Pico_mcd->rot_comp);
|
||||
CHECKED_WRITE_BUFF(CHUNK_MISC_CD, Pico_mcd->m);
|
||||
|
||||
if (Pico_mcd->s68k_regs[3]&4) // convert back
|
||||
wram_2M_to_1M(Pico_mcd->word_ram2M);
|
||||
}
|
||||
|
||||
if (carthw_chunks != NULL)
|
||||
{
|
||||
carthw_state_chunk *chwc;
|
||||
if (PicoStateProgressCB)
|
||||
PicoStateProgressCB("Saving.. cart hw state");
|
||||
for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++)
|
||||
CHECKED_WRITE(chwc->chunk, chwc->size, chwc->ptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int g_read_offs = 0;
|
||||
|
||||
#define R_ERROR_RETURN(error) \
|
||||
{ \
|
||||
elprintf(EL_STATUS, "PicoCdLoadState @ %x: " error, g_read_offs); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
// when is eof really set?
|
||||
#define CHECKED_READ(len,data) \
|
||||
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;
|
||||
|
||||
#define CHECKED_READ2(len2,data) \
|
||||
if (len2 != len) { \
|
||||
elprintf(EL_STATUS, "unexpected len %i, wanted %i (%s)", len, len2, #len2); \
|
||||
if (len > len2) R_ERROR_RETURN("failed."); \
|
||||
/* else read anyway and hope for the best.. */ \
|
||||
} \
|
||||
CHECKED_READ(len, data)
|
||||
|
||||
#define CHECKED_READ_BUFF(buff) CHECKED_READ2(sizeof(buff), &buff);
|
||||
|
||||
PICO_INTERNAL int PicoCdLoadState(void *file)
|
||||
{
|
||||
unsigned char buff[0x60], buff_m68k[0x60], buff_s68k[0x60];
|
||||
int ver, len;
|
||||
void *ym2612_regs = YM2612GetRegs();
|
||||
|
||||
g_read_offs = 0;
|
||||
CHECKED_READ(8, buff);
|
||||
if (strncmp((char *)buff, "PicoSMCD", 8) && strncmp((char *)buff, "PicoSEXT", 8))
|
||||
R_ERROR_RETURN("bad header");
|
||||
CHECKED_READ(4, &ver);
|
||||
|
||||
while (!areaEof(file))
|
||||
{
|
||||
CHECKED_READ(1, buff);
|
||||
CHECKED_READ(4, &len);
|
||||
if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");
|
||||
if (buff[0] > CHUNK_FM && buff[0] <= CHUNK_MISC_CD && !(PicoAHW & PAHW_MCD))
|
||||
R_ERROR_RETURN("cd chunk in non CD state?");
|
||||
|
||||
switch (buff[0])
|
||||
{
|
||||
case CHUNK_M68K:
|
||||
CHECKED_READ_BUFF(buff_m68k);
|
||||
break;
|
||||
|
||||
case CHUNK_Z80:
|
||||
CHECKED_READ_BUFF(buff);
|
||||
z80_unpack(buff);
|
||||
break;
|
||||
|
||||
case CHUNK_RAM: CHECKED_READ_BUFF(Pico.ram); break;
|
||||
case CHUNK_VRAM: CHECKED_READ_BUFF(Pico.vram); break;
|
||||
case CHUNK_ZRAM: CHECKED_READ_BUFF(Pico.zram); break;
|
||||
case CHUNK_CRAM: CHECKED_READ_BUFF(Pico.cram); break;
|
||||
case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); break;
|
||||
case CHUNK_MISC: CHECKED_READ_BUFF(Pico.m); break;
|
||||
case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); break;
|
||||
case CHUNK_PSG: CHECKED_READ2(28*4, sn76496_regs); break;
|
||||
case CHUNK_FM:
|
||||
CHECKED_READ2(0x200+4, ym2612_regs);
|
||||
ym2612_unpack_state();
|
||||
break;
|
||||
|
||||
// cd stuff
|
||||
case CHUNK_S68K:
|
||||
CHECKED_READ_BUFF(buff_s68k);
|
||||
break;
|
||||
|
||||
case CHUNK_PRG_RAM: CHECKED_READ_BUFF(Pico_mcd->prg_ram); break;
|
||||
case CHUNK_WORD_RAM: CHECKED_READ_BUFF(Pico_mcd->word_ram2M); break;
|
||||
case CHUNK_PCM_RAM: CHECKED_READ_BUFF(Pico_mcd->pcm_ram); break;
|
||||
case CHUNK_BRAM: CHECKED_READ_BUFF(Pico_mcd->bram); break;
|
||||
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_RC: CHECKED_READ_BUFF(Pico_mcd->rot_comp); break;
|
||||
case CHUNK_MISC_CD: CHECKED_READ_BUFF(Pico_mcd->m); break;
|
||||
|
||||
default:
|
||||
if (carthw_chunks != NULL)
|
||||
{
|
||||
carthw_state_chunk *chwc;
|
||||
for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++) {
|
||||
if (chwc->chunk == buff[0]) {
|
||||
CHECKED_READ2(chwc->size, chwc->ptr);
|
||||
goto breakswitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
elprintf(EL_STATUS, "PicoCdLoadState: skipping unknown chunk %i of size %i", buff[0], len);
|
||||
areaSeek(file, len, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
breakswitch:;
|
||||
}
|
||||
|
||||
readend:
|
||||
if (PicoAHW & PAHW_MCD)
|
||||
{
|
||||
/* after load events */
|
||||
if (Pico_mcd->s68k_regs[3]&4) // 1M mode?
|
||||
wram_2M_to_1M(Pico_mcd->word_ram2M);
|
||||
PicoMemResetCD(Pico_mcd->s68k_regs[3]);
|
||||
#ifdef _ASM_CD_MEMORY_C
|
||||
if (Pico_mcd->s68k_regs[3]&4)
|
||||
PicoMemResetCDdecode(Pico_mcd->s68k_regs[3]);
|
||||
#endif
|
||||
if (!(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))
|
||||
cdda_start_play();
|
||||
// restore hint vector
|
||||
*(unsigned short *)(Pico_mcd->bios + 0x72) = Pico_mcd->m.hint_vector;
|
||||
|
||||
// must unpack after other CD stuff is loaded
|
||||
PicoAreaUnpackCpu(buff_s68k, 1);
|
||||
}
|
||||
PicoAreaUnpackCpu(buff_m68k, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PicoCdLoadStateGfx(void *file)
|
||||
{
|
||||
int ver, len, found = 0;
|
||||
char buff[8];
|
||||
|
||||
g_read_offs = 0;
|
||||
CHECKED_READ(8, buff);
|
||||
if (strncmp((char *)buff, "PicoSMCD", 8) && strncmp((char *)buff, "PicoSEXT", 8))
|
||||
R_ERROR_RETURN("bad header");
|
||||
CHECKED_READ(4, &ver);
|
||||
|
||||
while (!areaEof(file) && found < 4)
|
||||
{
|
||||
CHECKED_READ(1, buff);
|
||||
CHECKED_READ(4, &len);
|
||||
if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");
|
||||
if (buff[0] > CHUNK_FM && buff[0] <= CHUNK_MISC_CD && !(PicoAHW & PAHW_MCD))
|
||||
R_ERROR_RETURN("cd chunk in non CD state?");
|
||||
|
||||
switch (buff[0])
|
||||
{
|
||||
case CHUNK_VRAM: CHECKED_READ_BUFF(Pico.vram); found++; break;
|
||||
case CHUNK_CRAM: CHECKED_READ_BUFF(Pico.cram); found++; break;
|
||||
case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); found++; break;
|
||||
case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); found++; break;
|
||||
default:
|
||||
areaSeek(file, len, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
readend:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
144
pico/cd/buffering.c
Normal file
144
pico/cd/buffering.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
// Buffering handling
|
||||
// (c) Copyright 2007, Grazvydas "notaz" Ignotas
|
||||
|
||||
#include "../pico_int.h"
|
||||
|
||||
int PicoCDBuffers = 0;
|
||||
static unsigned char *cd_buffer = NULL;
|
||||
static int prev_lba = 0x80000000;
|
||||
|
||||
static int hits, reads;
|
||||
|
||||
|
||||
void PicoCDBufferInit(void)
|
||||
{
|
||||
void *tmp = NULL;
|
||||
|
||||
prev_lba = 0x80000000;
|
||||
hits = reads = 0;
|
||||
|
||||
if (PicoCDBuffers <= 1) {
|
||||
PicoCDBuffers = 0;
|
||||
return; /* buffering off */
|
||||
}
|
||||
|
||||
/* try alloc'ing until we succeed */
|
||||
while (PicoCDBuffers > 0)
|
||||
{
|
||||
tmp = realloc(cd_buffer, PicoCDBuffers * 2048 + 304);
|
||||
if (tmp != NULL) break;
|
||||
PicoCDBuffers >>= 1;
|
||||
}
|
||||
|
||||
if (PicoCDBuffers <= 0) return; /* buffering became off */
|
||||
|
||||
cd_buffer = tmp;
|
||||
}
|
||||
|
||||
|
||||
void PicoCDBufferFree(void)
|
||||
{
|
||||
if (cd_buffer) {
|
||||
free(cd_buffer);
|
||||
cd_buffer = NULL;
|
||||
}
|
||||
if (reads)
|
||||
elprintf(EL_STATUS, "CD buffer hits: %i/%i (%i%%)\n", hits, reads, hits * 100 / reads);
|
||||
}
|
||||
|
||||
|
||||
void PicoCDBufferFlush(void)
|
||||
{
|
||||
prev_lba = 0x80000000;
|
||||
}
|
||||
|
||||
|
||||
/* this is was a try to fight slow SD access of GP2X */
|
||||
PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba)
|
||||
{
|
||||
int is_bin, offs, read_len, moved = 0;
|
||||
reads++;
|
||||
|
||||
is_bin = Pico_mcd->TOC.Tracks[0].ftype == TYPE_BIN;
|
||||
|
||||
if (PicoCDBuffers <= 0)
|
||||
{
|
||||
/* no buffering */
|
||||
int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
|
||||
pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
|
||||
pm_read(dest, 2048, Pico_mcd->TOC.Tracks[0].F);
|
||||
return;
|
||||
}
|
||||
|
||||
/* hit? */
|
||||
offs = lba - prev_lba;
|
||||
if (offs >= 0 && offs < PicoCDBuffers)
|
||||
{
|
||||
hits++;
|
||||
if (offs == 0) dprintf("CD buffer seek to old %i -> %i\n", prev_lba, lba);
|
||||
memcpy32(dest, (int *)(cd_buffer + offs*2048), 2048/4);
|
||||
return;
|
||||
}
|
||||
|
||||
if (prev_lba + PicoCDBuffers != lba)
|
||||
{
|
||||
int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
|
||||
dprintf("CD buffer seek %i -> %i\n", prev_lba, lba);
|
||||
pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
|
||||
}
|
||||
|
||||
dprintf("CD buffer miss %i -> %i\n", prev_lba, lba);
|
||||
|
||||
if (lba < prev_lba && prev_lba - lba < PicoCDBuffers)
|
||||
{
|
||||
read_len = prev_lba - lba;
|
||||
dprintf("CD buffer move=%i, read_len=%i", PicoCDBuffers - read_len, read_len);
|
||||
memmove(cd_buffer + read_len*2048, cd_buffer, (PicoCDBuffers - read_len)*2048);
|
||||
moved = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_len = PicoCDBuffers;
|
||||
}
|
||||
|
||||
if (PicoMessage != NULL && read_len >= 512)
|
||||
{
|
||||
PicoMessage("Buffering data...");
|
||||
}
|
||||
|
||||
if (is_bin)
|
||||
{
|
||||
int i = 0;
|
||||
#if REDUCE_IO_CALLS
|
||||
int bufs = (read_len*2048) / (2048+304);
|
||||
pm_read(cd_buffer, bufs*(2048+304), Pico_mcd->TOC.Tracks[0].F);
|
||||
for (i = 1; i < bufs; i++)
|
||||
// should really use memmove here, but my memcpy32 implementation is also suitable here
|
||||
memcpy32((int *)(cd_buffer + i*2048), (int *)(cd_buffer + i*(2048+304)), 2048/4);
|
||||
#endif
|
||||
for (; i < read_len - 1; i++)
|
||||
{
|
||||
pm_read(cd_buffer + i*2048, 2048 + 304, Pico_mcd->TOC.Tracks[0].F);
|
||||
// pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR); // seeking is slower, in PSP case even more
|
||||
}
|
||||
// further data might be moved, do not overwrite
|
||||
pm_read(cd_buffer + i*2048, 2048, Pico_mcd->TOC.Tracks[0].F);
|
||||
pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR);
|
||||
}
|
||||
else
|
||||
{
|
||||
pm_read(cd_buffer, read_len*2048, Pico_mcd->TOC.Tracks[0].F);
|
||||
}
|
||||
memcpy32(dest, (int *) cd_buffer, 2048/4);
|
||||
prev_lba = lba;
|
||||
|
||||
if (moved)
|
||||
{
|
||||
/* file pointer must point to the same data in file, as would-be data after our buffer */
|
||||
int where_seek;
|
||||
lba += PicoCDBuffers;
|
||||
where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
|
||||
pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
374
pico/cd/cd_file.c
Normal file
374
pico/cd/cd_file.c
Normal file
|
@ -0,0 +1,374 @@
|
|||
/***********************************************************
|
||||
* *
|
||||
* This source 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"
|
||||
#include "cd_file.h"
|
||||
#include "cue.h"
|
||||
|
||||
//#define cdprintf(f,...) printf(f "\n",##__VA_ARGS__) // tmp
|
||||
|
||||
static int audio_track_mp3(const char *fname, int index)
|
||||
{
|
||||
_scd_track *Tracks = Pico_mcd->TOC.Tracks;
|
||||
FILE *tmp_file;
|
||||
int fs, ret;
|
||||
|
||||
tmp_file = fopen(fname, "rb");
|
||||
if (tmp_file == NULL)
|
||||
return -1;
|
||||
|
||||
ret = fseek(tmp_file, 0, SEEK_END);
|
||||
fs = ftell(tmp_file); // used to calculate length
|
||||
fseek(tmp_file, 0, SEEK_SET);
|
||||
|
||||
#if DONT_OPEN_MANY_FILES
|
||||
// some systems (like PSP) can't have many open files at a time,
|
||||
// so we work with their names instead.
|
||||
fclose(tmp_file);
|
||||
tmp_file = (void *) strdup(fname);
|
||||
#endif
|
||||
Tracks[index].KBtps = (short) mp3_get_bitrate(tmp_file, fs);
|
||||
Tracks[index].KBtps >>= 3;
|
||||
if (ret != 0 || Tracks[index].KBtps <= 0)
|
||||
{
|
||||
elprintf(EL_STATUS, "track %2i: mp3 bitrate %i", index+1, Tracks[index].KBtps);
|
||||
#if !DONT_OPEN_MANY_FILES
|
||||
fclose(tmp_file);
|
||||
#else
|
||||
free(tmp_file);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
Tracks[index].F = tmp_file;
|
||||
|
||||
// MP3 File
|
||||
Tracks[index].ftype = TYPE_MP3;
|
||||
fs *= 75;
|
||||
fs /= Tracks[index].KBtps * 1000;
|
||||
Tracks[index].Length = fs;
|
||||
Tracks[index].Offset = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PICO_INTERNAL int Load_CD_Image(const char *cd_img_name, cd_img_type type)
|
||||
{
|
||||
int i, j, num_track, Cur_LBA, index, ret, iso_name_len, missed, cd_img_sectors;
|
||||
_scd_track *Tracks = Pico_mcd->TOC.Tracks;
|
||||
char tmp_name[1024], tmp_ext[10];
|
||||
cue_data_t *cue_data = NULL;
|
||||
pm_file *pmf;
|
||||
static char *exts[] = {
|
||||
"%02d.mp3", " %02d.mp3", "-%02d.mp3", "_%02d.mp3", " - %02d.mp3",
|
||||
"%d.mp3", " %d.mp3", "-%d.mp3", "_%d.mp3", " - %d.mp3",
|
||||
#if CASE_SENSITIVE_FS
|
||||
"%02d.MP3", " %02d.MP3", "-%02d.MP3", "_%02d.MP3", " - %02d.MP3",
|
||||
#endif
|
||||
};
|
||||
|
||||
if (PicoCDLoadProgressCB != NULL) PicoCDLoadProgressCB(1);
|
||||
|
||||
Unload_ISO();
|
||||
|
||||
/* is this .cue? */
|
||||
ret = strlen(cd_img_name);
|
||||
if (ret >= 3 && strcasecmp(cd_img_name + ret - 3, "cue") == 0)
|
||||
cue_data = cue_parse(cd_img_name);
|
||||
if (cue_data != NULL)
|
||||
cd_img_name = cue_data->tracks[1].fname;
|
||||
|
||||
Tracks[0].ftype = type == CIT_BIN ? TYPE_BIN : TYPE_ISO;
|
||||
|
||||
Tracks[0].F = pmf = pm_open(cd_img_name);
|
||||
if (Tracks[0].F == NULL)
|
||||
{
|
||||
Tracks[0].ftype = 0;
|
||||
Tracks[0].Length = 0;
|
||||
if (cue_data != NULL)
|
||||
cue_destroy(cue_data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (Tracks[0].ftype == TYPE_ISO)
|
||||
cd_img_sectors = pmf->size >>= 11; // size in sectors
|
||||
else cd_img_sectors = pmf->size /= 2352;
|
||||
Tracks[0].Offset = 0;
|
||||
|
||||
Tracks[0].MSF.M = 0; // minutes
|
||||
Tracks[0].MSF.S = 2; // seconds
|
||||
Tracks[0].MSF.F = 0; // frames
|
||||
|
||||
elprintf(EL_STATUS, "Track 1: %02d:%02d:%02d %9i DATA",
|
||||
Tracks[0].MSF.M, Tracks[0].MSF.S, Tracks[0].MSF.F, Tracks[0].Length);
|
||||
|
||||
Cur_LBA = Tracks[0].Length = cd_img_sectors;
|
||||
|
||||
if (cue_data != NULL)
|
||||
{
|
||||
if (cue_data->tracks[2].fname == NULL) { // NULL means track2 is in same file as track1
|
||||
Cur_LBA = Tracks[0].Length = cue_data->tracks[2].sector_offset;
|
||||
}
|
||||
i = 100 / cue_data->track_count+1;
|
||||
for (num_track = 2; num_track <= cue_data->track_count; num_track++)
|
||||
{
|
||||
if (PicoCDLoadProgressCB != NULL) PicoCDLoadProgressCB(i * num_track);
|
||||
index = num_track - 1;
|
||||
Cur_LBA += cue_data->tracks[num_track].pregap;
|
||||
if (cue_data->tracks[num_track].type == CT_MP3) {
|
||||
ret = audio_track_mp3(cue_data->tracks[num_track].fname, index);
|
||||
if (ret != 0) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Tracks[index].ftype = cue_data->tracks[num_track].type;
|
||||
if (cue_data->tracks[num_track].fname != NULL)
|
||||
{
|
||||
pm_file *pmfn = pm_open(cue_data->tracks[num_track].fname);
|
||||
if (pmfn != NULL)
|
||||
{
|
||||
// addume raw, ignore header for wav..
|
||||
Tracks[index].F = pmfn;
|
||||
Tracks[index].Length = pmfn->size / 2352;
|
||||
Tracks[index].Offset = cue_data->tracks[num_track].sector_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
elprintf(EL_STATUS, "track %2i (%s): can't determine length",
|
||||
num_track, cue_data->tracks[num_track].fname);
|
||||
Tracks[index].Length = 2*75;
|
||||
Tracks[index].Offset = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num_track < cue_data->track_count)
|
||||
Tracks[index].Length = cue_data->tracks[num_track+1].sector_offset -
|
||||
cue_data->tracks[num_track].sector_offset;
|
||||
else
|
||||
Tracks[index].Length = cd_img_sectors - cue_data->tracks[num_track].sector_offset;
|
||||
Tracks[index].Offset = cue_data->tracks[num_track].sector_offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (cue_data->tracks[num_track].sector_xlength != 0)
|
||||
// overriden by custom cue command
|
||||
Tracks[index].Length = cue_data->tracks[num_track].sector_xlength;
|
||||
|
||||
LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
|
||||
Cur_LBA += Tracks[index].Length;
|
||||
|
||||
elprintf(EL_STATUS, "Track %2i: %02d:%02d:%02d %9i AUDIO - %s", num_track, Tracks[index].MSF.M,
|
||||
Tracks[index].MSF.S, Tracks[index].MSF.F, Tracks[index].Length,
|
||||
cue_data->tracks[num_track].fname);
|
||||
}
|
||||
cue_destroy(cue_data);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* mp3 track autosearch, Gens-like */
|
||||
iso_name_len = strlen(cd_img_name);
|
||||
if (iso_name_len >= sizeof(tmp_name))
|
||||
iso_name_len = sizeof(tmp_name) - 1;
|
||||
|
||||
for (num_track = 2, i = 0, missed = 0; i < 100 && missed < 4; i++)
|
||||
{
|
||||
if (PicoCDLoadProgressCB != NULL && i > 1) PicoCDLoadProgressCB(i + (100-i)*missed/4);
|
||||
|
||||
for (j = 0; j < sizeof(exts)/sizeof(char *); j++)
|
||||
{
|
||||
int ext_len;
|
||||
sprintf(tmp_ext, exts[j], i);
|
||||
ext_len = strlen(tmp_ext);
|
||||
|
||||
memcpy(tmp_name, cd_img_name, iso_name_len + 1);
|
||||
tmp_name[iso_name_len - 4] = 0;
|
||||
strcat(tmp_name, tmp_ext);
|
||||
|
||||
index = num_track - 1;
|
||||
ret = audio_track_mp3(tmp_name, index);
|
||||
if (ret != 0 && i > 1 && iso_name_len > ext_len) {
|
||||
tmp_name[iso_name_len - ext_len] = 0;
|
||||
strcat(tmp_name, tmp_ext);
|
||||
ret = audio_track_mp3(tmp_name, index);
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
|
||||
Cur_LBA += Tracks[index].Length;
|
||||
|
||||
elprintf(EL_STATUS, "Track %2i: %02d:%02d:%02d %9i AUDIO - %s", num_track, Tracks[index].MSF.M,
|
||||
Tracks[index].MSF.S, Tracks[index].MSF.F, Tracks[index].Length, tmp_name);
|
||||
|
||||
num_track++;
|
||||
missed = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret != 0 && i > 1) missed++;
|
||||
}
|
||||
|
||||
finish:
|
||||
Pico_mcd->TOC.Last_Track = num_track - 1;
|
||||
|
||||
index = num_track - 1;
|
||||
|
||||
LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
|
||||
|
||||
elprintf(EL_STATUS, "End CD - %02d:%02d:%02d\n", Tracks[index].MSF.M,
|
||||
Tracks[index].MSF.S, Tracks[index].MSF.F);
|
||||
|
||||
if (PicoCDLoadProgressCB != NULL) PicoCDLoadProgressCB(100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL void Unload_ISO(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (Pico_mcd == NULL) return;
|
||||
|
||||
if (Pico_mcd->TOC.Tracks[0].F) pm_close(Pico_mcd->TOC.Tracks[0].F);
|
||||
|
||||
for(i = 1; i < 100; i++)
|
||||
{
|
||||
if (Pico_mcd->TOC.Tracks[i].F != NULL)
|
||||
{
|
||||
if (Pico_mcd->TOC.Tracks[i].ftype == TYPE_MP3)
|
||||
#if DONT_OPEN_MANY_FILES
|
||||
free(Pico_mcd->TOC.Tracks[i].F);
|
||||
#else
|
||||
fclose(Pico_mcd->TOC.Tracks[i].F);
|
||||
#endif
|
||||
else
|
||||
pm_close(Pico_mcd->TOC.Tracks[i].F);
|
||||
}
|
||||
}
|
||||
memset(Pico_mcd->TOC.Tracks, 0, sizeof(Pico_mcd->TOC.Tracks));
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int FILE_Read_One_LBA_CDC(void)
|
||||
{
|
||||
if (Pico_mcd->s68k_regs[0x36] & 1) // DATA
|
||||
{
|
||||
if (Pico_mcd->TOC.Tracks[0].F == NULL) return -1;
|
||||
|
||||
// moved below..
|
||||
//fseek(Pico_mcd->TOC.Tracks[0].F, where_read, SEEK_SET);
|
||||
//fread(cp_buf, 1, 2048, Pico_mcd->TOC.Tracks[0].F);
|
||||
|
||||
cdprintf("Read file CDC 1 data sector :\n");
|
||||
}
|
||||
else // AUDIO
|
||||
{
|
||||
cdprintf("Read file CDC 1 audio sector :\n");
|
||||
}
|
||||
|
||||
// Update CDC stuff
|
||||
|
||||
CDC_Update_Header();
|
||||
|
||||
if (Pico_mcd->s68k_regs[0x36] & 1) // DATA track
|
||||
{
|
||||
if (Pico_mcd->cdc.CTRL.B.B0 & 0x80) // DECEN = decoding enable
|
||||
{
|
||||
if (Pico_mcd->cdc.CTRL.B.B0 & 0x04) // WRRQ : this bit enable write to buffer
|
||||
{
|
||||
int where_read = 0;
|
||||
|
||||
// CAUTION : lookahead bit not implemented
|
||||
|
||||
if (Pico_mcd->scd.Cur_LBA < 0)
|
||||
where_read = 0;
|
||||
else if (Pico_mcd->scd.Cur_LBA >= Pico_mcd->TOC.Tracks[0].Length)
|
||||
where_read = Pico_mcd->TOC.Tracks[0].Length - 1;
|
||||
else where_read = Pico_mcd->scd.Cur_LBA;
|
||||
|
||||
Pico_mcd->scd.Cur_LBA++;
|
||||
|
||||
Pico_mcd->cdc.WA.N = (Pico_mcd->cdc.WA.N + 2352) & 0x7FFF; // add one sector to WA
|
||||
Pico_mcd->cdc.PT.N = (Pico_mcd->cdc.PT.N + 2352) & 0x7FFF;
|
||||
|
||||
*(unsigned int *)(Pico_mcd->cdc.Buffer + Pico_mcd->cdc.PT.N) = Pico_mcd->cdc.HEAD.N;
|
||||
//memcpy(&Pico_mcd->cdc.Buffer[Pico_mcd->cdc.PT.N + 4], cp_buf, 2048);
|
||||
|
||||
//pm_seek(Pico_mcd->TOC.Tracks[0].F, where_read, SEEK_SET);
|
||||
//pm_read(Pico_mcd->cdc.Buffer + Pico_mcd->cdc.PT.N + 4, 2048, Pico_mcd->TOC.Tracks[0].F);
|
||||
PicoCDBufferRead(Pico_mcd->cdc.Buffer + Pico_mcd->cdc.PT.N + 4, where_read);
|
||||
|
||||
cdprintf("Read -> WA = %d Buffer[%d] =", Pico_mcd->cdc.WA.N, Pico_mcd->cdc.PT.N & 0x3FFF);
|
||||
cdprintf("Header 1 = %.2X %.2X %.2X %.2X", Pico_mcd->cdc.HEAD.B.B0,
|
||||
Pico_mcd->cdc.HEAD.B.B1, Pico_mcd->cdc.HEAD.B.B2, Pico_mcd->cdc.HEAD.B.B3);
|
||||
cdprintf("Header 2 = %.2X %.2X %.2X %.2X --- %.2X %.2X\n\n",
|
||||
Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 0) & 0x3FFF],
|
||||
Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 1) & 0x3FFF],
|
||||
Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 2) & 0x3FFF],
|
||||
Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 3) & 0x3FFF],
|
||||
Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 4) & 0x3FFF],
|
||||
Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 5) & 0x3FFF]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else // music track
|
||||
{
|
||||
Pico_mcd->scd.Cur_LBA++;
|
||||
|
||||
Pico_mcd->cdc.WA.N = (Pico_mcd->cdc.WA.N + 2352) & 0x7FFF; // add one sector to WA
|
||||
Pico_mcd->cdc.PT.N = (Pico_mcd->cdc.PT.N + 2352) & 0x7FFF;
|
||||
|
||||
if (Pico_mcd->cdc.CTRL.B.B0 & 0x80) // DECEN = decoding enable
|
||||
{
|
||||
if (Pico_mcd->cdc.CTRL.B.B0 & 0x04) // WRRQ : this bit enable write to buffer
|
||||
{
|
||||
// CAUTION : lookahead bit not implemented
|
||||
|
||||
// this is pretty rough, but oh well - not much depends on this anyway
|
||||
memcpy(&Pico_mcd->cdc.Buffer[Pico_mcd->cdc.PT.N], cdda_out_buffer, 2352);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Pico_mcd->cdc.CTRL.B.B0 & 0x80) // DECEN = decoding enable
|
||||
{
|
||||
Pico_mcd->cdc.STAT.B.B0 = 0x80;
|
||||
|
||||
if (Pico_mcd->cdc.CTRL.B.B0 & 0x10) // determine form bit form sub header ?
|
||||
{
|
||||
Pico_mcd->cdc.STAT.B.B2 = Pico_mcd->cdc.CTRL.B.B1 & 0x08;
|
||||
}
|
||||
else
|
||||
{
|
||||
Pico_mcd->cdc.STAT.B.B2 = Pico_mcd->cdc.CTRL.B.B1 & 0x0C;
|
||||
}
|
||||
|
||||
if (Pico_mcd->cdc.CTRL.B.B0 & 0x02) Pico_mcd->cdc.STAT.B.B3 = 0x20; // ECC done
|
||||
else Pico_mcd->cdc.STAT.B.B3 = 0x00; // ECC not done
|
||||
|
||||
if (Pico_mcd->cdc.IFCTRL & 0x20)
|
||||
{
|
||||
if (Pico_mcd->s68k_regs[0x33] & (1<<5))
|
||||
{
|
||||
elprintf(EL_INTS, "cdc dec irq 5");
|
||||
SekInterruptS68k(5);
|
||||
}
|
||||
|
||||
Pico_mcd->cdc.IFSTAT &= ~0x20; // DEC interrupt happen
|
||||
Pico_mcd->cdc.Decode_Reg_Read = 0; // Reset read after DEC int
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
32
pico/cd/cd_file.h
Normal file
32
pico/cd/cd_file.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef _CD_FILE_H
|
||||
#define _CD_FILE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TYPE_ISO 1
|
||||
#define TYPE_BIN 2
|
||||
#define TYPE_MP3 3
|
||||
#define TYPE_WAV 4
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CIT_NOT_CD = 0,
|
||||
CIT_ISO,
|
||||
CIT_BIN,
|
||||
CIT_CUE
|
||||
}
|
||||
cd_img_type;
|
||||
|
||||
|
||||
PICO_INTERNAL int Load_CD_Image(const char *iso_name, cd_img_type type);
|
||||
PICO_INTERNAL void Unload_ISO(void);
|
||||
PICO_INTERNAL int FILE_Read_One_LBA_CDC(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
739
pico/cd/cd_sys.c
Normal file
739
pico/cd/cd_sys.c
Normal file
|
@ -0,0 +1,739 @@
|
|||
/***********************************************************
|
||||
* *
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "../pico_int.h"
|
||||
#include "cd_sys.h"
|
||||
#include "cd_file.h"
|
||||
|
||||
#define DEBUG_CD
|
||||
|
||||
#define TRAY_OPEN 0x0500 // TRAY OPEN CDD status
|
||||
#define NOCD 0x0000 // CD removed CDD status
|
||||
#define STOPPED 0x0900 // STOPPED CDD status (happen after stop or close tray command)
|
||||
#define READY 0x0400 // READY CDD status (also used for seeking)
|
||||
#define FAST_FOW 0x0300 // FAST FORWARD track CDD status
|
||||
#define FAST_REV 0x10300 // FAST REVERSE track CDD status
|
||||
#define PLAYING 0x0100 // PLAYING audio track CDD status
|
||||
|
||||
|
||||
static int CD_Present = 0;
|
||||
|
||||
|
||||
#define CHECK_TRAY_OPEN \
|
||||
if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) \
|
||||
{ \
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; \
|
||||
\
|
||||
Pico_mcd->cdd.Minute = 0; \
|
||||
Pico_mcd->cdd.Seconde = 0; \
|
||||
Pico_mcd->cdd.Frame = 0; \
|
||||
Pico_mcd->cdd.Ext = 0; \
|
||||
\
|
||||
Pico_mcd->scd.CDD_Complete = 1; \
|
||||
\
|
||||
return 2; \
|
||||
}
|
||||
|
||||
|
||||
#define CHECK_CD_PRESENT \
|
||||
if (!CD_Present) \
|
||||
{ \
|
||||
Pico_mcd->scd.Status_CDD = NOCD; \
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; \
|
||||
\
|
||||
Pico_mcd->cdd.Minute = 0; \
|
||||
Pico_mcd->cdd.Seconde = 0; \
|
||||
Pico_mcd->cdd.Frame = 0; \
|
||||
Pico_mcd->cdd.Ext = 0; \
|
||||
\
|
||||
Pico_mcd->scd.CDD_Complete = 1; \
|
||||
\
|
||||
return 3; \
|
||||
}
|
||||
|
||||
|
||||
static int MSF_to_LBA(_msf *MSF)
|
||||
{
|
||||
return (MSF->M * 60 * 75) + (MSF->S * 75) + MSF->F - 150;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL void LBA_to_MSF(int lba, _msf *MSF)
|
||||
{
|
||||
if (lba < -150) lba = 0;
|
||||
else lba += 150;
|
||||
MSF->M = lba / (60 * 75);
|
||||
MSF->S = (lba / 75) % 60;
|
||||
MSF->F = lba % 75;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int MSF_to_Track(_msf *MSF)
|
||||
{
|
||||
int i, Start, Cur;
|
||||
|
||||
Start = (MSF->M << 16) + (MSF->S << 8) + MSF->F;
|
||||
|
||||
for(i = 1; i <= (Pico_mcd->TOC.Last_Track + 1); i++)
|
||||
{
|
||||
Cur = Pico_mcd->TOC.Tracks[i - 1].MSF.M << 16;
|
||||
Cur += Pico_mcd->TOC.Tracks[i - 1].MSF.S << 8;
|
||||
Cur += Pico_mcd->TOC.Tracks[i - 1].MSF.F;
|
||||
|
||||
if (Cur > Start) break;
|
||||
}
|
||||
|
||||
--i;
|
||||
|
||||
if (i > Pico_mcd->TOC.Last_Track) return 100;
|
||||
else if (i < 1) i = 1;
|
||||
|
||||
return (unsigned) i;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int LBA_to_Track(int lba)
|
||||
{
|
||||
_msf MSF;
|
||||
|
||||
LBA_to_MSF(lba, &MSF);
|
||||
return MSF_to_Track(&MSF);
|
||||
}
|
||||
|
||||
|
||||
static void Track_to_MSF(int track, _msf *MSF)
|
||||
{
|
||||
if (track < 1) track = 1;
|
||||
else if (track > Pico_mcd->TOC.Last_Track) track = Pico_mcd->TOC.Last_Track;
|
||||
|
||||
MSF->M = Pico_mcd->TOC.Tracks[track - 1].MSF.M;
|
||||
MSF->S = Pico_mcd->TOC.Tracks[track - 1].MSF.S;
|
||||
MSF->F = Pico_mcd->TOC.Tracks[track - 1].MSF.F;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Track_to_LBA(int track)
|
||||
{
|
||||
_msf MSF;
|
||||
|
||||
Track_to_MSF(track, &MSF);
|
||||
return MSF_to_LBA(&MSF);
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL void Check_CD_Command(void)
|
||||
{
|
||||
cdprintf("CHECK CD COMMAND");
|
||||
|
||||
// Check CDC
|
||||
if (Pico_mcd->scd.Status_CDC & 1) // CDC is reading data ...
|
||||
{
|
||||
cdprintf("Got a read command");
|
||||
|
||||
// DATA ?
|
||||
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();
|
||||
}
|
||||
else Pico_mcd->scd.File_Add_Delay--;
|
||||
}
|
||||
|
||||
// Check CDD
|
||||
if (Pico_mcd->scd.CDD_Complete)
|
||||
{
|
||||
Pico_mcd->scd.CDD_Complete = 0;
|
||||
|
||||
CDD_Export_Status();
|
||||
}
|
||||
|
||||
if (Pico_mcd->scd.Status_CDD == FAST_FOW)
|
||||
{
|
||||
Pico_mcd->scd.Cur_LBA += 10;
|
||||
CDC_Update_Header();
|
||||
|
||||
}
|
||||
else if (Pico_mcd->scd.Status_CDD == FAST_REV)
|
||||
{
|
||||
Pico_mcd->scd.Cur_LBA -= 10;
|
||||
if (Pico_mcd->scd.Cur_LBA < -150) Pico_mcd->scd.Cur_LBA = -150;
|
||||
CDC_Update_Header();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Init_CD_Driver(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL void End_CD_Driver(void)
|
||||
{
|
||||
Unload_ISO();
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL void Reset_CD(void)
|
||||
{
|
||||
Pico_mcd->scd.Cur_Track = 0;
|
||||
Pico_mcd->scd.Cur_LBA = -150;
|
||||
Pico_mcd->scd.Status_CDC &= ~1;
|
||||
Pico_mcd->scd.Status_CDD = CD_Present ? READY : NOCD;
|
||||
Pico_mcd->scd.CDD_Complete = 0;
|
||||
Pico_mcd->scd.File_Add_Delay = 0;
|
||||
}
|
||||
|
||||
|
||||
int Insert_CD(char *cdimg_name, int type)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
CD_Present = 0;
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
|
||||
if (cdimg_name != NULL && type != CIT_NOT_CD)
|
||||
{
|
||||
ret = Load_CD_Image(cdimg_name, type);
|
||||
if (ret == 0) {
|
||||
CD_Present = 1;
|
||||
Pico_mcd->scd.Status_CDD = READY;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void Stop_CD(void)
|
||||
{
|
||||
Unload_ISO();
|
||||
CD_Present = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
PICO_INTERNAL void Change_CD(void)
|
||||
{
|
||||
if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) Close_Tray_CDD_cC();
|
||||
else Open_Tray_CDD_cD();
|
||||
}
|
||||
*/
|
||||
|
||||
PICO_INTERNAL int Get_Status_CDD_c0(void)
|
||||
{
|
||||
cdprintf("Status command : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);
|
||||
|
||||
// Clear immediat status
|
||||
if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0200)
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);
|
||||
else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0700)
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);
|
||||
else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0E00)
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Stop_CDD_c1(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
|
||||
|
||||
if (CD_Present) Pico_mcd->scd.Status_CDD = STOPPED;
|
||||
else Pico_mcd->scd.Status_CDD = NOCD;
|
||||
Pico_mcd->cdd.Status = 0x0000;
|
||||
|
||||
Pico_mcd->s68k_regs[0x36] |= 0x01; // Data bit set because stopped
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Get_Pos_CDD_c20(void)
|
||||
{
|
||||
_msf MSF;
|
||||
|
||||
cdprintf("command 200 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);
|
||||
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->cdd.Status &= 0xFF;
|
||||
if (!CD_Present)
|
||||
{
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
}
|
||||
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
|
||||
cdprintf("Status CDD = %.4X Status = %.4X", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);
|
||||
|
||||
LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);
|
||||
Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);
|
||||
Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Get_Track_Pos_CDD_c21(void)
|
||||
{
|
||||
int elapsed_time;
|
||||
_msf MSF;
|
||||
|
||||
cdprintf("command 201 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);
|
||||
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->cdd.Status &= 0xFF;
|
||||
if (!CD_Present)
|
||||
{
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
}
|
||||
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
|
||||
elapsed_time = Pico_mcd->scd.Cur_LBA - Track_to_LBA(LBA_to_Track(Pico_mcd->scd.Cur_LBA));
|
||||
LBA_to_MSF(elapsed_time - 150, &MSF);
|
||||
|
||||
cdprintf(" elapsed = %d", elapsed_time);
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);
|
||||
Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);
|
||||
Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Get_Current_Track_CDD_c22(void)
|
||||
{
|
||||
cdprintf("Status CDD = %.4X Status = %.4X", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);
|
||||
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->cdd.Status &= 0xFF;
|
||||
if (!CD_Present)
|
||||
{
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
}
|
||||
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
|
||||
Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);
|
||||
|
||||
if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;
|
||||
else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Get_Total_Lenght_CDD_c23(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->cdd.Status &= 0xFF;
|
||||
if (!CD_Present)
|
||||
{
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
}
|
||||
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.M);
|
||||
Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.S);
|
||||
Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.F);
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Get_First_Last_Track_CDD_c24(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->cdd.Status &= 0xFF;
|
||||
if (!CD_Present)
|
||||
{
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
}
|
||||
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(1);
|
||||
Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Last_Track);
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Get_Track_Adr_CDD_c25(void)
|
||||
{
|
||||
int track_number;
|
||||
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
// track number in TC4 & TC5
|
||||
|
||||
track_number = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);
|
||||
|
||||
Pico_mcd->cdd.Status &= 0xFF;
|
||||
if (!CD_Present)
|
||||
{
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
}
|
||||
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
|
||||
if (track_number > Pico_mcd->TOC.Last_Track) track_number = Pico_mcd->TOC.Last_Track;
|
||||
else if (track_number < 1) track_number = 1;
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.M);
|
||||
Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.S);
|
||||
Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.F);
|
||||
Pico_mcd->cdd.Ext = track_number % 10;
|
||||
|
||||
if (track_number == 1) Pico_mcd->cdd.Frame |= 0x0800; // data track
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Play_CDD_c3(void)
|
||||
{
|
||||
_msf MSF;
|
||||
int delay, new_lba;
|
||||
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
// MSF of the track to play in TC buffer
|
||||
|
||||
MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);
|
||||
MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);
|
||||
MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);
|
||||
|
||||
Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);
|
||||
|
||||
new_lba = MSF_to_LBA(&MSF);
|
||||
delay = new_lba - Pico_mcd->scd.Cur_LBA;
|
||||
if (delay < 0) delay = -delay;
|
||||
delay >>= 12;
|
||||
|
||||
Pico_mcd->scd.Cur_LBA = new_lba;
|
||||
CDC_Update_Header();
|
||||
|
||||
cdprintf("Read : Cur LBA = %d, M=%d, S=%d, F=%d", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);
|
||||
|
||||
if (Pico_mcd->scd.Status_CDD != PLAYING) delay += 20;
|
||||
|
||||
Pico_mcd->scd.Status_CDD = PLAYING;
|
||||
Pico_mcd->cdd.Status = 0x0102;
|
||||
// Pico_mcd->cdd.Status = COMM_OK;
|
||||
|
||||
if (Pico_mcd->scd.File_Add_Delay == 0) Pico_mcd->scd.File_Add_Delay = delay;
|
||||
|
||||
if (Pico_mcd->scd.Cur_Track == 1)
|
||||
{
|
||||
Pico_mcd->s68k_regs[0x36] |= 0x01; // DATA
|
||||
}
|
||||
else
|
||||
{
|
||||
Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO
|
||||
cdda_start_play();
|
||||
}
|
||||
|
||||
if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;
|
||||
else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.Status_CDC |= 1; // Read data with CDC
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Seek_CDD_c4(void)
|
||||
{
|
||||
_msf MSF;
|
||||
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
// MSF to seek in TC buffer
|
||||
|
||||
MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);
|
||||
MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);
|
||||
MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);
|
||||
|
||||
Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);
|
||||
Pico_mcd->scd.Cur_LBA = MSF_to_LBA(&MSF);
|
||||
CDC_Update_Header();
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
|
||||
|
||||
Pico_mcd->scd.Status_CDD = READY;
|
||||
Pico_mcd->cdd.Status = 0x0200;
|
||||
|
||||
// DATA ?
|
||||
if (Pico_mcd->scd.Cur_Track == 1)
|
||||
Pico_mcd->s68k_regs[0x36] |= 0x01;
|
||||
else Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Pause_CDD_c6(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read to start a new one if raw data
|
||||
|
||||
Pico_mcd->scd.Status_CDD = READY;
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;
|
||||
|
||||
Pico_mcd->s68k_regs[0x36] |= 0x01; // Data bit set because stopped
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Resume_CDD_c7(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);
|
||||
|
||||
#ifdef DEBUG_CD
|
||||
{
|
||||
_msf MSF;
|
||||
LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);
|
||||
cdprintf("Resume read : Cur LBA = %d, M=%d, S=%d, F=%d", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);
|
||||
}
|
||||
#endif
|
||||
|
||||
Pico_mcd->scd.Status_CDD = PLAYING;
|
||||
Pico_mcd->cdd.Status = 0x0102;
|
||||
|
||||
if (Pico_mcd->scd.Cur_Track == 1)
|
||||
{
|
||||
Pico_mcd->s68k_regs[0x36] |= 0x01; // DATA
|
||||
}
|
||||
else
|
||||
{
|
||||
Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO
|
||||
cdda_start_play();
|
||||
}
|
||||
|
||||
if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;
|
||||
else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.Status_CDC |= 1; // Read data with CDC
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Fast_Foward_CDD_c8(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
|
||||
|
||||
Pico_mcd->scd.Status_CDD = FAST_FOW;
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Fast_Rewind_CDD_c9(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
|
||||
|
||||
Pico_mcd->scd.Status_CDD = FAST_REV;
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Close_Tray_CDD_cC(void)
|
||||
{
|
||||
CD_Present = 0;
|
||||
//Clear_Sound_Buffer();
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
|
||||
|
||||
elprintf(EL_STATUS, "tray close\n");
|
||||
|
||||
if (PicoMCDcloseTray != NULL)
|
||||
CD_Present = PicoMCDcloseTray();
|
||||
|
||||
Pico_mcd->scd.Status_CDD = CD_Present ? STOPPED : NOCD;
|
||||
Pico_mcd->cdd.Status = 0x0000;
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int Open_Tray_CDD_cD(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
|
||||
|
||||
elprintf(EL_STATUS, "tray open\n");
|
||||
|
||||
Unload_ISO();
|
||||
CD_Present = 0;
|
||||
|
||||
if (PicoMCDopenTray != NULL)
|
||||
PicoMCDopenTray();
|
||||
|
||||
Pico_mcd->scd.Status_CDD = TRAY_OPEN;
|
||||
Pico_mcd->cdd.Status = 0x0E00;
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int CDD_cA(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1;
|
||||
|
||||
Pico_mcd->scd.Status_CDD = READY;
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = INT_TO_BCDW(1);
|
||||
Pico_mcd->cdd.Frame = INT_TO_BCDW(1);
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL int CDD_Def(void)
|
||||
{
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
111
pico/cd/cd_sys.h
Normal file
111
pico/cd/cd_sys.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/***********************************************************
|
||||
* *
|
||||
* This source 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 *
|
||||
* *
|
||||
***********************************************************/
|
||||
|
||||
#ifndef _CD_SYS_H
|
||||
#define _CD_SYS_H
|
||||
|
||||
#include "cd_file.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define INT_TO_BCDB(c) \
|
||||
((c) > 99)?(0x99):((((c) / 10) << 4) + ((c) % 10));
|
||||
|
||||
#define INT_TO_BCDW(c) \
|
||||
((c) > 99)?(0x0909):((((c) / 10) << 8) + ((c) % 10));
|
||||
|
||||
#define BCDB_TO_INT(c) \
|
||||
(((c) >> 4) * 10) + ((c) & 0xF);
|
||||
|
||||
#define BCDW_TO_INT(c) \
|
||||
(((c) >> 8) * 10) + ((c) & 0xF);
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char M;
|
||||
unsigned char S;
|
||||
unsigned char F;
|
||||
} _msf;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// unsigned char Type; // always 1 (data) for 1st track, 0 (audio) for others
|
||||
// unsigned char Num; // unused
|
||||
_msf MSF;
|
||||
//
|
||||
char ftype; // TYPE_ISO, TYPE_BIN, TYPE_MP3
|
||||
void *F;
|
||||
int Length;
|
||||
int Offset; // sector offset, when single file is used for multiple virtual tracks
|
||||
short KBtps; // kbytes per sec for mp3s (bitrate / 1000 / 8)
|
||||
short pad;
|
||||
} _scd_track;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// unsigned char First_Track; // always 1
|
||||
_scd_track Tracks[100];
|
||||
unsigned int Last_Track;
|
||||
} _scd_toc;
|
||||
|
||||
typedef struct {
|
||||
unsigned int Status_CDD;
|
||||
unsigned int Status_CDC;
|
||||
int Cur_LBA;
|
||||
unsigned int Cur_Track;
|
||||
int File_Add_Delay;
|
||||
char CDD_Complete;
|
||||
int pad[6];
|
||||
} _scd;
|
||||
|
||||
|
||||
PICO_INTERNAL void LBA_to_MSF(int lba, _msf *MSF);
|
||||
PICO_INTERNAL int Track_to_LBA(int track);
|
||||
|
||||
// moved to pico.h
|
||||
// int Insert_CD(char *iso_name, int is_bin);
|
||||
// void Stop_CD(void);
|
||||
|
||||
PICO_INTERNAL void Check_CD_Command(void);
|
||||
|
||||
PICO_INTERNAL int Init_CD_Driver(void);
|
||||
PICO_INTERNAL void End_CD_Driver(void);
|
||||
PICO_INTERNAL void Reset_CD(void);
|
||||
|
||||
PICO_INTERNAL int Get_Status_CDD_c0(void);
|
||||
PICO_INTERNAL int Stop_CDD_c1(void);
|
||||
PICO_INTERNAL int Get_Pos_CDD_c20(void);
|
||||
PICO_INTERNAL int Get_Track_Pos_CDD_c21(void);
|
||||
PICO_INTERNAL int Get_Current_Track_CDD_c22(void);
|
||||
PICO_INTERNAL int Get_Total_Lenght_CDD_c23(void);
|
||||
PICO_INTERNAL int Get_First_Last_Track_CDD_c24(void);
|
||||
PICO_INTERNAL int Get_Track_Adr_CDD_c25(void);
|
||||
PICO_INTERNAL int Play_CDD_c3(void);
|
||||
PICO_INTERNAL int Seek_CDD_c4(void);
|
||||
PICO_INTERNAL int Pause_CDD_c6(void);
|
||||
PICO_INTERNAL int Resume_CDD_c7(void);
|
||||
PICO_INTERNAL int Fast_Foward_CDD_c8(void);
|
||||
PICO_INTERNAL int Fast_Rewind_CDD_c9(void);
|
||||
PICO_INTERNAL int CDD_cA(void);
|
||||
PICO_INTERNAL int Close_Tray_CDD_cC(void);
|
||||
PICO_INTERNAL int Open_Tray_CDD_cD(void);
|
||||
|
||||
PICO_INTERNAL int CDD_Def(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
40
pico/cd/cell_map.c
Normal file
40
pico/cd/cell_map.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Convert "cell arrange" address to normal address.
|
||||
// (c) Copyright 2007, Grazvydas "notaz" Ignotas
|
||||
|
||||
// 64 x32 x16 x8 x4 x4
|
||||
static unsigned int cell_map(int celln)
|
||||
{
|
||||
int col, row;
|
||||
|
||||
switch ((celln >> 12) & 7) { // 0-0x8000
|
||||
case 0: // x32 cells
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
col = celln >> 8;
|
||||
row = celln & 0xff;
|
||||
break;
|
||||
case 4: // x16
|
||||
case 5:
|
||||
col = celln >> 7;
|
||||
row = celln & 0x7f;
|
||||
row |= 0x10000 >> 8;
|
||||
break;
|
||||
case 6: // x8
|
||||
col = celln >> 6;
|
||||
row = celln & 0x3f;
|
||||
row |= 0x18000 >> 8;
|
||||
break;
|
||||
case 7: // x4
|
||||
col = celln >> 5;
|
||||
row = celln & 0x1f;
|
||||
row |= (celln & 0x7800) >> 6;
|
||||
break;
|
||||
default: // never happens, only here to make compiler happy
|
||||
col = row = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return (col & 0x3f) + row*64;
|
||||
}
|
||||
|
268
pico/cd/cue.c
Normal file
268
pico/cd/cue.c
Normal file
|
@ -0,0 +1,268 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "cue.h"
|
||||
|
||||
#include "../pico_int.h"
|
||||
// #define elprintf(w,f,...) printf(f "\n",##__VA_ARGS__);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#ifdef __EPOC32__
|
||||
#define snprintf(b,s,...) sprintf(b,##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
static char *mystrip(char *str)
|
||||
{
|
||||
int i, len;
|
||||
|
||||
len = strlen(str);
|
||||
for (i = 0; i < len; i++)
|
||||
if (str[i] != ' ') break;
|
||||
if (i > 0) memmove(str, str + i, len - i + 1);
|
||||
|
||||
len = strlen(str);
|
||||
for (i = len - 1; i >= 0; i--)
|
||||
if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
|
||||
str[i+1] = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static int get_token(const char *buff, char *dest, int len)
|
||||
{
|
||||
const char *p = buff;
|
||||
char sep = ' ';
|
||||
int d = 0, skip = 0;
|
||||
|
||||
while (*p && *p == ' ') {
|
||||
skip++;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p == '\"') {
|
||||
sep = '\"';
|
||||
p++;
|
||||
}
|
||||
while (*p && *p != sep && d < len-1)
|
||||
dest[d++] = *p++;
|
||||
dest[d] = 0;
|
||||
|
||||
if (sep == '\"' && *p != sep)
|
||||
elprintf(EL_STATUS, "cue: bad token: \"%s\"", buff);
|
||||
|
||||
return d + skip;
|
||||
}
|
||||
|
||||
static char *get_ext(char *fname)
|
||||
{
|
||||
int len = strlen(fname);
|
||||
return (len >= 3) ? (fname + len - 3) : fname;
|
||||
}
|
||||
|
||||
|
||||
#define BEGINS(buff,str) (strncmp(buff,str,sizeof(str)-1) == 0)
|
||||
|
||||
/* note: tracks[0] is not used */
|
||||
cue_data_t *cue_parse(const char *fname)
|
||||
{
|
||||
char buff[256], current_file[256], buff2[32], *current_filep;
|
||||
FILE *f, *tmpf;
|
||||
int ret, count = 0, count_alloc = 2, pending_pregap = 0;
|
||||
cue_data_t *data;
|
||||
void *tmp;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (f == NULL) return NULL;
|
||||
|
||||
snprintf(current_file, sizeof(current_file), "%s", fname);
|
||||
for (current_filep = current_file + strlen(current_file); current_filep > current_file; current_filep--)
|
||||
if (current_filep[-1] == '/' || current_filep[-1] == '\\') break;
|
||||
|
||||
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cue_track));
|
||||
if (data == NULL) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (!feof(f))
|
||||
{
|
||||
tmp = fgets(buff, sizeof(buff), f);
|
||||
if (tmp == NULL) break;
|
||||
|
||||
mystrip(buff);
|
||||
if (buff[0] == 0) continue;
|
||||
if (BEGINS(buff, "TITLE ") || BEGINS(buff, "PERFORMER ") || BEGINS(buff, "SONGWRITER "))
|
||||
continue; /* who would put those here? Ignore! */
|
||||
else if (BEGINS(buff, "FILE "))
|
||||
{
|
||||
get_token(buff+5, current_filep, sizeof(current_file) - (current_filep - current_file));
|
||||
}
|
||||
else if (BEGINS(buff, "TRACK "))
|
||||
{
|
||||
count++;
|
||||
if (count >= count_alloc) {
|
||||
count_alloc *= 2;
|
||||
tmp = realloc(data, sizeof(*data) + count_alloc * sizeof(cue_track));
|
||||
if (tmp == NULL) { count--; break; }
|
||||
data = tmp;
|
||||
}
|
||||
memset(&data->tracks[count], 0, sizeof(data->tracks[0]));
|
||||
if (count == 1 || strcmp(data->tracks[1].fname, current_file) != 0)
|
||||
{
|
||||
data->tracks[count].fname = strdup(current_file);
|
||||
if (data->tracks[count].fname == NULL) break;
|
||||
|
||||
tmpf = fopen(current_file, "rb");
|
||||
if (tmpf == NULL) {
|
||||
elprintf(EL_STATUS, "cue: bad/missing file: \"%s\"", current_file);
|
||||
count--; break;
|
||||
}
|
||||
fclose(tmpf);
|
||||
}
|
||||
data->tracks[count].pregap = pending_pregap;
|
||||
pending_pregap = 0;
|
||||
// track number
|
||||
ret = get_token(buff+6, buff2, sizeof(buff2));
|
||||
if (count != atoi(buff2))
|
||||
elprintf(EL_STATUS, "cue: track index mismatch: track %i is track %i in cue",
|
||||
count, atoi(buff2));
|
||||
// check type
|
||||
get_token(buff+6+ret, buff2, sizeof(buff2));
|
||||
if (strcmp(buff2, "MODE1/2352") == 0)
|
||||
data->tracks[count].type = CT_BIN;
|
||||
else if (strcmp(buff2, "MODE1/2048") == 0)
|
||||
data->tracks[count].type = CT_ISO;
|
||||
else if (strcmp(buff2, "AUDIO") == 0)
|
||||
{
|
||||
if (data->tracks[count].fname != NULL)
|
||||
{
|
||||
// rely on extension, not type in cue..
|
||||
char *ext = get_ext(data->tracks[count].fname);
|
||||
if (strcasecmp(ext, "mp3") == 0)
|
||||
data->tracks[count].type = CT_MP3;
|
||||
else if (strcasecmp(ext, "wav") == 0)
|
||||
data->tracks[count].type = CT_WAV;
|
||||
else {
|
||||
elprintf(EL_STATUS, "unhandled audio format: \"%s\"",
|
||||
data->tracks[count].fname);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// propagate previous
|
||||
data->tracks[count].type = data->tracks[count-1].type;
|
||||
}
|
||||
}
|
||||
else {
|
||||
elprintf(EL_STATUS, "unhandled track type: \"%s\"", buff2);
|
||||
}
|
||||
}
|
||||
else if (BEGINS(buff, "INDEX "))
|
||||
{
|
||||
int m, s, f;
|
||||
// type
|
||||
ret = get_token(buff+6, buff2, sizeof(buff2));
|
||||
if (atoi(buff2) == 0) continue;
|
||||
if (atoi(buff2) != 1) {
|
||||
elprintf(EL_STATUS, "cue: don't know how to handle: \"%s\"", buff);
|
||||
count--; break;
|
||||
}
|
||||
// offset in file
|
||||
get_token(buff+6+ret, buff2, sizeof(buff2));
|
||||
ret = sscanf(buff2, "%d:%d:%d", &m, &s, &f);
|
||||
if (ret != 3) {
|
||||
elprintf(EL_STATUS, "cue: failed to parse: \"%s\"", buff);
|
||||
count--; break;
|
||||
}
|
||||
data->tracks[count].sector_offset = m*60*75 + s*75 + f;
|
||||
// some strange .cues may need this
|
||||
if (data->tracks[count].fname != NULL && strcmp(data->tracks[count].fname, current_file) != 0)
|
||||
{
|
||||
free(data->tracks[count].fname);
|
||||
data->tracks[count].fname = strdup(current_file);
|
||||
}
|
||||
if (data->tracks[count].fname == NULL && strcmp(data->tracks[1].fname, current_file) != 0)
|
||||
{
|
||||
data->tracks[count].fname = strdup(current_file);
|
||||
}
|
||||
}
|
||||
else if (BEGINS(buff, "PREGAP ") || BEGINS(buff, "POSTGAP "))
|
||||
{
|
||||
int m, s, f;
|
||||
get_token(buff+7, buff2, sizeof(buff2));
|
||||
ret = sscanf(buff2, "%d:%d:%d", &m, &s, &f);
|
||||
if (ret != 3) {
|
||||
elprintf(EL_STATUS, "cue: failed to parse: \"%s\"", buff);
|
||||
continue;
|
||||
}
|
||||
// pregap overrides previous postgap?
|
||||
// by looking at some .cues produced by some programs I've decided that..
|
||||
if (BEGINS(buff, "PREGAP "))
|
||||
data->tracks[count].pregap = m*60*75 + s*75 + f;
|
||||
else
|
||||
pending_pregap = m*60*75 + s*75 + f;
|
||||
}
|
||||
else if (BEGINS(buff, "REM LENGTH ")) // custom "extension"
|
||||
{
|
||||
int m, s, f;
|
||||
get_token(buff+11, buff2, sizeof(buff2));
|
||||
ret = sscanf(buff2, "%d:%d:%d", &m, &s, &f);
|
||||
if (ret != 3) continue;
|
||||
data->tracks[count].sector_xlength = m*60*75 + s*75 + f;
|
||||
}
|
||||
else if (BEGINS(buff, "REM"))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
elprintf(EL_STATUS, "cue: unhandled line: \"%s\"", buff);
|
||||
}
|
||||
}
|
||||
|
||||
if (count < 1 || data->tracks[1].fname == NULL) {
|
||||
// failed..
|
||||
for (; count > 0; count--)
|
||||
if (data->tracks[count].fname != NULL)
|
||||
free(data->tracks[count].fname);
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data->track_count = count;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void cue_destroy(cue_data_t *data)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (data == NULL) return;
|
||||
|
||||
for (c = data->track_count; c > 0; c--)
|
||||
if (data->tracks[c].fname != NULL)
|
||||
free(data->tracks[c].fname);
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
cue_data_t *data = cue_parse(argv[1]);
|
||||
int c;
|
||||
|
||||
if (data == NULL) return 1;
|
||||
|
||||
for (c = 1; c <= data->track_count; c++)
|
||||
printf("%2i: %i %9i %02i:%02i:%02i %9i %s\n", c, data->tracks[c].type, data->tracks[c].sector_offset,
|
||||
data->tracks[c].sector_offset / (75*60), data->tracks[c].sector_offset / 75 % 60,
|
||||
data->tracks[c].sector_offset % 75, data->tracks[c].pregap, data->tracks[c].fname);
|
||||
|
||||
cue_destroy(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
29
pico/cd/cue.h
Normal file
29
pico/cd/cue.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
|
||||
typedef enum
|
||||
{
|
||||
CT_UNKNOWN = 0,
|
||||
CT_ISO = 1, /* 2048 B/sector */
|
||||
CT_BIN = 2, /* 2352 B/sector */
|
||||
CT_MP3 = 3,
|
||||
CT_WAV = 4
|
||||
} cue_track_type;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *fname;
|
||||
int pregap; /* pregap for current track */
|
||||
int sector_offset; /* in current file */
|
||||
int sector_xlength;
|
||||
cue_track_type type;
|
||||
} cue_track;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int track_count;
|
||||
cue_track tracks[0];
|
||||
} cue_data_t;
|
||||
|
||||
|
||||
cue_data_t *cue_parse(const char *fname);
|
||||
void cue_destroy(cue_data_t *data);
|
||||
|
489
pico/cd/gfx_cd.c
Normal file
489
pico/cd/gfx_cd.c
Normal file
|
@ -0,0 +1,489 @@
|
|||
// This is a direct rewrite of gfx_cd.asm (x86 asm to C).
|
||||
// You can even find some x86 register names :)
|
||||
// Original code (c) 2002 by Stéphane Dallongeville
|
||||
|
||||
// (c) Copyright 2007, Grazvydas "notaz" Ignotas
|
||||
|
||||
|
||||
#include "../pico_int.h"
|
||||
|
||||
#define _rot_comp Pico_mcd->rot_comp
|
||||
|
||||
static const int Table_Rot_Time[] =
|
||||
{
|
||||
0x00054000, 0x00048000, 0x00040000, 0x00036000, //; 008-032 ; briefing - sprite
|
||||
0x0002E000, 0x00028000, 0x00024000, 0x00022000, //; 036-064 ; arbre souvent
|
||||
0x00021000, 0x00020000, 0x0001E000, 0x0001B800, //; 068-096 ; map thunderstrike
|
||||
0x00019800, 0x00017A00, 0x00015C00, 0x00013E00, //; 100-128 ; logo défoncé
|
||||
|
||||
0x00012000, 0x00011800, 0x00011000, 0x00010800, //; 132-160 ; briefing - map
|
||||
0x00010000, 0x0000F800, 0x0000F000, 0x0000E800, //; 164-192
|
||||
0x0000E000, 0x0000D800, 0x0000D000, 0x0000C800, //; 196-224
|
||||
0x0000C000, 0x0000B800, 0x0000B000, 0x0000A800, //; 228-256 ; batman visage
|
||||
|
||||
0x0000A000, 0x00009F00, 0x00009E00, 0x00009D00, //; 260-288
|
||||
0x00009C00, 0x00009B00, 0x00009A00, 0x00009900, //; 292-320
|
||||
0x00009800, 0x00009700, 0x00009600, 0x00009500, //; 324-352
|
||||
0x00009400, 0x00009300, 0x00009200, 0x00009100, //; 356-384
|
||||
|
||||
0x00009000, 0x00008F00, 0x00008E00, 0x00008D00, //; 388-416
|
||||
0x00008C00, 0x00008B00, 0x00008A00, 0x00008900, //; 420-448
|
||||
0x00008800, 0x00008700, 0x00008600, 0x00008500, //; 452-476
|
||||
0x00008400, 0x00008300, 0x00008200, 0x00008100, //; 480-512
|
||||
};
|
||||
|
||||
|
||||
static void gfx_cd_start(void)
|
||||
{
|
||||
int upd_len;
|
||||
|
||||
// _rot_comp.XD_Mul = ((_rot_comp.Reg_5C & 0x1f) + 1) * 4; // unused
|
||||
_rot_comp.Function = (_rot_comp.Reg_58 & 7) | (Pico_mcd->s68k_regs[3] & 0x18); // Jmp_Adr
|
||||
// _rot_comp.Buffer_Adr = (_rot_comp.Reg_5E & 0xfff8) << 2; // unused?
|
||||
_rot_comp.YD = (_rot_comp.Reg_60 >> 3) & 7;
|
||||
_rot_comp.Vector_Adr = (_rot_comp.Reg_66 & 0xfffe) << 2;
|
||||
|
||||
upd_len = (_rot_comp.Reg_62 >> 3) & 0x3f;
|
||||
upd_len = Table_Rot_Time[upd_len];
|
||||
_rot_comp.Draw_Speed = _rot_comp.Float_Part = upd_len;
|
||||
|
||||
_rot_comp.Reg_58 |= 0x8000; // Stamp_Size, we start a new GFX operation
|
||||
|
||||
switch (_rot_comp.Reg_58 & 6) // Scr_16?
|
||||
{
|
||||
case 0: // ?
|
||||
_rot_comp.Stamp_Map_Adr = (_rot_comp.Reg_5A & 0xff80) << 2;
|
||||
break;
|
||||
case 2: // .Dot_32
|
||||
_rot_comp.Stamp_Map_Adr = (_rot_comp.Reg_5A & 0xffe0) << 2;
|
||||
break;
|
||||
case 4: // .Scr_16
|
||||
_rot_comp.Stamp_Map_Adr = 0x20000;
|
||||
break;
|
||||
case 6: // .Scr_16_Dot_32
|
||||
_rot_comp.Stamp_Map_Adr = (_rot_comp.Reg_5A & 0xe000) << 2;
|
||||
break;
|
||||
}
|
||||
|
||||
dprintf("gfx_cd_start, stamp_map_addr=%06x", _rot_comp.Stamp_Map_Adr);
|
||||
|
||||
gfx_cd_update();
|
||||
}
|
||||
|
||||
|
||||
static void gfx_completed(void)
|
||||
{
|
||||
_rot_comp.Reg_58 &= 0x7fff; // Stamp_Size
|
||||
_rot_comp.Reg_64 = 0;
|
||||
if (Pico_mcd->s68k_regs[0x33] & (1<<1))
|
||||
{
|
||||
elprintf(EL_INTS, "gfx_cd irq 1");
|
||||
SekInterruptS68k(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gfx_do(unsigned int func, unsigned short *stamp_base, unsigned int H_Dot)
|
||||
{
|
||||
unsigned int eax, ebx, ecx, edx, esi, edi, pixel;
|
||||
unsigned int XD, Buffer_Adr;
|
||||
int DYXS;
|
||||
|
||||
XD = _rot_comp.Reg_60 & 7;
|
||||
Buffer_Adr = ((_rot_comp.Reg_5E & 0xfff8) + _rot_comp.YD) << 2;
|
||||
ecx = *(unsigned int *)(Pico_mcd->word_ram2M + _rot_comp.Vector_Adr);
|
||||
edx = ecx >> 16;
|
||||
ecx = (ecx & 0xffff) << 8;
|
||||
edx <<= 8;
|
||||
DYXS = *(int *)(Pico_mcd->word_ram2M + _rot_comp.Vector_Adr + 4);
|
||||
_rot_comp.Vector_Adr += 8;
|
||||
|
||||
// MAKE_IMAGE_LINE
|
||||
while (H_Dot)
|
||||
{
|
||||
// MAKE_IMAGE_PIXEL
|
||||
if (!(func & 1)) // NOT TILED
|
||||
{
|
||||
int mask = (func & 4) ? 0x00800000 : 0x00f80000;
|
||||
if ((ecx | edx) & mask)
|
||||
{
|
||||
if (func & 0x18) goto Next_Pixel;
|
||||
pixel = 0;
|
||||
goto Pixel_Out;
|
||||
}
|
||||
}
|
||||
|
||||
if (func & 2) // mode 32x32 dot
|
||||
{
|
||||
if (func & 4) // 16x16 screen
|
||||
{
|
||||
ebx = ((ecx >> (11+5)) & 0x007f) |
|
||||
((edx >> (11-2)) & 0x3f80);
|
||||
}
|
||||
else // 1x1 screen
|
||||
{
|
||||
ebx = ((ecx >> (11+5)) & 0x07) |
|
||||
((edx >> (11+2)) & 0x38);
|
||||
}
|
||||
}
|
||||
else // mode 16x16 dot
|
||||
{
|
||||
if (func & 4) // 16x16 screen
|
||||
{
|
||||
ebx = ((ecx >> (11+4)) & 0x00ff) |
|
||||
((edx >> (11-4)) & 0xff00);
|
||||
}
|
||||
else // 1x1 screen
|
||||
{
|
||||
ebx = ((ecx >> (11+4)) & 0x0f) |
|
||||
((edx >> (11+0)) & 0xf0);
|
||||
}
|
||||
}
|
||||
|
||||
edi = stamp_base[ebx];
|
||||
esi = (edi & 0x7ff) << 7;
|
||||
if (!esi) { pixel = 0; goto Pixel_Out; }
|
||||
edi >>= (11+1);
|
||||
edi &= (0x1c>>1);
|
||||
eax = ecx;
|
||||
ebx = edx;
|
||||
if (func & 2) edi |= 1; // 32 dots?
|
||||
switch (edi)
|
||||
{
|
||||
case 0x00: // No_Flip_0, 16x16 dots
|
||||
ebx = (ebx >> 9) & 0x3c;
|
||||
ebx += esi;
|
||||
edi = (eax & 0x3800) ^ 0x1000; // bswap
|
||||
eax = ((eax >> 8) & 0x40) + ebx;
|
||||
break;
|
||||
case 0x01: // No_Flip_0, 32x32 dots
|
||||
ebx = (ebx >> 9) & 0x7c;
|
||||
ebx += esi;
|
||||
edi = (eax & 0x3800) ^ 0x1000; // bswap
|
||||
eax = ((eax >> 7) & 0x180) + ebx;
|
||||
break;
|
||||
case 0x02: // No_Flip_90, 16x16 dots
|
||||
eax = (eax >> 9) & 0x3c;
|
||||
eax += esi;
|
||||
edi = (ebx & 0x3800) ^ 0x2800; // bswap
|
||||
eax += ((ebx >> 8) & 0x40) ^ 0x40;
|
||||
break;
|
||||
case 0x03: // No_Flip_90, 32x32 dots
|
||||
eax = (eax >> 9) & 0x7c;
|
||||
eax += esi;
|
||||
edi = (ebx & 0x3800) ^ 0x2800; // bswap
|
||||
eax += ((ebx >> 7) & 0x180) ^ 0x180;
|
||||
break;
|
||||
case 0x04: // No_Flip_180, 16x16 dots
|
||||
ebx = ((ebx >> 9) & 0x3c) ^ 0x3c;
|
||||
ebx += esi;
|
||||
edi = (eax & 0x3800) ^ 0x2800; // bswap and flip
|
||||
eax = (((eax >> 8) & 0x40) ^ 0x40) + ebx;
|
||||
break;
|
||||
case 0x05: // No_Flip_180, 32x32 dots
|
||||
ebx = ((ebx >> 9) & 0x7c) ^ 0x7c;
|
||||
ebx += esi;
|
||||
edi = (eax & 0x3800) ^ 0x2800; // bswap and flip
|
||||
eax = (((eax >> 7) & 0x180) ^ 0x180) + ebx;
|
||||
break;
|
||||
case 0x06: // No_Flip_270, 16x16 dots
|
||||
eax = ((eax >> 9) & 0x3c) ^ 0x3c;
|
||||
eax += esi;
|
||||
edi = (ebx & 0x3800) ^ 0x1000; // bswap
|
||||
eax += (ebx >> 8) & 0x40;
|
||||
break;
|
||||
case 0x07: // No_Flip_270, 32x32 dots
|
||||
eax = ((eax >> 9) & 0x7c) ^ 0x7c;
|
||||
eax += esi;
|
||||
edi = (ebx & 0x3800) ^ 0x1000; // bswap
|
||||
eax += (ebx >> 7) & 0x180;
|
||||
break;
|
||||
case 0x08: // Flip_0, 16x16 dots
|
||||
ebx = (ebx >> 9) & 0x3c;
|
||||
ebx += esi;
|
||||
edi = (eax & 0x3800) ^ 0x2800; // bswap, flip
|
||||
eax = (((eax >> 8) & 0x40) ^ 0x40) + ebx;
|
||||
break;
|
||||
case 0x09: // Flip_0, 32x32 dots
|
||||
ebx = (ebx >> 9) & 0x7c;
|
||||
ebx += esi;
|
||||
edi = (eax & 0x3800) ^ 0x2800; // bswap, flip
|
||||
eax = (((eax >> 7) & 0x180) ^ 0x180) + ebx;
|
||||
break;
|
||||
case 0x0a: // Flip_90, 16x16 dots
|
||||
eax = ((eax >> 9) & 0x3c) ^ 0x3c;
|
||||
eax += esi;
|
||||
edi = (ebx & 0x3800) ^ 0x2800; // bswap, flip
|
||||
eax += ((ebx >> 8) & 0x40) ^ 0x40;
|
||||
break;
|
||||
case 0x0b: // Flip_90, 32x32 dots
|
||||
eax = ((eax >> 9) & 0x7c) ^ 0x7c;
|
||||
eax += esi;
|
||||
edi = (ebx & 0x3800) ^ 0x2800; // bswap, flip
|
||||
eax += ((ebx >> 7) & 0x180) ^ 0x180;
|
||||
break;
|
||||
case 0x0c: // Flip_180, 16x16 dots
|
||||
ebx = ((ebx >> 9) & 0x3c) ^ 0x3c;
|
||||
ebx += esi;
|
||||
edi = (eax & 0x3800) ^ 0x1000; // bswap
|
||||
eax = ((eax >> 8) & 0x40) + ebx;
|
||||
break;
|
||||
case 0x0d: // Flip_180, 32x32 dots
|
||||
ebx = ((ebx >> 9) & 0x7c) ^ 0x7c;
|
||||
ebx += esi;
|
||||
edi = (eax & 0x3800) ^ 0x1000; // bswap
|
||||
eax = ((eax >> 7) & 0x180) + ebx;
|
||||
break;
|
||||
case 0x0e: // Flip_270, 16x16 dots
|
||||
eax = (eax >> 9) & 0x3c;
|
||||
eax += esi;
|
||||
edi = (ebx & 0x3800) ^ 0x1000; // bswap, flip
|
||||
eax += (ebx >> 8) & 0x40;
|
||||
break;
|
||||
case 0x0f: // Flip_270, 32x32 dots
|
||||
eax = (eax >> 9) & 0x7c;
|
||||
eax += esi;
|
||||
edi = (ebx & 0x3800) ^ 0x1000; // bswap, flip
|
||||
eax += (ebx >> 7) & 0x180;
|
||||
break;
|
||||
}
|
||||
|
||||
pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
|
||||
if (!(edi & 0x800)) pixel >>= 4;
|
||||
else pixel &= 0x0f;
|
||||
|
||||
Pixel_Out:
|
||||
if (!pixel && (func & 0x18)) goto Next_Pixel;
|
||||
esi = Buffer_Adr + ((XD>>1)^1); // pixel addr
|
||||
eax = *(Pico_mcd->word_ram2M + esi); // old pixel
|
||||
if (XD & 1)
|
||||
{
|
||||
if ((eax & 0x0f) && (func & 0x18) == 0x08) goto Next_Pixel; // underwrite
|
||||
*(Pico_mcd->word_ram2M + esi) = pixel | (eax & 0xf0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((eax & 0xf0) && (func & 0x18) == 0x08) goto Next_Pixel; // underwrite
|
||||
*(Pico_mcd->word_ram2M + esi) = (pixel << 4) | (eax & 0xf);
|
||||
}
|
||||
|
||||
|
||||
Next_Pixel:
|
||||
ecx += (DYXS << 16) >> 16; // _rot_comp.DXS;
|
||||
edx += DYXS >> 16; // _rot_comp.DYS;
|
||||
XD++;
|
||||
if (XD >= 8)
|
||||
{
|
||||
Buffer_Adr += ((_rot_comp.Reg_5C & 0x1f) + 1) << 5;
|
||||
XD = 0;
|
||||
}
|
||||
H_Dot--;
|
||||
}
|
||||
// end while
|
||||
|
||||
|
||||
// nothing_to_draw:
|
||||
_rot_comp.YD++;
|
||||
// _rot_comp.V_Dot--; // will be done by caller
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL void gfx_cd_update(void)
|
||||
{
|
||||
int V_Dot = _rot_comp.Reg_64 & 0xff;
|
||||
int jobs;
|
||||
|
||||
dprintf("gfx_cd_update, Reg_64 = %04x", _rot_comp.Reg_64);
|
||||
|
||||
if (!V_Dot)
|
||||
{
|
||||
gfx_completed();
|
||||
return;
|
||||
}
|
||||
|
||||
jobs = _rot_comp.Float_Part >> 16;
|
||||
|
||||
if (!jobs)
|
||||
{
|
||||
_rot_comp.Float_Part += _rot_comp.Draw_Speed;
|
||||
return;
|
||||
}
|
||||
|
||||
_rot_comp.Float_Part &= 0xffff;
|
||||
_rot_comp.Float_Part += _rot_comp.Draw_Speed;
|
||||
|
||||
if (PicoOpt & POPT_EN_MCD_GFX)
|
||||
{
|
||||
unsigned int func = _rot_comp.Function;
|
||||
unsigned int H_Dot = _rot_comp.Reg_62 & 0x1ff;
|
||||
unsigned short *stamp_base = (unsigned short *) (Pico_mcd->word_ram2M + _rot_comp.Stamp_Map_Adr);
|
||||
|
||||
while (jobs--)
|
||||
{
|
||||
gfx_do(func, stamp_base, H_Dot); // jmp [Jmp_Adr]:
|
||||
|
||||
V_Dot--; // dec byte [V_Dot]
|
||||
if (V_Dot == 0)
|
||||
{
|
||||
// GFX_Completed:
|
||||
gfx_completed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (jobs >= V_Dot)
|
||||
{
|
||||
gfx_completed();
|
||||
return;
|
||||
}
|
||||
V_Dot -= jobs;
|
||||
}
|
||||
|
||||
_rot_comp.Reg_64 = V_Dot;
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL_ASM unsigned int gfx_cd_read(unsigned int a)
|
||||
{
|
||||
unsigned int d = 0;
|
||||
|
||||
switch (a) {
|
||||
case 0x58: d = _rot_comp.Reg_58; break;
|
||||
case 0x5A: d = _rot_comp.Reg_5A; break;
|
||||
case 0x5C: d = _rot_comp.Reg_5C; break;
|
||||
case 0x5E: d = _rot_comp.Reg_5E; break;
|
||||
case 0x60: d = _rot_comp.Reg_60; break;
|
||||
case 0x62: d = _rot_comp.Reg_62; break;
|
||||
case 0x64: d = _rot_comp.Reg_64; break;
|
||||
case 0x66: break;
|
||||
default: dprintf("gfx_cd_read FIXME: unexpected address: %02x", a); break;
|
||||
}
|
||||
|
||||
dprintf("gfx_cd_read(%02x) = %04x", a, d);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
PICO_INTERNAL_ASM void gfx_cd_write16(unsigned int a, unsigned int d)
|
||||
{
|
||||
dprintf("gfx_cd_write16(%x, %04x)", a, d);
|
||||
|
||||
switch (a) {
|
||||
case 0x58: // .Reg_Stamp_Size
|
||||
_rot_comp.Reg_58 = d & 7;
|
||||
return;
|
||||
|
||||
case 0x5A: // .Reg_Stamp_Adr
|
||||
_rot_comp.Reg_5A = d & 0xffe0;
|
||||
return;
|
||||
|
||||
case 0x5C: // .Reg_IM_VCell_Size
|
||||
_rot_comp.Reg_5C = d & 0x1f;
|
||||
return;
|
||||
|
||||
case 0x5E: // .Reg_IM_Adr
|
||||
_rot_comp.Reg_5E = d & 0xFFF8;
|
||||
return;
|
||||
|
||||
case 0x60: // .Reg_IM_Offset
|
||||
_rot_comp.Reg_60 = d & 0x3f;
|
||||
return;
|
||||
|
||||
case 0x62: // .Reg_IM_HDot_Size
|
||||
_rot_comp.Reg_62 = d & 0x1ff;
|
||||
return;
|
||||
|
||||
case 0x64: // .Reg_IM_VDot_Size
|
||||
_rot_comp.Reg_64 = d & 0xff; // V_Dot, must be 32bit?
|
||||
return;
|
||||
|
||||
case 0x66: // .Reg_Vector_Adr
|
||||
_rot_comp.Reg_66 = d & 0xfffe;
|
||||
if (Pico_mcd->s68k_regs[3]&4) return; // can't do tanformations in 1M mode
|
||||
gfx_cd_start();
|
||||
return;
|
||||
|
||||
default: dprintf("gfx_cd_write16 FIXME: unexpected address: %02x", a); return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL void gfx_cd_reset(void)
|
||||
{
|
||||
memset(&_rot_comp.Reg_58, 0, sizeof(_rot_comp));
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------
|
||||
|
||||
#include "cell_map.c"
|
||||
|
||||
#ifndef UTYPES_DEFINED
|
||||
typedef unsigned short u16;
|
||||
#endif
|
||||
|
||||
// check: Heart of the alien, jaguar xj 220
|
||||
PICO_INTERNAL void DmaSlowCell(unsigned int source, unsigned int a, int len, unsigned char inc)
|
||||
{
|
||||
unsigned char *base;
|
||||
unsigned int asrc, a2;
|
||||
u16 *r;
|
||||
|
||||
base = Pico_mcd->word_ram1M[Pico_mcd->s68k_regs[3]&1];
|
||||
|
||||
switch (Pico.video.type)
|
||||
{
|
||||
case 1: // vram
|
||||
r = Pico.vram;
|
||||
for(; len; len--)
|
||||
{
|
||||
asrc = cell_map(source >> 2) << 2;
|
||||
asrc |= source & 2;
|
||||
// if(a&1) d=(d<<8)|(d>>8); // ??
|
||||
r[a>>1] = *(u16 *)(base + asrc);
|
||||
source += 2;
|
||||
// AutoIncrement
|
||||
a=(u16)(a+inc);
|
||||
}
|
||||
rendstatus |= PDRAW_SPRITES_MOVED;
|
||||
break;
|
||||
|
||||
case 3: // cram
|
||||
Pico.m.dirtyPal = 1;
|
||||
r = Pico.cram;
|
||||
for(a2=a&0x7f; len; len--)
|
||||
{
|
||||
asrc = cell_map(source >> 2) << 2;
|
||||
asrc |= source & 2;
|
||||
r[a2>>1] = *(u16 *)(base + asrc);
|
||||
source += 2;
|
||||
// AutoIncrement
|
||||
a2+=inc;
|
||||
// good dest?
|
||||
if(a2 >= 0x80) break;
|
||||
}
|
||||
a=(a&0xff00)|a2;
|
||||
break;
|
||||
|
||||
case 5: // vsram[a&0x003f]=d;
|
||||
r = Pico.vsram;
|
||||
for(a2=a&0x7f; len; len--)
|
||||
{
|
||||
asrc = cell_map(source >> 2) << 2;
|
||||
asrc |= source & 2;
|
||||
r[a2>>1] = *(u16 *)(base + asrc);
|
||||
source += 2;
|
||||
// AutoIncrement
|
||||
a2+=inc;
|
||||
// good dest?
|
||||
if(a2 >= 0x80) break;
|
||||
}
|
||||
a=(a&0xff00)|a2;
|
||||
break;
|
||||
}
|
||||
// remember addr
|
||||
Pico.video.addr=(u16)a;
|
||||
}
|
||||
|
37
pico/cd/gfx_cd.h
Normal file
37
pico/cd/gfx_cd.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef _GFX_CD_H
|
||||
#define _GFX_CD_H
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int Reg_58; // Stamp_Size
|
||||
unsigned int Reg_5A;
|
||||
unsigned int Reg_5C;
|
||||
unsigned int Reg_5E;
|
||||
unsigned int Reg_60;
|
||||
unsigned int Reg_62;
|
||||
unsigned int Reg_64; // V_Dot
|
||||
unsigned int Reg_66;
|
||||
|
||||
unsigned int Stamp_Map_Adr;
|
||||
unsigned int Vector_Adr;
|
||||
unsigned int Function; // Jmp_Adr;
|
||||
unsigned int Float_Part;
|
||||
unsigned int Draw_Speed;
|
||||
unsigned int YD;
|
||||
|
||||
int pad[10];
|
||||
} Rot_Comp;
|
||||
|
||||
|
||||
PICO_INTERNAL void gfx_cd_update(void);
|
||||
|
||||
PICO_INTERNAL_ASM unsigned int gfx_cd_read(unsigned int a);
|
||||
PICO_INTERNAL_ASM void gfx_cd_write16(unsigned int a, unsigned int d);
|
||||
|
||||
PICO_INTERNAL void gfx_cd_reset(void);
|
||||
|
||||
PICO_INTERNAL void DmaSlowCell(unsigned int source, unsigned int a, int len, unsigned char inc);
|
||||
|
||||
#endif // _GFX_CD_H
|
||||
|
1853
pico/cd/memory.c
Normal file
1853
pico/cd/memory.c
Normal file
File diff suppressed because it is too large
Load diff
2364
pico/cd/memory_arm.s
Normal file
2364
pico/cd/memory_arm.s
Normal file
File diff suppressed because it is too large
Load diff
61
pico/cd/misc.c
Normal file
61
pico/cd/misc.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Some misc stuff
|
||||
// (c) Copyright 2007, Grazvydas "notaz" Ignotas
|
||||
|
||||
#include "../pico_int.h"
|
||||
|
||||
unsigned char formatted_bram[4*0x10] =
|
||||
{
|
||||
#if 0
|
||||
0x00, 0xd4, 0x63, 0x00, 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x53, 0xd2, 0xf5, 0x3a, 0x48, 0x50, 0x35, 0x0f,
|
||||
0x47, 0x14, 0xf5, 0x7e, 0x5c, 0xd4, 0xf3, 0x03, 0x00, 0x03, 0x12, 0x00, 0x0a, 0xff, 0xca, 0xa6,
|
||||
0xf5, 0x27, 0xed, 0x22, 0x47, 0xfa, 0x22, 0x96, 0x6c, 0xa5, 0x88, 0x14, 0x48, 0x48, 0x0a, 0xbb,
|
||||
#endif
|
||||
0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x40,
|
||||
0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x53, 0x45, 0x47, 0x41, 0x5f, 0x43, 0x44, 0x5f, 0x52, 0x4f, 0x4d, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x52, 0x41, 0x4d, 0x5f, 0x43, 0x41, 0x52, 0x54, 0x52, 0x49, 0x44, 0x47, 0x45, 0x5f, 0x5f, 0x5f,
|
||||
// SEGA_CD_ROM.....RAM_CARTRIDGE___
|
||||
};
|
||||
|
||||
|
||||
// offs | 2Mbit | 1Mbit |
|
||||
// 0 | [ 2M | unused |
|
||||
// 128K | bit ] | bank0 |
|
||||
// 256K | unused | bank1 |
|
||||
|
||||
#ifndef _ASM_MISC_C
|
||||
PICO_INTERNAL_ASM void wram_2M_to_1M(unsigned char *m)
|
||||
{
|
||||
unsigned short *m1M_b0, *m1M_b1;
|
||||
unsigned int i, tmp, *m2M;
|
||||
|
||||
m2M = (unsigned int *) (m + 0x40000);
|
||||
m1M_b0 = (unsigned short *) m2M;
|
||||
m1M_b1 = (unsigned short *) (m + 0x60000);
|
||||
|
||||
for (i = 0x40000/4; i; i--)
|
||||
{
|
||||
tmp = *(--m2M);
|
||||
*(--m1M_b0) = tmp;
|
||||
*(--m1M_b1) = tmp >> 16;
|
||||
}
|
||||
}
|
||||
|
||||
PICO_INTERNAL_ASM void wram_1M_to_2M(unsigned char *m)
|
||||
{
|
||||
unsigned short *m1M_b0, *m1M_b1;
|
||||
unsigned int i, tmp, *m2M;
|
||||
|
||||
m2M = (unsigned int *) m;
|
||||
m1M_b0 = (unsigned short *) (m + 0x20000);
|
||||
m1M_b1 = (unsigned short *) (m + 0x40000);
|
||||
|
||||
for (i = 0x40000/4; i; i--)
|
||||
{
|
||||
tmp = *m1M_b0++ | (*m1M_b1++ << 16);
|
||||
*m2M++ = tmp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
76
pico/cd/misc_arm.s
Normal file
76
pico/cd/misc_arm.s
Normal file
|
@ -0,0 +1,76 @@
|
|||
@ vim:filetype=armasm
|
||||
|
||||
@ Memory converters for different modes
|
||||
@ (c) Copyright 2007, Grazvydas "notaz" Ignotas
|
||||
|
||||
|
||||
@ r10 is tmp, io1 is lsb halfword, io2 is msb
|
||||
@ | 0 1 | 2 3 | -> | 0 2 | 1 3 | (little endian)
|
||||
.macro _conv_reg io1 io2
|
||||
mov r10, \io2, lsl #16
|
||||
and \io2, \io2, r11, lsl #16
|
||||
orr \io2, \io2, \io1, lsr #16
|
||||
and \io1, \io1, r11
|
||||
orr \io1, \io1, r10
|
||||
/*
|
||||
mov \io2, \io2, ror #16
|
||||
mov r10, \io1, lsl #16
|
||||
orr r10, r10, \io2, lsr #16
|
||||
mov \io1, \io1, lsr #16
|
||||
orr \io1, \io1, \io2, lsl #16
|
||||
mov \io2, r10, ror #16
|
||||
*/
|
||||
.endm
|
||||
|
||||
|
||||
.global wram_2M_to_1M
|
||||
wram_2M_to_1M:
|
||||
stmfd sp!,{r4-r11,lr}
|
||||
add r1, r0, #0x60000 @ m1M_b1
|
||||
add r0, r0, #0x40000 @ m1M_b0
|
||||
mov r2, r0 @ m2M
|
||||
|
||||
mov r11, #0xff
|
||||
orr r11, r11, r11, lsl #8
|
||||
mov r12, #(0x40000/8/4)
|
||||
|
||||
_2Mto1M_loop:
|
||||
ldmdb r2!,{r3-r9,lr}
|
||||
_conv_reg r3,r4
|
||||
_conv_reg r5,r6
|
||||
_conv_reg r7,r8
|
||||
_conv_reg r9,lr
|
||||
subs r12, r12, #1
|
||||
stmdb r0!,{r3,r5,r7,r9}
|
||||
stmdb r1!,{r4,r6,r8,lr}
|
||||
bne _2Mto1M_loop
|
||||
|
||||
ldmfd sp!,{r4-r11,pc}
|
||||
|
||||
|
||||
|
||||
.global wram_1M_to_2M
|
||||
wram_1M_to_2M:
|
||||
stmfd sp!,{r4-r11,lr}
|
||||
mov r2, r0 @ m2M
|
||||
add r1, r0, #0x40000 @ m1M_b1
|
||||
add r0, r0, #0x20000 @ m1M_b0
|
||||
|
||||
mov r11, #0xff
|
||||
orr r11, r11, r11, lsl #8
|
||||
mov r12, #(0x40000/8/4)
|
||||
|
||||
_1Mto2M_loop:
|
||||
ldmia r0!,{r3,r5,r7,r9}
|
||||
ldmia r1!,{r4,r6,r8,lr}
|
||||
_conv_reg r3,r4
|
||||
_conv_reg r5,r6
|
||||
_conv_reg r7,r8
|
||||
_conv_reg r9,lr
|
||||
subs r12, r12, #1
|
||||
stmia r2!,{r3-r9,lr}
|
||||
bne _1Mto2M_loop
|
||||
|
||||
ldmfd sp!,{r4-r11,pc}
|
||||
|
||||
|
133
pico/cd/pcm.c
Normal file
133
pico/cd/pcm.c
Normal file
|
@ -0,0 +1,133 @@
|
|||
// Emulation routines for the RF5C164 PCM chip.
|
||||
// Based on Gens code by Stéphane Dallongeville
|
||||
// (c) Copyright 2007, Grazvydas "notaz" Ignotas
|
||||
|
||||
#include "../pico_int.h"
|
||||
#include "pcm.h"
|
||||
|
||||
static unsigned int g_rate = 0; // 18.14 fixed point
|
||||
|
||||
PICO_INTERNAL_ASM void pcm_write(unsigned int a, unsigned int d)
|
||||
{
|
||||
//printf("pcm_write(%i, %02x)\n", a, d);
|
||||
|
||||
if (a < 7)
|
||||
{
|
||||
Pico_mcd->pcm.ch[Pico_mcd->pcm.cur_ch].regs[a] = d;
|
||||
}
|
||||
else if (a == 7) // control register
|
||||
{
|
||||
if (d & 0x40) Pico_mcd->pcm.cur_ch = d & 7;
|
||||
else Pico_mcd->pcm.bank = d & 0xf;
|
||||
Pico_mcd->pcm.control = d;
|
||||
// dprintf("pcm control=%02x", Pico_mcd->pcm.control);
|
||||
}
|
||||
else if (a == 8) // sound on/off
|
||||
{
|
||||
if (!(Pico_mcd->pcm.enabled & 0x01)) Pico_mcd->pcm.ch[0].addr =
|
||||
Pico_mcd->pcm.ch[0].regs[6] << (PCM_STEP_SHIFT + 8);
|
||||
if (!(Pico_mcd->pcm.enabled & 0x02)) Pico_mcd->pcm.ch[1].addr =
|
||||
Pico_mcd->pcm.ch[1].regs[6] << (PCM_STEP_SHIFT + 8);
|
||||
if (!(Pico_mcd->pcm.enabled & 0x04)) Pico_mcd->pcm.ch[2].addr =
|
||||
Pico_mcd->pcm.ch[2].regs[6] << (PCM_STEP_SHIFT + 8);
|
||||
if (!(Pico_mcd->pcm.enabled & 0x08)) Pico_mcd->pcm.ch[3].addr =
|
||||
Pico_mcd->pcm.ch[3].regs[6] << (PCM_STEP_SHIFT + 8);
|
||||
if (!(Pico_mcd->pcm.enabled & 0x10)) Pico_mcd->pcm.ch[4].addr =
|
||||
Pico_mcd->pcm.ch[4].regs[6] << (PCM_STEP_SHIFT + 8);
|
||||
if (!(Pico_mcd->pcm.enabled & 0x20)) Pico_mcd->pcm.ch[5].addr =
|
||||
Pico_mcd->pcm.ch[5].regs[6] << (PCM_STEP_SHIFT + 8);
|
||||
if (!(Pico_mcd->pcm.enabled & 0x40)) Pico_mcd->pcm.ch[6].addr =
|
||||
Pico_mcd->pcm.ch[6].regs[6] << (PCM_STEP_SHIFT + 8);
|
||||
if (!(Pico_mcd->pcm.enabled & 0x80)) Pico_mcd->pcm.ch[7].addr =
|
||||
Pico_mcd->pcm.ch[7].regs[6] << (PCM_STEP_SHIFT + 8);
|
||||
// printf("addr %x %x %x %x %x %x %x %x\n", Pico_mcd->pcm.ch[0].addr, Pico_mcd->pcm.ch[1].addr
|
||||
// , Pico_mcd->pcm.ch[2].addr, Pico_mcd->pcm.ch[3].addr, Pico_mcd->pcm.ch[4].addr, Pico_mcd->pcm.ch[5].addr
|
||||
// , Pico_mcd->pcm.ch[6].addr, Pico_mcd->pcm.ch[7].addr);
|
||||
|
||||
Pico_mcd->pcm.enabled = ~d;
|
||||
//printf("enabled=%02x\n", Pico_mcd->pcm.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL void pcm_set_rate(int rate)
|
||||
{
|
||||
float step = 31.8 * 1024.0 / (float) rate; // max <4 @ 8000Hz
|
||||
step *= 256*256/4;
|
||||
g_rate = (unsigned int) step;
|
||||
if (step - (float) g_rate >= 0.5) g_rate++;
|
||||
elprintf(EL_STATUS, "g_rate: %f %08x\n", (double)step, g_rate);
|
||||
}
|
||||
|
||||
|
||||
PICO_INTERNAL void pcm_update(int *buffer, int length, int stereo)
|
||||
{
|
||||
struct pcm_chan *ch;
|
||||
unsigned int step, addr;
|
||||
int mul_l, mul_r, smp;
|
||||
int i, j, k;
|
||||
int *out;
|
||||
|
||||
|
||||
// PCM disabled or all channels off (to be checked by caller)
|
||||
//if (!(Pico_mcd->pcm.control & 0x80) || !Pico_mcd->pcm.enabled) return;
|
||||
|
||||
//printf("-- upd %i\n", length);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (!(Pico_mcd->pcm.enabled & (1 << i))) continue; // channel disabled
|
||||
|
||||
out = buffer;
|
||||
ch = &Pico_mcd->pcm.ch[i];
|
||||
|
||||
addr = ch->addr; // >> PCM_STEP_SHIFT;
|
||||
mul_l = ((int)ch->regs[0] * (ch->regs[1] & 0xf)) >> (5+1); // (env * pan) >> 5
|
||||
mul_r = ((int)ch->regs[0] * (ch->regs[1] >> 4)) >> (5+1);
|
||||
step = ((unsigned int)(*(unsigned short *)&ch->regs[2]) * g_rate) >> 14; // freq step
|
||||
// fprintf(stderr, "step=%i, cstep=%i, mul_l=%i, mul_r=%i, ch=%i, addr=%x, en=%02x\n",
|
||||
// *(unsigned short *)&ch->regs[2], step, mul_l, mul_r, i, addr, Pico_mcd->pcm.enabled);
|
||||
|
||||
if (!stereo && mul_l < mul_r) mul_l = mul_r;
|
||||
|
||||
for (j = 0; j < length; j++)
|
||||
{
|
||||
// printf("addr=%08x\n", addr);
|
||||
smp = Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT];
|
||||
|
||||
// test for loop signal
|
||||
if (smp == 0xff)
|
||||
{
|
||||
addr = *(unsigned short *)&ch->regs[4]; // loop_addr
|
||||
smp = Pico_mcd->pcm_ram[addr];
|
||||
addr <<= PCM_STEP_SHIFT;
|
||||
if (smp == 0xff) break;
|
||||
}
|
||||
|
||||
if (smp & 0x80) smp = -(smp & 0x7f);
|
||||
|
||||
*out++ += smp * mul_l; // max 128 * 119 = 15232
|
||||
if(stereo)
|
||||
*out++ += smp * mul_r;
|
||||
|
||||
// update address register
|
||||
k = (addr >> PCM_STEP_SHIFT) + 1;
|
||||
addr = (addr + step) & 0x7FFFFFF;
|
||||
|
||||
for(; k < (addr >> PCM_STEP_SHIFT); k++)
|
||||
{
|
||||
if (Pico_mcd->pcm_ram[k] == 0xff)
|
||||
{
|
||||
addr = (unsigned int)(*(unsigned short *)&ch->regs[4]) << PCM_STEP_SHIFT; // loop_addr
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT] == 0xff)
|
||||
addr = (unsigned int)(*(unsigned short *)&ch->regs[4]) << PCM_STEP_SHIFT; // loop_addr
|
||||
|
||||
ch->addr = addr;
|
||||
}
|
||||
}
|
||||
|
7
pico/cd/pcm.h
Normal file
7
pico/cd/pcm.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
#define PCM_STEP_SHIFT 11
|
||||
|
||||
PICO_INTERNAL_ASM void pcm_write(unsigned int a, unsigned int d);
|
||||
PICO_INTERNAL void pcm_set_rate(int rate);
|
||||
PICO_INTERNAL void pcm_update(int *buffer, int length, int stereo);
|
||||
|
249
pico/cd/pico.c
Normal file
249
pico/cd/pico.c
Normal file
|
@ -0,0 +1,249 @@
|
|||
// (c) Copyright 2007 notaz, All rights reserved.
|
||||
|
||||
|
||||
#include "../pico_int.h"
|
||||
#include "../sound/ym2612.h"
|
||||
|
||||
extern unsigned char formatted_bram[4*0x10];
|
||||
extern unsigned int s68k_poll_adclk;
|
||||
|
||||
void (*PicoMCDopenTray)(void) = NULL;
|
||||
int (*PicoMCDcloseTray)(void) = NULL;
|
||||
|
||||
|
||||
PICO_INTERNAL void PicoInitMCD(void)
|
||||
{
|
||||
SekInitS68k();
|
||||
Init_CD_Driver();
|
||||
}
|
||||
|
||||
PICO_INTERNAL void PicoExitMCD(void)
|
||||
{
|
||||
End_CD_Driver();
|
||||
}
|
||||
|
||||
PICO_INTERNAL void PicoPowerMCD(void)
|
||||
{
|
||||
int fmt_size = sizeof(formatted_bram);
|
||||
memset(Pico_mcd->prg_ram, 0, sizeof(Pico_mcd->prg_ram));
|
||||
memset(Pico_mcd->word_ram2M, 0, sizeof(Pico_mcd->word_ram2M));
|
||||
memset(Pico_mcd->pcm_ram, 0, sizeof(Pico_mcd->pcm_ram));
|
||||
memset(Pico_mcd->bram, 0, sizeof(Pico_mcd->bram));
|
||||
memcpy(Pico_mcd->bram + sizeof(Pico_mcd->bram) - fmt_size, formatted_bram, fmt_size);
|
||||
}
|
||||
|
||||
PICO_INTERNAL int PicoResetMCD(void)
|
||||
{
|
||||
memset(Pico_mcd->s68k_regs, 0, sizeof(Pico_mcd->s68k_regs));
|
||||
memset(&Pico_mcd->pcm, 0, sizeof(Pico_mcd->pcm));
|
||||
memset(&Pico_mcd->m, 0, sizeof(Pico_mcd->m));
|
||||
|
||||
*(unsigned int *)(Pico_mcd->bios + 0x70) = 0xffffffff; // reset hint vector (simplest way to implement reg6)
|
||||
Pico_mcd->m.state_flags |= 1; // s68k reset pending
|
||||
Pico_mcd->s68k_regs[3] = 1; // 2M word RAM mode with m68k access after reset
|
||||
|
||||
Reset_CD();
|
||||
LC89510_Reset();
|
||||
gfx_cd_reset();
|
||||
PicoMemResetCD(1);
|
||||
#ifdef _ASM_CD_MEMORY_C
|
||||
//PicoMemResetCDdecode(1); // don't have to call this in 2M mode
|
||||
#endif
|
||||
|
||||
// use SRam.data for RAM cart
|
||||
if (PicoOpt&POPT_EN_MCD_RAMCART) {
|
||||
if (SRam.data == NULL)
|
||||
SRam.data = calloc(1, 0x12000);
|
||||
}
|
||||
else if (SRam.data != NULL) {
|
||||
free(SRam.data);
|
||||
SRam.data = NULL;
|
||||
}
|
||||
SRam.start = SRam.end = 0; // unused
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline void SekRunM68k(int cyc)
|
||||
{
|
||||
int cyc_do;
|
||||
SekCycleAim+=cyc;
|
||||
if ((cyc_do=SekCycleAim-SekCycleCnt) <= 0) return;
|
||||
#if defined(EMU_CORE_DEBUG)
|
||||
SekCycleCnt+=CM_compareRun(cyc_do, 0);
|
||||
#elif defined(EMU_C68K)
|
||||
PicoCpuCM68k.cycles=cyc_do;
|
||||
CycloneRun(&PicoCpuCM68k);
|
||||
SekCycleCnt+=cyc_do-PicoCpuCM68k.cycles;
|
||||
#elif defined(EMU_M68K)
|
||||
m68k_set_context(&PicoCpuMM68k);
|
||||
SekCycleCnt+=m68k_execute(cyc_do);
|
||||
#elif defined(EMU_F68K)
|
||||
g_m68kcontext=&PicoCpuFM68k;
|
||||
SekCycleCnt+=fm68k_emulate(cyc_do, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static __inline void SekRunS68k(int cyc)
|
||||
{
|
||||
int cyc_do;
|
||||
SekCycleAimS68k+=cyc;
|
||||
if ((cyc_do=SekCycleAimS68k-SekCycleCntS68k) <= 0) return;
|
||||
#if defined(EMU_CORE_DEBUG)
|
||||
SekCycleCntS68k+=CM_compareRun(cyc_do, 1);
|
||||
#elif defined(EMU_C68K)
|
||||
PicoCpuCS68k.cycles=cyc_do;
|
||||
CycloneRun(&PicoCpuCS68k);
|
||||
SekCycleCntS68k+=cyc_do-PicoCpuCS68k.cycles;
|
||||
#elif defined(EMU_M68K)
|
||||
m68k_set_context(&PicoCpuMS68k);
|
||||
SekCycleCntS68k+=m68k_execute(cyc_do);
|
||||
#elif defined(EMU_F68K)
|
||||
g_m68kcontext=&PicoCpuFS68k;
|
||||
SekCycleCntS68k+=fm68k_emulate(cyc_do, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define PS_STEP_M68K ((488<<16)/20) // ~24
|
||||
//#define PS_STEP_S68K 13
|
||||
|
||||
#if defined(_ASM_CD_PICO_C)
|
||||
extern void SekRunPS(int cyc_m68k, int cyc_s68k);
|
||||
#elif defined(EMU_F68K)
|
||||
static __inline void SekRunPS(int cyc_m68k, int cyc_s68k)
|
||||
{
|
||||
SekCycleAim+=cyc_m68k;
|
||||
SekCycleAimS68k+=cyc_s68k;
|
||||
fm68k_emulate(0, 1, 0);
|
||||
}
|
||||
#else
|
||||
static __inline void SekRunPS(int cyc_m68k, int cyc_s68k)
|
||||
{
|
||||
int cycn, cycn_s68k, cyc_do;
|
||||
SekCycleAim+=cyc_m68k;
|
||||
SekCycleAimS68k+=cyc_s68k;
|
||||
|
||||
// fprintf(stderr, "=== start %3i/%3i [%3i/%3i] {%05i.%i} ===\n", cyc_m68k, cyc_s68k,
|
||||
// SekCycleAim-SekCycleCnt, SekCycleAimS68k-SekCycleCntS68k, Pico.m.frame_count, Pico.m.scanline);
|
||||
|
||||
/* loop 488 downto 0 in steps of PS_STEP */
|
||||
for (cycn = (488<<16)-PS_STEP_M68K; cycn >= 0; cycn -= PS_STEP_M68K)
|
||||
{
|
||||
cycn_s68k = (cycn + cycn/2 + cycn/8) >> 16;
|
||||
if ((cyc_do = SekCycleAim-SekCycleCnt-(cycn>>16)) > 0) {
|
||||
#if defined(EMU_C68K)
|
||||
PicoCpuCM68k.cycles = cyc_do;
|
||||
CycloneRun(&PicoCpuCM68k);
|
||||
SekCycleCnt += cyc_do - PicoCpuCM68k.cycles;
|
||||
#elif defined(EMU_M68K)
|
||||
m68k_set_context(&PicoCpuMM68k);
|
||||
SekCycleCnt += m68k_execute(cyc_do);
|
||||
#elif defined(EMU_F68K)
|
||||
g_m68kcontext = &PicoCpuFM68k;
|
||||
SekCycleCnt += fm68k_emulate(cyc_do, 0, 0);
|
||||
#endif
|
||||
}
|
||||
if ((cyc_do = SekCycleAimS68k-SekCycleCntS68k-cycn_s68k) > 0) {
|
||||
#if defined(EMU_C68K)
|
||||
PicoCpuCS68k.cycles = cyc_do;
|
||||
CycloneRun(&PicoCpuCS68k);
|
||||
SekCycleCntS68k += cyc_do - PicoCpuCS68k.cycles;
|
||||
#elif defined(EMU_M68K)
|
||||
m68k_set_context(&PicoCpuMS68k);
|
||||
SekCycleCntS68k += m68k_execute(cyc_do);
|
||||
#elif defined(EMU_F68K)
|
||||
g_m68kcontext = &PicoCpuFS68k;
|
||||
SekCycleCntS68k += fm68k_emulate(cyc_do, 0, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static __inline void check_cd_dma(void)
|
||||
{
|
||||
int ddx;
|
||||
|
||||
if (!(Pico_mcd->scd.Status_CDC & 0x08)) return;
|
||||
|
||||
ddx = Pico_mcd->s68k_regs[4] & 7;
|
||||
if (ddx < 2) return; // invalid
|
||||
if (ddx < 4) {
|
||||
Pico_mcd->s68k_regs[4] |= 0x40; // Data set ready in host port
|
||||
return;
|
||||
}
|
||||
if (ddx == 6) return; // invalid
|
||||
|
||||
Update_CDC_TRansfer(ddx); // now go and do the actual transfer
|
||||
}
|
||||
|
||||
static __inline void update_chips(void)
|
||||
{
|
||||
int counter_timer, int3_set;
|
||||
int counter75hz_lim = Pico.m.pal ? 2080 : 2096;
|
||||
|
||||
// 75Hz CDC update
|
||||
if ((Pico_mcd->m.counter75hz+=10) >= counter75hz_lim) {
|
||||
Pico_mcd->m.counter75hz -= counter75hz_lim;
|
||||
Check_CD_Command();
|
||||
}
|
||||
|
||||
// update timers
|
||||
counter_timer = Pico.m.pal ? 0x21630 : 0x2121c; // 136752 : 135708;
|
||||
Pico_mcd->m.timer_stopwatch += counter_timer;
|
||||
if ((int3_set = Pico_mcd->s68k_regs[0x31])) {
|
||||
Pico_mcd->m.timer_int3 -= counter_timer;
|
||||
if (Pico_mcd->m.timer_int3 < 0) {
|
||||
if (Pico_mcd->s68k_regs[0x33] & (1<<3)) {
|
||||
elprintf(EL_INTS, "s68k: timer irq 3");
|
||||
SekInterruptS68k(3);
|
||||
Pico_mcd->m.timer_int3 += int3_set << 16;
|
||||
}
|
||||
// is this really what happens if irq3 is masked out?
|
||||
Pico_mcd->m.timer_int3 &= 0xffffff;
|
||||
}
|
||||
}
|
||||
|
||||
// update gfx chip
|
||||
if (Pico_mcd->rot_comp.Reg_58 & 0x8000)
|
||||
gfx_cd_update();
|
||||
|
||||
// delayed setting of DMNA bit (needed for Silpheed)
|
||||
if (Pico_mcd->m.state_flags & 2) {
|
||||
Pico_mcd->m.state_flags &= ~2;
|
||||
if (!(Pico_mcd->s68k_regs[3] & 4)) {
|
||||
Pico_mcd->s68k_regs[3] |= 2;
|
||||
Pico_mcd->s68k_regs[3] &= ~1;
|
||||
#ifdef USE_POLL_DETECT
|
||||
if ((s68k_poll_adclk&0xfe) == 2) {
|
||||
SekSetStopS68k(0); s68k_poll_adclk = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static __inline void getSamples(int y)
|
||||
{
|
||||
int len = PsndRender(0, PsndLen);
|
||||
if (PicoWriteSound) PicoWriteSound(len);
|
||||
// clear sound buffer
|
||||
PsndClear();
|
||||
}
|
||||
|
||||
|
||||
#define PICO_CD
|
||||
#include "../pico_cmn.c"
|
||||
|
||||
|
||||
PICO_INTERNAL void PicoFrameMCD(void)
|
||||
{
|
||||
if (!(PicoOpt&POPT_ALT_RENDERER))
|
||||
PicoFrameStart();
|
||||
|
||||
PicoFrameHints();
|
||||
}
|
||||
|
||||
|
181
pico/cd/pico_arm.s
Normal file
181
pico/cd/pico_arm.s
Normal file
|
@ -0,0 +1,181 @@
|
|||
@ vim:filetype=armasm
|
||||
|
||||
@ SekRunPS runs PicoCpuCM68k and PicoCpuCS68k interleaved in steps of PS_STEP_M68K
|
||||
@ cycles. This is done without calling CycloneRun and jumping directly to
|
||||
@ Cyclone code to avoid pushing/popping all the registers every time.
|
||||
|
||||
@ (c) Copyright 2007, Grazvydas "notaz" Ignotas
|
||||
@ All Rights Reserved
|
||||
|
||||
|
||||
.equiv PS_STEP_M68K, ((488<<16)/20) @ ~24
|
||||
|
||||
@ .extern is ignored by gas, we add these here just to see what we depend on.
|
||||
.extern CycloneJumpTab
|
||||
.extern CycloneDoInterrupt
|
||||
.extern PicoCpuCM68k
|
||||
.extern PicoCpuCS68k
|
||||
.extern SekCycleAim
|
||||
.extern SekCycleCnt
|
||||
.extern SekCycleAimS68k
|
||||
.extern SekCycleCntS68k
|
||||
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
|
||||
.global SekRunPS @ cyc_m68k, cyc_s68k
|
||||
|
||||
SekRunPS:
|
||||
stmfd sp!, {r4-r8,r10,r11,lr}
|
||||
sub sp, sp, #2*4 @ sp[0] = main_cycle_cnt, sp[4] = run_cycle_cnt
|
||||
|
||||
@ override CycloneEnd for both contexts
|
||||
ldr r7, =PicoCpuCM68k
|
||||
ldr lr, =PicoCpuCS68k
|
||||
ldr r2, =CycloneEnd_M68k
|
||||
ldr r3, =CycloneEnd_S68k
|
||||
str r2, [r7,#0x98]
|
||||
str r3, [lr,#0x98]
|
||||
|
||||
@ update aims
|
||||
ldr r8, =SekCycleAim
|
||||
ldr r10,=SekCycleAimS68k
|
||||
ldr r2, [r8]
|
||||
ldr r3, [r10]
|
||||
add r2, r2, r0
|
||||
add r3, r3, r1
|
||||
str r2, [r8]
|
||||
str r3, [r10]
|
||||
|
||||
ldr r6, =CycloneJumpTab
|
||||
ldr r1, =SekCycleCnt
|
||||
ldr r0, =((488<<16)-PS_STEP_M68K)
|
||||
str r6, [r7,#0x54]
|
||||
str r6, [lr,#0x54] @ make copies to avoid literal pools
|
||||
|
||||
@ schedule m68k for the first time..
|
||||
ldr r1, [r1]
|
||||
str r0, [sp] @ main target 'left cycle' counter
|
||||
sub r1, r2, r1
|
||||
subs r5, r1, r0, asr #16
|
||||
ble schedule_s68k @ m68k has not enough cycles
|
||||
|
||||
str r5, [sp,#4] @ run_cycle_cnt
|
||||
b CycloneRunLocal
|
||||
|
||||
|
||||
|
||||
CycloneEnd_M68k:
|
||||
ldr r3, =SekCycleCnt
|
||||
ldr r0, [sp,#4] @ run_cycle_cnt
|
||||
ldr r1, [r3]
|
||||
str r4, [r7,#0x40] ;@ Save Current PC + Memory Base
|
||||
strb r10,[r7,#0x46] ;@ Save Flags (NZCV)
|
||||
sub r0, r0, r5 @ subtract leftover cycles (which should be negative)
|
||||
add r0, r0, r1
|
||||
str r0, [r3]
|
||||
|
||||
schedule_s68k:
|
||||
ldr r8, =SekCycleCntS68k
|
||||
ldr r10,=SekCycleAimS68k
|
||||
ldr r3, [sp]
|
||||
ldr r8, [r8]
|
||||
ldr r10,[r10]
|
||||
|
||||
sub r0, r10, r8
|
||||
mov r2, r3
|
||||
add r3, r3, r2, asr #1
|
||||
add r3, r3, r2, asr #3 @ cycn_s68k = (cycn + cycn/2 + cycn/8)
|
||||
|
||||
subs r5, r0, r3, asr #16
|
||||
ble schedule_m68k @ s68k has not enough cycles
|
||||
|
||||
ldr r7, =PicoCpuCS68k
|
||||
str r5, [sp,#4] @ run_cycle_cnt
|
||||
b CycloneRunLocal
|
||||
|
||||
|
||||
|
||||
CycloneEnd_S68k:
|
||||
ldr r3, =SekCycleCntS68k
|
||||
ldr r0, [sp,#4] @ run_cycle_cnt
|
||||
ldr r1, [r3]
|
||||
str r4, [r7,#0x40] ;@ Save Current PC + Memory Base
|
||||
strb r10,[r7,#0x46] ;@ Save Flags (NZCV)
|
||||
sub r0, r0, r5 @ subtract leftover cycles (should be negative)
|
||||
add r0, r0, r1
|
||||
str r0, [r3]
|
||||
|
||||
schedule_m68k:
|
||||
ldr r1, =PS_STEP_M68K
|
||||
ldr r3, [sp] @ main_cycle_cnt
|
||||
ldr r8, =SekCycleCnt
|
||||
ldr r10,=SekCycleAim
|
||||
subs r3, r3, r1
|
||||
bmi SekRunPS_end
|
||||
|
||||
ldr r8, [r8]
|
||||
ldr r10,[r10]
|
||||
str r3, [sp] @ update main_cycle_cnt
|
||||
sub r0, r10, r8
|
||||
|
||||
subs r5, r0, r3, asr #16
|
||||
ble schedule_s68k @ m68k has not enough cycles
|
||||
|
||||
ldr r7, =PicoCpuCM68k
|
||||
str r5, [sp,#4] @ run_cycle_cnt
|
||||
b CycloneRunLocal
|
||||
|
||||
|
||||
|
||||
SekRunPS_end:
|
||||
ldr r7, =PicoCpuCM68k
|
||||
ldr lr, =PicoCpuCS68k
|
||||
mov r0, #0
|
||||
str r0, [r7,#0x98] @ remove CycloneEnd handler
|
||||
str r0, [lr,#0x98]
|
||||
@ return
|
||||
add sp, sp, #2*4
|
||||
ldmfd sp!, {r4-r8,r10,r11,pc}
|
||||
|
||||
|
||||
|
||||
CycloneRunLocal:
|
||||
;@ r0-3 = Temporary registers
|
||||
ldr r4,[r7,#0x40] ;@ r4 = Current PC + Memory Base
|
||||
;@ r5 = Cycles
|
||||
;@ r6 = Opcode Jump table
|
||||
;@ r7 = Pointer to Cpu Context
|
||||
;@ r8 = Current Opcode
|
||||
ldrb r10,[r7,#0x46];@ r10 = Flags (NZCV)
|
||||
ldr r1,[r7,#0x44] ;@ get SR high and IRQ level
|
||||
orr r10,r10,r10,lsl #28 ;@ r10 = Flags 0xf0000000, cpsr format
|
||||
|
||||
;@ CheckInterrupt:
|
||||
movs r0,r1,lsr #24 ;@ Get IRQ level
|
||||
beq NoIntsLocal
|
||||
cmp r0,#6 ;@ irq>6 ?
|
||||
andle r1,r1,#7 ;@ Get interrupt mask
|
||||
cmple r0,r1 ;@ irq<=6: Is irq<=mask ?
|
||||
bgt CycloneDoInterrupt
|
||||
NoIntsLocal:
|
||||
|
||||
;@ Check if our processor is in special state
|
||||
;@ and jump to opcode handler if not
|
||||
ldr r0,[r7,#0x58] ;@ state_flags
|
||||
ldrh r8,[r4],#2 ;@ Fetch first opcode
|
||||
tst r0,#0x03 ;@ special state?
|
||||
andeq r10,r10,#0xf0000000
|
||||
ldreq pc,[r6,r8,asl #2] ;@ Jump to opcode handler
|
||||
|
||||
CycloneSpecial2:
|
||||
tst r0,#2 ;@ tracing?
|
||||
bne CycloneDoTrace
|
||||
;@ stopped or halted
|
||||
sub r4,r4,#2
|
||||
ldr r1,[r7,#0x98]
|
||||
mov r5,#0
|
||||
bx r1
|
||||
|
196
pico/cd/sek.c
Normal file
196
pico/cd/sek.c
Normal file
|
@ -0,0 +1,196 @@
|
|||
// (c) Copyright 2007 notaz, All rights reserved.
|
||||
|
||||
|
||||
#include "../pico_int.h"
|
||||
|
||||
|
||||
int SekCycleCntS68k=0; // cycles done in this frame
|
||||
int SekCycleAimS68k=0; // cycle aim
|
||||
|
||||
|
||||
/* context */
|
||||
// Cyclone 68000
|
||||
#ifdef EMU_C68K
|
||||
struct Cyclone PicoCpuCS68k;
|
||||
#endif
|
||||
// MUSASHI 68000
|
||||
#ifdef EMU_M68K
|
||||
m68ki_cpu_core PicoCpuMS68k;
|
||||
#endif
|
||||
// FAME 68000
|
||||
#ifdef EMU_F68K
|
||||
M68K_CONTEXT PicoCpuFS68k;
|
||||
#endif
|
||||
|
||||
|
||||
static int new_irq_level(int level)
|
||||
{
|
||||
int level_new = 0, irqs;
|
||||
Pico_mcd->m.s68k_pend_ints &= ~(1 << level);
|
||||
irqs = Pico_mcd->m.s68k_pend_ints;
|
||||
irqs &= Pico_mcd->s68k_regs[0x33];
|
||||
while ((irqs >>= 1)) level_new++;
|
||||
|
||||
return level_new;
|
||||
}
|
||||
|
||||
#ifdef EMU_C68K
|
||||
// interrupt acknowledgement
|
||||
static int SekIntAckS68k(int level)
|
||||
{
|
||||
int level_new = new_irq_level(level);
|
||||
|
||||
elprintf(EL_INTS, "s68kACK %i -> %i", level, level_new);
|
||||
PicoCpuCS68k.irq = level_new;
|
||||
return CYCLONE_INT_ACK_AUTOVECTOR;
|
||||
}
|
||||
|
||||
static void SekResetAckS68k(void)
|
||||
{
|
||||
elprintf(EL_ANOMALY, "s68k: Reset encountered @ %06x", SekPcS68k);
|
||||
}
|
||||
|
||||
static int SekUnrecognizedOpcodeS68k(void)
|
||||
{
|
||||
unsigned int pc, op;
|
||||
pc = SekPcS68k;
|
||||
op = PicoCpuCS68k.read16(pc);
|
||||
elprintf(EL_ANOMALY, "Unrecognized Opcode %04x @ %06x", op, pc);
|
||||
//exit(1);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EMU_M68K
|
||||
static int SekIntAckMS68k(int level)
|
||||
{
|
||||
#ifndef EMU_CORE_DEBUG
|
||||
int level_new = new_irq_level(level);
|
||||
elprintf(EL_INTS, "s68kACK %i -> %i", level, level_new);
|
||||
CPU_INT_LEVEL = level_new << 8;
|
||||
#else
|
||||
CPU_INT_LEVEL = 0;
|
||||
#endif
|
||||
return M68K_INT_ACK_AUTOVECTOR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EMU_F68K
|
||||
static void SekIntAckFS68k(unsigned level)
|
||||
{
|
||||
int level_new = new_irq_level(level);
|
||||
elprintf(EL_INTS, "s68kACK %i -> %i", level, level_new);
|
||||
#ifndef EMU_CORE_DEBUG
|
||||
PicoCpuFS68k.interrupts[0] = level_new;
|
||||
#else
|
||||
{
|
||||
extern int dbg_irq_level_sub;
|
||||
dbg_irq_level_sub = level_new;
|
||||
PicoCpuFS68k.interrupts[0] = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
PICO_INTERNAL void SekInitS68k(void)
|
||||
{
|
||||
#ifdef EMU_C68K
|
||||
// CycloneInit();
|
||||
memset(&PicoCpuCS68k,0,sizeof(PicoCpuCS68k));
|
||||
PicoCpuCS68k.IrqCallback=SekIntAckS68k;
|
||||
PicoCpuCS68k.ResetCallback=SekResetAckS68k;
|
||||
PicoCpuCS68k.UnrecognizedCallback=SekUnrecognizedOpcodeS68k;
|
||||
#endif
|
||||
#ifdef EMU_M68K
|
||||
{
|
||||
// Musashi is not very context friendly..
|
||||
void *oldcontext = m68ki_cpu_p;
|
||||
m68k_set_context(&PicoCpuMS68k);
|
||||
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
|
||||
m68k_init();
|
||||
m68k_set_int_ack_callback(SekIntAckMS68k);
|
||||
// m68k_pulse_reset(); // not yet, memmap is not set up
|
||||
m68k_set_context(oldcontext);
|
||||
}
|
||||
#endif
|
||||
#ifdef EMU_F68K
|
||||
{
|
||||
void *oldcontext = g_m68kcontext;
|
||||
g_m68kcontext = &PicoCpuFS68k;
|
||||
memset(&PicoCpuFS68k, 0, sizeof(PicoCpuFS68k));
|
||||
fm68k_init();
|
||||
PicoCpuFS68k.iack_handler = SekIntAckFS68k;
|
||||
PicoCpuFS68k.sr = 0x2704; // Z flag
|
||||
g_m68kcontext = oldcontext;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Reset the 68000:
|
||||
PICO_INTERNAL int SekResetS68k(void)
|
||||
{
|
||||
if (Pico.rom==NULL) return 1;
|
||||
|
||||
#ifdef EMU_C68K
|
||||
PicoCpuCS68k.state_flags=0;
|
||||
PicoCpuCS68k.osp=0;
|
||||
PicoCpuCS68k.srh =0x27; // Supervisor mode
|
||||
PicoCpuCS68k.flags=4; // Z set
|
||||
PicoCpuCS68k.irq=0;
|
||||
PicoCpuCS68k.a[7]=PicoCpuCS68k.read32(0); // Stack Pointer
|
||||
PicoCpuCS68k.membase=0;
|
||||
PicoCpuCS68k.pc=PicoCpuCS68k.checkpc(PicoCpuCS68k.read32(4)); // Program Counter
|
||||
#endif
|
||||
#ifdef EMU_M68K
|
||||
{
|
||||
void *oldcontext = m68ki_cpu_p;
|
||||
|
||||
m68k_set_context(&PicoCpuMS68k);
|
||||
m68ki_cpu.sp[0]=0;
|
||||
m68k_set_irq(0);
|
||||
m68k_pulse_reset();
|
||||
m68k_set_context(oldcontext);
|
||||
}
|
||||
#endif
|
||||
#ifdef EMU_F68K
|
||||
{
|
||||
void *oldcontext = g_m68kcontext;
|
||||
g_m68kcontext = &PicoCpuFS68k;
|
||||
fm68k_reset();
|
||||
g_m68kcontext = oldcontext;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PICO_INTERNAL int SekInterruptS68k(int irq)
|
||||
{
|
||||
int irqs, real_irq = 1;
|
||||
Pico_mcd->m.s68k_pend_ints |= 1 << irq;
|
||||
irqs = Pico_mcd->m.s68k_pend_ints >> 1;
|
||||
while ((irqs >>= 1)) real_irq++;
|
||||
|
||||
#ifdef EMU_CORE_DEBUG
|
||||
{
|
||||
extern int dbg_irq_level_sub;
|
||||
dbg_irq_level_sub=real_irq;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef EMU_C68K
|
||||
PicoCpuCS68k.irq=real_irq;
|
||||
#endif
|
||||
#ifdef EMU_M68K
|
||||
void *oldcontext = m68ki_cpu_p;
|
||||
m68k_set_context(&PicoCpuMS68k);
|
||||
m68k_set_irq(real_irq);
|
||||
m68k_set_context(oldcontext);
|
||||
#endif
|
||||
#ifdef EMU_F68K
|
||||
PicoCpuFS68k.interrupts[0]=real_irq;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue