\r
// setup correct memory map for loaded ROM\r
// call PicoMemReset again due to possible memmap change\r
- if (PicoAHW & PAHW_MCD)\r
- PicoMemSetupCD();\r
- else PicoMemSetup();\r
+ switch (PicoAHW) {\r
+ default:\r
+ elprintf(EL_STATUS|EL_ANOMALY, "starting in unknown hw configuration: %x", PicoAHW);\r
+ case 0:\r
+ case PAHW_SVP: PicoMemSetup(); break;\r
+ case PAHW_MCD: PicoMemSetupCD(); break;\r
+ case PAHW_PICO: PicoMemSetupPico(); break;\r
+ }\r
PicoMemReset();\r
\r
PicoPower();\r
PicoSVPStartup();\r
}\r
\r
+ // Pico\r
+ else if (rom_strcmp(0x100, "SEGA PICO") == 0 ||\r
+ rom_strcmp(0x100, "IMA IKUNOUJYUKU") == 0) // what is that supposed to mean?\r
+ {\r
+ PicoInitPico();\r
+ }\r
+\r
// Detect 12-in-1 mapper\r
else if ((name_cmp("ROBOCOP 3") == 0 && Pico.romsize == 0x200000) ||\r
(rom_strcmp(0x160, "FLICKY") == 0 && Pico.romsize >= 0x200000) ||\r
{\r
u32 d=0;\r
\r
+ // 32x test\r
+/*\r
+ if (a == 0xa130ec) { d = 0x4d41; goto end; } // MA\r
+ else if (a == 0xa130ee) { d = 0x5253; goto end; } // RS\r
+ else if (a == 0xa15100) { d = 0x0080; goto end; }\r
+ else\r
+*/\r
+\r
// for games with simple protection devices, discovered by Haze\r
// some dumb detection is used, but that should be enough to make things work\r
if ((a>>22) == 1 && Pico.romsize >= 512*1024) {\r
\r
// -----------------------------------------------------------------\r
\r
-// TODO: asm code\r
static void OtherWrite16End(u32 a,u32 d,int realsize)\r
{\r
PicoWrite8Hook(a, d>>8, realsize);\r
PicoWrite16Hook = OtherWrite16End;\r
}\r
\r
+#ifdef EMU_M68K\r
+static void m68k_mem_setup(void);\r
+#endif\r
+\r
PICO_INTERNAL void PicoMemSetup(void)\r
{\r
// Setup memory callbacks:\r
// setup FAME fetchmap\r
{\r
int i;\r
- // by default, point everything to fitst 64k of ROM\r
+ // by default, point everything to first 64k of ROM\r
for (i = 0; i < M68K_FETCHBANK1; i++)\r
PicoCpuFM68k.Fetch[i] = (unsigned int)Pico.rom - (i<<(24-FAMEC_FETCHBITS));\r
// now real ROM\r
PicoCpuFM68k.Fetch[i] = (unsigned int)Pico.ram - (i<<(24-FAMEC_FETCHBITS));\r
}\r
#endif\r
+#ifdef EMU_M68K\r
+ m68k_mem_setup();\r
+#endif\r
}\r
\r
-\r
+/* some nasty things below :( */\r
#ifdef EMU_M68K\r
-unsigned int m68k_read_pcrelative_CD8 (unsigned int a);\r
-unsigned int m68k_read_pcrelative_CD16(unsigned int a);\r
-unsigned int m68k_read_pcrelative_CD32(unsigned int a);\r
-\r
-// these are allowed to access RAM\r
+unsigned int (*pm68k_read_memory_8) (unsigned int address) = NULL;\r
+unsigned int (*pm68k_read_memory_16)(unsigned int address) = NULL;\r
+unsigned int (*pm68k_read_memory_32)(unsigned int address) = NULL;\r
+void (*pm68k_write_memory_8) (unsigned int address, unsigned char value) = NULL;\r
+void (*pm68k_write_memory_16)(unsigned int address, unsigned short value) = NULL;\r
+void (*pm68k_write_memory_32)(unsigned int address, unsigned int value) = NULL;\r
+unsigned int (*pm68k_read_memory_pcr_8) (unsigned int address) = NULL;\r
+unsigned int (*pm68k_read_memory_pcr_16)(unsigned int address) = NULL;\r
+unsigned int (*pm68k_read_memory_pcr_32)(unsigned int address) = NULL;\r
+\r
+// these are here for core debugging mode\r
static unsigned int m68k_read_8 (unsigned int a, int do_fake)\r
{\r
a&=0xffffff;\r
#ifdef EMU_CORE_DEBUG\r
if(do_fake&&((ppop&0x3f)==0x3a||(ppop&0x3f)==0x3b)) return lastread_d[lrp_mus++&15];\r
#endif\r
- if(PicoAHW&1) return m68k_read_pcrelative_CD8(a);\r
- if((a&0xe00000)==0xe00000) return *(u8 *)(Pico.ram+((a^1)&0xffff)); // Ram\r
- return 0;\r
+ return pm68k_read_memory_pcr_8(a);\r
}\r
static unsigned int m68k_read_16(unsigned int a, int do_fake)\r
{\r
#ifdef EMU_CORE_DEBUG\r
if(do_fake&&((ppop&0x3f)==0x3a||(ppop&0x3f)==0x3b)) return lastread_d[lrp_mus++&15];\r
#endif\r
- if(PicoAHW&1) return m68k_read_pcrelative_CD16(a);\r
- if((a&0xe00000)==0xe00000) return *(u16 *)(Pico.ram+(a&0xfffe)); // Ram\r
- return 0;\r
+ return pm68k_read_memory_pcr_16(a);\r
}\r
static unsigned int m68k_read_32(unsigned int a, int do_fake)\r
{\r
#ifdef EMU_CORE_DEBUG\r
if(do_fake&&((ppop&0x3f)==0x3a||(ppop&0x3f)==0x3b)) return lastread_d[lrp_mus++&15];\r
#endif\r
- if(PicoAHW&1) return m68k_read_pcrelative_CD32(a);\r
- if((a&0xe00000)==0xe00000) { u16 *pm=(u16 *)(Pico.ram+(a&0xfffe)); return (pm[0]<<16)|pm[1]; } // Ram\r
- return 0;\r
+ return pm68k_read_memory_pcr_32(a);\r
}\r
\r
unsigned int m68k_read_pcrelative_8 (unsigned int a) { return m68k_read_8 (a, 1); }\r
unsigned int m68k_read_disassembler_16(unsigned int a) { return m68k_read_16(a, 0); }\r
unsigned int m68k_read_disassembler_32(unsigned int a) { return m68k_read_32(a, 0); }\r
\r
+static unsigned int m68k_read_memory_pcr_8(unsigned int a)\r
+{\r
+ if((a&0xe00000)==0xe00000) return *(u8 *)(Pico.ram+((a^1)&0xffff)); // Ram\r
+ return 0;\r
+}\r
+\r
+static unsigned int m68k_read_memory_pcr_16(unsigned int a)\r
+{\r
+ if((a&0xe00000)==0xe00000) return *(u16 *)(Pico.ram+(a&0xfffe)); // Ram\r
+ return 0;\r
+}\r
+\r
+static unsigned int m68k_read_memory_pcr_32(unsigned int a)\r
+{\r
+ if((a&0xe00000)==0xe00000) { u16 *pm=(u16 *)(Pico.ram+(a&0xfffe)); return (pm[0]<<16)|pm[1]; } // Ram\r
+ return 0;\r
+}\r
+\r
#ifdef EMU_CORE_DEBUG\r
// ROM only\r
unsigned int m68k_read_memory_8(unsigned int a)\r
void m68k_write_memory_8(unsigned int address, unsigned int value) { lastwrite_mus_d[lwp_mus++&15] = value; }\r
void m68k_write_memory_16(unsigned int address, unsigned int value) { lastwrite_mus_d[lwp_mus++&15] = value; }\r
void m68k_write_memory_32(unsigned int address, unsigned int value) { lastwrite_mus_d[lwp_mus++&15] = value; }\r
-#else\r
-unsigned char PicoReadCD8w (unsigned int a);\r
-unsigned short PicoReadCD16w(unsigned int a);\r
-unsigned int PicoReadCD32w(unsigned int a);\r
-void PicoWriteCD8w (unsigned int a, unsigned char d);\r
-void PicoWriteCD16w(unsigned int a, unsigned short d);\r
-void PicoWriteCD32w(unsigned int a, unsigned int d);\r
-\r
-/* it appears that Musashi doesn't always mask the unused bits */\r
-unsigned int m68k_read_memory_8(unsigned int address)\r
-{\r
- unsigned int d = (PicoAHW&1) ? PicoReadCD8w(address) : PicoRead8(address);\r
- return d&0xff;\r
-}\r
-\r
-unsigned int m68k_read_memory_16(unsigned int address)\r
-{\r
- unsigned int d = (PicoAHW&1) ? PicoReadCD16w(address) : PicoRead16(address);\r
- return d&0xffff;\r
-}\r
-\r
-unsigned int m68k_read_memory_32(unsigned int address)\r
-{\r
- return (PicoAHW&1) ? PicoReadCD32w(address) : PicoRead32(address);\r
-}\r
-\r
-void m68k_write_memory_8(unsigned int address, unsigned int value)\r
-{\r
- if (PicoAHW&1) PicoWriteCD8w(address, (u8)value); else PicoWrite8(address, (u8)value);\r
-}\r
\r
-void m68k_write_memory_16(unsigned int address, unsigned int value)\r
-{\r
- if (PicoAHW&1) PicoWriteCD16w(address,(u16)value); else PicoWrite16(address,(u16)value);\r
-}\r
+#else // if !EMU_CORE_DEBUG\r
\r
-void m68k_write_memory_32(unsigned int address, unsigned int value)\r
-{\r
- if (PicoAHW&1) PicoWriteCD32w(address, value); else PicoWrite32(address, value);\r
+/* it appears that Musashi doesn't always mask the unused bits */\r
+unsigned int m68k_read_memory_8 (unsigned int address) { return pm68k_read_memory_8 (address) & 0xff; }\r
+unsigned int m68k_read_memory_16(unsigned int address) { return pm68k_read_memory_16(address) & 0xffff; }\r
+unsigned int m68k_read_memory_32(unsigned int address) { return pm68k_read_memory_32(address); }\r
+void m68k_write_memory_8 (unsigned int address, unsigned int value) { pm68k_write_memory_8 (address, (u8)value); }\r
+void m68k_write_memory_16(unsigned int address, unsigned int value) { pm68k_write_memory_16(address,(u16)value); }\r
+void m68k_write_memory_32(unsigned int address, unsigned int value) { pm68k_write_memory_32(address, value); }\r
+#endif // !EMU_CORE_DEBUG\r
+\r
+static void m68k_mem_setup(void)\r
+{\r
+ pm68k_read_memory_8 = PicoRead8;\r
+ pm68k_read_memory_16 = PicoRead16;\r
+ pm68k_read_memory_32 = PicoRead32;\r
+ pm68k_write_memory_8 = PicoWrite8;\r
+ pm68k_write_memory_16 = PicoWrite16;\r
+ pm68k_write_memory_32 = PicoWrite32;\r
+ pm68k_read_memory_pcr_8 = m68k_read_memory_pcr_8;\r
+ pm68k_read_memory_pcr_16 = m68k_read_memory_pcr_16;\r
+ pm68k_read_memory_pcr_32 = m68k_read_memory_pcr_32;\r
}\r
-#endif\r
#endif // EMU_M68K\r
\r
\r
int PicoSkipFrame = 0; // skip rendering frame?\r
int emustatus = 0; // rapid_ym2612, multi_ym_updates\r
int PicoPad[2]; // Joypads, format is SACB RLDU\r
-int PicoAHW = 0; // active addon hardware: scd_active, 32x_active, svp_active\r
+int PicoAHW = 0; // active addon hardware: scd_active, 32x_active, svp_active, pico_active\r
int PicoRegionOverride = 0; // override the region detection 0: Auto, 1: Japan NTSC, 2: Japan PAL, 4: US, 8: Europe\r
int PicoAutoRgnOrder = 0;\r
int z80startCycle, z80stopCycle; // in 68k cycles\r
--- /dev/null
+#include "../PicoInt.h"
+
+#ifndef UTYPES_DEFINED
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+#define UTYPES_DEFINED
+#endif
+
+// -----------------------------------------------------------------
+// Read Rom and read Ram
+
+static u32 PicoReadPico8(u32 a)
+{
+ u32 d=0;
+
+ if ((a&0xe00000)==0xe00000) { d = *(u8 *)(Pico.ram+((a^1)&0xffff)); goto end; } // Ram
+ if (a<Pico.romsize) { d = *(u8 *)(Pico.rom+(a^1)); goto end; } // Rom
+
+ a&=0xffffff;
+
+ if ((a&0xffffe0)==0xc00000) { // VDP
+ d=PicoVideoRead(a);
+ if ((a&1)==0) d>>=8;
+ goto end;
+ }
+
+ elprintf(EL_UIO, "r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPc);
+
+end:
+ elprintf(EL_IO, "r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPc);
+ return d;
+}
+
+static u32 PicoReadPico16(u32 a)
+{
+ u32 d=0;
+
+ if ((a&0xe00000)==0xe00000) { d=*(u16 *)(Pico.ram+(a&0xfffe)); goto end; } // Ram
+
+ a&=0xfffffe;
+
+ if (a<Pico.romsize) { d = *(u16 *)(Pico.rom+a); goto end; } // Rom
+
+ if ((a&0xffffe0)==0xc00000) {
+ d = PicoVideoRead(a);
+ goto end;
+ }
+
+ elprintf(EL_UIO, "r16: %06x, %04x @%06x", a&0xffffff, d, SekPc);
+
+end:
+ elprintf(EL_IO, "r16: %06x, %04x @%06x", a&0xffffff, d, SekPc);
+ return d;
+}
+
+static u32 PicoReadPico32(u32 a)
+{
+ u32 d=0;
+
+ if ((a&0xe00000)==0xe00000) { u16 *pm=(u16 *)(Pico.ram+(a&0xfffe)); d = (pm[0]<<16)|pm[1]; goto end; } // Ram
+
+ a&=0xfffffe;
+
+ if (a<Pico.romsize) { u16 *pm=(u16 *)(Pico.rom+a); d = (pm[0]<<16)|pm[1]; goto end; } // Rom
+
+ if ((a&0xffffe0)==0xc00000) {
+ d = (PicoVideoRead(a)<<16)|PicoVideoRead(a+2);
+ goto end;
+ }
+
+ elprintf(EL_UIO, "r32: %06x, %08x @%06x", a&0xffffff, d, SekPc);
+
+end:
+ elprintf(EL_IO, "r32: %06x, %08x @%06x", a&0xffffff, d, SekPc);
+ return d;
+}
+
+// -----------------------------------------------------------------
+// Write Ram
+
+static void PicoWritePico8(u32 a,u8 d)
+{
+ elprintf(EL_IO, "w8 : %06x, %02x @%06x", a&0xffffff, d, SekPc);
+
+ if ((a&0xe00000)==0xe00000) { *(u8 *)(Pico.ram+((a^1)&0xffff))=d; return; } // Ram
+
+ a&=0xffffff;
+ if ((a&0xffffe0)==0xc00000) { // VDP
+ d&=0xff;
+ PicoVideoWrite(a,(u16)(d|(d<<8))); // Byte access gets mirrored
+ return;
+ }
+
+ elprintf(EL_UIO, "w8 : %06x, %02x @%06x", a&0xffffff, d, SekPc);
+}
+
+static void PicoWritePico16(u32 a,u16 d)
+{
+ elprintf(EL_IO, "w16: %06x, %04x", a&0xffffff, d);
+
+ if ((a&0xe00000)==0xe00000) { *(u16 *)(Pico.ram+(a&0xfffe))=d; return; } // Ram
+
+ a&=0xfffffe;
+ if ((a&0xffffe0)==0xc00000) { PicoVideoWrite(a,(u16)d); return; } // VDP
+
+ elprintf(EL_UIO, "w16: %06x, %04x", a&0xffffff, d);
+}
+
+static void PicoWritePico32(u32 a,u32 d)
+{
+ elprintf(EL_IO, "w32: %06x, %08x", a&0xffffff, d);
+
+ if ((a&0xe00000)==0xe00000)
+ {
+ // Ram:
+ u16 *pm=(u16 *)(Pico.ram+(a&0xfffe));
+ pm[0]=(u16)(d>>16); pm[1]=(u16)d;
+ return;
+ }
+
+ a&=0xfffffe;
+ if ((a&0xffffe0)==0xc00000)
+ {
+ // VDP:
+ PicoVideoWrite(a, (u16)(d>>16));
+ PicoVideoWrite(a+2,(u16)d);
+ return;
+ }
+
+ elprintf(EL_UIO, "w32: %06x, %08x", a&0xffffff, d);
+}
+
+#ifdef EMU_M68K
+extern unsigned int (*pm68k_read_memory_8) (unsigned int address);
+extern unsigned int (*pm68k_read_memory_16)(unsigned int address);
+extern unsigned int (*pm68k_read_memory_32)(unsigned int address);
+extern void (*pm68k_write_memory_8) (unsigned int address, unsigned char value);
+extern void (*pm68k_write_memory_16)(unsigned int address, unsigned short value);
+extern void (*pm68k_write_memory_32)(unsigned int address, unsigned int value);
+extern unsigned int (*pm68k_read_memory_pcr_8) (unsigned int address);
+extern unsigned int (*pm68k_read_memory_pcr_16)(unsigned int address);
+extern unsigned int (*pm68k_read_memory_pcr_32)(unsigned int address);
+
+static unsigned int m68k_read_memory_pcrp_8(unsigned int a)
+{
+ if((a&0xe00000)==0xe00000) return *(u8 *)(Pico.ram+((a^1)&0xffff)); // Ram
+ return 0;
+}
+
+static unsigned int m68k_read_memory_pcrp_16(unsigned int a)
+{
+ if((a&0xe00000)==0xe00000) return *(u16 *)(Pico.ram+(a&0xfffe)); // Ram
+ return 0;
+}
+
+static unsigned int m68k_read_memory_pcrp_32(unsigned int a)
+{
+ if((a&0xe00000)==0xe00000) { u16 *pm=(u16 *)(Pico.ram+(a&0xfffe)); return (pm[0]<<16)|pm[1]; } // Ram
+ return 0;
+}
+#endif // EMU_M68K
+
+
+PICO_INTERNAL void PicoMemSetupPico(void)
+{
+#ifdef EMU_M68K
+ pm68k_read_memory_8 = PicoReadPico8;
+ pm68k_read_memory_16 = PicoReadPico16;
+ pm68k_read_memory_32 = PicoReadPico32;
+ pm68k_write_memory_8 = PicoWritePico8;
+ pm68k_write_memory_16 = PicoWritePico16;
+ pm68k_write_memory_32 = PicoWritePico32;
+ pm68k_read_memory_pcr_8 = m68k_read_memory_pcrp_8;
+ pm68k_read_memory_pcr_16 = m68k_read_memory_pcrp_16;
+ pm68k_read_memory_pcr_32 = m68k_read_memory_pcrp_32;
+#endif
+}
+
--- /dev/null
+#include "../PicoInt.h"
+
+PICO_INTERNAL int PicoInitPico(void)
+{
+ elprintf(EL_STATUS, "Pico detected");
+ PicoAHW = PAHW_PICO;
+
+ return 0;
+}
+
// ---------------------------------------------------------\r
\r
// Pico active hw\r
-#define PAHW_MCD (1<<0)\r
-#define PAHW_32X (1<<1)\r
-#define PAHW_SVP (1<<2)\r
+#define PAHW_MCD (1<<0)\r
+#define PAHW_32X (1<<1)\r
+#define PAHW_SVP (1<<2)\r
+#define PAHW_PICO (1<<3)\r
extern int PicoAHW;\r
\r
// main oscillator clock which controls timing\r
PICO_INTERNAL_ASM void PicoMemResetCD(int r3);\r
PICO_INTERNAL_ASM void PicoMemResetCDdecode(int r3);\r
\r
+// Pico/Memory.c\r
+PICO_INTERNAL void PicoMemSetupPico(void);\r
+\r
// Pico.c\r
extern struct Pico Pico;\r
extern struct PicoSRAM SRam;\r
PICO_INTERNAL int PicoResetMCD(void);\r
PICO_INTERNAL int PicoFrameMCD(void);\r
\r
+// Pico/Pico.c\r
+PICO_INTERNAL int PicoInitPico(void);\r
+\r
// Sek.c\r
PICO_INTERNAL int SekInit(void);\r
PICO_INTERNAL int SekReset(void);\r
m68k_init();\r
m68k_set_int_ack_callback(SekIntAckM68K);\r
m68k_set_tas_instr_callback(SekTasCallback);\r
- m68k_pulse_reset(); // Init cpu emulator\r
+ //m68k_pulse_reset();\r
m68k_set_context(oldcontext);\r
}\r
#endif\r
}\r
#endif\r
\r
+#ifdef EMU_M68K\r
+static void m68k_mem_setup_cd(void);\r
+#endif\r
+\r
PICO_INTERNAL void PicoMemSetupCD(void)\r
{\r
// additional handlers for common code\r
// PicoMemResetCD() will setup word ram for both\r
}\r
#endif\r
+#ifdef EMU_M68K\r
+ m68k_mem_setup_cd();\r
+#endif\r
\r
// m68k_poll_addr = m68k_poll_cnt = 0;\r
s68k_poll_adclk = s68k_poll_cnt = 0;\r
\r
\r
#ifdef EMU_M68K\r
-unsigned char PicoReadCD8w (unsigned int a) {\r
+static unsigned int PicoReadCD8w (unsigned int a) {\r
return m68ki_cpu_p == &PicoCpuMS68k ? PicoReadS68k8(a) : PicoReadM68k8(a);\r
}\r
-unsigned short PicoReadCD16w(unsigned int a) {\r
+static unsigned int PicoReadCD16w(unsigned int a) {\r
return m68ki_cpu_p == &PicoCpuMS68k ? PicoReadS68k16(a) : PicoReadM68k16(a);\r
}\r
-unsigned int PicoReadCD32w(unsigned int a) {\r
+static unsigned int PicoReadCD32w(unsigned int a) {\r
return m68ki_cpu_p == &PicoCpuMS68k ? PicoReadS68k32(a) : PicoReadM68k32(a);\r
}\r
-void PicoWriteCD8w (unsigned int a, unsigned char d) {\r
+static void PicoWriteCD8w (unsigned int a, unsigned char d) {\r
if (m68ki_cpu_p == &PicoCpuMS68k) PicoWriteS68k8(a, d); else PicoWriteM68k8(a, d);\r
}\r
-void PicoWriteCD16w(unsigned int a, unsigned short d) {\r
+static void PicoWriteCD16w(unsigned int a, unsigned short d) {\r
if (m68ki_cpu_p == &PicoCpuMS68k) PicoWriteS68k16(a, d); else PicoWriteM68k16(a, d);\r
}\r
-void PicoWriteCD32w(unsigned int a, unsigned int d) {\r
+static void PicoWriteCD32w(unsigned int a, unsigned int d) {\r
if (m68ki_cpu_p == &PicoCpuMS68k) PicoWriteS68k32(a, d); else PicoWriteM68k32(a, d);\r
}\r
\r
// these are allowed to access RAM\r
-unsigned int m68k_read_pcrelative_CD8 (unsigned int a)\r
+static unsigned int m68k_read_pcrelative_CD8 (unsigned int a)\r
{\r
a&=0xffffff;\r
if(m68ki_cpu_p == &PicoCpuMS68k) {\r
}\r
return 0;//(u8) lastread_d;\r
}\r
-unsigned int m68k_read_pcrelative_CD16(unsigned int a)\r
+static unsigned int m68k_read_pcrelative_CD16(unsigned int a)\r
{\r
a&=0xffffff;\r
if(m68ki_cpu_p == &PicoCpuMS68k) {\r
}\r
return 0;\r
}\r
-unsigned int m68k_read_pcrelative_CD32(unsigned int a)\r
+static unsigned int m68k_read_pcrelative_CD32(unsigned int a)\r
{\r
u16 *pm;\r
a&=0xffffff;\r
}\r
return 0;\r
}\r
+\r
+extern unsigned int (*pm68k_read_memory_8) (unsigned int address);\r
+extern unsigned int (*pm68k_read_memory_16)(unsigned int address);\r
+extern unsigned int (*pm68k_read_memory_32)(unsigned int address);\r
+extern void (*pm68k_write_memory_8) (unsigned int address, unsigned char value);\r
+extern void (*pm68k_write_memory_16)(unsigned int address, unsigned short value);\r
+extern void (*pm68k_write_memory_32)(unsigned int address, unsigned int value);\r
+extern unsigned int (*pm68k_read_memory_pcr_8) (unsigned int address);\r
+extern unsigned int (*pm68k_read_memory_pcr_16)(unsigned int address);\r
+extern unsigned int (*pm68k_read_memory_pcr_32)(unsigned int address);\r
+\r
+static void m68k_mem_setup_cd(void)\r
+{\r
+ pm68k_read_memory_8 = PicoReadCD8w;\r
+ pm68k_read_memory_16 = PicoReadCD16w;\r
+ pm68k_read_memory_32 = PicoReadCD32w;\r
+ pm68k_write_memory_8 = PicoWriteCD8w;\r
+ pm68k_write_memory_16 = PicoWriteCD16w;\r
+ pm68k_write_memory_32 = PicoWriteCD32w;\r
+ pm68k_read_memory_pcr_8 = m68k_read_pcrelative_CD8;\r
+ pm68k_read_memory_pcr_16 = m68k_read_pcrelative_CD16;\r
+ pm68k_read_memory_pcr_32 = m68k_read_pcrelative_CD32;\r
+}\r
#endif // EMU_M68K\r
\r
#include "../PicoInt.h"
#include "cd_file.h"
+#include "cue.h"
//#define cdprintf(f,...) printf(f "\n",##__VA_ARGS__) // tmp
-#define DEBUG_CD
-PICO_INTERNAL int Load_CD_Image(const char *iso_name, cd_img_type type)
+static int audio_track_mp3(const char *fname, int index)
{
- int i, j, num_track, Cur_LBA, index, ret, iso_name_len;
+ _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",
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(iso_name);
+ 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)
- Tracks[0].Length = pmf->size >>= 11; // size in sectors
- else Tracks[0].Length = pmf->size /= 2352;
+ 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
- cdprintf("Track 0 - %02d:%02d:%02d DATA", Tracks[0].MSF.M, Tracks[0].MSF.S, Tracks[0].MSF.F);
+ elprintf(EL_STATUS, "Track 0: %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;
+ }
+ for (num_track = 2; num_track <= cue_data->track_count; 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)
+ {
+ Tracks[index].F = fopen(cue_data->tracks[num_track].fname, "rb");
+ elprintf(EL_STATUS, "track %2i (%s): can't determine length",
+ 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;
+ }
+ }
+
+ LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
+ Cur_LBA += Tracks[index].Length;
- Cur_LBA = Tracks[0].Length; // Size in sectors
+ elprintf(EL_STATUS, "Track %2i: %02d:%02d:%02d %9i AUDIO - %s", index, 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;
+ }
- iso_name_len = strlen(iso_name);
+ /* 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; i < 100; i++)
+ for (num_track = 2, i = 0, missed = 0; i < 100 && missed < 4; i++)
{
- if (PicoCDLoadProgressCB != NULL && i > 1) PicoCDLoadProgressCB(i);
+ if (PicoCDLoadProgressCB != NULL && i > 1) PicoCDLoadProgressCB(i + (100-i)*missed/4);
for (j = 0; j < sizeof(exts)/sizeof(char *); j++)
{
int ext_len;
- FILE *tmp_file;
sprintf(tmp_ext, exts[j], i);
ext_len = strlen(tmp_ext);
- memcpy(tmp_name, iso_name, iso_name_len + 1);
+ memcpy(tmp_name, cd_img_name, iso_name_len + 1);
tmp_name[iso_name_len - 4] = 0;
strcat(tmp_name, tmp_ext);
- tmp_file = fopen(tmp_name, "rb");
- if (!tmp_file && i > 1 && iso_name_len > ext_len) {
+ 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);
- tmp_file = fopen(tmp_name, "rb");
+ ret = audio_track_mp3(tmp_name, index);
}
- if (tmp_file)
+ if (ret == 0)
{
- int fs;
- index = num_track - 1;
-
- ret = fseek(tmp_file, 0, SEEK_END);
- fs = ftell(tmp_file); // used to calculate lenght
- 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(tmp_name);
-#endif
- Tracks[index].KBtps = (short) mp3_get_bitrate(tmp_file, fs);
- Tracks[index].KBtps >>= 3;
- if (ret != 0 || Tracks[index].KBtps <= 0)
- {
- cdprintf("Error track %i: rate %i", index, Tracks[index].KBtps);
-#if !DONT_OPEN_MANY_FILES
- fclose(tmp_file);
-#else
- free(tmp_file);
-#endif
- continue;
- }
-
- Tracks[index].F = tmp_file;
-
LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
-
- // MP3 File
- Tracks[index].ftype = TYPE_MP3;
- fs *= 75;
- fs /= Tracks[index].KBtps * 1000;
- Tracks[index].Length = fs;
Cur_LBA += Tracks[index].Length;
- cdprintf("Track %i: %s - %02d:%02d:%02d len=%i AUDIO", index, tmp_name, Tracks[index].MSF.M,
- Tracks[index].MSF.S, Tracks[index].MSF.F, fs);
+ elprintf(EL_STATUS, "Track %2i: %02d:%02d:%02d %9i AUDIO - %s", index, 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) missed++;
}
+finish:
Pico_mcd->TOC.Last_Track = num_track - 1;
index = num_track - 1;
LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
- cdprintf("End CD - %02d:%02d:%02d\n\n", Tracks[index].MSF.M,
+ 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);
for(i = 1; i < 100; i++)
{
if (Pico_mcd->TOC.Tracks[i].F != NULL)
-#if !DONT_OPEN_MANY_FILES
- fclose(Pico_mcd->TOC.Tracks[i].F);
-#else
- free(Pico_mcd->TOC.Tracks[i].F);
+ {
+#if DONT_OPEN_MANY_FILES
+ if (Pico_mcd->TOC.Tracks[i].type == TYPE_MP3)
+ free(Pico_mcd->TOC.Tracks[i].F);
+ else
#endif
+ fclose(Pico_mcd->TOC.Tracks[i].F);
+ }
}
memset(Pico_mcd->TOC.Tracks, 0, sizeof(Pico_mcd->TOC.Tracks));
}
//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);
-#ifdef DEBUG_CD
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);
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]);
-#endif
}
}
char ftype; // TYPE_ISO, TYPE_BIN, TYPE_MP3\r
void *F;\r
int Length;\r
+ int Offset; // sector offset, when single file is used for multiple virtual tracks\r
short KBtps; // kbytes per sec for mp3s (bitrate / 1000 / 8)\r
short pad;\r
} _scd_track;\r
#include <string.h>
#include "cue.h"
-//#include "../PicoInt.h"
-#define elprintf(w,f,...) printf(f "\n",##__VA_ARGS__);
+#include "../PicoInt.h"
+// #define elprintf(w,f,...) printf(f "\n",##__VA_ARGS__);
static char *mystrip(char *str)
{
dest[d++] = *p++;
dest[d] = 0;
- if (*p != sep)
+ 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 - 3) : (fname - len);
+ 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 *cue_parse(const char *fname)
+cue_data_t *cue_parse(const char *fname)
{
char buff[256], current_file[256], buff2[32];
FILE *f, *tmpf;
int ret, count = 0, count_alloc = 2;
- cue_data *data;
+ cue_data_t *data;
void *tmp;
f = fopen(fname, "r");
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)
count, atoi(buff2));
// check type
get_token(buff+6+ret, buff2, sizeof(buff2));
- if (strcmp(buff2, "MODE1/2352"))
+ if (strcmp(buff2, "MODE1/2352") == 0)
data->tracks[count].type = CT_BIN;
- else if (strcmp(buff2, "MODE1/2048"))
+ else if (strcmp(buff2, "MODE1/2048") == 0)
data->tracks[count].type = CT_ISO;
- else if (strcmp(buff2, "AUDIO"))
+ else if (strcmp(buff2, "AUDIO") == 0)
{
if (data->tracks[count].fname != NULL)
{
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);
}
// offset in file
get_token(buff+6+ret, buff2, sizeof(buff2));
- ret = sscanf(buff2, "%i:%i:%i", &m, &s, &f);
+ 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 "))
{
int m, s, f;
get_token(buff+7, buff2, sizeof(buff2));
- ret = sscanf(buff2, "%i:%i:%i", &m, &s, &f);
+ ret = sscanf(buff2, "%d:%d:%d", &m, &s, &f);
if (ret != 3) {
elprintf(EL_STATUS, "cue: failed to parse: \"%s\"", buff);
continue;
}
else
{
- elprintf(EL_STATUS, "cue: failed to parse: \"%s\"", buff);
+ elprintf(EL_STATUS, "cue: unhandled line: \"%s\"", buff);
}
}
}
-void cue_destroy(cue_data *data)
+void cue_destroy(cue_data_t *data)
{
int c;
}
+#if 0
int main(int argc, char *argv[])
{
- cue_data *data = cue_parse(argv[1]);
+ 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 %9i %s\n", c, data->tracks[c].type, data->tracks[c].sector_offset,
- data->tracks[c].pregap, data->tracks[c].fname);
+ 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
{
int track_count;
cue_track tracks[0];
-} cue_data;
+} cue_data_t;
-cue_data *cue_parse(const char *fname);
-void cue_destroy(cue_data *data);
+cue_data_t *cue_parse(const char *fname);
+void cue_destroy(cue_data_t *data);
\r
#include <Pico/PicoInt.h>\r
#include <Pico/Patch.h>\r
+#include <Pico/cd/cue.h>\r
#include <zlib/zlib.h>\r
\r
#if defined(__GP2X__)\r
{\r
unsigned char buf[32];\r
pm_file *cd_f;\r
- int type = 0, region = 4; // 1: Japan, 4: US, 8: Europe\r
- char ext[5];\r
+ int region = 4; // 1: Japan, 4: US, 8: Europe\r
+ char ext[5], *fname = romFileName;\r
+ cue_track_type type = CT_UNKNOWN;\r
+ cue_data_t *cue_data = NULL;\r
\r
get_ext(romFileName, ext);\r
+ if (strcasecmp(ext, ".cue") == 0) {\r
+ cue_data = cue_parse(romFileName);\r
+ if (cue_data != NULL) {\r
+ fname = cue_data->tracks[1].fname;\r
+ type = cue_data->tracks[1].type;\r
+ }\r
+ }\r
+\r
+ cd_f = pm_open(fname);\r
+ if (cue_data != NULL)\r
+ cue_destroy(cue_data);\r
\r
- cd_f = pm_open(romFileName);\r
if (!cd_f) return 0; // let the upper level handle this\r
\r
if (pm_read(buf, 32, cd_f) != 32) {\r
return 0;\r
}\r
\r
- if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x00, 14)) type = 1; // Sega CD (ISO)\r
- if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x10, 14)) type = 2; // Sega CD (BIN)\r
- if (type == 0) {\r
+ if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x00, 14)) {\r
+ if (type && type != CT_ISO)\r
+ elprintf(EL_STATUS, ".cue has wrong type: %i", type);\r
+ type = CT_ISO; // Sega CD (ISO)\r
+ }\r
+ if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x10, 14)) {\r
+ if (type && type != CT_BIN)\r
+ elprintf(EL_STATUS, ".cue has wrong type: %i", type);\r
+ type = CT_BIN; // Sega CD (BIN)\r
+ }\r
+\r
+ if (type == CT_UNKNOWN) {\r
pm_close(cd_f);\r
return 0;\r
}\r
\r
- pm_seek(cd_f, (type == 1) ? 0x100 : 0x110, SEEK_SET);\r
+ pm_seek(cd_f, (type == CT_ISO) ? 0x100 : 0x110, SEEK_SET);\r
pm_read(id_header, sizeof(id_header), cd_f);\r
\r
/* it seems we have a CD image here. Try to detect region now.. */\r
- pm_seek(cd_f, (type == 1) ? 0x100+0x10B : 0x110+0x10B, SEEK_SET);\r
+ pm_seek(cd_f, (type == CT_ISO) ? 0x100+0x10B : 0x110+0x10B, SEEK_SET);\r
pm_read(buf, 1, cd_f);\r
pm_close(cd_f);\r
\r
if (buf[0] == 0xa1) region = 1; // JAP\r
\r
lprintf("detected %s Sega/Mega CD image with %s region\n",\r
- type == 2 ? "BIN" : "ISO", region != 4 ? (region == 8 ? "EU" : "JAP") : "USA");\r
+ type == CT_BIN ? "BIN" : "ISO", region != 4 ? (region == 8 ? "EU" : "JAP") : "USA");\r
\r
if (pregion != NULL) *pregion = region;\r
\r
../../Pico/Patch.o\r
# Pico - CD\r
OBJS += ../../Pico/cd/Pico.o ../../Pico/cd/Memory.o ../../Pico/cd/Sek.o ../../Pico/cd/LC89510.o \\r
- ../../Pico/cd/cd_sys.o ../../Pico/cd/cd_file.o ../../Pico/cd/gfx_cd.o \\r
+ ../../Pico/cd/cd_sys.o ../../Pico/cd/cd_file.o ../../Pico/cd/cue.o ../../Pico/cd/gfx_cd.o \\r
../../Pico/cd/Area.o ../../Pico/cd/Misc.o ../../Pico/cd/pcm.o ../../Pico/cd/buffering.o\r
endif\r
# Pico - carthw\r
Pico/VideoPort.o Pico/Draw2.o Pico/Draw.o Pico/Patch.o
# Pico - CD
OBJS += Pico/cd/Pico.o Pico/cd/Memory.o Pico/cd/Sek.o Pico/cd/LC89510.o \
- Pico/cd/cd_sys.o Pico/cd/cd_file.o Pico/cd/gfx_cd.o \
+ Pico/cd/cd_sys.o Pico/cd/cd_file.o Pico/cd/cue.o Pico/cd/gfx_cd.o \
Pico/cd/Area.o Pico/cd/Misc.o Pico/cd/pcm.o Pico/cd/buffering.o
+# Pico - Pico
+OBJS += Pico/Pico/Pico.o Pico/Pico/Memory.o
# Pico - sound
OBJS += Pico/sound/sound.o Pico/sound/sn76496.o Pico/sound/ym2612.o Pico/sound/mix.o
# Pico - carthw
endif
vpath %.c = ../..
-DIRS = platform platform/gp2x platform/common Pico Pico/cd Pico/sound Pico/carthw/svp \
+DIRS = platform platform/gp2x platform/common Pico Pico/cd Pico/Pico Pico/sound Pico/carthw/svp \
zlib unzip cpu cpu/musashi cpu/fame cpu/mz80 cpu/cz80
all: mkdirs PicoDrive
../../Pico/Patch.o ../../Pico/Draw_amips.o ../../Pico/Memory_amips.o ../../Pico/Misc_amips.o\r
# Pico - CD\r
OBJS += ../../Pico/cd/Pico.o ../../Pico/cd/Memory.o ../../Pico/cd/Sek.o ../../Pico/cd/LC89510.o \\r
- ../../Pico/cd/cd_sys.o ../../Pico/cd/cd_file.o ../../Pico/cd/gfx_cd.o \\r
+ ../../Pico/cd/cd_sys.o ../../Pico/cd/cd_file.o ../../Pico/cd/cue.o ../../Pico/cd/gfx_cd.o \\r
../../Pico/cd/Area.o ../../Pico/cd/Misc.o ../../Pico/cd/pcm.o ../../Pico/cd/buffering.o\r
# Pico - carthw\r
OBJS += ../../Pico/carthw/carthw.o ../../Pico/carthw/svp/svp.o ../../Pico/carthw/svp/Memory.o \\r