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