lowercasing filenames, part3

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@576 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
notaz 2008-08-28 12:36:57 +00:00
parent d158df697d
commit 1cfc5cc4ce
71 changed files with 0 additions and 0 deletions

624
pico/cd/LC89510.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}