pandora: use hw scaler (resolves 32x+sms), frontend refactoring
[picodrive.git] / pico / z80if.c
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   // FIXME: reset is not correct
75   memset(&drZ80, 0, 0x54);
76   drZ80.Z80F  = (1<<2);  // set ZFlag
77   drZ80.Z80F2 = (1<<2);  // set ZFlag
78   drZ80.Z80IX = 0xFFFF << 16;
79   drZ80.Z80IY = 0xFFFF << 16;
80   drZ80.Z80I = 0;
81   drZ80.Z80IM = 0; // 1?
82   drZ80.z80irqvector = 0xff0000; // RST 38h
83   drZ80.Z80PC_BASE = drZ80.Z80PC = z80_read_map[0] << 1;
84   // drZ80 is locked in single bank
85   drz80_sp_base = (PicoAHW & PAHW_SMS) ? 0xc000 : 0x0000;
86   drZ80.Z80SP_BASE = z80_read_map[drz80_sp_base >> Z80_MEM_SHIFT] << 1;
87   if (PicoAHW & PAHW_SMS)
88     drZ80.Z80SP = drZ80.Z80SP_BASE + 0xdff0; // simulate BIOS
89 #endif
90 #ifdef _USE_CZ80
91   Cz80_Reset(&CZ80);
92   Cz80_Set_Reg(&CZ80, CZ80_IX, 0xffff);
93   Cz80_Set_Reg(&CZ80, CZ80_IY, 0xffff);
94   if (PicoAHW & PAHW_SMS)
95     Cz80_Set_Reg(&CZ80, CZ80_SP, 0xdff0);
96 #endif
97 }
98
99 /* save state stuff */
100 static int z80_unpack_legacy(const void *data)
101 {
102 #if defined(_USE_DRZ80)
103   if (*(int *)data == 0x015A7244) { // "DrZ" v1 save?
104     u32 pc, sp;
105     memcpy(&drZ80, data+4, 0x54);
106     pc = (drZ80.Z80PC - drZ80.Z80PC_BASE) & 0xffff;
107     sp = (drZ80.Z80SP - drZ80.Z80SP_BASE) & 0xffff;
108     // update bases
109     drz80_load_pcsp(pc, sp);
110     return 0;
111   }
112 #elif defined(_USE_CZ80)
113   if (*(int *)data == 0x00007a43) { // "Cz" save?
114     memcpy(&CZ80, data+8, offsetof(cz80_struc, BasePC));
115     Cz80_Set_Reg(&CZ80, CZ80_PC, *(int *)(data+4));
116     return 0;
117   }
118 #endif
119   return -1;
120 }
121
122 struct z80sr_main {
123   u8 a, f;
124   u8 b, c;
125   u8 d, e;
126   u8 h, l;
127 };
128
129 struct z80_state {
130   char magic[4];
131   // regs
132   struct z80sr_main m; // main regs
133   struct z80sr_main a; // alt (') regs
134   u8  i, r;
135   u16 ix, iy;
136   u16 sp;
137   u16 pc;
138   // other
139   u8 halted;
140   u8 iff1, iff2;
141   u8 im;            // irq mode
142   u8 irq_pending;   // irq line level, 1 if active
143   u8 irq_vector[3]; // up to 3 byte vector for irq mode0 handling
144   u8 reserved[8];
145 };
146
147 void z80_pack(void *data)
148 {
149   struct z80_state *s = data;
150   memset(data, 0, Z80_STATE_SIZE);
151   strcpy(s->magic, "Z80");
152 #if defined(_USE_DRZ80)
153   #define DRR8(n)   (drZ80.Z80##n >> 24)
154   #define DRR16(n)  (drZ80.Z80##n >> 16)
155   #define DRR16H(n) (drZ80.Z80##n >> 24)
156   #define DRR16L(n) ((drZ80.Z80##n >> 16) & 0xff)
157   s->m.a = DRR8(A);     s->m.f = DRR8(F);
158   s->m.b = DRR16H(BC);  s->m.c = DRR16L(BC);
159   s->m.d = DRR16H(DE);  s->m.e = DRR16L(DE);
160   s->m.h = DRR16H(HL);  s->m.l = DRR16L(HL);
161   s->a.a = DRR8(A2);    s->a.f = DRR8(F2);
162   s->a.b = DRR16H(BC2); s->a.c = DRR16L(BC2);
163   s->a.d = DRR16H(DE2); s->a.e = DRR16L(DE2);
164   s->a.h = DRR16H(HL2); s->a.l = DRR16L(HL2);
165   s->i = DRR8(I);       s->r = drZ80.spare;
166   s->ix = DRR16(IX);    s->iy = DRR16(IY);
167   s->sp = drZ80.Z80SP - drZ80.Z80SP_BASE;
168   s->pc = drZ80.Z80PC - drZ80.Z80PC_BASE;
169   s->halted = !!(drZ80.Z80IF & 4);
170   s->iff1 = !!(drZ80.Z80IF & 1);
171   s->iff2 = !!(drZ80.Z80IF & 2);
172   s->im = drZ80.Z80IM;
173   s->irq_pending = !!drZ80.Z80_IRQ;
174   s->irq_vector[0] = drZ80.z80irqvector >> 16;
175   s->irq_vector[1] = drZ80.z80irqvector >> 8;
176   s->irq_vector[2] = drZ80.z80irqvector;
177 #elif defined(_USE_CZ80)
178   {
179     const cz80_struc *CPU = &CZ80;
180     s->m.a = zA;  s->m.f = zF;
181     s->m.b = zB;  s->m.c = zC;
182     s->m.d = zD;  s->m.e = zE;
183     s->m.h = zH;  s->m.l = zL;
184     s->a.a = zA2; s->a.f = zF2;
185     s->a.b = CZ80.BC2.B.H; s->a.c = CZ80.BC2.B.L;
186     s->a.d = CZ80.DE2.B.H; s->a.e = CZ80.DE2.B.L;
187     s->a.h = CZ80.HL2.B.H; s->a.l = CZ80.HL2.B.L;
188     s->i  = zI;   s->r  = zR;
189     s->ix = zIX;  s->iy = zIY;
190     s->sp = Cz80_Get_Reg(&CZ80, CZ80_SP);
191     s->pc = Cz80_Get_Reg(&CZ80, CZ80_PC);
192     s->halted = !!Cz80_Get_Reg(&CZ80, CZ80_HALT);
193     s->iff1 = !!zIFF1;
194     s->iff2 = !!zIFF2;
195     s->im = zIM;
196     s->irq_pending = (Cz80_Get_Reg(&CZ80, CZ80_IRQ) == HOLD_LINE);
197     s->irq_vector[0] = 0xff;
198   }
199 #endif
200 }
201
202 int z80_unpack(const void *data)
203 {
204   const struct z80_state *s = data;
205   if (strcmp(s->magic, "Z80") != 0) {
206     if (z80_unpack_legacy(data) != 0)
207       goto fail;
208     elprintf(EL_STATUS, "legacy z80 state");
209     return 0;
210   }
211
212 #if defined(_USE_DRZ80)
213   #define DRW8(n, v)       drZ80.Z80##n = (u32)(v) << 24
214   #define DRW16(n, v)      drZ80.Z80##n = (u32)(v) << 16
215   #define DRW16HL(n, h, l) drZ80.Z80##n = ((u32)(h) << 24) | ((u32)(l) << 16)
216   DRW8(A, s->m.a);  DRW8(F, s->m.f);
217   DRW16HL(BC, s->m.b, s->m.c);
218   DRW16HL(DE, s->m.d, s->m.e);
219   DRW16HL(HL, s->m.h, s->m.l);
220   DRW8(A2, s->a.a); DRW8(F2, s->a.f);
221   DRW16HL(BC2, s->a.b, s->a.c);
222   DRW16HL(DE2, s->a.d, s->a.e);
223   DRW16HL(HL2, s->a.h, s->a.l);
224   DRW8(I, s->i);    drZ80.spare = s->r;
225   DRW16(IX, s->ix); DRW16(IY, s->iy);
226   drz80_load_pcsp(s->pc, s->sp);
227   drZ80.Z80IF = 0;
228   if (s->halted) drZ80.Z80IF |= 4;
229   if (s->iff1)   drZ80.Z80IF |= 1;
230   if (s->iff2)   drZ80.Z80IF |= 2;
231   drZ80.Z80IM = s->im;
232   drZ80.Z80_IRQ = s->irq_pending;
233   drZ80.z80irqvector = ((u32)s->irq_vector[0] << 16) |
234     ((u32)s->irq_vector[1] << 8) | s->irq_vector[2];
235   return 0;
236 #elif defined(_USE_CZ80)
237   {
238     cz80_struc *CPU = &CZ80;
239     zA  = s->m.a; zF  = s->m.f;
240     zB  = s->m.b; zC  = s->m.c;
241     zD  = s->m.d; zE  = s->m.e;
242     zH  = s->m.h; zL  = s->m.l;
243     zA2 = s->a.a; zF2 = s->a.f;
244     CZ80.BC2.B.H = s->a.b; CZ80.BC2.B.L = s->a.c;
245     CZ80.DE2.B.H = s->a.d; CZ80.DE2.B.L = s->a.e;
246     CZ80.HL2.B.H = s->a.h; CZ80.HL2.B.L = s->a.l;
247     zI  = s->i;   zR  = s->r;
248     zIX = s->ix;  zIY = s->iy;
249     Cz80_Set_Reg(&CZ80, CZ80_SP, s->sp);
250     Cz80_Set_Reg(&CZ80, CZ80_PC, s->pc);
251     Cz80_Set_Reg(&CZ80, CZ80_HALT, s->halted);
252     Cz80_Set_Reg(&CZ80, CZ80_IFF1, s->iff1);
253     Cz80_Set_Reg(&CZ80, CZ80_IFF2, s->iff2);
254     zIM = s->im;
255     Cz80_Set_Reg(&CZ80, CZ80_IRQ, s->irq_pending ? HOLD_LINE : CLEAR_LINE);
256     return 0;
257   }
258 #endif
259
260 fail:
261   elprintf(EL_STATUS|EL_ANOMALY, "z80_unpack failed");
262   z80_reset();
263   z80_int();
264   return -1;
265 }
266
267 void z80_exit(void)
268 {
269 }
270
271 void z80_debug(char *dstr)
272 {
273 #if defined(_USE_DRZ80)
274   sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", drZ80.Z80PC-drZ80.Z80PC_BASE, drZ80.Z80SP-drZ80.Z80SP_BASE);
275 #elif defined(_USE_CZ80)
276   sprintf(dstr, "Z80 state: PC: %04x SP: %04x\n", (unsigned int)(CZ80.PC - CZ80.BasePC), CZ80.SP.W);
277 #endif
278 }