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