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
34 extern uint32 PC_prev, OP_prev;
35 extern uint8 dreads[4];
36 extern uint32 dwrites_c[2];
37 extern int dread_count_c, dwrite_count_c;
38 extern int mapirq_cyc_c;
39 extern void (*MapIRQHook)(int a);
40 #define DummyRdMem(...)
42 #define DummyRdMem RdMem
43 void FP_FASTAPASS(1) (*MapIRQHook)(int a);
56 //#define _PZ X.PZ // unused?
58 #define _count X.count
59 #define _tcount X.tcount
60 #define _IRQlow X.IRQlow
61 #define _jammed X.jammed
64 static INLINE uint8 RdMem(unsigned int A)
66 // notaz: try to avoid lookup of every address at least for ROM and RAM areas
67 // I've verified that if ARead[0xfff0] points to CartBR, it is always normal ROM read.
69 if ((A&0x8000)/* && ARead[0xfff0] == CartBR*/) {
70 return (_DB=Page[A>>11][A]);
73 #if 0 // enabling this causes 4fps slowdown. Why?
74 if ((A&0xe000) == 0) { // RAM area (always 0-0x1fff)
75 return (_DB=RAM[A&0x7FF]);
80 //printf("a == %x, pc == %x\n", A, _PC);
81 if (A >= 0x2000 && A != _PC && A != _PC - 1 && A != _PC + 1) {
82 dreads[dread_count_c++] = _DB;
83 if (dread_count_c > 4) { printf("dread_count out of range\n"); exit(1); }
89 static INLINE void WrMem(unsigned int A, uint8 V)
91 //printf("w [%04x] %02x\n", A, V);
92 if ((A&0xe000) == 0) { // RAM area (always 0-0x1fff)
98 dwrites_c[dwrite_count_c++] = (A<<8)|V;
99 if (dwrite_count_c > 2) { printf("dwrite_count_c out of range\n"); exit(1); }
103 static INLINE uint8 RdRAM(unsigned int A)
105 return((_DB=RAM[A]));
108 static INLINE void WrRAM(unsigned int A, uint8 V)
113 static INLINE void ADDCYC(int x)
120 void FASTAPASS(1) X6502_AddCycles_c(int x)
125 static INLINE void PUSH(uint8 V)
131 static INLINE uint8 POP(void)
134 return(RdRAM(0x100+_S));
138 static uint8 ZNTable[256] = {
139 Z_FLAG,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
140 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
141 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
142 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
143 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
144 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
145 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
146 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
147 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,
148 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,
149 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,
150 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,
151 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,
152 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,
153 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,
154 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
157 /* Some of these operations will only make sense if you know what the flag
159 //#define X_ZN(zort) _P&=~(Z_FLAG|N_FLAG);_P|=ZNTable[zort]
160 //#define X_ZNT(zort) _P|=ZNTable[zort]
161 #define X_ZN(zort) _P&=~(Z_FLAG|N_FLAG);if(!zort) _P|=Z_FLAG;else _P|=zort&N_FLAG
162 #define X_ZNT(zort) if(!zort) _P|=Z_FLAG;else _P|=(zort&N_FLAG)
164 /* Care must be taken if you want to turn this into a macro. Use { and }. */
173 if((tmp^_PC)&0x100) \
177 #define LDA _A=x;X_ZN(_A)
178 #define LDX _X=x;X_ZN(_X)
179 #define LDY _Y=x;X_ZN(_Y)
181 /* All of the freaky arithmetic operations. */
182 #define AND _A&=x;X_ZN(_A)
183 //#define BIT _P&=~(Z_FLAG|V_FLAG|N_FLAG);_P|=ZNTable[x&_A]&Z_FLAG;_P|=x&(V_FLAG|N_FLAG)
184 #define BIT _P&=~(Z_FLAG|V_FLAG|N_FLAG);if(!(x&_A)) _P|=Z_FLAG;_P|=x&(V_FLAG|N_FLAG)
185 #define EOR _A^=x;X_ZN(_A)
186 #define ORA _A|=x;X_ZN(_A)
189 uint32 l=_A+x+(_P&1); \
190 _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \
191 _P|=((((_A^x)&0x80)^0x80) & ((_A^l)&0x80))>>1; \
197 uint32 l=_A-x-((_P&1)^1); \
198 _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \
199 _P|=((_A^l)&(_A^x)&0x80)>>1; \
200 _P|=((l>>8)&C_FLAG)^C_FLAG; \
205 #define CMPL(a1,a2) { \
209 _P|=((t>>8)&C_FLAG)^C_FLAG; \
212 /* Special undocumented operation. Very similar to CMP. */
214 uint32 t=(_A&_X)-x; \
217 _P|=((t>>8)&C_FLAG)^C_FLAG; \
221 #define CMP CMPL(_A,x)
222 #define CPX CMPL(_X,x)
223 #define CPY CMPL(_Y,x)
225 /* The following operations modify the byte being worked on. */
226 #define DEC x--;X_ZN(x)
227 #define INC x++;X_ZN(x)
229 #define ASL _P&=~C_FLAG;_P|=x>>7;x<<=1;X_ZN(x)
230 #define LSR _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=x&1;x>>=1;X_ZNT(x)
232 /* For undocumented instructions, maybe for other things later... */
233 #define LSRA _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=_A&1;_A>>=1;X_ZNT(_A)
239 _P&=~(Z_FLAG|N_FLAG|C_FLAG); \
247 _P&=~(Z_FLAG|N_FLAG|C_FLAG); \
252 /* Icky icky thing for some undocumented instructions. Can easily be
253 broken if names of local variables are changed.
257 #define GetAB(target) \
259 target=RdMem(_PC++); \
260 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) \
292 target=RdMem(_PC++); \
295 /* Zero Page Indexed */
296 #define GetZPI(target,i) \
298 target=i+RdMem(_PC++); \
301 /* Indexed Indirect */
302 #define GetIX(target) \
307 target=RdRAM(tmp++); \
308 target|=RdRAM(tmp)<<8; \
311 /* Indirect Indexed(for reads) */
312 #define GetIYRD(target) \
321 if((target^rt)&0x100) \
324 DummyRdMem(target^0x100); \
329 /* Indirect Indexed(for writes and rmws) */
330 #define GetIYWR(target) \
339 DummyRdMem((target&0x00FF)|(rt&0xFF00)); \
342 /* Now come the macros to wrap up all of the above stuff addressing mode functions
343 and operation macros. Note that operation macros will always operate(redundant
344 redundant) on the variable "x".
347 #define RMW_A(op) {uint8 x=_A; op; _A=x; break; } /* Meh... */
348 #define RMW_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
349 #define RMW_ABI(reg,op) {unsigned int A; uint8 x; GetABIWR(A,reg); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
350 #define RMW_ABX(op) RMW_ABI(_X,op)
351 #define RMW_ABY(op) RMW_ABI(_Y,op)
352 #define RMW_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
353 #define RMW_IY(op) {unsigned int A; uint8 x; GetIYWR(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
354 #define RMW_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; WrRAM(A,x); break; }
355 #define RMW_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; WrRAM(A,x); break;}
357 #define LD_IM(op) {uint8 x; x=RdMem(_PC++); op; break;}
358 #define LD_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; break;}
359 #define LD_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; break;}
360 #define LD_ZPY(op) {uint8 A; uint8 x; GetZPI(A,_Y); x=RdRAM(A); op; break;}
361 #define LD_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); op; break; }
362 #define LD_ABI(reg,op) {unsigned int A; uint8 x; GetABIRD(A,reg); x=RdMem(A); op; break;}
363 #define LD_ABX(op) LD_ABI(_X,op)
364 #define LD_ABY(op) LD_ABI(_Y,op)
365 #define LD_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); op; break;}
366 #define LD_IY(op) {unsigned int A; uint8 x; GetIYRD(A); x=RdMem(A); op; break;}
368 #define ST_ZP(r) {uint8 A; GetZP(A); WrRAM(A,r); break;}
369 #define ST_ZPX(r) {uint8 A; GetZPI(A,_X); WrRAM(A,r); break;}
370 #define ST_ZPY(r) {uint8 A; GetZPI(A,_Y); WrRAM(A,r); break;}
371 #define ST_AB(r) {unsigned int A; GetAB(A); WrMem(A,r); break;}
372 #define ST_ABI(reg,r) {unsigned int A; GetABIWR(A,reg); WrMem(A,r); break; }
373 #define ST_ABX(r) ST_ABI(_X,r)
374 #define ST_ABY(r) ST_ABI(_Y,r)
375 #define ST_IX(r) {unsigned int A; GetIX(A); WrMem(A,r); break; }
376 #define ST_IY(r) {unsigned int A; GetIYWR(A); WrMem(A,r); break; }
378 static uint8 CycTable[256] =
380 /*0x00*/ 7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,
381 /*0x10*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
382 /*0x20*/ 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,
383 /*0x30*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
384 /*0x40*/ 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,
385 /*0x50*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
386 /*0x60*/ 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,
387 /*0x70*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
388 /*0x80*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
389 /*0x90*/ 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,
390 /*0xA0*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
391 /*0xB0*/ 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,
392 /*0xC0*/ 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
393 /*0xD0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
394 /*0xE0*/ 2,6,3,8,3,3,5,5,2,2,2,2,4,4,6,6,
395 /*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
398 void FASTAPASS(1) X6502_IRQBegin_c(int w)
400 dprintf("IRQB %02x",w);
404 void FASTAPASS(1) X6502_IRQEnd_c(int w)
406 dprintf("IRQE %02x",w);
410 void TriggerIRQ_c(void) /* This function should probably be phased out. */
412 _IRQlow|=FCEU_IQTEMP;
415 void TriggerNMINSF_c(void)
420 PUSH((_P&~B_FLAG)|(U_FLAG));
424 void TriggerNMI_c(void)
429 static void TriggerNMIReal(void)
440 _PC|=RdMem(0xFFFB)<<8;
441 #ifdef DEBUG_ASM_6502
448 void TriggerIRQReal(void)
450 if(!(_PI&I_FLAG) && !_jammed)
460 _PC|=RdMem(0xFFFF)<<8;
461 #ifdef DEBUG_ASM_6502
468 void X6502_Reset_c(void)
471 _PC|=RdMem(0xFFFD)<<8;
476 void X6502_Power_c(void)
478 memset((void *)&X,0,sizeof(X));
485 void X6502_Run_c(void/*int32 cycles*/)
489 cycles*=15; // 15*4=60
491 cycles*=16; // 16*4=64
495 // if (_count <= 0) asdc++;
504 if(_IRQlow&FCEU_IQNMI)
509 _IRQlow&=~(FCEU_IQTEMP|FCEU_IQNMI);
512 #ifdef DEBUG_ASM_6502
513 if(MapIRQHook) mapirq_cyc_c = _tcount;
517 return; /* Should increase accuracy without a major speed hit. */
522 ADDCYC(CycTable[b1]);
540 if((PSG[0x10]&0x80) && !(PSG[0x10]&0x40))
542 extern uint8 SIRQStat;
544 X6502_IRQBegin_c(FCEU_IQDPCM);
549 #ifdef DEBUG_ASM_6502
553 //printf("$%04x:$%02x\n",_PC,b1);
555 //printf("$%02x\n",b1);
562 temp=_tcount; /* Gradius II (J) glitches if _tcount is not used */
566 #ifdef DEBUG_ASM_6502
572 #ifdef DEBUG_ASM_6502