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 |
13 | uptr z80_read_map [0x10000 >> Z80_MEM_SHIFT]; |
14 | uptr z80_write_map[0x10000 >> Z80_MEM_SHIFT]; |
c8d1e9b6 |
15 | |
46cbe781 |
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 | |
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 |
33 | struct DrZ80 drZ80; |
46cbe781 |
34 | // import flag conversion from DrZ80 |
35 | extern u8 DrZ80_ARM[]; |
36 | extern u8 DrARM_Z80[]; |
c8d1e9b6 |
37 | |
b4db550e |
38 | static 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 |
63 | static 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 |
70 | static void dz80_noop_irq_ack(void) {} |
71 | |
61290a35 |
72 | #ifdef FAST_Z80SP |
73 | static u32 drz80_sp_base; |
74 | |
b4db550e |
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 | } |
61290a35 |
81 | #else |
82 | #define dz80_rebase_sp NULL |
c8d1e9b6 |
83 | #endif |
61290a35 |
84 | #endif // _USE_DRZ80 |
c8d1e9b6 |
85 | |
86 | |
b4db550e |
87 | void 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 |
107 | void 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 |
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 |
52cb58c5 |
159 | u16 cyc; |
d4b5888a |
160 | u16 busdelay; |
161 | u8 reserved[4]; |
b4db550e |
162 | }; |
163 | |
164 | void 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 |
221 | int 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 | |
293 | void z80_exit(void) |
294 | { |
295 | } |
296 | |
297 | void 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 |