32x: built-in BIOS; reset handling; 68k memhandler split

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@801 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
notaz 2009-10-03 16:21:59 +00:00
parent 5fadfb1c37
commit 83ff19ec52
7 changed files with 405 additions and 150 deletions

View file

@ -41,20 +41,11 @@ void p32x_sh2_write32(unsigned int a, unsigned int d, int id);
void sh2_reset(SH2 *sh2) void sh2_reset(SH2 *sh2)
{ {
int save_is_slave;
void *save_irqcallback;
save_irqcallback = sh2->irq_callback;
save_is_slave = sh2->is_slave;
memset(sh2, 0, sizeof(SH2));
sh2->is_slave = save_is_slave;
sh2->irq_callback = save_irqcallback;
sh2->pc = RL(0); sh2->pc = RL(0);
sh2->r[15] = RL(4); sh2->r[15] = RL(4);
sh2->sr = I; sh2->sr = I;
sh2->vbr = 0;
sh2->pending_int_irq = 0;
} }
static void sh2_do_irq(SH2 *sh2, int level, int vector) static void sh2_do_irq(SH2 *sh2, int level, int vector)

View file

@ -1,8 +1,8 @@
#include "../pico_int.h" #include "../pico_int.h"
#include "../sound/ym2612.h" #include "../sound/ym2612.h"
SH2 sh2s[2];
struct Pico32x Pico32x; struct Pico32x Pico32x;
SH2 sh2s[2];
static void sh2_irq_cb(int id, int level) static void sh2_irq_cb(int id, int level)
{ {
@ -39,15 +39,12 @@ void Pico32xStartup(void)
elprintf(EL_STATUS|EL_32X, "32X startup"); elprintf(EL_STATUS|EL_32X, "32X startup");
PicoAHW |= PAHW_32X; PicoAHW |= PAHW_32X;
PicoMemSetup32x();
sh2_init(&msh2, 0); sh2_init(&msh2, 0);
msh2.irq_callback = sh2_irq_cb; msh2.irq_callback = sh2_irq_cb;
sh2_reset(&msh2);
sh2_init(&ssh2, 1); sh2_init(&ssh2, 1);
ssh2.irq_callback = sh2_irq_cb; ssh2.irq_callback = sh2_irq_cb;
sh2_reset(&ssh2);
PicoMemSetup32x();
if (!Pico.m.pal) if (!Pico.m.pal)
Pico32x.vdp_regs[0] |= P32XV_nPAL; Pico32x.vdp_regs[0] |= P32XV_nPAL;
@ -58,6 +55,54 @@ void Pico32xStartup(void)
emu_32x_startup(); emu_32x_startup();
} }
#define HWSWAP(x) (((x) << 16) | ((x) >> 16))
void p32x_reset_sh2s(void)
{
elprintf(EL_32X, "sh2 reset");
sh2_reset(&msh2);
sh2_reset(&ssh2);
// if we don't have BIOS set, perform it's work here.
// MSH2
if (p32x_bios_m == NULL) {
unsigned int idl_src, idl_dst, idl_size; // initial data load
unsigned int vbr;
// initial data
idl_src = HWSWAP(*(unsigned int *)(Pico.rom + 0x3d4)) & ~0xf0000000;
idl_dst = HWSWAP(*(unsigned int *)(Pico.rom + 0x3d8)) & ~0xf0000000;
idl_size= HWSWAP(*(unsigned int *)(Pico.rom + 0x3dc));
if (idl_size > Pico.romsize || idl_src + idl_size > Pico.romsize ||
idl_size > 0x40000 || idl_dst + idl_size > 0x40000 || (idl_src & 3) || (idl_dst & 3)) {
elprintf(EL_STATUS|EL_ANOMALY, "32x: invalid initial data ptrs: %06x -> %06x, %06x",
idl_src, idl_dst, idl_size);
}
else
memcpy(Pico32xMem->sdram + idl_dst, Pico.rom + idl_src, idl_size);
// GBR/VBR
vbr = HWSWAP(*(unsigned int *)(Pico.rom + 0x3e8));
sh2_set_gbr(0, 0x20004000);
sh2_set_vbr(0, vbr);
// checksum and M_OK
Pico32x.regs[0x28 / 2] = *(unsigned short *)(Pico.rom + 0x18e);
// program will set M_OK
}
// SSH2
if (p32x_bios_s == NULL) {
unsigned int vbr;
// GBR/VBR
vbr = HWSWAP(*(unsigned int *)(Pico.rom + 0x3ec));
sh2_set_gbr(1, 0x20004000);
sh2_set_vbr(1, vbr);
// program will set S_OK
}
}
void Pico32xInit(void) void Pico32xInit(void)
{ {
} }
@ -66,7 +111,7 @@ void PicoPower32x(void)
{ {
memset(&Pico32x, 0, sizeof(Pico32x)); memset(&Pico32x, 0, sizeof(Pico32x));
Pico32x.regs[0] = 0x0082; // SH2 reset? Pico32x.regs[0] = P32XS_REN|P32XS_nRES; // verified
Pico32x.vdp_regs[0x0a/2] = P32XV_VBLK|P32XV_HBLK|P32XV_PEN; Pico32x.vdp_regs[0x0a/2] = P32XV_VBLK|P32XV_HBLK|P32XV_PEN;
Pico32x.sh2_regs[0] = P32XS2_ADEN; Pico32x.sh2_regs[0] = P32XS2_ADEN;
} }
@ -82,8 +127,11 @@ void PicoUnload32x(void)
void PicoReset32x(void) void PicoReset32x(void)
{ {
extern int p32x_csum_faked; if (PicoAHW & PAHW_32X) {
p32x_csum_faked = 0; // tmp Pico32x.sh2irqs |= P32XI_VRES;
p32x_update_irls();
p32x_poll_event(3, 0);
}
} }
static void p32x_start_blank(void) static void p32x_start_blank(void)
@ -129,6 +177,8 @@ static __inline void run_m68k(int cyc)
while (SekCycleCnt < SekCycleAim) { \ while (SekCycleCnt < SekCycleAim) { \
slice = SekCycleCnt; \ slice = SekCycleCnt; \
run_m68k(SekCycleAim - SekCycleCnt); \ run_m68k(SekCycleAim - SekCycleCnt); \
if (!(Pico32x.regs[0] & P32XS_nRES)) \
continue; /* SH2s reseting */ \
slice = SekCycleCnt - slice; /* real count from 68k */ \ slice = SekCycleCnt - slice; /* real count from 68k */ \
if (SekCycleCnt < SekCycleAim) \ if (SekCycleCnt < SekCycleAim) \
elprintf(EL_32X, "slice %d", slice); \ elprintf(EL_32X, "slice %d", slice); \

View file

@ -1,3 +1,22 @@
/*
* Register map:
* a15100 F....... R.....EA F.....AC N...VHMP 4000 // Fm Ren nrEs Aden Cart heN V H cMd Pwm
* a15102 ........ ......SM ? 4002 // intS intM
* a15104 ........ ......10 ........ hhhhhhhh 4004 // bk1 bk0 Hint
* a15106 F....... .....SDR UE...... .....SDR 4006 // Full 68S Dma Rv fUll[fb] Empt[fb]
* a15108 (32bit DREQ src) 4008
* a1510c (32bit DREQ dst) 400c
* a15110 llllllll llllll00 4010 // DREQ Len
* a15112 (16bit FIFO reg) 4012
* a15114 ? (16bit VRES clr) 4014
* a15116 ? (16bit Vint clr) 4016
* a15118 ? (16bit Hint clr) 4018
* a1511a ........ .......C (16bit CMD clr) 401a // Cm
* a1511c ? (16bit PWM clr) 401c
* a1511e ? ? 401e
* a15120 (16 bytes comm) 2020
* a15130 (PWM) 2030
*/
#include "../pico_int.h" #include "../pico_int.h"
#include "../memory.h" #include "../memory.h"
@ -10,6 +29,7 @@
static const char str_mars[] = "MARS"; static const char str_mars[] = "MARS";
void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
struct Pico32xMem *Pico32xMem; struct Pico32xMem *Pico32xMem;
static void bank_switch(int b); static void bank_switch(int b);
@ -187,18 +207,14 @@ static void p32x_reg_write8(u32 a, u32 d)
// for things like bset on comm port // for things like bset on comm port
m68k_poll.cnt = 0; m68k_poll.cnt = 0;
if (a == 1 && !(r[0] & 1)) {
r[0] |= 1;
Pico32xStartup();
return;
}
if (!(r[0] & 1))
return;
switch (a) { switch (a) {
case 0: // adapter ctl case 0: // adapter ctl
r[0] = (r[0] & 0x83) | ((d << 8) & P32XS_FM); r[0] = (r[0] & ~P32XS_FM) | ((d << 8) & P32XS_FM);
return;
case 1: // adapter ctl, RES bit writeable
if ((d ^ r[0]) & d & P32XS_nRES)
p32x_reset_sh2s();
r[0] = (r[0] & ~P32XS_nRES) | (d & P32XS_nRES);
return; return;
case 3: // irq ctl case 3: // irq ctl
if ((d & 1) && !(Pico32x.sh2irqi[0] & P32XI_CMD)) { if ((d & 1) && !(Pico32x.sh2irqi[0] & P32XI_CMD)) {
@ -249,7 +265,9 @@ static void p32x_reg_write16(u32 a, u32 d)
switch (a) { switch (a) {
case 0x00: // adapter ctl case 0x00: // adapter ctl
r[0] = (r[0] & 0x83) | (d & P32XS_FM); if ((d ^ r[0]) & d & P32XS_nRES)
p32x_reset_sh2s();
r[0] = (r[0] & ~(P32XS_FM|P32XS_nRES)) | (d & (P32XS_FM|P32XS_nRES));
return; return;
case 0x10: // DREQ len case 0x10: // DREQ len
r[a / 2] = d & ~3; r[a / 2] = d & ~3;
@ -591,8 +609,10 @@ static void sh2_peripheral_write32(u32 a, u32 d, int id)
} }
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// default 32x handlers // 32x handlers
u32 PicoRead8_32x(u32 a)
// after ADEN
static u32 PicoRead8_32x_on(u32 a)
{ {
u32 d = 0; u32 d = 0;
if ((a & 0xffc0) == 0x5100) { // a15100 if ((a & 0xffc0) == 0x5100) { // a15100
@ -600,8 +620,8 @@ u32 PicoRead8_32x(u32 a)
goto out_16to8; goto out_16to8;
} }
if (!(Pico32x.regs[0] & 1)) if ((a & 0xfc00) != 0x5000)
goto no_vdp; return PicoRead8_io(a);
if ((a & 0xfff0) == 0x5180) { // a15180 if ((a & 0xfff0) == 0x5180) { // a15180
d = p32x_vdp_read16(a); d = p32x_vdp_read16(a);
@ -613,7 +633,6 @@ u32 PicoRead8_32x(u32 a)
goto out_16to8; goto out_16to8;
} }
no_vdp:
if ((a & 0xfffc) == 0x30ec) { // a130ec if ((a & 0xfffc) == 0x30ec) { // a130ec
d = str_mars[a & 3]; d = str_mars[a & 3];
goto out; goto out;
@ -633,7 +652,7 @@ out:
return d; return d;
} }
u32 PicoRead16_32x(u32 a) static u32 PicoRead16_32x_on(u32 a)
{ {
u32 d = 0; u32 d = 0;
if ((a & 0xffc0) == 0x5100) { // a15100 if ((a & 0xffc0) == 0x5100) { // a15100
@ -641,8 +660,8 @@ u32 PicoRead16_32x(u32 a)
goto out; goto out;
} }
if (!(Pico32x.regs[0] & 1)) if ((a & 0xfc00) != 0x5000)
goto no_vdp; return PicoRead16_io(a);
if ((a & 0xfff0) == 0x5180) { // a15180 if ((a & 0xfff0) == 0x5180) { // a15180
d = p32x_vdp_read16(a); d = p32x_vdp_read16(a);
@ -654,7 +673,110 @@ u32 PicoRead16_32x(u32 a)
goto out; goto out;
} }
no_vdp: if ((a & 0xfffc) == 0x30ec) { // a130ec
d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S';
goto out;
}
elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc);
return d;
out:
elprintf(EL_32X, "m68k 32x r16 [%06x] %04x @%06x", a, d, SekPc);
return d;
}
static void PicoWrite8_32x_on(u32 a, u32 d)
{
if ((a & 0xfc00) == 0x5000)
elprintf(EL_32X, "m68k 32x w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
if ((a & 0xffc0) == 0x5100) { // a15100
p32x_reg_write8(a, d);
return;
}
if ((a & 0xfc00) != 0x5000) {
PicoWrite8_io(a, d);
return;
}
if ((a & 0xfff0) == 0x5180) { // a15180
p32x_vdp_write8(a, d);
return;
}
// TODO: verify
if ((a & 0xfe00) == 0x5200) { // a15200
elprintf(EL_32X|EL_ANOMALY, "m68k 32x PAL w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
((u8 *)Pico32xMem->pal)[(a & 0x1ff) ^ 1] = d;
Pico32x.dirty_pal = 1;
return;
}
elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
}
static void PicoWrite16_32x_on(u32 a, u32 d)
{
if ((a & 0xfc00) == 0x5000)
elprintf(EL_UIO, "m68k 32x w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
if ((a & 0xffc0) == 0x5100) { // a15100
p32x_reg_write16(a, d);
return;
}
if ((a & 0xfc00) != 0x5000) {
PicoWrite16_io(a, d);
return;
}
if ((a & 0xfff0) == 0x5180) { // a15180
p32x_vdp_write16(a, d);
return;
}
if ((a & 0xfe00) == 0x5200) { // a15200
Pico32xMem->pal[(a & 0x1ff) / 2] = d;
Pico32x.dirty_pal = 1;
return;
}
elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
}
// before ADEN
u32 PicoRead8_32x(u32 a)
{
u32 d = 0;
if ((a & 0xffc0) == 0x5100) { // a15100
// regs are always readable
d = ((u8 *)Pico32x.regs)[(a & 0x3f) ^ 1];
goto out;
}
if ((a & 0xfffc) == 0x30ec) { // a130ec
d = str_mars[a & 3];
goto out;
}
elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc);
return d;
out:
elprintf(EL_32X, "m68k 32x r8 [%06x] %02x @%06x", a, d, SekPc);
return d;
}
u32 PicoRead16_32x(u32 a)
{
u32 d = 0;
if ((a & 0xffc0) == 0x5100) { // a15100
d = Pico32x.regs[(a & 0x3f) / 2];
goto out;
}
if ((a & 0xfffc) == 0x30ec) { // a130ec if ((a & 0xfffc) == 0x30ec) { // a130ec
d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S'; d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S';
goto out; goto out;
@ -670,62 +792,60 @@ out:
void PicoWrite8_32x(u32 a, u32 d) void PicoWrite8_32x(u32 a, u32 d)
{ {
if ((a & 0xfc00) == 0x5000)
elprintf(EL_32X, "m68k 32x w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
if ((a & 0xffc0) == 0x5100) { // a15100 if ((a & 0xffc0) == 0x5100) { // a15100
p32x_reg_write8(a, d); u16 *r = Pico32x.regs;
elprintf(EL_32X, "m68k 32x w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
a &= 0x3f;
if (a == 1) {
if ((d ^ r[0]) & d & P32XS_ADEN) {
Pico32xStartup();
r[0] &= ~P32XS_nRES; // causes reset if specified by this write
r[0] |= P32XS_ADEN;
p32x_reg_write8(a, d); // forward for reset processing
}
return; return;
} }
if (!(Pico32x.regs[0] & 1)) // allow only COMM for now
goto no_vdp; if ((a & 0x30) == 0x20) {
u8 *r8 = (u8 *)r;
if ((a & 0xfff0) == 0x5180) { // a15180 r8[a ^ 1] = d;
p32x_vdp_write8(a, d); }
return; return;
} }
// TODO: verify
if ((a & 0xfe00) == 0x5200) { // a15200
elprintf(EL_32X|EL_ANOMALY, "m68k 32x PAL w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
((u8 *)Pico32xMem->pal)[(a & 0x1ff) ^ 1] = d;
Pico32x.dirty_pal = 1;
return;
}
no_vdp:
elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
} }
void PicoWrite16_32x(u32 a, u32 d) void PicoWrite16_32x(u32 a, u32 d)
{ {
if ((a & 0xfc00) == 0x5000)
elprintf(EL_UIO, "m68k 32x w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
if ((a & 0xffc0) == 0x5100) { // a15100 if ((a & 0xffc0) == 0x5100) { // a15100
p32x_reg_write16(a, d); u16 *r = Pico32x.regs;
elprintf(EL_UIO, "m68k 32x w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
a &= 0x3e;
if (a == 0) {
if ((d ^ r[0]) & d & P32XS_ADEN) {
Pico32xStartup();
r[0] &= ~P32XS_nRES; // causes reset if specified by this write
r[0] |= P32XS_ADEN;
p32x_reg_write16(a, d); // forward for reset processing
}
return; return;
} }
if (!(Pico32x.regs[0] & 1)) // allow only COMM for now
goto no_vdp; if ((a & 0x30) == 0x20)
r[a / 2] = d;
if ((a & 0xfff0) == 0x5180) { // a15180
p32x_vdp_write16(a, d);
return; return;
} }
if ((a & 0xfe00) == 0x5200) { // a15200
Pico32xMem->pal[(a & 0x1ff) / 2] = d;
Pico32x.dirty_pal = 1;
return;
}
no_vdp:
elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
} }
// -----------------------------------------------------------------
// hint vector is writeable // hint vector is writeable
static void PicoWrite8_hint(u32 a, u32 d) static void PicoWrite8_hint(u32 a, u32 d)
{ {
@ -1017,25 +1137,62 @@ void p32x_sh2_write32(u32 a, u32 d, int id)
p32x_sh2_write16(a + 2, d, id); p32x_sh2_write16(a + 2, d, id);
} }
static const u16 msh2_code[] = {
// trap instructions
0xaffe, // bra <self>
0x0009, // nop
// have to wait a bit until m68k initial program finishes clearing stuff
// to avoid races with game SH2 code, like in Tempo
0xd004, // mov.l @(_m_ok,pc), r0
0xd105, // mov.l @(_cnt,pc), r1
0xd205, // mov.l @(_start,pc), r2
0x71ff, // add #-1, r1
0x4115, // cmp/pl r1
0x89fc, // bt -2
0xc208, // mov.l r0, @(h'20,gbr)
0x6822, // mov.l @r2, r8
0x482b, // jmp @r8
0x0009, // nop
('M'<<8)|'_', ('O'<<8)|'K',
0x0001, 0x0000,
0x2200, 0x03e0 // master start pointer in ROM
};
static const u16 ssh2_code[] = {
0xaffe, // bra <self>
0x0009, // nop
// code to wait for master, in case authentic master BIOS is used
0xd104, // mov.l @(_m_ok,pc), r1
0xd206, // mov.l @(_start,pc), r2
0xc608, // mov.l @(h'20,gbr), r0
0x3100, // cmp/eq r0, r1
0x8bfc, // bf #-2
0xd003, // mov.l @(_s_ok,pc), r0
0xc209, // mov.l r0, @(h'24,gbr)
0x6822, // mov.l @r2, r8
0x482b, // jmp @r8
0x0009, // nop
('M'<<8)|'_', ('O'<<8)|'K',
('S'<<8)|'_', ('O'<<8)|'K',
0x2200, 0x03e4 // slave start pointer in ROM
};
#define HWSWAP(x) (((x) << 16) | ((x) >> 16)) #define HWSWAP(x) (((x) << 16) | ((x) >> 16))
void PicoMemSetup32x(void) static void get_bios(void)
{ {
unsigned short *ps; u16 *ps;
unsigned int *pl; u32 *pl;
unsigned int rs;
int i; int i;
Pico32xMem = calloc(1, sizeof(*Pico32xMem)); // M68K ROM
if (Pico32xMem == NULL) { if (p32x_bios_g != NULL) {
elprintf(EL_STATUS, "OOM"); elprintf(EL_STATUS|EL_32X, "32x: using supplied 68k BIOS");
return; Byteswap(Pico32xMem->m68k_rom, p32x_bios_g, 0x100);
} }
else {
dmac0 = (void *)&Pico32xMem->sh2_peri_regs[0][0x180 / 4];
// generate 68k ROM // generate 68k ROM
ps = (unsigned short *)Pico32xMem->m68k_rom; ps = (u16 *)Pico32xMem->m68k_rom;
pl = (unsigned int *)Pico32xMem->m68k_rom; pl = (u32 *)ps;
for (i = 1; i < 0xc0/4; i++) for (i = 1; i < 0xc0/4; i++)
pl[i] = HWSWAP(0x880200 + (i - 1) * 6); pl[i] = HWSWAP(0x880200 + (i - 1) * 6);
@ -1050,41 +1207,67 @@ void PicoMemSetup32x(void)
#else #else
ps[0xfe/2] = 0x4e75; // rts ps[0xfe/2] = 0x4e75; // rts
#endif #endif
}
// fill remaining mem with ROM // fill remaining m68k_rom page with game ROM
memcpy(Pico32xMem->m68k_rom + 0x100, Pico.rom + 0x100, sizeof(Pico32xMem->m68k_rom) - 0x100); memcpy(Pico32xMem->m68k_rom + 0x100, Pico.rom + 0x100, sizeof(Pico32xMem->m68k_rom) - 0x100);
// 32X ROM // MSH2
// TODO: move if (p32x_bios_m != NULL) {
{ elprintf(EL_STATUS|EL_32X, "32x: using supplied master SH2 BIOS");
FILE *f = fopen("32X_M_BIOS.BIN", "rb"); Byteswap(Pico32xMem->sh2_rom_m, p32x_bios_m, sizeof(Pico32xMem->sh2_rom_m));
int i;
if (f == NULL) {
printf("missing 32X_M_BIOS.BIN\n");
exit(1);
} }
fread(Pico32xMem->sh2_rom_m, 1, sizeof(Pico32xMem->sh2_rom_m), f); else {
fclose(f); pl = (u32 *)Pico32xMem->sh2_rom_m;
f = fopen("32X_S_BIOS.BIN", "rb");
if (f == NULL) { // fill exception vector table to our trap address
printf("missing 32X_S_BIOS.BIN\n"); for (i = 0; i < 128; i++)
exit(1); pl[i] = HWSWAP(0x200);
// startup code
memcpy(Pico32xMem->sh2_rom_m + 0x200, msh2_code, sizeof(msh2_code));
// reset SP
pl[1] = pl[3] = HWSWAP(0x6040000);
// start
pl[0] = pl[2] = HWSWAP(0x204);
} }
fread(Pico32xMem->sh2_rom_s, 1, sizeof(Pico32xMem->sh2_rom_s), f);
fclose(f); // SSH2
// byteswap if (p32x_bios_s != NULL) {
for (i = 0; i < sizeof(Pico32xMem->sh2_rom_m); i += 2) { elprintf(EL_STATUS|EL_32X, "32x: using supplied slave SH2 BIOS");
int t = Pico32xMem->sh2_rom_m[i]; Byteswap(Pico32xMem->sh2_rom_s, p32x_bios_s, sizeof(Pico32xMem->sh2_rom_s));
Pico32xMem->sh2_rom_m[i] = Pico32xMem->sh2_rom_m[i + 1];
Pico32xMem->sh2_rom_m[i + 1] = t;
} }
for (i = 0; i < sizeof(Pico32xMem->sh2_rom_s); i += 2) { else {
int t = Pico32xMem->sh2_rom_s[i]; pl = (u32 *)Pico32xMem->sh2_rom_s;
Pico32xMem->sh2_rom_s[i] = Pico32xMem->sh2_rom_s[i + 1];
Pico32xMem->sh2_rom_s[i + 1] = t; // fill exception vector table to our trap address
for (i = 0; i < 128; i++)
pl[i] = HWSWAP(0x200);
// startup code
memcpy(Pico32xMem->sh2_rom_s + 0x200, ssh2_code, sizeof(ssh2_code));
// reset SP
pl[1] = pl[3] = HWSWAP(0x603f800);
// start
pl[0] = pl[2] = HWSWAP(0x204);
} }
}
void PicoMemSetup32x(void)
{
unsigned int rs;
Pico32xMem = calloc(1, sizeof(*Pico32xMem));
if (Pico32xMem == NULL) {
elprintf(EL_STATUS, "OOM");
return;
} }
dmac0 = (void *)&Pico32xMem->sh2_peri_regs[0][0x180 / 4];
get_bios();
// cartridge area becomes unmapped // cartridge area becomes unmapped
// XXX: we take the easy way and don't unmap ROM, // XXX: we take the easy way and don't unmap ROM,
// so that we can avoid handling the RV bit. // so that we can avoid handling the RV bit.
@ -1110,6 +1293,12 @@ void PicoMemSetup32x(void)
// 32X ROM (banked) // 32X ROM (banked)
bank_switch(0); bank_switch(0);
// SYS regs
cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, PicoRead8_32x_on, 1);
cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, PicoRead16_32x_on, 1);
cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, PicoWrite8_32x_on, 1);
cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, PicoWrite16_32x_on, 1);
// setup poll detector // setup poll detector
m68k_poll.flag = P32XF_68KPOLL; m68k_poll.flag = P32XF_68KPOLL;
m68k_poll.cyc_max = 64; m68k_poll.cyc_max = 64;

View file

@ -378,23 +378,21 @@ int pm_close(pm_file *fp)
return ret; return ret;
} }
// byteswap, data needs to be int aligned, src can match dst
static void Byteswap(unsigned char *data,int len) void Byteswap(void *dst, const void *src, int len)
{ {
int i=0; const unsigned int *ps = src;
unsigned int *pd = dst;
int i, m;
if (len<2) return; // Too short if (len < 2)
return;
do m = 0x00ff00ff;
{ for (i = 0; i < len / 4; i++) {
unsigned short *pd=(unsigned short *)(data+i); unsigned int t = ps[i];
int value=*pd; // Get 2 bytes pd[i] = ((t & m) << 8) | ((t & ~m) >> 8);
value=(value<<8)|(value>>8); // Byteswap it
*pd=(unsigned short)value; // Put 2b ytes
i+=2;
} }
while (i+2<=len);
} }
// Interleve a 16k block and byteswap // Interleve a 16k block and byteswap
@ -524,7 +522,7 @@ int PicoCartLoad(pm_file *f,unsigned char **prom,unsigned int *psize,int is_sms)
elprintf(EL_STATUS, "SMD format detected."); elprintf(EL_STATUS, "SMD format detected.");
DecodeSmd(rom,size); size-=0x200; // Decode and byteswap SMD DecodeSmd(rom,size); size-=0x200; // Decode and byteswap SMD
} }
else Byteswap(rom,size); // Just byteswap else Byteswap(rom, rom, size); // Just byteswap
} }
else else
{ {
@ -621,9 +619,9 @@ static unsigned int rom_crc32(void)
elprintf(EL_STATUS, "caclulating CRC32.."); elprintf(EL_STATUS, "caclulating CRC32..");
// have to unbyteswap for calculation.. // have to unbyteswap for calculation..
Byteswap(Pico.rom, Pico.romsize); Byteswap(Pico.rom, Pico.rom, Pico.romsize);
crc = crc32(0, Pico.rom, Pico.romsize); crc = crc32(0, Pico.rom, Pico.romsize);
Byteswap(Pico.rom, Pico.romsize); Byteswap(Pico.rom, Pico.rom, Pico.romsize);
return crc; return crc;
} }

