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