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