1 /* Mednafen - Multi-system Emulator
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include "pce.h"
19 #include "vdc.h"
20
21 static uint8 dummy_bank[8192 + 8192]; // + 8192 for PC-as-ptr safety padding
22 HuC6280 HuCPU;
23
24 #define HU_PC PC_local //HuCPU.PC
25 #define HU_PC_base HuCPU.PC_base
26 #define HU_A HuCPU.A
27 #define HU_X X_local //HuCPU.X
28 #define HU_Y Y_local //HuCPU.Y
29 #define HU_S HuCPU.S
30 #define HU_P P_local //HuCPU.P
31 #define HU_PI HuCPU.mooPI
32 #define HU_IRQlow HuCPU.IRQlow
33 #define HU_Page1 Page1_local
34 //HuCPU.Page1
35 //Page1_local //HuCPU.Page1
36
37 #ifdef HUC6280_LAZY_FLAGS
38 #define HU_ZNFlags HuCPU.ZNFlags
39 #endif
40
41
42 #ifdef HUC6280_CRAZY_VERSION
43 #define LOAD_LOCALS_PC() uintptr_t PC_local = HuCPU.PC;
44 #else
45 #define LOAD_LOCALS_PC() uint32 PC_local /*asm ("edi")*/ = HuCPU.PC; // asm ("edi") = HuCPU.PC;
46 #endif
47
48 #define LOAD_LOCALS() \
49 LOAD_LOCALS_PC(); \
50 uint8 X_local = HuCPU.X; \
51 uint8 Y_local = HuCPU.Y; \
52 uint8 P_local = HuCPU.P; \
53 uint8 *Page1_local = HuCPU.Page1;
54
55 #define SAVE_LOCALS() HuCPU.PC = PC_local; \
56 HuCPU.X = X_local; \
57 HuCPU.Y = Y_local; \
58 HuCPU.P = P_local; \
59 HuCPU.Page1 = Page1_local;
60
61 #ifdef HUC6280_LAZY_FLAGS
62 #define COMPRESS_FLAGS() HU_P &= ~(N_FLAG | Z_FLAG); HU_P |= ((HU_ZNFlags >> 24) & 0x80) | ((HU_ZNFlags & 0xFF) ? 0 : Z_FLAG);
63 //((((HU_ZNFlags & 0xFF) - 1) >> 8) & Z_FLAG);
64 #define EXPAND_FLAGS() HU_ZNFlags = (HU_P << 24) | ((HU_P & Z_FLAG) ^ Z_FLAG);
65 #else
66 #define COMPRESS_FLAGS()
67 #define EXPAND_FLAGS()
68 #endif
69
70 #ifdef HUC6280_CRAZY_VERSION
71 #define GetRealPC() ((unsigned int)(HU_PC - HU_PC_base))
72 #define GetRealPC_EXTERNAL() ((unsigned int)(HuCPU.PC - HuCPU.PC_base))
73 #else
74 #define GetRealPC() (HU_PC)
75 #define GetRealPC_EXTERNAL() (HuCPU.PC)
76 #endif
77
78 #ifdef HUC6280_CRAZY_VERSION
79 #define SetPC(value) { unsigned int tempmoo = value; HU_PC = HuCPU.FastPageR[tempmoo >> 13] + tempmoo; \
80 HU_PC_base = HU_PC - tempmoo; }
81 #define SetPC_EXTERNAL(value) { unsigned int tempmoo = value; \
82 HuCPU.PC = HuCPU.FastPageR[tempmoo >> 13] + tempmoo; HuCPU.PC_base = HuCPU.PC - tempmoo; }
83 #else
84 #define SetPC(value) { HU_PC = (value); }
85 #define SetPC_EXTERNAL(value) { HuCPU.PC = (value); }
86 #endif
87
88 // Page change PC, GET IT?!
89 #ifdef HUC6280_CRAZY_VERSION
90 #define FixPC_PC() SetPC(GetRealPC());
91 #else
92 #define FixPC_PC()
93 #endif
94
95 //#define IncPC() { HU_PC++; if(!(GetRealPC() & 0x1FFF)) printf("Bank crossing: %04x\n", GetRealPC()); }
96 //#define IncPC() HU_PC++;
97 #if 0
98 #define IncPC() { HU_PC++; if(!(GetRealPC() & 0x1FFF) && \
99 HuCPU.MPR[(GetRealPC() - 1) >> 13] != (HuCPU.MPR[(GetRealPC()) >> 13] - 1)) \
100 printf("Bank crossing: %04x, %02x, %02x\n", GetRealPC(), HuCPU.MPR[(GetRealPC() - 1) >> 13], \
101 HuCPU.MPR[GetRealPC() >> 13]); }
102 #else
103 #define IncPC() HU_PC++;
104 #endif
105
106 #ifdef HUC6280_CRAZY_VERSION
107 #define RdAtPC() (*(uint8*)HU_PC)
108 #else
109 #define RdAtPC() RdOp(HU_PC)
110 #endif
111
112 // If we change this definition, we'll need to also fix HuC6280_StealCycle() in huc6280.h
113 #define ADDCYC(x) { HuCPU.timestamp += x; }
114
115 #define SET_MPR(arg_i, arg_v) \
116 { \
117 const unsigned int wmpr = arg_i, wbank = arg_v; \
118 if(wmpr == 1) \
119 { \
120 HU_Page1 = HuCPU.FastMap[wbank]; \
121 } \
122 HuCPU.MPR[wmpr] = wbank; \
123 HuCPU.FastPageR[wmpr] = (uintptr_t)HuCPU.FastMap[wbank] - wmpr * 8192; \
124 }
125
HuC6280_SetMPR(int i,int v)126 void HuC6280_SetMPR(int i, int v)
127 {
128 uint8 *Page1_local = HuCPU.Page1;
129
130 SET_MPR(i, v);
131
132 HuCPU.Page1 = Page1_local;
133 }
134
135
HuC6280_FlushMPRCache(void)136 static void HuC6280_FlushMPRCache(void)
137 {
138 for(int x = 0; x < 9; x++)
139 HuC6280_SetMPR(x, HuCPU.MPR[x & 0x7]);
140 }
141
RdMem(unsigned int A)142 static INLINE uint8 RdMem(unsigned int A)
143 {
144 uint8 wmpr = HuCPU.MPR[A >> 13];
145 return(HuCPU.PCERead[wmpr]((wmpr << 13) | (A & 0x1FFF)));
146 }
147
RdMem16(unsigned int A)148 static INLINE uint16 RdMem16(unsigned int A)
149 {
150 uint16 ret;
151
152 ret = RdMem(A);
153 ret |= RdMem(A + 1) << 8;
154
155 return(ret);
156 }
157
WrMem(unsigned int A,uint8 V)158 static INLINE void WrMem(unsigned int A, uint8 V)
159 {
160 uint8 wmpr = HuCPU.MPR[A >> 13];
161 HuCPU.PCEWrite[wmpr]((wmpr << 13) | (A & 0x1FFF), V);
162 }
163
RdOp(unsigned int A)164 static INLINE uint8 RdOp(unsigned int A)
165 {
166 return *(uint8*)(HuCPU.FastPageR[A >> 13] + A);
167 }
168
169 #define PUSH(V) \
170 { \
171 HU_Page1[0x100 + HU_S] = V; \
172 HU_S--; \
173 }
174
175 #define PUSH_PC() \
176 { \
177 unsigned int real_pc = GetRealPC(); \
178 PUSH(real_pc >> 8); \
179 PUSH(real_pc); \
180 }
181
182 #define POP() HU_Page1[0x100 + ++HU_S]
183
184 #define POP_PC() \
185 { \
186 unsigned int npc; \
187 npc = POP(); \
188 npc |= POP() << 8; \
189 SetPC(npc); \
190 }
191
192 // Hopefully we never RTS to 0x0000. ;)
193 #define POP_PC_AP() \
194 { \
195 uint32 npc; \
196 npc = POP(); \
197 npc |= POP() << 8; \
198 npc++; \
199 SetPC(npc); \
200 }
201
202 /* Some of these operations will only make sense if you know what the flag
203 constants are. */
204
205 #ifdef HUC6280_LAZY_FLAGS
206 #define X_ZN(zort) { HU_ZNFlags = (int32)(int8)(uint8)(zort); }
207 #define X_ZN_BIT(opres, argie) { HU_ZNFlags = (opres) | ((argie) << 24); }
208 #else
209 static uint8 ZNTable[256];
210 #define X_ZN(zort) HU_P&=~(Z_FLAG|N_FLAG);HU_P|=ZNTable[zort]
211 #define X_ZN_BIT(opres, argie) { HU_P &= ~(Z_FLAG | N_FLAG); HU_P |= ZNTable[opres] & Z_FLAG; HU_P |= argie & N_FLAG; }
212 #endif
213
214 #define JR(cond) \
215 { \
216 if(cond) \
217 { \
218 int32 disp; \
219 disp = 1 + (int8)RdAtPC(); \
220 ADDCYC(2); \
221 HU_PC+=disp; \
222 } \
223 else IncPC(); \
224 }
225
226 #define BRA \
227 { \
228 int32 disp; \
229 disp = 1 + (int8)RdAtPC(); \
230 HU_PC+=disp; \
231 }
232
233 #define BBRi(bitto) JR(!(x & (1 << bitto)))
234 #define BBSi(bitto) JR(x & (1 << bitto))
235
236 #define ST0 VDC_Write_ST(0, x)
237 #define ST1 VDC_Write_ST(2, x)
238 #define ST2 VDC_Write_ST(3, x)
239
240 #define LDA HU_A=x;X_ZN(HU_A)
241 #define LDX HU_X=x;X_ZN(HU_X)
242 #define LDY HU_Y=x;X_ZN(HU_Y)
243
244 /* All of the freaky arithmetic operations. */
245 #define AND HU_A&=x;X_ZN(HU_A);
246
247 #define BIT HU_P&=~V_FLAG; X_ZN_BIT(x & HU_A, x); HU_P |= x & V_FLAG;
248 #define EOR HU_A^=x;X_ZN(HU_A);
249 #define ORA HU_A|=x;X_ZN(HU_A);
250
251 #define ADC { \
252 if(HU_P & D_FLAG) \
253 { \
254 uint32 tmp; \
255 tmp = (HU_A & 0x0F) + (x & 0x0F) + (HU_P & 1); \
256 if(tmp >= 0x0A) \
257 tmp += 0x06; \
258 tmp += (HU_A & 0xF0) + (x & 0xF0); \
259 if(tmp >= 0xA0) \
260 tmp += 0x60; \
261 HU_P &= ~C_FLAG; \
262 if(tmp & 0xFF00) \
263 HU_P |= C_FLAG; \
264 HU_A = tmp; \
265 X_ZN(HU_A); \
266 } \
267 else \
268 { \
269 uint32 l=HU_A+x+(HU_P&1); \
270 HU_P&=~(C_FLAG|V_FLAG); \
271 HU_P|=((((HU_A^x)&0x80)^0x80) & ((HU_A^l)&0x80))>>1; \
272 HU_P|=(l>>8)&C_FLAG; \
273 HU_A=l; \
274 X_ZN(HU_A); \
275 } \
276 }
277
278 #define SBC if(HU_P & D_FLAG) \
279 { \
280 const uint8 m = (HU_A & 0xF) - (x & 0xF) - ((HU_P & 1) ^ 1); \
281 const uint8 n = (HU_A >> 4) - (x >> 4) - ((m >> 4) & 1); \
282 uint8 res = (n << 4) | (m & 0xF); \
283 if(m & 0x10) \
284 res -= 0x06; \
285 if(n & 0x10) \
286 res -= 0x60; \
287 HU_A = res; \
288 HU_P &= ~C_FLAG; \
289 HU_P |= ((n >> 4) & 0x1) ^ 1; \
290 X_ZN(HU_A); \
291 } else { \
292 uint32 l=HU_A-x-((HU_P&1)^1); \
293 HU_P&=~(C_FLAG|V_FLAG); \
294 HU_P|=((HU_A^l)&(HU_A^x)&0x80)>>1; \
295 HU_P|=((l>>8)&C_FLAG)^C_FLAG; \
296 HU_A=l; \
297 X_ZN(HU_A); \
298 }
299
300 #define CMPL(a1,a2) { \
301 uint32 t=a1-a2; \
302 X_ZN(t&0xFF); \
303 HU_P&=~C_FLAG; \
304 HU_P|=((t>>8)&C_FLAG)^C_FLAG; \
305 }
306
307 #define TAM for(int i = 0; i < 8; i ++) { \
308 if(x & (1 << i)) \
309 { \
310 SET_MPR(i, HU_A); \
311 } \
312 } SET_MPR(8, HuCPU.MPR[0]);
313
314 #define TMA for(int i = 0; i < 8; i ++) { \
315 if(x & (1 << i)) \
316 HU_A = HuCPU.MPR[i]; \
317 }
318
319 #define CSL
320 #define CSH
321
322 #define RMB(bitto) x &= ~(1 << (bitto & 7))
323 #define SMB(bitto) x |= 1 << (bitto & 7)
324
325 #define TSB { HU_P &= ~V_FLAG; X_ZN_BIT(x | HU_A, x); HU_P |= x & V_FLAG; x |= HU_A; }
326 #define TRB { HU_P &= ~V_FLAG; X_ZN_BIT(x & ~HU_A, x); HU_P |= x & V_FLAG; x &= ~HU_A; }
327 #define TST { HU_P &= ~V_FLAG; X_ZN_BIT(x & zoomhack, x); HU_P |= x & V_FLAG; }
328
329 #define CMP CMPL(HU_A,x)
330 #define CPX CMPL(HU_X,x)
331 #define CPY CMPL(HU_Y,x)
332
333 /* The following operations modify the byte being worked on. */
334 #define DEC x--;X_ZN(x)
335 #define INC x++;X_ZN(x)
336
337 #define ASL HU_P&=~C_FLAG;HU_P|=x>>7;x<<=1;X_ZN(x)
338 #define LSR HU_P&=~C_FLAG;HU_P|=x&1;x>>=1;X_ZN(x)
339
340 #define ROL { \
341 uint8 l=x>>7; \
342 x<<=1; \
343 x|=HU_P&C_FLAG; \
344 HU_P&=~C_FLAG; \
345 HU_P|=l; \
346 X_ZN(x); \
347 }
348 #define ROR { \
349 uint8 l=x&1; \
350 x>>=1; \
351 x|=(HU_P&C_FLAG)<<7; \
352 HU_P&=~C_FLAG; \
353 HU_P|=l; \
354 X_ZN(x); \
355 }
356
357 /* Absolute */
358 #define GetAB(target) \
359 { \
360 target=RdAtPC(); \
361 IncPC(); \
362 target|=RdAtPC()<<8; \
363 IncPC(); \
364 }
365
366 /* Absolute Indexed(for reads) */
367 #define GetABI(target, i) \
368 { \
369 unsigned int tmp; \
370 GetAB(tmp); \
371 target=tmp; \
372 target+=i; \
373 }
374
375 /* Zero Page */
376 #define GetZP(target) \
377 { \
378 target=RdAtPC(); \
379 IncPC(); \
380 }
381
382 /* Zero Page Indexed */
383 #define GetZPI(target,i) \
384 { \
385 target=i+RdAtPC(); \
386 IncPC(); \
387 }
388
389 /* Indirect */
390 #define GetIND(target) \
391 { \
392 uint8 tmp; \
393 tmp=RdAtPC(); \
394 IncPC(); \
395 target=HU_Page1[tmp]; \
396 tmp++; \
397 target|=HU_Page1[tmp]<<8; \
398 }
399
400
401 /* Indexed Indirect */
402 #define GetIX(target) \
403 { \
404 uint8 tmp; \
405 tmp=RdAtPC(); \
406 IncPC(); \
407 tmp+=HU_X; \
408 target=HU_Page1[tmp]; \
409 tmp++; \
410 target|=HU_Page1[tmp] <<8; \
411 }
412
413 /* Indirect Indexed(for reads) */
414 #define GetIY(target) \
415 { \
416 unsigned int rt; \
417 uint8 tmp; \
418 tmp=RdAtPC(); \
419 rt=HU_Page1[tmp]; \
420 tmp++; \
421 rt|=HU_Page1[tmp]<<8; \
422 target = (rt + HU_Y); \
423 IncPC(); \
424 }
425
426 /* Now come the macros to wrap up all of the above stuff addressing mode functions
427 and operation macros. Note that operation macros will always operate(redundant
428 redundant) on the variable "x".
429 */
430
431 #define RMW_A(op) {uint8 x=HU_A; op; HU_A=x; break; } /* Meh... */
432 #define RMW_AB(op) {unsigned int EA; uint8 x; GetAB(EA); x=RdMem(EA); op; WrMem(EA,x); break; }
433 #define RMW_ABI(reg,op) {unsigned int EA; uint8 x; GetABI(EA,reg); x=RdMem(EA); op; WrMem(EA,x); break; }
434 #define RMW_ABX(op) RMW_ABI(HU_X,op)
435 #define RMW_ABY(op) RMW_ABI(HU_Y,op)
436 #define RMW_IND(op) { unsigned int EA; uint8 x; GetIND(EA); x = RdMem(EA); op; WrMem(EA, x); break; }
437 #define RMW_IX(op) { unsigned int EA; uint8 x; GetIX(EA); x=RdMem(EA); op; WrMem(EA,x); break; }
438 #define RMW_IY(op) { unsigned int EA; uint8 x; GetIY(EA); x=RdMem(EA); op; WrMem(EA,x); break; }
439 #define RMW_ZP(op) { uint8 EA; uint8 x; GetZP(EA); x=HU_Page1[EA]; op; HU_Page1[EA] = x; break; }
440 #define RMW_ZPX(op) { uint8 EA; uint8 x; GetZPI(EA,HU_X); x=HU_Page1[EA]; op; HU_Page1[EA] = x; break;}
441
442 #define LD_IM(op) { uint8 x; x=RdAtPC(); IncPC(); op; break; }
443 #define LD_ZP(op) { uint8 EA; uint8 x; GetZP(EA); x=HU_Page1[EA]; op; break; }
444 #define LD_ZPX(op) { uint8 EA; uint8 x; GetZPI(EA,HU_X); x=HU_Page1[EA]; op; break; }
445 #define LD_ZPY(op) { uint8 EA; uint8 x; GetZPI(EA,HU_Y); x=HU_Page1[EA]; op; break; }
446 #define LD_AB(op) { unsigned int EA; uint8 x; GetAB(EA); x=RdMem(EA); op; break; }
447 #define LD_ABI(reg,op) { unsigned int EA; uint8 x; GetABI(EA,reg); x=RdMem(EA); op; break; }
448 #define LD_ABX(op) LD_ABI(HU_X,op)
449 #define LD_ABY(op) LD_ABI(HU_Y,op)
450
451 #define LD_IND(op) { unsigned int EA; uint8 x; GetIND(EA); x=RdMem(EA); op; break; }
452 #define LD_IX(op) { unsigned int EA; uint8 x; GetIX(EA); x=RdMem(EA); op; break; }
453 #define LD_IY(op) { unsigned int EA; uint8 x; GetIY(EA); x=RdMem(EA); op; break; }
454
455 #define BMT_PREHONK(pork) HuCPU.in_block_move = IBM_##pork;
456 #define BMT_HONKHONK(pork) if(HuCPU.timestamp >= next_user_event) goto GetOutBMT; continue_the_##pork:
457
458 #define BMT_TDD BMT_PREHONK(TDD); do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src--; HuCPU.bmt_dest--; BMT_HONKHONK(TDD); HuCPU.bmt_length--; } while(HuCPU.bmt_length);
459 #define BMT_TAI BMT_PREHONK(TAI); {HuCPU.bmt_alternate = 0; do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src + HuCPU.bmt_alternate)); HuCPU.bmt_dest++; HuCPU.bmt_alternate ^= 1; BMT_HONKHONK(TAI); HuCPU.bmt_length--; } while(HuCPU.bmt_length); }
460 #define BMT_TIA BMT_PREHONK(TIA); {HuCPU.bmt_alternate = 0; do { ADDCYC(6); WrMem(HuCPU.bmt_dest + HuCPU.bmt_alternate, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src++; HuCPU.bmt_alternate ^= 1; BMT_HONKHONK(TIA); HuCPU.bmt_length--; } while(HuCPU.bmt_length); }
461 #define BMT_TII BMT_PREHONK(TII); do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src++; HuCPU.bmt_dest++; BMT_HONKHONK(TII); HuCPU.bmt_length--; } while(HuCPU.bmt_length);
462 #define BMT_TIN BMT_PREHONK(TIN); do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src++; BMT_HONKHONK(TIN); HuCPU.bmt_length--; } while(HuCPU.bmt_length);
463
464 // Block memory transfer load
465 #define LD_BMT(op) { PUSH(HU_Y); PUSH(HU_A); PUSH(HU_X); GetAB(HuCPU.bmt_src); GetAB(HuCPU.bmt_dest); GetAB(HuCPU.bmt_length); op; HuCPU.in_block_move = 0; HU_X = POP(); HU_A = POP(); HU_Y = POP(); break; }
466
467 #define ST_ZP(r) {uint8 EA; GetZP(EA); HU_Page1[EA] = r; break;}
468 #define ST_ZPX(r) {uint8 EA; GetZPI(EA,HU_X); HU_Page1[EA] = r; break;}
469 #define ST_ZPY(r) {uint8 EA; GetZPI(EA,HU_Y); HU_Page1[EA] = r; break;}
470 #define ST_AB(r) {unsigned int EA; GetAB(EA); WrMem(EA, r); break;}
471 #define ST_ABI(reg,r) {unsigned int EA; GetABI(EA,reg); WrMem(EA,r); break; }
472 #define ST_ABX(r) ST_ABI(HU_X,r)
473 #define ST_ABY(r) ST_ABI(HU_Y,r)
474
475 #define ST_IND(r) {unsigned int EA; GetIND(EA); WrMem(EA,r); break; }
476 #define ST_IX(r) {unsigned int EA; GetIX(EA); WrMem(EA,r); break; }
477 #define ST_IY(r) {unsigned int EA; GetIY(EA); WrMem(EA,r); break; }
478
479 static const uint8 CycTable[256] =
480 {
481 /*0x00*/ 8, 7, 3, 4, 6, 4, 6, 7, 3, 2, 2, 2, 7, 5, 7, 6,
482 /*0x10*/ 2, 7, 7, 4, 6, 4, 6, 7, 2, 5, 2, 2, 7, 5, 7, 6,
483 /*0x20*/ 7, 7, 3, 4, 4, 4, 6, 7, 4, 2, 2, 2, 5, 5, 7, 6,
484 /*0x30*/ 2, 7, 7, 2, 4, 4, 6, 7, 2, 5, 2, 2, 5, 5, 7, 6,
485 /*0x40*/ 7, 7, 3, 4, 8, 4, 6, 7, 3, 2, 2, 2, 4, 5, 7, 6,
486 /*0x50*/ 2, 7, 7, 5, 3, 4, 6, 7, 2, 5, 3, 2, 2, 5, 7, 6,
487 /*0x60*/ 7, 7, 2, 2, 4, 4, 6, 7, 4, 2, 2, 2, 7, 5, 7, 6,
488 /*0x70*/ 2, 7, 7, 17, 4, 4, 6, 7, 2, 5, 4, 2, 7, 5, 7, 6,
489
490 /*0x80*/ 4, 7, 2, 7, 4, 4, 4, 7, 2, 2, 2, 2, 5, 5, 5, 6,
491 /*0x90*/ 2, 7, 7, 8, 4, 4, 4, 7, 2, 5, 2, 2, 5, 5, 5, 6,
492 /*0xA0*/ 2, 7, 2, 7, 4, 4, 4, 7, 2, 2, 2, 2, 5, 5, 5, 6,
493 /*0xB0*/ 2, 7, 7, 8, 4, 4, 4, 7, 2, 5, 2, 2, 5, 5, 5, 6,
494 /*0xC0*/ 2, 7, 2, 17, 4, 4, 6, 7, 2, 2, 2, 2, 5, 5, 7, 6,
495 /*0xD0*/ 2, 7, 7, 17, 3, 4, 6, 7, 2, 5, 3, 2, 2, 5, 7, 6,
496 /*0xE0*/ 2, 7, 2, 17, 4, 4, 6, 7, 2, 2, 2, 2, 5, 5, 7, 6,
497 /*0xF0*/ 2, 7, 7, 17, 2, 4, 6, 7, 2, 5, 4, 2, 2, 5, 7, 6,
498 };
499 #if 0
500 static NO_INLINE bool WillIRQOccur(void)
501 {
502 bool ret = false;
503
504 if(HU_IRQlow)
505 {
506 if(!(HU_PI&I_FLAG))
507 {
508 if(HU_IRQlow & MDFN_IQTIMER & HuCPU.IRQMaskDelay)
509 ret = true;
510 else if((HU_IRQlow & MDFN_IQIRQ1 & HuCPU.IRQMaskDelay) || ((HU_IRQlow >> 8) & MDFN_IQIRQ1 & HuCPU.IRQMaskDelay))
511 ret = true;
512 else if(HU_IRQlow & MDFN_IQIRQ2 & HuCPU.IRQMaskDelay)
513 ret = true;
514 }
515 }
516
517 return(true);
518 }
519 #endif
520
HuC6280_Reset(void)521 void HuC6280_Reset(void)
522 {
523 HuCPU.timer_next_timestamp = HuCPU.timestamp + 1024;
524
525 HuCPU.timer_load = 0;
526 HuCPU.timer_value = 0;
527 HuCPU.timer_status = 0;
528 HuCPU.in_block_move = 0;
529
530 unsigned int npc;
531
532 HuCPU.IRQMask = HuCPU.IRQMaskDelay = 7;
533
534 HuC6280_SetMPR(0, 0xFF);
535 HuC6280_SetMPR(8, 0xFF);
536 HuC6280_SetMPR(1, 0xF8);
537
538 for(int i = 2; i < 8; i++)
539 HuC6280_SetMPR(i, 0);
540
541 npc = RdMem16(0xFFFE);
542
543 #define PC_local HuCPU.PC
544 SetPC(npc);
545 #undef PC_local
546
547 HuCPU.mooPI = I_FLAG;
548 HuCPU.P = I_FLAG;
549
550 HU_IRQlow = 0;
551 }
552
HuC6280_Init(void)553 void HuC6280_Init(void)
554 {
555 //printf("%zu\n", sizeof(HuC6280));
556 //printf("%d\n", (int)((uint8*)&HuCPU.previous_next_user_event - (uint8*)&HuCPU));
557 //printf("%d\n", (int)((uint8*)&HuCPU.IRQlow - (uint8*)&HuCPU));
558
559 memset(&HuCPU,0,sizeof(HuCPU));
560
561 #ifdef HUC6280_LAZY_FLAGS
562 #else
563 for(int x=0; x < 256; x++)
564 {
565 if(!x) ZNTable[x]=Z_FLAG;
566 else if (x&0x80) ZNTable[x]=N_FLAG;
567 else ZNTable[x]=0;
568 }
569 #endif
570
571 for (unsigned i = 0; i < 0x100; i++)
572 HuCPU.FastMap[i] = dummy_bank;
573 }
574
HuC6280_Power(void)575 void HuC6280_Power(void)
576 {
577 memset(dummy_bank, 0, sizeof(dummy_bank));
578
579 HuCPU.IRQlow = 0;
580
581 HuCPU.A = 0;
582 HuCPU.X = 0;
583 HuCPU.Y = 0;
584 HuCPU.S = 0;
585 HuCPU.P = 0;
586 HuCPU.mooPI = 0;
587
588 #if 0
589 HU_PC = HU_PC_base = NULL;
590 #else
591 HuCPU.PC = 0;
592 #endif
593
594 HuCPU.timestamp = 0;
595
596 for(int i = 0; i < 9; i++)
597 {
598 HuCPU.MPR[i] = 0;
599 HuCPU.FastPageR[i] = 0;
600 }
601 HuC6280_Reset();
602 }
603
HuC6280_Run(int32 cycles)604 void HuC6280_Run(int32 cycles)
605 {
606 const int32 next_user_event = HuCPU.previous_next_user_event + cycles * pce_overclocked;
607
608 HuCPU.previous_next_user_event = next_user_event;
609
610 LOAD_LOCALS();
611
612 if(HuCPU.timestamp >= next_user_event)
613 return;
614
615 int32 next_event;
616
617 if(HuCPU.in_block_move)
618 {
619 next_event = (next_user_event < HuCPU.timer_next_timestamp) ? next_user_event : HuCPU.timer_next_timestamp;
620
621 switch(HuCPU.in_block_move)
622 {
623 case IBM_TIA: goto continue_the_TIA;
624 case IBM_TAI: goto continue_the_TAI;
625 case IBM_TDD: goto continue_the_TDD;
626 case IBM_TII: goto continue_the_TII;
627 case IBM_TIN: goto continue_the_TIN;
628 }
629 }
630
631 while(MDFN_LIKELY(HuCPU.timestamp < next_user_event))
632 {
633 next_event = (next_user_event < HuCPU.timer_next_timestamp) ? next_user_event : HuCPU.timer_next_timestamp;
634
635 while(MDFN_LIKELY(HuCPU.timestamp < next_event))
636 {
637 uint8 b1;
638
639 if(HU_IRQlow)
640 {
641 if(!(HU_PI&I_FLAG))
642 {
643 uint32 tmpa = 0;
644
645 if(HU_IRQlow & MDFN_IQTIMER & HuCPU.IRQMaskDelay)
646 tmpa = 0xFFFA;
647 else if((HU_IRQlow & MDFN_IQIRQ1 & HuCPU.IRQMaskDelay) || ((HU_IRQlow >> 8) & MDFN_IQIRQ1 & HuCPU.IRQMaskDelay))
648 tmpa = 0xFFF8;
649 else if(HU_IRQlow & MDFN_IQIRQ2 & HuCPU.IRQMaskDelay)
650 tmpa = 0xFFF6;
651
652 if(tmpa)
653 {
654 unsigned int npc;
655
656 ADDCYC(8);
657 PUSH_PC();
658
659 COMPRESS_FLAGS();
660 PUSH((HU_P&~B_FLAG));
661 HU_P |= I_FLAG;
662 HU_P &= ~(T_FLAG | D_FLAG);
663 HU_PI = HU_P;
664
665 npc = RdMem16(tmpa);
666 SetPC(npc);
667
668 if(tmpa == 0xFFF8)
669 HU_IRQlow &= ~0x200;
670
671 continue;
672 }
673 }
674 } // end if(HU_IRQlow)
675
676 //printf("%04x\n", GetRealPC());
677 HU_PI = HU_P;
678 HuCPU.IRQMaskDelay = HuCPU.IRQMask;
679
680 b1 = RdAtPC();
681
682 ADDCYC(CycTable[b1]);
683
684 IncPC();
685
686 switch(b1)
687 {
688 #include "huc6280_ops.inc"
689 }
690
691 #ifndef HUC6280_EXTRA_CRAZY
692 FixPC_PC();
693 #endif
694 } // end while(HuCPU.timestamp < next_event)
695
696 while(HuCPU.timestamp >= HuCPU.timer_next_timestamp)
697 {
698 HuCPU.timer_next_timestamp += 1024 * pce_overclocked;
699
700 if(HuCPU.timer_status)
701 {
702 HuCPU.timer_value --;
703 if(HuCPU.timer_value < 0)
704 {
705 HuCPU.timer_value = HuCPU.timer_load;
706 HuC6280_IRQBegin(MDFN_IQTIMER);
707 }
708 }
709 }
710 } // end while(HuCPU.timestamp < next_user_event)
711
712 GetOutBMT:
713
714 SAVE_LOCALS();
715 }
716
HuC6280_ResetTS(void)717 void HuC6280_ResetTS(void)
718 {
719 HuCPU.timer_next_timestamp -= HuCPU.timestamp;
720 HuCPU.previous_next_user_event -= HuCPU.timestamp;
721 HuCPU.timestamp = 0;
722 }
723
HuC6280_StateAction(StateMem * sm,int load,int data_only)724 int HuC6280_StateAction(StateMem *sm, int load, int data_only)
725 {
726 uint16 tmp_PC = GetRealPC_EXTERNAL();
727
728 #define P_local HuCPU.P
729 COMPRESS_FLAGS();
730
731 SFORMAT SFCPU[]=
732 {
733 SFVARN(tmp_PC, "PC"),
734 SFVARN(HuCPU.A, "A"),
735 SFVARN(HuCPU.P, "P"),
736 SFVARN(HuCPU.X, "X"),
737 SFVARN(HuCPU.Y, "Y"),
738 SFVARN(HuCPU.S, "S"),
739 SFVARN(HuCPU.mooPI, "PI"),
740
741 SFVARN(HuCPU.IRQMask, "IRQMask"),
742 SFVARN(HuCPU.IRQMaskDelay, "IRQMaskDelay"),
743 SFARRAYN(HuCPU.MPR, 8, "MPR"),
744 SFVARN(HuCPU.timer_status, "timer_status"),
745 SFVARN(HuCPU.timer_value, "timer_value"),
746 SFVARN(HuCPU.timer_load, "timer_load"),
747
748
749 SFVARN(HuCPU.IRQlow, "IRQlow"),
750 SFVARN(HuCPU.in_block_move, "IBM"),
751 SFVARN(HuCPU.bmt_src, "IBM_SRC"),
752 SFVARN(HuCPU.bmt_dest, "IBM_DEST"),
753 SFVARN(HuCPU.bmt_length, "IBM_LENGTH"),
754 SFVARN(HuCPU.bmt_alternate, "IBM_ALTERNATE"),
755
756 SFVARN(HuCPU.timer_next_timestamp, "timer_next_timestamp"),
757 SFVARN(HuCPU.previous_next_user_event, "previous_next_user_event"),
758
759 SFEND
760 };
761
762 HuCPU.timer_next_timestamp -= HuCPU.timestamp;
763 HuCPU.previous_next_user_event -= HuCPU.timestamp;
764
765 int ret = MDFNSS_StateAction(sm, load, data_only, SFCPU, "CPU", false);
766
767 if(load)
768 {
769 if(HuCPU.previous_next_user_event > 455 * pce_overclocked)
770 HuCPU.previous_next_user_event = 455 * pce_overclocked;
771
772 // Update MPR cache
773 HuC6280_FlushMPRCache();
774
775 // This must be after the MPR cache is updated:
776 SetPC_EXTERNAL(tmp_PC);
777 }
778
779 HuCPU.timer_next_timestamp += HuCPU.timestamp;
780 HuCPU.previous_next_user_event += HuCPU.timestamp;
781
782 EXPAND_FLAGS();
783 #undef P_local
784
785 return(ret);
786 }
787