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