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