pandora: fix readme and pxml version
[picodrive.git] / pico / z80if.c
CommitLineData
cff531af 1/*
2 * PicoDrive
3 * (C) notaz, 2007-2010
4 *
5 * This work is licensed under the terms of MAME license.
6 * See COPYING file in the top-level directory.
7 */
8
b8a1c09a 9#include <stddef.h>
c8d1e9b6 10#include "pico_int.h"
b8a1c09a 11#include "memory.h"
c8d1e9b6 12
b8a1c09a 13uptr z80_read_map [0x10000 >> Z80_MEM_SHIFT];
14uptr z80_write_map[0x10000 >> Z80_MEM_SHIFT];
c8d1e9b6 15
46cbe781 16u32 z80_read(u32 a)
17{
18 uptr v;
19 a &= 0x00ffff;
20 v = z80_read_map[a >> Z80_MEM_SHIFT];
21 if (map_flag_set(v))
22 return ((z80_read_f *)(v << 1))(a);
23 else
24 return *(u8 *)((v << 1) + a);
25}
26
27
b4db550e 28#ifdef _USE_DRZ80
61290a35 29// this causes trouble in some cases, like doukutsu putting sp in bank area
30// no perf difference for most, upto 1-2% for some others
31//#define FAST_Z80SP
c8d1e9b6 32
61290a35 33struct DrZ80 drZ80;
46cbe781 34// import flag conversion from DrZ80
35extern u8 DrZ80_ARM[];
36extern u8 DrARM_Z80[];
c8d1e9b6 37
b4db550e 38static void drz80_load_pcsp(u32 pc, u32 sp)
c8d1e9b6 39{
b4db550e 40 drZ80.Z80PC_BASE = z80_read_map[pc >> Z80_MEM_SHIFT];
41 if (drZ80.Z80PC_BASE & (1<<31)) {
42 elprintf(EL_STATUS|EL_ANOMALY, "load_pcsp: bad PC: %04x", pc);
43 drZ80.Z80PC_BASE = drZ80.Z80PC = z80_read_map[0];
44 } else {
45 drZ80.Z80PC_BASE <<= 1;
46 drZ80.Z80PC = drZ80.Z80PC_BASE + pc;
47 }
61290a35 48 drZ80.Z80SP = sp;
49#ifdef FAST_Z80SP
b4db550e 50 drZ80.Z80SP_BASE = z80_read_map[sp >> Z80_MEM_SHIFT];
51 if (drZ80.Z80SP_BASE & (1<<31)) {
52 elprintf(EL_STATUS|EL_ANOMALY, "load_pcsp: bad SP: %04x", sp);
53 drZ80.Z80SP_BASE = z80_read_map[0];
54 drZ80.Z80SP = drZ80.Z80SP_BASE + (1 << Z80_MEM_SHIFT);
55 } else {
56 drZ80.Z80SP_BASE <<= 1;
57 drZ80.Z80SP = drZ80.Z80SP_BASE + sp;
58 }
61290a35 59#endif
b4db550e 60}
c8d1e9b6 61
b4db550e 62// called only if internal xmap rebase fails
63static unsigned int dz80_rebase_pc(unsigned short pc)
c8d1e9b6 64{
b4db550e 65 elprintf(EL_STATUS|EL_ANOMALY, "dz80_rebase_pc: fail on %04x", pc);
66 drZ80.Z80PC_BASE = z80_read_map[0] << 1;
67 return drZ80.Z80PC_BASE;
c8d1e9b6 68}
69
cf83610b 70static void dz80_noop_irq_ack(void) {}
71
61290a35 72#ifdef FAST_Z80SP
73static u32 drz80_sp_base;
74
b4db550e 75static unsigned int dz80_rebase_sp(unsigned short sp)
76{
77 elprintf(EL_STATUS|EL_ANOMALY, "dz80_rebase_sp: fail on %04x", sp);
78 drZ80.Z80SP_BASE = z80_read_map[drz80_sp_base >> Z80_MEM_SHIFT] << 1;
79 return drZ80.Z80SP_BASE + (1 << Z80_MEM_SHIFT) - 0x100;
80}
61290a35 81#else
82#define dz80_rebase_sp NULL
c8d1e9b6 83#endif
61290a35 84#endif // _USE_DRZ80
c8d1e9b6 85
86
b4db550e 87void z80_init(void)
c8d1e9b6 88{
c8d1e9b6 89#ifdef _USE_DRZ80
90 memset(&drZ80, 0, sizeof(drZ80));
b4db550e 91 drZ80.z80_rebasePC = dz80_rebase_pc;
92 drZ80.z80_rebaseSP = dz80_rebase_sp;
93 drZ80.z80_read8 = (void *)z80_read_map;
94 drZ80.z80_read16 = NULL;
95 drZ80.z80_write8 = (void *)z80_write_map;
96 drZ80.z80_write16 = NULL;
97 drZ80.z80_irq_callback = NULL;
c8d1e9b6 98#endif
99#ifdef _USE_CZ80
100 memset(&CZ80, 0, sizeof(CZ80));
101 Cz80_Init(&CZ80);
102 Cz80_Set_ReadB(&CZ80, NULL); // unused (hacked in)
103 Cz80_Set_WriteB(&CZ80, NULL);
104#endif
105}
106
b4db550e 107void z80_reset(void)
c8d1e9b6 108{
b7209504 109 int is_sms = (PicoIn.AHW & (PAHW_SMS|PAHW_SG|PAHW_SC)) == PAHW_SMS;
c8d1e9b6 110#ifdef _USE_DRZ80
cf82669f 111 drZ80.Z80I = 0;
112 drZ80.Z80IM = 0;
113 drZ80.Z80IF = 0;
114 drZ80.z80irqvector = 0xff0000; // RST 38h
115 drZ80.Z80PC_BASE = drZ80.Z80PC = z80_read_map[0] << 1;
c066c40b 116 // other registers not changed, undefined on cold boot
61290a35 117#ifdef FAST_Z80SP
d8f51995 118 // drZ80 is locked in single bank
b7209504 119 drz80_sp_base = (PicoIn.AHW & PAHW_8BIT) ? 0xc000 : 0x0000;
b4db550e 120 drZ80.Z80SP_BASE = z80_read_map[drz80_sp_base >> Z80_MEM_SHIFT] << 1;
61290a35 121#endif
b7209504 122 drZ80.Z80SP = drZ80.Z80SP_BASE + (is_sms ? 0xdff0 : 0xffff); // simulate BIOS
cf83610b 123 drZ80.z80_irq_callback = NULL; // use auto-clear
b7209504 124 if (PicoIn.AHW & PAHW_8BIT)
cf83610b 125 drZ80.z80_irq_callback = dz80_noop_irq_ack;
cf82669f 126 // XXX: since we use direct SP pointer, it might make sense to force it to RAM,
127 // but we'll rely on built-in stack protection for now
c8d1e9b6 128#endif
129#ifdef _USE_CZ80
130 Cz80_Reset(&CZ80);
c066c40b 131 Cz80_Set_Reg(&CZ80, CZ80_SP, 0xffff);
b7209504 132 if (is_sms)
b4db550e 133 Cz80_Set_Reg(&CZ80, CZ80_SP, 0xdff0);
c8d1e9b6 134#endif
135}
136
b4db550e 137struct z80sr_main {
138 u8 a, f;
139 u8 b, c;
140 u8 d, e;
141 u8 h, l;
142};
143
144struct z80_state {
145 char magic[4];
146 // regs
147 struct z80sr_main m; // main regs
148 struct z80sr_main a; // alt (') regs
149 u8 i, r;
150 u16 ix, iy;
151 u16 sp;
152 u16 pc;
153 // other
154 u8 halted;
155 u8 iff1, iff2;
156 u8 im; // irq mode
157 u8 irq_pending; // irq line level, 1 if active
158 u8 irq_vector[3]; // up to 3 byte vector for irq mode0 handling
52cb58c5 159 u16 cyc;
d4b5888a 160 u16 busdelay;
161 u8 reserved[4];
b4db550e 162};
163
164void z80_pack(void *data)
c8d1e9b6 165{
b4db550e 166 struct z80_state *s = data;
167 memset(data, 0, Z80_STATE_SIZE);
46cbe781 168 memcpy(s->magic, "Z80a", 4);
d4b5888a 169 s->cyc = Pico.t.z80c_cnt;
170 s->busdelay = Pico.t.z80_busdelay;
b4db550e 171#if defined(_USE_DRZ80)
172 #define DRR8(n) (drZ80.Z80##n >> 24)
173 #define DRR16(n) (drZ80.Z80##n >> 16)
174 #define DRR16H(n) (drZ80.Z80##n >> 24)
175 #define DRR16L(n) ((drZ80.Z80##n >> 16) & 0xff)
46cbe781 176 s->m.a = DRR8(A); s->m.f = DrARM_Z80[drZ80.Z80F];
b4db550e 177 s->m.b = DRR16H(BC); s->m.c = DRR16L(BC);
178 s->m.d = DRR16H(DE); s->m.e = DRR16L(DE);
179 s->m.h = DRR16H(HL); s->m.l = DRR16L(HL);
46cbe781 180 s->a.a = DRR8(A2); s->a.f = DrARM_Z80[drZ80.Z80F2];
b4db550e 181 s->a.b = DRR16H(BC2); s->a.c = DRR16L(BC2);
182 s->a.d = DRR16H(DE2); s->a.e = DRR16L(DE2);
183 s->a.h = DRR16H(HL2); s->a.l = DRR16L(HL2);
184 s->i = DRR8(I); s->r = drZ80.spare;
185 s->ix = DRR16(IX); s->iy = DRR16(IY);
186 s->sp = drZ80.Z80SP - drZ80.Z80SP_BASE;
187 s->pc = drZ80.Z80PC - drZ80.Z80PC_BASE;
188 s->halted = !!(drZ80.Z80IF & 4);
189 s->iff1 = !!(drZ80.Z80IF & 1);
190 s->iff2 = !!(drZ80.Z80IF & 2);
191 s->im = drZ80.Z80IM;
192 s->irq_pending = !!drZ80.Z80_IRQ;
193 s->irq_vector[0] = drZ80.z80irqvector >> 16;
194 s->irq_vector[1] = drZ80.z80irqvector >> 8;
195 s->irq_vector[2] = drZ80.z80irqvector;
196#elif defined(_USE_CZ80)
197 {
198 const cz80_struc *CPU = &CZ80;
199 s->m.a = zA; s->m.f = zF;
200 s->m.b = zB; s->m.c = zC;
201 s->m.d = zD; s->m.e = zE;
202 s->m.h = zH; s->m.l = zL;
203 s->a.a = zA2; s->a.f = zF2;
204 s->a.b = CZ80.BC2.B.H; s->a.c = CZ80.BC2.B.L;
205 s->a.d = CZ80.DE2.B.H; s->a.e = CZ80.DE2.B.L;
206 s->a.h = CZ80.HL2.B.H; s->a.l = CZ80.HL2.B.L;
d4b5888a 207 s->i = zI; s->r = (zR & 0x7f) | zR2;
b4db550e 208 s->ix = zIX; s->iy = zIY;
209 s->sp = Cz80_Get_Reg(&CZ80, CZ80_SP);
210 s->pc = Cz80_Get_Reg(&CZ80, CZ80_PC);
211 s->halted = !!Cz80_Get_Reg(&CZ80, CZ80_HALT);
212 s->iff1 = !!zIFF1;
213 s->iff2 = !!zIFF2;
214 s->im = zIM;
da414888 215 s->irq_pending = (Cz80_Get_Reg(&CZ80, CZ80_IRQ) != CLEAR_LINE);
b4db550e 216 s->irq_vector[0] = 0xff;
217 }
c8d1e9b6 218#endif
219}
220
b4db550e 221int z80_unpack(const void *data)
222{
223 const struct z80_state *s = data;
46cbe781 224 if (memcmp(s->magic, "Z80", 3) != 0) {
e6488636 225 elprintf(EL_STATUS, "legacy z80 state - ignored");
b4db550e 226 return 0;
227 }
52cb58c5 228 Pico.t.z80c_cnt = s->cyc;
d4b5888a 229 Pico.t.z80_busdelay = s->busdelay;
b4db550e 230
231#if defined(_USE_DRZ80)
232 #define DRW8(n, v) drZ80.Z80##n = (u32)(v) << 24
233 #define DRW16(n, v) drZ80.Z80##n = (u32)(v) << 16
234 #define DRW16HL(n, h, l) drZ80.Z80##n = ((u32)(h) << 24) | ((u32)(l) << 16)
46cbe781 235 u8 mf, af;
236 if (s->magic[3] == 'a') {
237 // new save: flags always in Z80 format
238 mf = DrZ80_ARM[s->m.f];
239 af = DrZ80_ARM[s->a.f];
240 } else {
241 // NB hack, swap Flag3 and NFlag for save file compatibility
242 mf = (s->m.f & 0x9f)|((s->m.f & 0x40)>>1)|((s->m.f & 0x20)<<1);
243 af = (s->a.f & 0x9f)|((s->a.f & 0x40)>>1)|((s->a.f & 0x20)<<1);
244 }
245 DRW8(A, s->m.a); drZ80.Z80F = mf;
b4db550e 246 DRW16HL(BC, s->m.b, s->m.c);
247 DRW16HL(DE, s->m.d, s->m.e);
248 DRW16HL(HL, s->m.h, s->m.l);
46cbe781 249 DRW8(A2, s->a.a); drZ80.Z80F2 = af;
b4db550e 250 DRW16HL(BC2, s->a.b, s->a.c);
251 DRW16HL(DE2, s->a.d, s->a.e);
252 DRW16HL(HL2, s->a.h, s->a.l);
253 DRW8(I, s->i); drZ80.spare = s->r;
254 DRW16(IX, s->ix); DRW16(IY, s->iy);
255 drz80_load_pcsp(s->pc, s->sp);
256 drZ80.Z80IF = 0;
257 if (s->halted) drZ80.Z80IF |= 4;
258 if (s->iff1) drZ80.Z80IF |= 1;
259 if (s->iff2) drZ80.Z80IF |= 2;
260 drZ80.Z80IM = s->im;
261 drZ80.Z80_IRQ = s->irq_pending;
262 drZ80.z80irqvector = ((u32)s->irq_vector[0] << 16) |
263 ((u32)s->irq_vector[1] << 8) | s->irq_vector[2];
264 return 0;
265#elif defined(_USE_CZ80)
266 {
267 cz80_struc *CPU = &CZ80;
268 zA = s->m.a; zF = s->m.f;
269 zB = s->m.b; zC = s->m.c;
270 zD = s->m.d; zE = s->m.e;
271 zH = s->m.h; zL = s->m.l;
272 zA2 = s->a.a; zF2 = s->a.f;
273 CZ80.BC2.B.H = s->a.b; CZ80.BC2.B.L = s->a.c;
274 CZ80.DE2.B.H = s->a.d; CZ80.DE2.B.L = s->a.e;
275 CZ80.HL2.B.H = s->a.h; CZ80.HL2.B.L = s->a.l;
d4b5888a 276 zI = s->i; zR = s->r; zR2 = s->r & 0x80;
b4db550e 277 zIX = s->ix; zIY = s->iy;
278 Cz80_Set_Reg(&CZ80, CZ80_SP, s->sp);
279 Cz80_Set_Reg(&CZ80, CZ80_PC, s->pc);
280 Cz80_Set_Reg(&CZ80, CZ80_HALT, s->halted);
281 Cz80_Set_Reg(&CZ80, CZ80_IFF1, s->iff1);
282 Cz80_Set_Reg(&CZ80, CZ80_IFF2, s->iff2);
283 zIM = s->im;
da414888 284 Cz80_Set_Reg(&CZ80, CZ80_IRQ, s->irq_pending ? ASSERT_LINE : CLEAR_LINE);
285 Cz80_Set_IRQ(&CZ80, 0, Cz80_Get_Reg(&CZ80, CZ80_IRQ));
b4db550e 286 return 0;
287 }
e6488636 288#else
289 return 0;
b4db550e 290#endif
b4db550e 291}
292
293void z80_exit(void)
294{
295}
296
297void z80_debug(char *dstr)
c8d1e9b6 298{
299#if defined(_USE_DRZ80)
300 sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", drZ80.Z80PC-drZ80.Z80PC_BASE, drZ80.Z80SP-drZ80.Z80SP_BASE);
301#elif defined(_USE_CZ80)
b8a1c09a 302 sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", (unsigned int)(CZ80.PC - CZ80.BasePC), CZ80.SP.W);
c8d1e9b6 303#endif
304}
61290a35 305
306// vim:ts=2:sw=2:expandtab