picodrive/pico/z80if.c
notaz cff531af94 clarify PicoDrive's license
- PicoDrive was originally released by fDave with simple
  "free for non-commercial use / For commercial use, separate licencing
  terms must be obtained" license and I kept it in my releases.
- in 2011, fDave re-released his code (same that I used as base
  many years ago) dual licensed with GPLv2 and MAME licenses:
    https://code.google.com/p/cyclone68000/

Based on the above I now proclaim that the whole source code is licensed
under the MAME license as more elaborate form of "for non-commercial use".
If that raises any doubt, I announce that all my modifications (which
is the vast majority of code by now) is licensed under the MAME license,
as it reads in COPYING file in this commit.

This does not affect ym2612.c/sn76496.c that were MAME licensed already
from the beginning.
2013-06-26 03:07:07 +03:00

288 lines
8 KiB
C

/*
* PicoDrive
* (C) notaz, 2007-2010
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include <stddef.h>
#include "pico_int.h"
#include "memory.h"
uptr z80_read_map [0x10000 >> Z80_MEM_SHIFT];
uptr z80_write_map[0x10000 >> Z80_MEM_SHIFT];
#ifdef _USE_DRZ80
struct DrZ80 drZ80;
static u32 drz80_sp_base;
static void drz80_load_pcsp(u32 pc, u32 sp)
{
drZ80.Z80PC_BASE = z80_read_map[pc >> Z80_MEM_SHIFT];
if (drZ80.Z80PC_BASE & (1<<31)) {
elprintf(EL_STATUS|EL_ANOMALY, "load_pcsp: bad PC: %04x", pc);
drZ80.Z80PC_BASE = drZ80.Z80PC = z80_read_map[0];
} else {
drZ80.Z80PC_BASE <<= 1;
drZ80.Z80PC = drZ80.Z80PC_BASE + pc;
}
drZ80.Z80SP_BASE = z80_read_map[sp >> Z80_MEM_SHIFT];
if (drZ80.Z80SP_BASE & (1<<31)) {
elprintf(EL_STATUS|EL_ANOMALY, "load_pcsp: bad SP: %04x", sp);
drZ80.Z80SP_BASE = z80_read_map[0];
drZ80.Z80SP = drZ80.Z80SP_BASE + (1 << Z80_MEM_SHIFT);
} else {
drZ80.Z80SP_BASE <<= 1;
drZ80.Z80SP = drZ80.Z80SP_BASE + sp;
}
}
// called only if internal xmap rebase fails
static unsigned int dz80_rebase_pc(unsigned short pc)
{
elprintf(EL_STATUS|EL_ANOMALY, "dz80_rebase_pc: fail on %04x", pc);
drZ80.Z80PC_BASE = z80_read_map[0] << 1;
return drZ80.Z80PC_BASE;
}
static unsigned int dz80_rebase_sp(unsigned short sp)
{
elprintf(EL_STATUS|EL_ANOMALY, "dz80_rebase_sp: fail on %04x", sp);
drZ80.Z80SP_BASE = z80_read_map[drz80_sp_base >> Z80_MEM_SHIFT] << 1;
return drZ80.Z80SP_BASE + (1 << Z80_MEM_SHIFT) - 0x100;
}
#endif
void z80_init(void)
{
#ifdef _USE_DRZ80
memset(&drZ80, 0, sizeof(drZ80));
drZ80.z80_rebasePC = dz80_rebase_pc;
drZ80.z80_rebaseSP = dz80_rebase_sp;
drZ80.z80_read8 = (void *)z80_read_map;
drZ80.z80_read16 = NULL;
drZ80.z80_write8 = (void *)z80_write_map;
drZ80.z80_write16 = NULL;
drZ80.z80_irq_callback = NULL;
#endif
#ifdef _USE_CZ80
memset(&CZ80, 0, sizeof(CZ80));
Cz80_Init(&CZ80);
Cz80_Set_ReadB(&CZ80, NULL); // unused (hacked in)
Cz80_Set_WriteB(&CZ80, NULL);
#endif
}
void z80_reset(void)
{
#ifdef _USE_DRZ80
drZ80.Z80I = 0;
drZ80.Z80IM = 0;
drZ80.Z80IF = 0;
drZ80.z80irqvector = 0xff0000; // RST 38h
drZ80.Z80PC_BASE = drZ80.Z80PC = z80_read_map[0] << 1;
// others not changed, undefined on cold boot
/*
drZ80.Z80F = (1<<2); // set ZFlag
drZ80.Z80F2 = (1<<2); // set ZFlag
drZ80.Z80IX = 0xFFFF << 16;
drZ80.Z80IY = 0xFFFF << 16;
*/
// drZ80 is locked in single bank
drz80_sp_base = (PicoAHW & PAHW_SMS) ? 0xc000 : 0x0000;
drZ80.Z80SP_BASE = z80_read_map[drz80_sp_base >> Z80_MEM_SHIFT] << 1;
if (PicoAHW & PAHW_SMS)
drZ80.Z80SP = drZ80.Z80SP_BASE + 0xdff0; // simulate BIOS
// XXX: since we use direct SP pointer, it might make sense to force it to RAM,
// but we'll rely on built-in stack protection for now
#endif
#ifdef _USE_CZ80
Cz80_Reset(&CZ80);
if (PicoAHW & PAHW_SMS)
Cz80_Set_Reg(&CZ80, CZ80_SP, 0xdff0);
#endif
}
/* save state stuff */
static int z80_unpack_legacy(const void *data)
{
#if defined(_USE_DRZ80)
if (*(int *)data == 0x015A7244) { // "DrZ" v1 save?
u32 pc, sp;
memcpy(&drZ80, data+4, 0x54);
pc = (drZ80.Z80PC - drZ80.Z80PC_BASE) & 0xffff;
sp = (drZ80.Z80SP - drZ80.Z80SP_BASE) & 0xffff;
// update bases
drz80_load_pcsp(pc, sp);
return 0;
}
#elif defined(_USE_CZ80)
if (*(int *)data == 0x00007a43) { // "Cz" save?
memcpy(&CZ80, data+8, offsetof(cz80_struc, BasePC));
Cz80_Set_Reg(&CZ80, CZ80_PC, *(int *)(data+4));
return 0;
}
#endif
return -1;
}
struct z80sr_main {
u8 a, f;
u8 b, c;
u8 d, e;
u8 h, l;
};
struct z80_state {
char magic[4];
// regs
struct z80sr_main m; // main regs
struct z80sr_main a; // alt (') regs
u8 i, r;
u16 ix, iy;
u16 sp;
u16 pc;
// other
u8 halted;
u8 iff1, iff2;
u8 im; // irq mode
u8 irq_pending; // irq line level, 1 if active
u8 irq_vector[3]; // up to 3 byte vector for irq mode0 handling
u8 reserved[8];
};
void z80_pack(void *data)
{
struct z80_state *s = data;
memset(data, 0, Z80_STATE_SIZE);
strcpy(s->magic, "Z80");
#if defined(_USE_DRZ80)
#define DRR8(n) (drZ80.Z80##n >> 24)
#define DRR16(n) (drZ80.Z80##n >> 16)
#define DRR16H(n) (drZ80.Z80##n >> 24)
#define DRR16L(n) ((drZ80.Z80##n >> 16) & 0xff)
s->m.a = DRR8(A); s->m.f = DRR8(F);
s->m.b = DRR16H(BC); s->m.c = DRR16L(BC);
s->m.d = DRR16H(DE); s->m.e = DRR16L(DE);
s->m.h = DRR16H(HL); s->m.l = DRR16L(HL);
s->a.a = DRR8(A2); s->a.f = DRR8(F2);
s->a.b = DRR16H(BC2); s->a.c = DRR16L(BC2);
s->a.d = DRR16H(DE2); s->a.e = DRR16L(DE2);
s->a.h = DRR16H(HL2); s->a.l = DRR16L(HL2);
s->i = DRR8(I); s->r = drZ80.spare;
s->ix = DRR16(IX); s->iy = DRR16(IY);
s->sp = drZ80.Z80SP - drZ80.Z80SP_BASE;
s->pc = drZ80.Z80PC - drZ80.Z80PC_BASE;
s->halted = !!(drZ80.Z80IF & 4);
s->iff1 = !!(drZ80.Z80IF & 1);
s->iff2 = !!(drZ80.Z80IF & 2);
s->im = drZ80.Z80IM;
s->irq_pending = !!drZ80.Z80_IRQ;
s->irq_vector[0] = drZ80.z80irqvector >> 16;
s->irq_vector[1] = drZ80.z80irqvector >> 8;
s->irq_vector[2] = drZ80.z80irqvector;
#elif defined(_USE_CZ80)
{
const cz80_struc *CPU = &CZ80;
s->m.a = zA; s->m.f = zF;
s->m.b = zB; s->m.c = zC;
s->m.d = zD; s->m.e = zE;
s->m.h = zH; s->m.l = zL;
s->a.a = zA2; s->a.f = zF2;
s->a.b = CZ80.BC2.B.H; s->a.c = CZ80.BC2.B.L;
s->a.d = CZ80.DE2.B.H; s->a.e = CZ80.DE2.B.L;
s->a.h = CZ80.HL2.B.H; s->a.l = CZ80.HL2.B.L;
s->i = zI; s->r = zR;
s->ix = zIX; s->iy = zIY;
s->sp = Cz80_Get_Reg(&CZ80, CZ80_SP);
s->pc = Cz80_Get_Reg(&CZ80, CZ80_PC);
s->halted = !!Cz80_Get_Reg(&CZ80, CZ80_HALT);
s->iff1 = !!zIFF1;
s->iff2 = !!zIFF2;
s->im = zIM;
s->irq_pending = (Cz80_Get_Reg(&CZ80, CZ80_IRQ) == HOLD_LINE);
s->irq_vector[0] = 0xff;
}
#endif
}
int z80_unpack(const void *data)
{
const struct z80_state *s = data;
if (strcmp(s->magic, "Z80") != 0) {
if (z80_unpack_legacy(data) != 0)
goto fail;
elprintf(EL_STATUS, "legacy z80 state");
return 0;
}
#if defined(_USE_DRZ80)
#define DRW8(n, v) drZ80.Z80##n = (u32)(v) << 24
#define DRW16(n, v) drZ80.Z80##n = (u32)(v) << 16
#define DRW16HL(n, h, l) drZ80.Z80##n = ((u32)(h) << 24) | ((u32)(l) << 16)
DRW8(A, s->m.a); DRW8(F, s->m.f);
DRW16HL(BC, s->m.b, s->m.c);
DRW16HL(DE, s->m.d, s->m.e);
DRW16HL(HL, s->m.h, s->m.l);
DRW8(A2, s->a.a); DRW8(F2, s->a.f);
DRW16HL(BC2, s->a.b, s->a.c);
DRW16HL(DE2, s->a.d, s->a.e);
DRW16HL(HL2, s->a.h, s->a.l);
DRW8(I, s->i); drZ80.spare = s->r;
DRW16(IX, s->ix); DRW16(IY, s->iy);
drz80_load_pcsp(s->pc, s->sp);
drZ80.Z80IF = 0;
if (s->halted) drZ80.Z80IF |= 4;
if (s->iff1) drZ80.Z80IF |= 1;
if (s->iff2) drZ80.Z80IF |= 2;
drZ80.Z80IM = s->im;
drZ80.Z80_IRQ = s->irq_pending;
drZ80.z80irqvector = ((u32)s->irq_vector[0] << 16) |
((u32)s->irq_vector[1] << 8) | s->irq_vector[2];
return 0;
#elif defined(_USE_CZ80)
{
cz80_struc *CPU = &CZ80;
zA = s->m.a; zF = s->m.f;
zB = s->m.b; zC = s->m.c;
zD = s->m.d; zE = s->m.e;
zH = s->m.h; zL = s->m.l;
zA2 = s->a.a; zF2 = s->a.f;
CZ80.BC2.B.H = s->a.b; CZ80.BC2.B.L = s->a.c;
CZ80.DE2.B.H = s->a.d; CZ80.DE2.B.L = s->a.e;
CZ80.HL2.B.H = s->a.h; CZ80.HL2.B.L = s->a.l;
zI = s->i; zR = s->r;
zIX = s->ix; zIY = s->iy;
Cz80_Set_Reg(&CZ80, CZ80_SP, s->sp);
Cz80_Set_Reg(&CZ80, CZ80_PC, s->pc);
Cz80_Set_Reg(&CZ80, CZ80_HALT, s->halted);
Cz80_Set_Reg(&CZ80, CZ80_IFF1, s->iff1);
Cz80_Set_Reg(&CZ80, CZ80_IFF2, s->iff2);
zIM = s->im;
Cz80_Set_Reg(&CZ80, CZ80_IRQ, s->irq_pending ? HOLD_LINE : CLEAR_LINE);
return 0;
}
#endif
fail:
elprintf(EL_STATUS|EL_ANOMALY, "z80_unpack failed");
z80_reset();
z80_int();
return -1;
}
void z80_exit(void)
{
}
void z80_debug(char *dstr)
{
#if defined(_USE_DRZ80)
sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", drZ80.Z80PC-drZ80.Z80PC_BASE, drZ80.Z80SP-drZ80.Z80SP_BASE);
#elif defined(_USE_CZ80)
sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", (unsigned int)(CZ80.PC - CZ80.BasePC), CZ80.SP.W);
#endif
}