b730bfa750e51a7a5cdb7cd22cf15dffa6fb5de9
[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 u32 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
28 #ifdef _USE_DRZ80
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
32
33 struct DrZ80 drZ80;
34 // import flag conversion from DrZ80
35 extern u8 DrZ80_ARM[];
36 extern u8 DrARM_Z80[];
37
38 static void drz80_load_pcsp(u32 pc, u32 sp)
39 {
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   }
48   drZ80.Z80SP = sp;
49 #ifdef FAST_Z80SP
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   }
59 #endif
60 }
61
62 // called only if internal xmap rebase fails
63 static unsigned int dz80_rebase_pc(unsigned short pc)
64 {
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;
68 }
69
70 static void dz80_noop_irq_ack(void) {}
71
72 #ifdef FAST_Z80SP
73 static u32 drz80_sp_base;
74
75 static 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 }
81 #else
82 #define dz80_rebase_sp NULL
83 #endif
84 #endif // _USE_DRZ80
85
86
87 void z80_init(void)
88 {
89 #ifdef _USE_DRZ80
90   memset(&drZ80, 0, sizeof(drZ80));
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;
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
107 void z80_reset(void)
108 {
109   int is_sms = (PicoIn.AHW & (PAHW_SMS|PAHW_SG|PAHW_SC)) == PAHW_SMS;
110 #ifdef _USE_DRZ80
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;
116   // other registers not changed, undefined on cold boot
117 #ifdef FAST_Z80SP
118   // drZ80 is locked in single bank
119   drz80_sp_base = (PicoIn.AHW & PAHW_8BIT) ? 0xc000 : 0x0000;
120   drZ80.Z80SP_BASE = z80_read_map[drz80_sp_base >> Z80_MEM_SHIFT] << 1;
121 #endif
122   drZ80.Z80SP = drZ80.Z80SP_BASE + (is_sms ? 0xdff0 : 0xffff); // simulate BIOS
123   drZ80.z80_irq_callback = NULL; // use auto-clear
124   if (PicoIn.AHW & PAHW_8BIT)
125     drZ80.z80_irq_callback = dz80_noop_irq_ack;
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
128 #endif
129 #ifdef _USE_CZ80
130   Cz80_Reset(&CZ80);
131   Cz80_Set_Reg(&CZ80, CZ80_SP, 0xffff);
132   if (is_sms)
133     Cz80_Set_Reg(&CZ80, CZ80_SP, 0xdff0);
134 #endif
135 }
136
137 struct z80sr_main {
138   u8 a, f;
139   u8 b, c;
140   u8 d, e;
141   u8 h, l;
142 };
143
144 struct 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
159   u16 cyc;
160   u16 busdelay;
161   u8 reserved[4];
162 };
163
164 void z80_pack(void *data)
165 {
166   struct z80_state *s = data;
167   memset(data, 0, Z80_STATE_SIZE);
168   memcpy(s->magic, "Z80a", 4);
169   s->cyc = Pico.t.z80c_cnt;
170   s->busdelay = Pico.t.z80_busdelay;
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)
176   s->m.a = DRR8(A);     s->m.f = DrARM_Z80[drZ80.Z80F];
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);
180   s->a.a = DRR8(A2);    s->a.f = DrARM_Z80[drZ80.Z80F2];
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;
207     s->i  = zI;   s->r  = (zR & 0x7f) | zR2;
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;
215     s->irq_pending = (Cz80_Get_Reg(&CZ80, CZ80_IRQ) != CLEAR_LINE);
216     s->irq_vector[0] = 0xff;
217   }
218 #endif
219 }
220
221 int z80_unpack(const void *data)
222 {
223   const struct z80_state *s = data;
224   if (memcmp(s->magic, "Z80", 3) != 0) {
225     elprintf(EL_STATUS, "legacy z80 state - ignored");
226     return 0;
227   }
228   Pico.t.z80c_cnt = s->cyc;
229   Pico.t.z80_busdelay = s->busdelay;
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)
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;
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);
249   DRW8(A2, s->a.a); drZ80.Z80F2 = af;
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;
276     zI  = s->i;   zR  = s->r; zR2 = s->r & 0x80;
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;
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));
286     return 0;
287   }
288 #else
289   return 0;
290 #endif
291 }
292
293 void z80_exit(void)
294 {
295 }
296
297 void z80_debug(char *dstr)
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)
302   sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", (unsigned int)(CZ80.PC - CZ80.BasePC), CZ80.SP.W);
303 #endif
304 }
305
306 // vim:ts=2:sw=2:expandtab