1 /* FCE Ultra - NES/Famicom Emulator
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Ben Parnell
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 extern uint32 PC_prev, OP_prev;
33 extern uint8 dreads[4];
34 extern uint32 dwrites_c[2];
35 extern int dread_count_c, dwrite_count_c;
36 extern int mapirq_cyc_c;
37 extern void (*MapIRQHook)(int a);
38 #define DummyRdMem(...)
40 #define DummyRdMem RdMem
41 void FP_FASTAPASS(1) (*MapIRQHook)(int a);
62 //#define _PZ X.PZ // unused?
64 #define _count X.count
65 #define _tcount X.tcount
66 #define _IRQlow X.IRQlow
67 #define _jammed X.jammed
70 static INLINE uint8 RdMem(unsigned int A)
75 //printf("a == %x, pc == %x\n", A, _PC);
77 if (A == _PC || A == _PC - 1 || A == _PC + 1) {
78 //printf("fr: %02x\n", _DB1);
82 if (A >= 0x2000 && A != _PC - 1) {
83 dreads[dread_count_c++] = _DB1;
84 if (dread_count_c > 4) { printf("dread_count out of range\n"); exit(1); }
92 static INLINE void WrMem(unsigned int A, uint8 V)
94 //printf("w [%04x] %02x\n", A, V);
95 if ((A&0xe000) == 0) { // RAM area (always 0-0x1fff)
100 #ifdef DEBUG_ASM_6502
101 dwrites_c[dwrite_count_c++] = (A<<8)|V;
102 if (dwrite_count_c > 2) { printf("dwrite_count_c out of range\n"); exit(1); }
106 static INLINE uint8 RdRAM(unsigned int A)
108 //return((_DB=RAM[A]));
110 #ifndef DEBUG_ASM_6502
116 static INLINE void WrRAM(unsigned int A, uint8 V)
121 uint8 X6502_DMR(uint32 A)
124 return(X.DB=ARead[A](A));
127 void X6502_DMW(uint32 A, uint8 V)
132 CallRegisteredLuaMemHook(A, 1, V, LUAMEMHOOK_WRITE);
136 void FASTAPASS(1) X6502_AddCycles_c(int x)
144 WrRAM(0x100+_S,VTMP); \
148 #define POP() RdRAM(0x100+(++_S))
150 static uint8 ZNTable[256];
151 /* Some of these operations will only make sense if you know what the flag
154 #define X_ZN(zort) _P&=~(Z_FLAG|N_FLAG);_P|=ZNTable[zort]
155 #define X_ZNT(zort) _P|=ZNTable[zort]
163 disp=(int8)RdMem(_PC); \
168 if((tmp^_PC)&0x100) \
175 #define LDA _A=x;X_ZN(_A)
176 #define LDX _X=x;X_ZN(_X)
177 #define LDY _Y=x;X_ZN(_Y)
179 /* All of the freaky arithmetic operations. */
180 #define AND _A&=x;X_ZN(_A)
181 #define BIT _P&=~(Z_FLAG|V_FLAG|N_FLAG);_P|=ZNTable[x&_A]&Z_FLAG;_P|=x&(V_FLAG|N_FLAG)
182 #define EOR _A^=x;X_ZN(_A)
183 #define ORA _A|=x;X_ZN(_A)
186 uint32 l=_A+x+(_P&1); \
187 _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \
188 _P|=((((_A^x)&0x80)^0x80) & ((_A^l)&0x80))>>1; \
195 uint32 l=_A-x-((_P&1)^1); \
196 _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \
197 _P|=((_A^l)&(_A^x)&0x80)>>1; \
198 _P|=((l>>8)&C_FLAG)^C_FLAG; \
203 #define CMPL(a1,a2) { \
207 _P|=((t>>8)&C_FLAG)^C_FLAG; \
210 /* Special undocumented operation. Very similar to CMP. */
212 uint32 t=(_A&_X)-x; \
215 _P|=((t>>8)&C_FLAG)^C_FLAG; \
219 #define CMP CMPL(_A,x)
220 #define CPX CMPL(_X,x)
221 #define CPY CMPL(_Y,x)
223 /* The following operations modify the byte being worked on. */
224 #define DEC x--;X_ZN(x)
225 #define INC x++;X_ZN(x)
227 #define ASL _P&=~C_FLAG;_P|=x>>7;x<<=1;X_ZN(x)
228 #define LSR _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=x&1;x>>=1;X_ZNT(x)
230 /* For undocumented instructions, maybe for other things later... */
231 #define LSRA _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=_A&1;_A>>=1;X_ZNT(_A)
237 _P&=~(Z_FLAG|N_FLAG|C_FLAG); \
245 _P&=~(Z_FLAG|N_FLAG|C_FLAG); \
250 /* Icky icky thing for some undocumented instructions. Can easily be
251 broken if names of local variables are changed.
255 #define GetAB(target) \
259 target|=RdMem(_PC)<<8; \
263 /* Absolute Indexed(for reads) */
264 #define GetABIRD(target, i) \
270 if((target^tmp)&0x100) \
273 DummyRdMem(target^0x100); \
278 /* Absolute Indexed(for writes and rmws) */
279 #define GetABIWR(target, i) \
286 DummyRdMem((target&0x00FF)|(rt&0xFF00)); \
290 #define GetZP(target) \
296 /* Zero Page Indexed */
297 #define GetZPI(target,i) \
299 target=i+RdMem(_PC); \
303 /* Indexed Indirect */
304 #define GetIX(target) \
312 target|=RdRAM(tmp)<<8; \
315 /* Indirect Indexed(for reads) */
316 #define GetIYRD(target) \
327 if((target^rt)&0x100) \
330 DummyRdMem(target^0x100); \
335 /* Indirect Indexed(for writes and rmws) */
336 #define GetIYWR(target) \
348 DummyRdMem((target&0x00FF)|(rt&0xFF00)); \
351 /* Now come the macros to wrap up all of the above stuff addressing mode functions
352 and operation macros. Note that operation macros will always operate(redundant
353 redundant) on the variable "x".
356 #define RMW_A(op) {uint8 x=_A; op; _A=x; break; } /* Meh... */
357 #define RMW_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
358 #define RMW_ABI(reg,op) {unsigned int A; uint8 x; GetABIWR(A,reg); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
359 #define RMW_ABX(op) RMW_ABI(_X,op)
360 #define RMW_ABY(op) RMW_ABI(_Y,op)
361 #define RMW_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
362 #define RMW_IY(op) {unsigned int A; uint8 x; GetIYWR(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
363 #define RMW_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; WrRAM(A,x); break; }
364 #define RMW_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; WrRAM(A,x); break;}
366 #define LD_IM(op) {uint8 x; x=RdMem(_PC); _PC++; op; break;}
367 #define LD_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; break;}
368 #define LD_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; break;}
369 #define LD_ZPY(op) {uint8 A; uint8 x; GetZPI(A,_Y); x=RdRAM(A); op; break;}
370 #define LD_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); op; break; }
371 #define LD_ABI(reg,op) {unsigned int A; uint8 x; GetABIRD(A,reg); x=RdMem(A); op; break;}
372 #define LD_ABX(op) LD_ABI(_X,op)
373 #define LD_ABY(op) LD_ABI(_Y,op)
374 #define LD_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); op; break;}
375 #define LD_IY(op) {unsigned int A; uint8 x; GetIYRD(A); x=RdMem(A); op; break;}
377 #define ST_ZP(r) {uint8 A; GetZP(A); WrRAM(A,r); break;}
378 #define ST_ZPX(r) {uint8 A; GetZPI(A,_X); WrRAM(A,r); break;}
379 #define ST_ZPY(r) {uint8 A; GetZPI(A,_Y); WrRAM(A,r); break;}
380 #define ST_AB(r) {unsigned int A; GetAB(A); WrMem(A,r); break;}
381 #define ST_ABI(reg,r) {unsigned int A; GetABIWR(A,reg); WrMem(A,r); break; }
382 #define ST_ABX(r) ST_ABI(_X,r)
383 #define ST_ABY(r) ST_ABI(_Y,r)
384 #define ST_IX(r) {unsigned int A; GetIX(A); WrMem(A,r); break; }
385 #define ST_IY(r) {unsigned int A; GetIYWR(A); WrMem(A,r); break; }
387 static uint8 CycTable[256] =
389 /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
390 /*0x00*/ 7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,
391 /*0x10*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
392 /*0x20*/ 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,
393 /*0x30*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
394 /*0x40*/ 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,
395 /*0x50*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
396 /*0x60*/ 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,
397 /*0x70*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
398 /*0x80*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
399 /*0x90*/ 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,
400 /*0xA0*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
401 /*0xB0*/ 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,
402 /*0xC0*/ 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
403 /*0xD0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
404 /*0xE0*/ 2,6,3,8,3,3,5,5,2,2,2,2,4,4,6,6,
405 /*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
408 void FASTAPASS(1) X6502_IRQBegin_c(int w)
413 void FASTAPASS(1) X6502_IRQEnd_c(int w)
418 void TriggerIRQ_c(void) /* This function should probably be phased out. */
420 _IRQlow|=FCEU_IQTEMP;
423 void TriggerNMI_c(void)
428 void TriggerNMI2(void)
430 //_IRQlow|=FCEU_IQNMI2;
434 void X6502_Reset_c(void)
436 //_IRQlow=FCEU_IQRESET;
438 _PC|=RdMem(0xFFFD)<<8;
444 * Initializes the 6502 CPU
446 void X6502_Init_c(void)
450 // Initialize the CPU structure
451 memset((void *)&X,0,sizeof(X));
453 for(i = 0; i < sizeof(ZNTable); i++)
470 void X6502_Power_c(void)
472 memset((void *)&X,0,sizeof(X));
477 void X6502_Run_c(void/*int32 cycles*/)
481 cycles*=15; // 15*4=60
483 cycles*=16; // 16*4=64
494 if(_IRQlow&FCEU_IQNMI)
501 PUSH((_P&~B_FLAG)|(U_FLAG));
504 _PC|=RdMem(0xFFFB)<<8;
505 _IRQlow&=~FCEU_IQNMI;
506 #ifdef DEBUG_ASM_6502
514 if(!(_PI&I_FLAG) && !_jammed)
519 PUSH((_P&~B_FLAG)|(U_FLAG));
522 _PC|=RdMem(0xFFFF)<<8;
523 #ifdef DEBUG_ASM_6502
529 _IRQlow&=~(FCEU_IQTEMP);
532 #ifdef DEBUG_ASM_6502
533 if(MapIRQHook) mapirq_cyc_c = _tcount;
538 } //Should increase accuracy without a
543 #ifdef DEBUG_ASM_6502
544 b1=RdMem(_PC++); _PC--;
549 ADDCYC(CycTable[b1]);
551 temp=_tcount; /* Gradius II (J) glitches if _tcount is not used */
554 #ifdef DEBUG_ASM_6502
559 FCEU_SoundCPUHook(temp*48);
561 #ifdef DEBUG_ASM_6502
570 #ifdef DEBUG_ASM_6502