Skip to content

Commit

Permalink
platform, basic md+ support
Browse files Browse the repository at this point in the history
like msu-md. loading a .cue file will look for a cartridge image with
the same basename and an extension of "gen", "smd", "md", "32x".
  • Loading branch information
irixxxx committed Sep 21, 2024
1 parent dd7c8c0 commit 5cb7058
Show file tree
Hide file tree
Showing 8 changed files with 287 additions and 10 deletions.
15 changes: 9 additions & 6 deletions pico/cd/cdd.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ static void ogg_free(int i)

void cdd_reset(void)
{
/* stop audio streaming */
Pico_mcd->cdda_stream = NULL;

/* reset cycle counter */
cdd.cycles = 0;

Expand Down Expand Up @@ -715,13 +718,13 @@ void cdd_read_audio(unsigned int samples)


void cdd_update(void)
{
{
#ifdef LOG_CDD
error("LBA = %d (track n°%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
#endif

/* update decoder, depending on track type */
if (cdd.status == CD_PLAY && !is_audio(cdd.index))
if (cdd.status == CD_PLAY && !is_audio(cdd.index) && !cdd.latency)
{
/* DATA sector header (CD-ROM Mode 1) */
uint8 header[4];
Expand Down Expand Up @@ -1043,12 +1046,12 @@ void cdd_process(void)
cdd.latency += (((cdd.lba - lba) * 120) / 270000);
}

/* block transfer always starts 3 blocks earlier */
lba -= 3;

/* get track index */
while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;

/* block transfer always starts 3 blocks earlier */
lba -= 3;

/* seek to block */
cdd_seek(index, lba);

Expand Down Expand Up @@ -1131,7 +1134,7 @@ void cdd_process(void)

case 0x07: /* Resume */
{
int lba = (cdd.lba < 0 ? 0 : cdd.lba);
int lba = (cdd.lba < 4 ? 4 : cdd.lba);

/* CD drive latency */
if (!cdd.latency)
Expand Down
4 changes: 4 additions & 0 deletions pico/cd/mcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "../pico_int.h"
#include "../sound/ym2612.h"
#include "megasd.h"

extern unsigned char formatted_bram[4*0x10];

Expand Down Expand Up @@ -96,6 +97,7 @@ PICO_INTERNAL int PicoResetMCD(void)
}
Pico.sv.start = Pico.sv.end = 0; // unused

msd_reset();
return 0;
}

Expand Down Expand Up @@ -151,6 +153,8 @@ static void pcd_cdc_event(unsigned int now)
Pico_mcd->s68k_regs[0x4b] = 0xf0;
}

msd_update();

if ((Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) && (Pico_mcd->s68k_regs[0x37] & 4)) {
elprintf(EL_INTS|EL_CD, "s68k: cdd irq 4");
pcd_irq_s68k(4, 1);
Expand Down
256 changes: 256 additions & 0 deletions pico/cd/megasd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
/*
* PicoDrive
* (C) irixxxx, 2024
*
* MEGASD enhancement support
*/

#include "../pico_int.h"
#include "../memory.h"

#include "genplus_macros.h"
#include "cdd.h"
#include "megasd.h"

// modifiable fields visible through the interface
u16 msd_command, msd_result;
u16 msd_data[0x800/2];

// internal state
static int msd_initialized;
static s32 msd_startlba, msd_endlba, msd_looplba;
static s32 msd_readlba = -1; // >= 0 if sector read is running
static int msd_loop, msd_index = -1; // >= 0 if audio track is playing

static u16 verser[] = // mimick version 1.04 R7, serial 0x01234567
{ 0x4d45, 0x4741, 0x5344, 0x0104, 0x0700, 0xffff, 0x0123, 0x4567 };
// { 0x4d45, 0x4741, 0x5344, 0x9999, 0x9900, 0xffff, 0x1234, 0x5678 };

// get a 32bit value from the data area
static s32 get32(int offs)
{
u16 *a = msd_data + (offs/2);
return (a[0] << 16) | a[1];
}

// send commands to cdd
static void cdd_play(s32 lba)
{
int secs = lba / 75;
int mins = secs / 60;
lba -= secs * 75;
secs -= mins * 60;
s68k_write8(0xff8044, mins/10);
s68k_write8(0xff8045, mins%10);
s68k_write8(0xff8046, secs/10);
s68k_write8(0xff8047, secs%10);
s68k_write8(0xff8048, lba /10);
s68k_write8(0xff8049, lba %10);

s68k_write8(0xff8042, 0x03);
s68k_write8(0xff804b, 0xff);
}

static void cdd_pause(void)
{
s68k_write8(0xff8042, 0x06);
s68k_write8(0xff804b, 0xff);
}

static void cdd_resume(void)
{
s68k_write8(0xff8042, 0x07);
s68k_write8(0xff804b, 0xff);
}

static void cdd_stop(void)
{
msd_index = msd_readlba = -1;
s68k_write8(0xff8042, 0x01);
s68k_write8(0xff804b, 0xff);
}

// play a track, looping from offset if enabled
static void msd_playtrack(int idx, s32 offs, int loop)
{
msd_index = idx-1;
msd_loop = loop;
msd_readlba = -1;

msd_startlba = cdd.toc.tracks[msd_index].start + 150;
msd_endlba = cdd.toc.tracks[msd_index].end;
msd_looplba = msd_startlba + offs;

cdd_play(msd_startlba);
}

// play a range of sectors, with looping if enabled
static void msd_playsectors(s32 startlba, s32 endlba, s32 looplba, int loop)
{
msd_index = 99;
msd_loop = loop;
msd_readlba = -1;

msd_startlba = startlba + 150;
msd_endlba = endlba + 150;
msd_looplba = looplba + 150;

cdd_play(msd_startlba);
}

// read a block of data
static void msd_readdata(s32 lba)
{
msd_index = -1;
msd_readlba = lba;

cdd_play(msd_readlba);
}

// transfer data to data area
static void msd_transfer()
{
if (cdd.status == CD_PLAY)
cdd_read_data((u8 *)msd_data);

// transfer done
msd_command = 0;
}

// update msd state (called every 1/75s)
void msd_update()
{
if (msd_initialized) {
// CD LEDs
s68k_write8(0xff8000,(cdd.status == CD_PLAY) | 0x2);

if (cdd.status == CD_PLAY) {
if (msd_readlba >= 0 && cdd.lba >= msd_readlba) {
// read done
msd_command = 0;
}
else if (msd_index >= 0 && (cdd.lba > msd_endlba || cdd.index > msd_index)) {
if (!msd_loop || msd_index < 0) {
cdd_stop();
// audio done
msd_command = 0;
} else
cdd_play(msd_looplba);
}
}
}
}

// process a MEGASD command
void msd_process(u16 d)
{
msd_command = d; // busy

switch (d >> 8) {
case 0x10: memcpy(msd_data, verser, sizeof(verser)); msd_command = 0; break;

case 0x11: msd_playtrack(d&0xff, 0, 0); break;
case 0x12: msd_playtrack(d&0xff, 0, 1); break;
case 0x1a: msd_playtrack(d&0xff, get32(0), 1); break;
case 0x1b: msd_playsectors(get32(0), get32(4), get32(8), d&0xff); break;

case 0x13: cdd_pause(); break;
case 0x14: cdd_resume(); break;

case 0x16: msd_result = !(s68k_read8(0xff8036) & 0x1) << 8;
msd_command = 0; break;

case 0x17: msd_readdata(get32(0)); break;
case 0x18: msd_transfer(); break;
case 0x19: msd_readdata(++msd_readlba); break;

case 0x27: msd_result = cdd.toc.last << 8;
msd_command = 0; break;

default: msd_command = msd_result = 0; break; // not supported
}
}

// initialize MEGASD
static void msd_init(void)
{
if (!msd_initialized) {
msd_initialized = 1;

// enable CD drive
s68k_write8(0xff8037, 0x4);

PicoResetHook = msd_reset;
}
}

void msd_reset(void)
{
if (msd_initialized) {
msd_initialized = msd_command = 0;
cdd_stop();

s68k_write8(0xff8000, 0x0);
s68k_write8(0xff8001, 0x0);

PicoResetHook = NULL;
}
}

// memory r/w functions
static u32 msd_read16(u32 a)
{
u16 d = 0;

if (a >= 0x03f800) {
d = msd_data[(a&0x7ff)>>1];
} else if (a >= 0x03f7f0) {
switch (a&0xe) {
case 0x6: d = 0x5241; break; // RA
case 0x8: d = 0x5445; break; // TE
case 0xc: d = msd_result; break;
case 0xe: d = msd_command; break;
}
} else if (a < Pico.romsize)
d = *(u16 *)(Pico.rom + a);

return d;
}

static u32 msd_read8(u32 a)
{
u16 d = msd_read16(a);

if (!(a&1)) d >>= 8;
return d;
}

void msd_write16(u32 a, u32 d)
{
if (a == 0x03f7fa) {
// en/disable overlay
u32 base = 0x040000-(1<<M68K_MEM_SHIFT);
if ((u16)d == 0xcd54) {
msd_init();
cpu68k_map_set(m68k_read8_map, base, 0x03ffff, msd_read8, 1);
cpu68k_map_set(m68k_read16_map, base, 0x03ffff, msd_read16, 1);
} else if (Pico.romsize > base) {
cpu68k_map_set(m68k_read8_map, base, 0x03ffff, Pico.rom+base, 0);
cpu68k_map_set(m68k_read16_map, base, 0x03ffff, Pico.rom+base, 0);
}
} else if (a == 0x03f7fe) {
// command port
msd_process(d);
} else if (a >= 0x03f800) {
// data area
msd_data[(a&0x7ff) >> 1] = d;
}
}

void msd_write8(u32 a, u32 d)
{
if (a >= 0x03f800) {
// data area
((u8 *)msd_data)[MEM_BE2(a&0x7ff)] = d;
}
}
11 changes: 11 additions & 0 deletions pico/cd/megasd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@


extern u16 msd_command, msd_result;
extern u16 msd_data[0x800/2];

extern void msd_update(void);
extern void msd_process(u16 d);
extern void msd_reset(void);

extern void msd_write8(u32 a, u32 d);
extern void msd_write16(u32 a, u32 d);
5 changes: 5 additions & 0 deletions pico/cd/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "../pico_int.h"
#include "../memory.h"
#include "megasd.h"

uptr s68k_read8_map [0x1000000 >> M68K_MEM_SHIFT];
uptr s68k_read16_map [0x1000000 >> M68K_MEM_SHIFT];
Expand Down Expand Up @@ -1244,6 +1245,10 @@ PICO_INTERNAL void PicoMemSetupCD(void)
// MSU cartridge. Fake BIOS detection
cpu68k_map_set(m68k_read8_map, 0x400000, 0x41ffff, PicoReadM68k8_bios, 1);
cpu68k_map_set(m68k_read16_map, 0x400000, 0x41ffff, PicoReadM68k16_bios, 1);
// MD+ on MEGASD.
cpu68k_map_set(m68k_write8_map, 0x040000-(1<<M68K_MEM_SHIFT), 0x03ffff, msd_write8, 1);
cpu68k_map_set(m68k_write16_map, 0x040000-(1<<M68K_MEM_SHIFT), 0x03ffff, msd_write16, 1);
msd_reset();
} else {
// RAM cart
cpu68k_map_set(m68k_read8_map, 0x400000, 0x7fffff, PicoReadM68k8_ramc, 1);
Expand Down
2 changes: 0 additions & 2 deletions pico/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,6 @@ static NOINLINE u32 port_read(int i)
// Decap Attack reportedly doesn't work on Nomad but works on must
// other MD revisions (different pull-up strength?).
u32 mask = 0x3f;
if (CYCLES_GE(padTHLatency[i], SekCyclesDone()+100))
padTHLatency[i] = SekCyclesDone(); // kludge to cope with cycle wrap
if (CYCLES_GE(SekCyclesDone(), padTHLatency[i])) {
mask |= 0x40;
padTHLatency[i] = SekCyclesDone();
Expand Down
2 changes: 1 addition & 1 deletion platform/common/common.mak
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ endif
SRCS_COMMON += $(R)pico/cd/mcd.c $(R)pico/cd/memory.c $(R)pico/cd/sek.c \
$(R)pico/cd/cdc.c $(R)pico/cd/cdd.c $(R)pico/cd/cd_image.c \
$(R)pico/cd/cd_parse.c $(R)pico/cd/gfx.c $(R)pico/cd/gfx_dma.c \
$(R)pico/cd/misc.c $(R)pico/cd/pcm.c
$(R)pico/cd/misc.c $(R)pico/cd/pcm.c $(R)pico/cd/megasd.c
# 32X
ifneq "$(no_32x)" "1"
SRCS_COMMON += $(R)pico/32x/32x.c $(R)pico/32x/memory.c $(R)pico/32x/draw.c \
Expand Down
2 changes: 1 addition & 1 deletion platform/common/emu.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ static const char *find_bios(int *region, const char *cd_fname)
(*region == 8 ? "EU" : "JAP") : "USA");
}

// look for MSU.MD rom file. XXX another extension list? ugh...
// look for MSU.MD or MD+ rom file. XXX another extension list? ugh...
static const char *md_exts[] = { "gen", "smd", "md", "32x" };
char *ext = strrchr(cd_fname, '.');
int extpos = ext ? ext-cd_fname : strlen(cd_fname);
Expand Down

0 comments on commit 5cb7058

Please sign in to comment.