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
30 void FP_FASTAPASS(1) (*MapIRQHook)(int a);
41 #define _count X.count
42 #define _tcount X.tcount
43 #define _IRQlow X.IRQlow
44 #define _jammed X.jammed
47 static INLINE uint8 RdMem(unsigned int A)
49 return((_DB=ARead[A](A)));
52 static INLINE void WrMem(unsigned int A, uint8 V)
57 static INLINE uint8 RdRAM(unsigned int A)
62 static INLINE void WrRAM(unsigned int A, uint8 V)
67 static INLINE void ADDCYC(int x)
74 void FASTAPASS(1) X6502_AddCycles(int x)
79 static INLINE void PUSH(uint8 V)
85 static INLINE uint8 POP(void)
88 return(RdRAM(0x100+_S));
91 static uint8 ZNTable[256] = {
92 Z_FLAG,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
93 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
94 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
95 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
96 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
97 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
98 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
99 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
100 N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
101 N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
102 N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
103 N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
104 N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
105 N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
106 N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
107 N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG
109 /* Some of these operations will only make sense if you know what the flag
111 #define X_ZN(zort) _P&=~(Z_FLAG|N_FLAG);_P|=ZNTable[zort]
112 #define X_ZNT(zort) _P|=ZNTable[zort]
114 /* Care must be taken if you want to turn this into a macro. Use { and }. */
123 if((tmp^_PC)&0x100) \
127 #define LDA _A=x;X_ZN(_A)
128 #define LDX _X=x;X_ZN(_X)
129 #define LDY _Y=x;X_ZN(_Y)
131 /* All of the freaky arithmetic operations. */
132 #define AND _A&=x;X_ZN(_A)
133 #define BIT _P&=~(Z_FLAG|V_FLAG|N_FLAG);_P|=ZNTable[x&_A]&Z_FLAG;_P|=x&(V_FLAG|N_FLAG)
134 #define EOR _A^=x;X_ZN(_A)
135 #define ORA _A|=x;X_ZN(_A)
138 uint32 l=_A+x+(_P&1); \
139 _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \
140 _P|=((((_A^x)&0x80)^0x80) & ((_A^l)&0x80))>>1; \
146 uint32 l=_A-x-((_P&1)^1); \
147 _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \
148 _P|=((_A^l)&(_A^x)&0x80)>>1; \
149 _P|=((l>>8)&C_FLAG)^C_FLAG; \
154 #define CMPL(a1,a2) { \
158 _P|=((t>>8)&C_FLAG)^C_FLAG; \
161 /* Special undocumented operation. Very similar to CMP. */
163 uint32 t=(_A&_X)-x; \
166 _P|=((t>>8)&C_FLAG)^C_FLAG; \
170 #define CMP CMPL(_A,x)
171 #define CPX CMPL(_X,x)
172 #define CPY CMPL(_Y,x)
174 /* The following operations modify the byte being worked on. */
175 #define DEC x--;X_ZN(x)
176 #define INC x++;X_ZN(x)
178 #define ASL _P&=~C_FLAG;_P|=x>>7;x<<=1;X_ZN(x)
179 #define LSR _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=x&1;x>>=1;X_ZNT(x)
181 /* For undocumented instructions, maybe for other things later... */
182 #define LSRA _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=_A&1;_A>>=1;X_ZNT(_A)
188 _P&=~(Z_FLAG|N_FLAG|C_FLAG); \
196 _P&=~(Z_FLAG|N_FLAG|C_FLAG); \
201 /* Icky icky thing for some undocumented instructions. Can easily be
202 broken if names of local variables are changed.
206 #define GetAB(target) \
208 target=RdMem(_PC++); \
209 target|=RdMem(_PC++)<<8; \
212 /* Absolute Indexed(for reads) */
213 #define GetABIRD(target, i) \
219 if((target^tmp)&0x100) \
222 RdMem(target^0x100); \
227 /* Absolute Indexed(for writes and rmws) */
228 #define GetABIWR(target, i) \
235 RdMem((target&0x00FF)|(rt&0xFF00)); \
239 #define GetZP(target) \
241 target=RdMem(_PC++); \
244 /* Zero Page Indexed */
245 #define GetZPI(target,i) \
247 target=i+RdMem(_PC++); \
250 /* Indexed Indirect */
251 #define GetIX(target) \
256 target=RdRAM(tmp++); \
257 target|=RdRAM(tmp)<<8; \
260 /* Indirect Indexed(for reads) */
261 #define GetIYRD(target) \
270 if((target^rt)&0x100) \
273 RdMem(target^0x100); \
278 /* Indirect Indexed(for writes and rmws) */
279 #define GetIYWR(target) \
288 RdMem((target&0x00FF)|(rt&0xFF00)); \
291 /* Now come the macros to wrap up all of the above stuff addressing mode functions
292 and operation macros. Note that operation macros will always operate(redundant
293 redundant) on the variable "x".
296 #define RMW_A(op) {uint8 x=_A; op; _A=x; break; } /* Meh... */
297 #define RMW_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
298 #define RMW_ABI(reg,op) {unsigned int A; uint8 x; GetABIWR(A,reg); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
299 #define RMW_ABX(op) RMW_ABI(_X,op)
300 #define RMW_ABY(op) RMW_ABI(_Y,op)
301 #define RMW_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
302 #define RMW_IY(op) {unsigned int A; uint8 x; GetIYWR(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
303 #define RMW_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; WrRAM(A,x); break; }
304 #define RMW_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; WrRAM(A,x); break;}
306 #define LD_IM(op) {uint8 x; x=RdMem(_PC++); op; break;}
307 #define LD_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; break;}
308 #define LD_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; break;}
309 #define LD_ZPY(op) {uint8 A; uint8 x; GetZPI(A,_Y); x=RdRAM(A); op; break;}
310 #define LD_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); op; break; }
311 #define LD_ABI(reg,op) {unsigned int A; uint8 x; GetABIRD(A,reg); x=RdMem(A); op; break;}
312 #define LD_ABX(op) LD_ABI(_X,op)
313 #define LD_ABY(op) LD_ABI(_Y,op)
314 #define LD_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); op; break;}
315 #define LD_IY(op) {unsigned int A; uint8 x; GetIYRD(A); x=RdMem(A); op; break;}
317 #define ST_ZP(r) {uint8 A; GetZP(A); WrRAM(A,r); break;}
318 #define ST_ZPX(r) {uint8 A; GetZPI(A,_X); WrRAM(A,r); break;}
319 #define ST_ZPY(r) {uint8 A; GetZPI(A,_Y); WrRAM(A,r); break;}
320 #define ST_AB(r) {unsigned int A; GetAB(A); WrMem(A,r); break;}
321 #define ST_ABI(reg,r) {unsigned int A; GetABIWR(A,reg); WrMem(A,r); break; }
322 #define ST_ABX(r) ST_ABI(_X,r)
323 #define ST_ABY(r) ST_ABI(_Y,r)
324 #define ST_IX(r) {unsigned int A; GetIX(A); WrMem(A,r); break; }
325 #define ST_IY(r) {unsigned int A; GetIYWR(A); WrMem(A,r); break; }
327 static uint8 CycTable[256] =
329 /*0x00*/ 7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,
330 /*0x10*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
331 /*0x20*/ 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,
332 /*0x30*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
333 /*0x40*/ 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,
334 /*0x50*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
335 /*0x60*/ 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,
336 /*0x70*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
337 /*0x80*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
338 /*0x90*/ 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,
339 /*0xA0*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
340 /*0xB0*/ 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,
341 /*0xC0*/ 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
342 /*0xD0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
343 /*0xE0*/ 2,6,3,8,3,3,5,5,2,2,2,2,4,4,6,6,
344 /*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
347 void FASTAPASS(1) X6502_IRQBegin(int w)
352 void FASTAPASS(1) X6502_IRQEnd(int w)
357 void TriggerIRQ(void) /* This function should probably be phased out. */
359 _IRQlow|=FCEU_IQTEMP;
362 void TriggerNMINSF(void)
367 PUSH((_P&~B_FLAG)|(U_FLAG));
371 void TriggerNMI(void)
376 static void TriggerNMIReal(void)
383 PUSH((_P&~B_FLAG)|(U_FLAG));
385 _PC|=RdMem(0xFFFB)<<8;
389 void TriggerIRQReal(void)
391 if(!(_PI&I_FLAG) && !_jammed)
396 PUSH((_P&~B_FLAG)|(U_FLAG));
399 _PC|=RdMem(0xFFFF)<<8;
403 void X6502_Reset(void)
406 _PC|=RdMem(0xFFFD)<<8;
407 if(FCEUGameInfo.type==GIT_NSF) _PC=0x3830;
412 void X6502_Power(void)
414 memset((void *)&X,0,sizeof(X));
419 void X6502_Run(int32 cycles)
422 cycles*=15; // 15*4=60
424 cycles*=16; // 16*4=64
435 if(_IRQlow&FCEU_IQNMI)
440 _IRQlow&=~(FCEU_IQTEMP|FCEU_IQNMI);
441 if(_count<=0) {_PI=_P;return;} /* Should increase accuracy without a */
442 /* major speed hit. */
446 ADDCYC(CycTable[b1]);
449 if(MapIRQHook) MapIRQHook(temp);
467 if((PSG[0x10]&0x80) && !(PSG[0x10]&0x40))
469 extern uint8 SIRQStat;
471 X6502_IRQBegin(FCEU_IQDPCM);
475 //printf("$%04x:$%02x\n",_PC,b1);
477 //printf("$%02x\n",b1);