various bugfixes
[picodrive.git] / cpu / cz80 / cz80.c
1 /******************************************************************************\r
2  *\r
3  * CZ80 (Z80 CPU emulator) version 0.9\r
4  * Compiled with Dev-C++\r
5  * Copyright 2004-2005 Stéphane Dallongeville\r
6  *\r
7  * (Modified by NJ)\r
8  *\r
9  *****************************************************************************/\r
10 \r
11 #include <stdio.h>\r
12 #include <stdlib.h>\r
13 #include <string.h>\r
14 #include "cz80.h"\r
15 \r
16 #ifndef ALIGN_DATA\r
17 #define ALIGN_DATA      __attribute__((aligned(4)))\r
18 #endif\r
19 \r
20 #define CF                                      0x01\r
21 #define NF                                      0x02\r
22 #define PF                                      0x04\r
23 #define VF                                      PF\r
24 #define XF                                      0x08\r
25 #define HF                                      0x10\r
26 #define YF                                      0x20\r
27 #define ZF                                      0x40\r
28 #define SF                                      0x80\r
29 \r
30 \r
31 /******************************************************************************\r
32         \83}\83N\83\8d\r
33 ******************************************************************************/\r
34 \r
35 #include "cz80macro.h"\r
36 \r
37 \r
38 /******************************************************************************\r
39         \83O\83\8d\81[\83o\83\8b\8d\\91¢\91Ì\r
40 ******************************************************************************/\r
41 \r
42 cz80_struc ALIGN_DATA CZ80;\r
43 \r
44 \r
45 /******************************************************************************\r
46         \83\8d\81[\83J\83\8b\95Ï\90\94\r
47 ******************************************************************************/\r
48 \r
49 static UINT8 ALIGN_DATA cz80_bad_address[1 << CZ80_FETCH_SFT];\r
50 \r
51 static UINT8 ALIGN_DATA SZ[256];\r
52 static UINT8 ALIGN_DATA SZP[256];\r
53 static UINT8 ALIGN_DATA SZ_BIT[256];\r
54 static UINT8 ALIGN_DATA SZHV_inc[256];\r
55 static UINT8 ALIGN_DATA SZHV_dec[256];\r
56 #if CZ80_BIG_FLAGS_ARRAY\r
57 static UINT8 ALIGN_DATA SZHVC_add[2*256*256];\r
58 static UINT8 ALIGN_DATA SZHVC_sub[2*256*256];\r
59 #endif\r
60 \r
61 \r
62 /******************************************************************************\r
63         \83\8d\81[\83J\83\8b\8aÖ\90\94\r
64 ******************************************************************************/\r
65 \r
66 /*--------------------------------------------------------\r
67         \8a\84\82è\8d\9e\82Ý\83R\81[\83\8b\83o\83b\83N\r
68 --------------------------------------------------------*/\r
69 \r
70 static INT32 Cz80_Interrupt_Callback(INT32 line)\r
71 {\r
72         return 0xff;\r
73 }\r
74 \r
75 \r
76 /******************************************************************************\r
77         CZ80\83C\83\93\83^\83t\83F\81[\83X\8aÖ\90\94\r
78 ******************************************************************************/\r
79 \r
80 /*--------------------------------------------------------\r
81         CPU\8f\89\8aú\89»\r
82 --------------------------------------------------------*/\r
83 \r
84 void Cz80_Init(cz80_struc *CPU)\r
85 {\r
86         UINT32 i, j, p;\r
87 #if CZ80_BIG_FLAGS_ARRAY\r
88         int oldval, newval, val;\r
89         UINT8 *padd, *padc, *psub, *psbc;\r
90 #endif\r
91 \r
92         memset(CPU, 0, sizeof(cz80_struc));\r
93 \r
94         memset(cz80_bad_address, 0xff, sizeof(cz80_bad_address));\r
95 \r
96         for (i = 0; i < CZ80_FETCH_BANK; i++)\r
97         {\r
98                 CPU->Fetch[i] = (UINT32)cz80_bad_address;\r
99 #if CZ80_ENCRYPTED_ROM\r
100                 CPU->OPFetch[i] = 0;\r
101 #endif\r
102         }\r
103 \r
104         // flags tables initialisation\r
105         for (i = 0; i < 256; i++)\r
106         {\r
107                 SZ[i] = i & (SF | YF | XF);\r
108                 if (!i) SZ[i] |= ZF;\r
109 \r
110                 SZ_BIT[i] = i & (SF | YF | XF);\r
111                 if (!i) SZ_BIT[i] |= ZF | PF;\r
112 \r
113                 for (j = 0, p = 0; j < 8; j++) if (i & (1 << j)) p++;\r
114                 SZP[i] = SZ[i];\r
115                 if (!(p & 1)) SZP[i] |= PF;\r
116 \r
117                 SZHV_inc[i] = SZ[i];\r
118                 if(i == 0x80) SZHV_inc[i] |= VF;\r
119                 if((i & 0x0f) == 0x00) SZHV_inc[i] |= HF;\r
120 \r
121                 SZHV_dec[i] = SZ[i] | NF;\r
122                 if (i == 0x7f) SZHV_dec[i] |= VF;\r
123                 if ((i & 0x0f) == 0x0f) SZHV_dec[i] |= HF;\r
124         }\r
125 \r
126 #if CZ80_BIG_FLAGS_ARRAY\r
127         padd = &SZHVC_add[  0*256];\r
128         padc = &SZHVC_add[256*256];\r
129         psub = &SZHVC_sub[  0*256];\r
130         psbc = &SZHVC_sub[256*256];\r
131 \r
132         for (oldval = 0; oldval < 256; oldval++)\r
133         {\r
134                 for (newval = 0; newval < 256; newval++)\r
135                 {\r
136                         /* add or adc w/o carry set */\r
137                         val = newval - oldval;\r
138                         *padd = (newval) ? ((newval & 0x80) ? SF : 0) : ZF;\r
139                         *padd |= (newval & (YF | XF));  /* undocumented flag bits 5+3 */\r
140                         if ((newval & 0x0f) < (oldval & 0x0f)) *padd |= HF;\r
141                         if (newval < oldval ) *padd |= CF;\r
142                         if ((val ^ oldval ^ 0x80) & (val ^ newval) & 0x80) *padd |= VF;\r
143                         padd++;\r
144 \r
145                         /* adc with carry set */\r
146                         val = newval - oldval - 1;\r
147                         *padc = (newval) ? ((newval & 0x80) ? SF : 0) : ZF;\r
148                         *padc |= (newval & (YF | XF));  /* undocumented flag bits 5+3 */\r
149                         if ((newval & 0x0f) <= (oldval & 0x0f)) *padc |= HF;\r
150                         if (newval <= oldval) *padc |= CF;\r
151                         if ((val ^ oldval ^ 0x80) & (val ^ newval) & 0x80) *padc |= VF;\r
152                         padc++;\r
153 \r
154                         /* cp, sub or sbc w/o carry set */\r
155                         val = oldval - newval;\r
156                         *psub = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);\r
157                         *psub |= (newval & (YF | XF));  /* undocumented flag bits 5+3 */\r
158                         if ((newval & 0x0f) > (oldval & 0x0f)) *psub |= HF;\r
159                         if (newval > oldval) *psub |= CF;\r
160                         if ((val^oldval) & (oldval^newval) & 0x80) *psub |= VF;\r
161                         psub++;\r
162 \r
163                         /* sbc with carry set */\r
164                         val = oldval - newval - 1;\r
165                         *psbc = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);\r
166                         *psbc |= (newval & (YF | XF));  /* undocumented flag bits 5+3 */\r
167                         if ((newval & 0x0f) >= (oldval & 0x0f)) *psbc |= HF;\r
168                         if (newval >= oldval) *psbc |= CF;\r
169                         if ((val ^ oldval) & (oldval^newval) & 0x80) *psbc |= VF;\r
170                         psbc++;\r
171                 }\r
172         }\r
173 #endif\r
174 \r
175         CPU->pzR8[0] = &zB;\r
176         CPU->pzR8[1] = &zC;\r
177         CPU->pzR8[2] = &zD;\r
178         CPU->pzR8[3] = &zE;\r
179         CPU->pzR8[4] = &zH;\r
180         CPU->pzR8[5] = &zL;\r
181         CPU->pzR8[6] = &zF;     // \8f\88\97\9d\82Ì\93s\8d\87\8fã\81AA\82Æ\93ü\82ê\91Ö\82¦\r
182         CPU->pzR8[7] = &zA;     // \8f\88\97\9d\82Ì\93s\8d\87\8fã\81AF\82Æ\93ü\82ê\91Ö\82¦\r
183 \r
184         CPU->pzR16[0] = pzBC;\r
185         CPU->pzR16[1] = pzDE;\r
186         CPU->pzR16[2] = pzHL;\r
187         CPU->pzR16[3] = pzAF;\r
188 \r
189         zIX = zIY = 0xffff;\r
190         zF = ZF;\r
191 \r
192         CPU->Interrupt_Callback = Cz80_Interrupt_Callback;\r
193 }\r
194 \r
195 \r
196 /*--------------------------------------------------------\r
197         CPU\83\8a\83Z\83b\83g\r
198 --------------------------------------------------------*/\r
199 \r
200 void Cz80_Reset(cz80_struc *CPU)\r
201 {\r
202         memset(CPU, 0, (INT32)&CPU->BasePC - (INT32)CPU);\r
203         Cz80_Set_Reg(CPU, CZ80_PC, 0);\r
204 }\r
205 \r
206 \r
207 /*--------------------------------------------------------\r
208         CPU\8eÀ\8ds\r
209 --------------------------------------------------------*/\r
210 \r
211 INT32 Cz80_Exec(cz80_struc *CPU, INT32 cycles)\r
212 {\r
213 #if CZ80_USE_JUMPTABLE\r
214 #include "cz80jmp.c"\r
215 #endif\r
216 \r
217         UINT32 PC;\r
218 #if CZ80_ENCRYPTED_ROM\r
219         INT32 OPBase;\r
220 #endif\r
221         UINT32 Opcode;\r
222         UINT32 adr = 0;\r
223         UINT32 res;\r
224         UINT32 val;\r
225         int afterEI = 0;\r
226 \r
227         PC = CPU->PC;\r
228 #if CZ80_ENCRYPTED_ROM\r
229         OPBase = CPU->OPBase;\r
230 #endif\r
231         CPU->ICount = cycles - CPU->ExtraCycles;\r
232         CPU->ExtraCycles = 0;\r
233 \r
234         if (!CPU->HaltState)\r
235         {\r
236 Cz80_Exec:\r
237                 if (CPU->ICount > 0)\r
238                 {\r
239                         union16 *data = pzHL;\r
240                         Opcode = READ_OP();\r
241 #if CZ80_EMULATE_R_EXACTLY\r
242                         zR++;\r
243 #endif\r
244                         #include "cz80_op.c"\r
245                 }\r
246 \r
247                 if (afterEI)\r
248                 {\r
249                         afterEI = 0;\r
250 Cz80_Check_Interrupt:\r
251                         if (CPU->IRQState != CLEAR_LINE)\r
252                         {\r
253                                 CHECK_INT\r
254                         }\r
255                         goto Cz80_Exec;\r
256                 }\r
257         }\r
258         else CPU->ICount = 0;\r
259 \r
260 Cz80_Exec_End:\r
261         CPU->PC = PC;\r
262 #if CZ80_ENCRYPTED_ROM\r
263         CPU->OPBase = OPBase;\r
264 #endif\r
265         cycles -= CPU->ICount;\r
266 #if !CZ80_EMULATE_R_EXACTLY\r
267         zR = (zR + (cycles >> 2)) & 0x7f;\r
268 #endif\r
269 \r
270         return cycles;\r
271 }\r
272 \r
273 \r
274 /*--------------------------------------------------------\r
275         \8a\84\82è\8d\9e\82Ý\8f\88\97\9d\r
276 --------------------------------------------------------*/\r
277 \r
278 void Cz80_Set_IRQ(cz80_struc *CPU, INT32 line, INT32 state)\r
279 {\r
280         if (line == IRQ_LINE_NMI)\r
281         {\r
282                 zIFF1 = 0;\r
283                 CPU->ExtraCycles += 11;\r
284                 CPU->HaltState = 0;\r
285                 PUSH_16(CPU->PC - CPU->BasePC)\r
286                 Cz80_Set_Reg(CPU, CZ80_PC, 0x66);\r
287         }\r
288         else\r
289         {\r
290                 CPU->IRQState = state;\r
291 \r
292                 if (state != CLEAR_LINE)\r
293                 {\r
294                         UINT32 PC = CPU->PC;\r
295 #if CZ80_ENCRYPTED_ROM\r
296                         INT32 OPBase = CPU->OPBase;\r
297 #endif\r
298 \r
299                         CPU->IRQLine = line;\r
300                         CHECK_INT\r
301                         CPU->PC = PC;\r
302 #if CZ80_ENCRYPTED_ROM\r
303                         CPU->OPBase = OPBase;\r
304 #endif\r
305                 }\r
306         }\r
307 }\r
308 \r
309 \r
310 /*--------------------------------------------------------\r
311         \83\8c\83W\83X\83^\8eæ\93¾\r
312 --------------------------------------------------------*/\r
313 \r
314 UINT32 Cz80_Get_Reg(cz80_struc *CPU, INT32 regnum)\r
315 {\r
316         switch (regnum)\r
317         {\r
318         case CZ80_PC:   return (CPU->PC - CPU->BasePC);\r
319         case CZ80_SP:   return zSP;\r
320         case CZ80_AF:   return zAF;\r
321         case CZ80_BC:   return zBC;\r
322         case CZ80_DE:   return zDE;\r
323         case CZ80_HL:   return zHL;\r
324         case CZ80_IX:   return zIX;\r
325         case CZ80_IY:   return zIY;\r
326         case CZ80_AF2:  return zAF2;\r
327         case CZ80_BC2:  return zBC2;\r
328         case CZ80_DE2:  return zDE2;\r
329         case CZ80_HL2:  return zHL2;\r
330         case CZ80_R:    return zR;\r
331         case CZ80_I:    return zI;\r
332         case CZ80_IM:   return zIM;\r
333         case CZ80_IFF1: return zIFF1;\r
334         case CZ80_IFF2: return zIFF2;\r
335         case CZ80_HALT: return CPU->HaltState;\r
336         case CZ80_IRQ:  return CPU->IRQState;\r
337         default: return 0;\r
338         }\r
339 }\r
340 \r
341 \r
342 /*--------------------------------------------------------\r
343         \83\8c\83W\83X\83^\90Ý\92è\r
344 --------------------------------------------------------*/\r
345 \r
346 void Cz80_Set_Reg(cz80_struc *CPU, INT32 regnum, UINT32 val)\r
347 {\r
348         switch (regnum)\r
349         {\r
350         case CZ80_PC:\r
351                 CPU->BasePC = CPU->Fetch[val >> CZ80_FETCH_SFT];\r
352 #if CZ80_ENCRYPTED_ROM\r
353                 CPU->OPBase = CPU->OPFetch[val >> CZ80_FETCH_SFT];\r
354 #endif\r
355                 CPU->PC = val + CPU->BasePC;\r
356                 break;\r
357 \r
358         case CZ80_SP:   zSP = val; break;\r
359         case CZ80_AF:   zAF = val; break;\r
360         case CZ80_BC:   zBC = val; break;\r
361         case CZ80_DE:   zDE = val; break;\r
362         case CZ80_HL:   zHL = val; break;\r
363         case CZ80_IX:   zIX = val; break;\r
364         case CZ80_IY:   zIY = val; break;\r
365         case CZ80_AF2:  zAF2 = val; break;\r
366         case CZ80_BC2:  zBC2 = val; break;\r
367         case CZ80_DE2:  zDE2 = val; break;\r
368         case CZ80_HL2:  zHL2 = val; break;\r
369         case CZ80_R:    zR = val; break;\r
370         case CZ80_I:    zI = val; break;\r
371         case CZ80_IM:   zIM = val; break;\r
372         case CZ80_IFF1: zIFF1 = val; break;\r
373         case CZ80_IFF2: zIFF2 = val; break;\r
374         case CZ80_HALT: CPU->HaltState = val; break;\r
375         case CZ80_IRQ:  CPU->IRQState = val; break;\r
376         default: break;\r
377         }\r
378 }\r
379 \r
380 \r
381 /*--------------------------------------------------------\r
382         \83t\83F\83b\83`\83A\83h\83\8c\83X\90Ý\92è\r
383 --------------------------------------------------------*/\r
384 \r
385 void Cz80_Set_Fetch(cz80_struc *CPU, UINT32 low_adr, UINT32 high_adr, UINT32 fetch_adr)\r
386 {\r
387         int i, j;\r
388 \r
389         i = low_adr >> CZ80_FETCH_SFT;\r
390         j = high_adr >> CZ80_FETCH_SFT;\r
391         fetch_adr -= i << CZ80_FETCH_SFT;\r
392 \r
393         while (i <= j)\r
394         {\r
395                 CPU->Fetch[i] = fetch_adr;\r
396 #if CZ80_ENCRYPTED_ROM\r
397                 CPU->OPFetch[i] = 0;\r
398 #endif\r
399                 i++;\r
400         }\r
401 }\r
402 \r
403 \r
404 /*--------------------------------------------------------\r
405         \83t\83F\83b\83`\83A\83h\83\8c\83X\90Ý\92è (\88Ã\8d\86\89»ROM\91Î\89\9e)\r
406 --------------------------------------------------------*/\r
407 \r
408 #if CZ80_ENCRYPTED_ROM\r
409 void Cz80_Set_Encrypt_Range(cz80_struc *CPU, UINT32 low_adr, UINT32 high_adr, UINT32 decrypted_rom)\r
410 {\r
411         int i, j;\r
412 \r
413         i = low_adr >> CZ80_FETCH_SFT;\r
414         j = high_adr >> CZ80_FETCH_SFT;\r
415         decrypted_rom -= i << CZ80_FETCH_SFT;\r
416 \r
417         while (i <= j)\r
418         {\r
419                 CPU->OPFetch[i] = (INT32)decrypted_rom - (INT32)CPU->Fetch[i];\r
420                 i++;\r
421         }\r
422 }\r
423 #endif\r
424 \r
425 \r
426 /*--------------------------------------------------------\r
427         \83\81\83\82\83\8a\83\8a\81[\83h/\83\89\83C\83g\8aÖ\90\94\90Ý\92è\r
428 --------------------------------------------------------*/\r
429 \r
430 void Cz80_Set_ReadB(cz80_struc *CPU, UINT8 (*Func)(UINT32 address))\r
431 {\r
432         CPU->Read_Byte = Func;\r
433 }\r
434 \r
435 void Cz80_Set_WriteB(cz80_struc *CPU, void (*Func)(UINT32 address, UINT8 data))\r
436 {\r
437         CPU->Write_Byte = Func;\r
438 }\r
439 \r
440 \r
441 /*--------------------------------------------------------\r
442         \83|\81[\83g\83\8a\81[\83h/\83\89\83C\83g\8aÖ\90\94\90Ý\92è\r
443 --------------------------------------------------------*/\r
444 \r
445 void Cz80_Set_INPort(cz80_struc *CPU, UINT8 (*Func)(UINT16 port))\r
446 {\r
447         CPU->IN_Port = Func;\r
448 }\r
449 \r
450 void Cz80_Set_OUTPort(cz80_struc *CPU, void (*Func)(UINT16 port, UINT8 value))\r
451 {\r
452         CPU->OUT_Port = Func;\r
453 }\r
454 \r
455 \r
456 /*--------------------------------------------------------\r
457         \83R\81[\83\8b\83o\83b\83N\8aÖ\90\94\90Ý\92è\r
458 --------------------------------------------------------*/\r
459 \r
460 void Cz80_Set_IRQ_Callback(cz80_struc *CPU, INT32 (*Func)(INT32 irqline))\r
461 {\r
462         CPU->Interrupt_Callback = Func;\r
463 }\r