View file

@ -37,6 +37,10 @@ extern void emu_video_mode_change(int start_line, int line_count, int is_32cols)
// this must switch to 32bpp mode // this must switch to 32bpp mode
extern void emu_32x_startup(void); extern void emu_32x_startup(void);
// optional 32X BIOS, should be left NULL if not used
// must be 256, 2048, 1024 bytes
extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
// Pico.c // Pico.c
#define POPT_EN_FM (1<< 0) // 00 000x #define POPT_EN_FM (1<< 0) // 00 000x
#define POPT_EN_PSG (1<< 1) #define POPT_EN_PSG (1<< 1)

View file

@ -252,6 +252,11 @@ extern SH2 sh2s[2];
#define sh2_vbr(c) (c) ? ssh2.vbr : msh2.vbr #define sh2_vbr(c) (c) ? ssh2.vbr : msh2.vbr
#define sh2_sr(c) (c) ? ssh2.sr : msh2.sr #define sh2_sr(c) (c) ? ssh2.sr : msh2.sr
#define sh2_set_gbr(c, v) \
{ if (c) ssh2.gbr = v; else msh2.gbr = v; }
#define sh2_set_vbr(c, v) \
{ if (c) ssh2.vbr = v; else msh2.vbr = v; }
// --------------------------------------------------------- // ---------------------------------------------------------
// main oscillator clock which controls timing // main oscillator clock which controls timing
@ -416,6 +421,9 @@ typedef struct
// 32X // 32X
#define P32XS_FM (1<<15) #define P32XS_FM (1<<15)
#define P32XS_REN (1<< 7)
#define P32XS_nRES (1<< 1)
#define P32XS_ADEN (1<< 0)
#define P32XS2_ADEN (1<< 9) #define P32XS2_ADEN (1<< 9)
#define P32XS_FULL (1<< 7) // DREQ FIFO full #define P32XS_FULL (1<< 7) // DREQ FIFO full
#define P32XS_68S (1<< 2) #define P32XS_68S (1<< 2)
@ -514,6 +522,7 @@ extern areaseek *areaSeek;
extern areaclose *areaClose; extern areaclose *areaClose;
// cart.c // cart.c
void Byteswap(void *dst, const void *src, int len);
extern void (*PicoCartMemSetup)(void); extern void (*PicoCartMemSetup)(void);
extern void (*PicoCartUnloadHook)(void); extern void (*PicoCartUnloadHook)(void);
@ -680,6 +689,7 @@ void Pico32xStartup(void);
void PicoUnload32x(void); void PicoUnload32x(void);
void PicoFrame32x(void); void PicoFrame32x(void);
void p32x_update_irls(void); void p32x_update_irls(void);
void p32x_reset_sh2s(void);
// 32x/memory.c // 32x/memory.c
struct Pico32xMem *Pico32xMem; struct Pico32xMem *Pico32xMem;

View file

@ -1299,6 +1299,19 @@ void emu_init(void)
char path[512]; char path[512];
int pos; int pos;
#if 0
// FIXME: handle through menu, etc
FILE *f;
f = fopen("32X_M_BIOS.BIN", "rb");
p32x_bios_m = malloc(2048);
fread(p32x_bios_m, 1, 2048, f);
fclose(f);
f = fopen("32X_S_BIOS.BIN", "rb");
p32x_bios_s = malloc(1024);
fread(p32x_bios_s, 1, 1024, f);
fclose(f);
#endif
/* make dirs for saves */ /* make dirs for saves */
pos = plat_get_root_dir(path, sizeof(path) - 4); pos = plat_get_root_dir(path, sizeof(path) - 4);
mkdir_path(path, pos, "mds"); mkdir_path(path, pos, "mds");