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