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 extern uint32 PC_prev, OP_prev;
31 extern int cpu_lastval;
36 void FP_FASTAPASS(1) (*MapIRQHook)(int a);
45 //#define _PZ X.PZ // unused?
47 #define _count X.count
48 #define _tcount X.tcount
49 #define _IRQlow X.IRQlow
50 #define _jammed X.jammed
53 static INLINE uint8 RdMem(unsigned int A)
55 // notaz: try to avoid lookup of every address at least for ROM and RAM areas
56 // I've verified that if ARead[0xfff0] points to CartBR, it is always normal ROM read.
58 if ((A&0x8000)/* && ARead[0xfff0] == CartBR*/) {
59 return (_DB=Page[A>>11][A]);
62 #if 0 // enabling this causes 4fps slowdown. Why?
63 if ((A&0xe000) == 0) { // RAM area (always 0-0x1fff)
64 return (_DB=RAM[A&0x7FF]);
69 // TODO: read counter, not 0x10000..
73 cpu_lastval=_DB|0x10000;
74 printf("read [%04x] %02x, cpu_lastval=%02x\n", A, _DB, cpu_lastval);
79 static INLINE void WrMem(unsigned int A, uint8 V)
81 if ((A&0xe000) == 0) { // RAM area (always 0-0x1fff)
88 static INLINE uint8 RdRAM(unsigned int A)
93 static INLINE void WrRAM(unsigned int A, uint8 V)
98 static INLINE void ADDCYC(int x)
105 void FASTAPASS(1) X6502_AddCycles_c(int x)
110 static INLINE void PUSH(uint8 V)
116 static INLINE uint8 POP(void)
119 return(RdRAM(0x100+_S));
123 static uint8 ZNTable[256] = {
124 Z_FLAG,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
125 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
126 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
127 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
128 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
129 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
130 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
131 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
132 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,
133 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,
134 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,
135 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,
136 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,
137 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,
138 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,
139 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
142 /* Some of these operations will only make sense if you know what the flag
144 //#define X_ZN(zort) _P&=~(Z_FLAG|N_FLAG);_P|=ZNTable[zort]
145 //#define X_ZNT(zort) _P|=ZNTable[zort]
146 #define X_ZN(zort) _P&=~(Z_FLAG|N_FLAG);if(!zort) _P|=Z_FLAG;else _P|=zort&N_FLAG
147 #define X_ZNT(zort) if(!zort) _P|=Z_FLAG;else _P|=(zort&N_FLAG)
149 /* Care must be taken if you want to turn this into a macro. Use { and }. */
158 if((tmp^_PC)&0x100) \
162 #define LDA _A=x;X_ZN(_A)
163 #define LDX _X=x;X_ZN(_X)
164 #define LDY _Y=x;X_ZN(_Y)
166 /* All of the freaky arithmetic operations. */
167 #define AND _A&=x;X_ZN(_A)
168 //#define BIT _P&=~(Z_FLAG|V_FLAG|N_FLAG);_P|=ZNTable[x&_A]&Z_FLAG;_P|=x&(V_FLAG|N_FLAG)
169 #define BIT _P&=~(Z_FLAG|V_FLAG|N_FLAG);if(!(x&_A)) _P|=Z_FLAG;_P|=x&(V_FLAG|N_FLAG)
170 #define EOR _A^=x;X_ZN(_A)
171 #define ORA _A|=x;X_ZN(_A)
174 uint32 l=_A+x+(_P&1); \
175 _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \
176 _P|=((((_A^x)&0x80)^0x80) & ((_A^l)&0x80))>>1; \
182 uint32 l=_A-x-((_P&1)^1); \
183 _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \
184 _P|=((_A^l)&(_A^x)&0x80)>>1; \
185 _P|=((l>>8)&C_FLAG)^C_FLAG; \
190 #define CMPL(a1,a2) { \
194 _P|=((t>>8)&C_FLAG)^C_FLAG; \
197 /* Special undocumented operation. Very similar to CMP. */
199 uint32 t=(_A&_X)-x; \
202 _P|=((t>>8)&C_FLAG)^C_FLAG; \
206 #define CMP CMPL(_A,x)
207 #define CPX CMPL(_X,x)
208 #define CPY CMPL(_Y,x)
210 /* The following operations modify the byte being worked on. */
211 #define DEC x--;X_ZN(x)
212 #define INC x++;X_ZN(x)
214 #define ASL _P&=~C_FLAG;_P|=x>>7;x<<=1;X_ZN(x)
215 #define LSR _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=x&1;x>>=1;X_ZNT(x)
217 /* For undocumented instructions, maybe for other things later... */
218 #define LSRA _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=_A&1;_A>>=1;X_ZNT(_A)
224 _P&=~(Z_FLAG|N_FLAG|C_FLAG); \
232 _P&=~(Z_FLAG|N_FLAG|C_FLAG); \
237 /* Icky icky thing for some undocumented instructions. Can easily be
238 broken if names of local variables are changed.
242 #define GetAB(target) \
244 target=RdMem(_PC++); \
245 target|=RdMem(_PC++)<<8; \
248 /* Absolute Indexed(for reads) */
249 #define GetABIRD(target, i) \
255 if((target^tmp)&0x100) \
258 RdMem(target^0x100); \
263 /* Absolute Indexed(for writes and rmws) */
264 #define GetABIWR(target, i) \
271 RdMem((target&0x00FF)|(rt&0xFF00)); \
275 #define GetZP(target) \
277 target=RdMem(_PC++); \
280 /* Zero Page Indexed */
281 #define GetZPI(target,i) \
283 target=i+RdMem(_PC++); \
286 /* Indexed Indirect */
287 #define GetIX(target) \
292 target=RdRAM(tmp++); \
293 target|=RdRAM(tmp)<<8; \
296 /* Indirect Indexed(for reads) */
297 #define GetIYRD(target) \
306 if((target^rt)&0x100) \
309 RdMem(target^0x100); \
314 /* Indirect Indexed(for writes and rmws) */
315 #define GetIYWR(target) \
324 RdMem((target&0x00FF)|(rt&0xFF00)); \
327 /* Now come the macros to wrap up all of the above stuff addressing mode functions
328 and operation macros. Note that operation macros will always operate(redundant
329 redundant) on the variable "x".
332 #define RMW_A(op) {uint8 x=_A; op; _A=x; break; } /* Meh... */
333 #define RMW_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
334 #define RMW_ABI(reg,op) {unsigned int A; uint8 x; GetABIWR(A,reg); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
335 #define RMW_ABX(op) RMW_ABI(_X,op)
336 #define RMW_ABY(op) RMW_ABI(_Y,op)
337 #define RMW_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
338 #define RMW_IY(op) {unsigned int A; uint8 x; GetIYWR(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
339 #define RMW_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; WrRAM(A,x); break; }
340 #define RMW_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; WrRAM(A,x); break;}
342 #define LD_IM(op) {uint8 x; x=RdMem(_PC++); op; break;}
343 #define LD_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; break;}
344 #define LD_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; break;}
345 #define LD_ZPY(op) {uint8 A; uint8 x; GetZPI(A,_Y); x=RdRAM(A); op; break;}
346 #define LD_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); op; break; }
347 #define LD_ABI(reg,op) {unsigned int A; uint8 x; GetABIRD(A,reg); x=RdMem(A); op; break;}
348 #define LD_ABX(op) LD_ABI(_X,op)
349 #define LD_ABY(op) LD_ABI(_Y,op)
350 #define LD_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); op; break;}
351 #define LD_IY(op) {unsigned int A; uint8 x; GetIYRD(A); x=RdMem(A); op; break;}
353 #define ST_ZP(r) {uint8 A; GetZP(A); WrRAM(A,r); break;}
354 #define ST_ZPX(r) {uint8 A; GetZPI(A,_X); WrRAM(A,r); break;}
355 #define ST_ZPY(r) {uint8 A; GetZPI(A,_Y); WrRAM(A,r); break;}
356 #define ST_AB(r) {unsigned int A; GetAB(A); WrMem(A,r); break;}
357 #define ST_ABI(reg,r) {unsigned int A; GetABIWR(A,reg); WrMem(A,r); break; }
358 #define ST_ABX(r) ST_ABI(_X,r)
359 #define ST_ABY(r) ST_ABI(_Y,r)
360 #define ST_IX(r) {unsigned int A; GetIX(A); WrMem(A,r); break; }
361 #define ST_IY(r) {unsigned int A; GetIYWR(A); WrMem(A,r); break; }
363 static uint8 CycTable[256] =
365 /*0x00*/ 7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,
366 /*0x10*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
367 /*0x20*/ 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,
368 /*0x30*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
369 /*0x40*/ 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,
370 /*0x50*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
371 /*0x60*/ 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,
372 /*0x70*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
373 /*0x80*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
374 /*0x90*/ 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,
375 /*0xA0*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
376 /*0xB0*/ 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,
377 /*0xC0*/ 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
378 /*0xD0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
379 /*0xE0*/ 2,6,3,8,3,3,5,5,2,2,2,2,4,4,6,6,
380 /*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
383 void FASTAPASS(1) X6502_IRQBegin_c(int w)
388 void FASTAPASS(1) X6502_IRQEnd_c(int w)
393 void TriggerIRQ_c(void) /* This function should probably be phased out. */
395 _IRQlow|=FCEU_IQTEMP;
398 void TriggerNMINSF_c(void)
403 PUSH((_P&~B_FLAG)|(U_FLAG));
407 void TriggerNMI_c(void)
412 static void TriggerNMIReal(void)
422 _PC|=RdMem(0xFFFB)<<8;
423 #ifdef DEBUG_ASM_6502
430 void TriggerIRQReal(void)
432 if(!(_PI&I_FLAG) && !_jammed)
441 _PC|=RdMem(0xFFFF)<<8;
442 #ifdef DEBUG_ASM_6502
449 void X6502_Reset_c(void)
452 _PC|=RdMem(0xFFFD)<<8;
453 if(FCEUGameInfo.type==GIT_NSF) _PC=0x3830;
458 void X6502_Power_c(void)
460 memset((void *)&X,0,sizeof(X));
467 void X6502_Run_c(void/*int32 cycles*/)
471 cycles*=15; // 15*4=60
473 cycles*=16; // 16*4=64
477 // if (_count <= 0) asdc++;
486 if(_IRQlow&FCEU_IQNMI)
491 _IRQlow&=~(FCEU_IQTEMP|FCEU_IQNMI);
492 if(_count<=0) {_PI=_P;return;} /* Should increase accuracy without a */
493 /* major speed hit. */
502 if(MapIRQHook) MapIRQHook(temp);
519 if((PSG[0x10]&0x80) && !(PSG[0x10]&0x40))
521 extern uint8 SIRQStat;
523 X6502_IRQBegin_c(FCEU_IQDPCM);
528 #ifdef DEBUG_ASM_6502
533 //printf("$%04x:$%02x\n",_PC,b1);
535 //printf("$%02x\n",b1);
542 #ifdef DEBUG_ASM_6502