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