mapper fixes for ncpu, debug is broken atm
[fceu.git] / x6502.c
CommitLineData
c62d2810 1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Ben Parnell
5 *
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.
10 *
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.
15 *
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
19 */
20
21#include <string.h>
22
23#include "types.h"
24#include "x6502.h"
25#include "fce.h"
26#include "sound.h"
937bf65b 27#include "cart.h"
c62d2810 28
c0bf6f9f 29#ifdef DEBUG_ASM_6502
30extern uint32 PC_prev, OP_prev;
31extern int cpu_lastval;
32#endif
33
c62d2810 34X6502 X;
35uint32 timestamp;
36void FP_FASTAPASS(1) (*MapIRQHook)(int a);
37
38#define _PC X.PC
39#define _A X.A
40#define _X X.X
41#define _Y X.Y
42#define _S X.S
43#define _P X.P
44#define _PI X.mooPI
92e249b1 45//#define _PZ X.PZ // unused?
c62d2810 46#define _DB X.DB
47#define _count X.count
48#define _tcount X.tcount
49#define _IRQlow X.IRQlow
50#define _jammed X.jammed
51
52
53static INLINE uint8 RdMem(unsigned int A)
54{
937bf65b 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.
57#if 0
58 if ((A&0x8000)/* && ARead[0xfff0] == CartBR*/) {
59 return (_DB=Page[A>>11][A]);
60 }
61#endif
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]);
65 }
66#endif
c0bf6f9f 67 _DB=ARead[A](A);
68#ifdef DEBUG_ASM_6502
69 // TODO: read counter, not 0x10000..
70 if (cpu_lastval)
71 cpu_lastval|=_DB<<8;
72 else
73 cpu_lastval=_DB|0x10000;
74 printf("read [%04x] %02x, cpu_lastval=%02x\n", A, _DB, cpu_lastval);
75#endif
76 return _DB;
c62d2810 77}
78
79static INLINE void WrMem(unsigned int A, uint8 V)
80{
937bf65b 81 if ((A&0xe000) == 0) { // RAM area (always 0-0x1fff)
82 RAM[A&0x7FF] = V;
83 return;
84 }
c62d2810 85 BWrite[A](A,V);
86}
87
88static INLINE uint8 RdRAM(unsigned int A)
89{
90 return((_DB=RAM[A]));
91}
92
93static INLINE void WrRAM(unsigned int A, uint8 V)
94{
95 RAM[A]=V;
96}
97
98static INLINE void ADDCYC(int x)
99{
937bf65b 100 //_tcount+=x;
c62d2810 101 _count-=x*48;
102 timestamp+=x;
103}
104
af32b6c2 105void FASTAPASS(1) X6502_AddCycles_c(int x)
c62d2810 106{
107 ADDCYC(x);
108}
109
110static INLINE void PUSH(uint8 V)
111{
112 WrRAM(0x100+_S,V);
113 _S--;
114}
115
116static INLINE uint8 POP(void)
117{
118 _S++;
119 return(RdRAM(0x100+_S));
120}
121
937bf65b 122#if 0
c62d2810 123static 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
140};
937bf65b 141#endif
c62d2810 142/* Some of these operations will only make sense if you know what the flag
143 constants are. */
937bf65b 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
c0bf6f9f 147#define X_ZNT(zort) if(!zort) _P|=Z_FLAG;else _P|=(zort&N_FLAG)
c62d2810 148
149/* Care must be taken if you want to turn this into a macro. Use { and }. */
150#define JR(); \
151{ \
152 uint32 tmp; \
153 int8 disp; \
154 disp=RdMem(_PC++); \
155 ADDCYC(1); \
156 tmp=_PC; \
157 _PC+=disp; \
158 if((tmp^_PC)&0x100) \
159 ADDCYC(1); \
160}
161
162#define LDA _A=x;X_ZN(_A)
163#define LDX _X=x;X_ZN(_X)
164#define LDY _Y=x;X_ZN(_Y)
165
166/* All of the freaky arithmetic operations. */
167#define AND _A&=x;X_ZN(_A)
937bf65b 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)
c62d2810 170#define EOR _A^=x;X_ZN(_A)
171#define ORA _A|=x;X_ZN(_A)
172
173#define ADC { \
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; \
177 _P|=(l>>8)&C_FLAG; \
178 _A=l; \
179 X_ZNT(_A); \
180 }
181#define SBC { \
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; \
186 _A=l; \
187 X_ZNT(_A); \
188 }
189
190#define CMPL(a1,a2) { \
191 uint32 t=a1-a2; \
192 X_ZN(t&0xFF); \
193 _P&=~C_FLAG; \
194 _P|=((t>>8)&C_FLAG)^C_FLAG; \
195 }
196
197/* Special undocumented operation. Very similar to CMP. */
198#define AXS { \
199 uint32 t=(_A&_X)-x; \
200 X_ZN(t&0xFF); \
201 _P&=~C_FLAG; \
202 _P|=((t>>8)&C_FLAG)^C_FLAG; \
203 _X=t; \
204 }
205
206#define CMP CMPL(_A,x)
207#define CPX CMPL(_X,x)
208#define CPY CMPL(_Y,x)
209
210/* The following operations modify the byte being worked on. */
211#define DEC x--;X_ZN(x)
212#define INC x++;X_ZN(x)
213
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)
216
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)
219
220#define ROL { \
221 uint8 l=x>>7; \
222 x<<=1; \
223 x|=_P&C_FLAG; \
224 _P&=~(Z_FLAG|N_FLAG|C_FLAG); \
225 _P|=l; \
226 X_ZNT(x); \
227 }
228#define ROR { \
229 uint8 l=x&1; \
230 x>>=1; \
231 x|=(_P&C_FLAG)<<7; \
232 _P&=~(Z_FLAG|N_FLAG|C_FLAG); \
233 _P|=l; \
234 X_ZNT(x); \
235 }
937bf65b 236
c62d2810 237/* Icky icky thing for some undocumented instructions. Can easily be
238 broken if names of local variables are changed.
239*/
240
241/* Absolute */
242#define GetAB(target) \
243{ \
244 target=RdMem(_PC++); \
245 target|=RdMem(_PC++)<<8; \
246}
247
248/* Absolute Indexed(for reads) */
249#define GetABIRD(target, i) \
250{ \
251 unsigned int tmp; \
252 GetAB(tmp); \
253 target=tmp; \
254 target+=i; \
255 if((target^tmp)&0x100) \
256 { \
257 target&=0xFFFF; \
258 RdMem(target^0x100); \
259 ADDCYC(1); \
260 } \
261}
262
263/* Absolute Indexed(for writes and rmws) */
264#define GetABIWR(target, i) \
265{ \
266 unsigned int rt; \
267 GetAB(rt); \
268 target=rt; \
269 target+=i; \
270 target&=0xFFFF; \
271 RdMem((target&0x00FF)|(rt&0xFF00)); \
272}
273
274/* Zero Page */
275#define GetZP(target) \
276{ \
277 target=RdMem(_PC++); \
278}
279
280/* Zero Page Indexed */
281#define GetZPI(target,i) \
282{ \
283 target=i+RdMem(_PC++); \
284}
285
286/* Indexed Indirect */
287#define GetIX(target) \
288{ \
289 uint8 tmp; \
290 tmp=RdMem(_PC++); \
291 tmp+=_X; \
292 target=RdRAM(tmp++); \
293 target|=RdRAM(tmp)<<8; \
294}
295
296/* Indirect Indexed(for reads) */
297#define GetIYRD(target) \
298{ \
299 unsigned int rt; \
300 uint8 tmp; \
301 tmp=RdMem(_PC++); \
302 rt=RdRAM(tmp++); \
303 rt|=RdRAM(tmp)<<8; \
304 target=rt; \
305 target+=_Y; \
306 if((target^rt)&0x100) \
307 { \
308 target&=0xFFFF; \
309 RdMem(target^0x100); \
310 ADDCYC(1); \
311 } \
312}
313
314/* Indirect Indexed(for writes and rmws) */
315#define GetIYWR(target) \
316{ \
317 unsigned int rt; \
318 uint8 tmp; \
319 tmp=RdMem(_PC++); \
320 rt=RdRAM(tmp++); \
321 rt|=RdRAM(tmp)<<8; \
322 target=rt; \
323 target+=_Y; \
324 RdMem((target&0x00FF)|(rt&0xFF00)); \
325}
326
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".
330*/
331
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;}
341
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;}
352
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; }
362
363static uint8 CycTable[256] =
937bf65b 364{
c62d2810 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,
381};
382
af32b6c2 383void FASTAPASS(1) X6502_IRQBegin_c(int w)
c62d2810 384{
385 _IRQlow|=w;
386}
387
af32b6c2 388void FASTAPASS(1) X6502_IRQEnd_c(int w)
c62d2810 389{
390 _IRQlow&=~w;
391}
392
af32b6c2 393void TriggerIRQ_c(void) /* This function should probably be phased out. */
c62d2810 394{
395 _IRQlow|=FCEU_IQTEMP;
396}
397
af32b6c2 398void TriggerNMINSF_c(void)
c62d2810 399{
400 ADDCYC(7);
401 PUSH(_PC>>8);
402 PUSH(_PC);
403 PUSH((_P&~B_FLAG)|(U_FLAG));
404 _PC=0x3800;
405}
406
af32b6c2 407void TriggerNMI_c(void)
c62d2810 408{
409 _IRQlow|=FCEU_IQNMI;
410}
411
412static void TriggerNMIReal(void)
413{
414 if(!_jammed)
415 {
416 ADDCYC(7);
417 PUSH(_PC>>8);
418 PUSH(_PC);
c0bf6f9f 419 _P&=~B_FLAG;
420 PUSH(_P|U_FLAG);
c62d2810 421 _PC=RdMem(0xFFFA);
422 _PC|=RdMem(0xFFFB)<<8;
c0bf6f9f 423#ifdef DEBUG_ASM_6502
424 PC_prev = _PC;
425 OP_prev = 0x100;
426#endif
c62d2810 427 }
428}
429
430void TriggerIRQReal(void)
431{
432 if(!(_PI&I_FLAG) && !_jammed)
433 {
434 ADDCYC(7);
435 PUSH(_PC>>8);
436 PUSH(_PC);
c0bf6f9f 437 _P&=~B_FLAG;
438 PUSH(_P|U_FLAG);
c62d2810 439 _P|=I_FLAG;
440 _PC=RdMem(0xFFFE);
441 _PC|=RdMem(0xFFFF)<<8;
c0bf6f9f 442#ifdef DEBUG_ASM_6502
443 PC_prev = _PC;
444 OP_prev = 0x101;
445#endif
c62d2810 446 }
447}
448
af32b6c2 449void X6502_Reset_c(void)
c62d2810 450{
451 _PC=RdMem(0xFFFC);
452 _PC|=RdMem(0xFFFD)<<8;
453 if(FCEUGameInfo.type==GIT_NSF) _PC=0x3830;
454 _jammed=0;
455 _PI=_P=I_FLAG;
456}
457
af32b6c2 458void X6502_Power_c(void)
c62d2810 459{
937bf65b 460 memset((void *)&X,0,sizeof(X));
c62d2810 461 timestamp=0;
af32b6c2 462 X6502_Reset_c();
c62d2810 463}
464
937bf65b 465
466//int asdc = 0;
af32b6c2 467void X6502_Run_c(void/*int32 cycles*/)
c62d2810 468{
937bf65b 469/*
c62d2810 470 if(PAL)
471 cycles*=15; // 15*4=60
472 else
473 cycles*=16; // 16*4=64
474
475 _count+=cycles;
937bf65b 476*/
477// if (_count <= 0) asdc++;
c62d2810 478
479 while(_count>0)
480 {
481 int32 temp;
482 uint8 b1;
483
484 if(_IRQlow)
485 {
486 if(_IRQlow&FCEU_IQNMI)
487 TriggerNMIReal();
488 else
489 TriggerIRQReal();
490
491 _IRQlow&=~(FCEU_IQTEMP|FCEU_IQNMI);
492 if(_count<=0) {_PI=_P;return;} /* Should increase accuracy without a */
493 /* major speed hit. */
494 }
495 _PI=_P;
496 b1=RdMem(_PC);
937bf65b 497 temp=CycTable[b1];
498 ADDCYC(temp);
499 //temp=_tcount;
500 //_tcount=0;
92e249b1 501
c62d2810 502 if(MapIRQHook) MapIRQHook(temp);
503
504 temp*=48;
505
506 fhcnt-=temp;
507 if(fhcnt<=0)
508 {
509 FrameSoundUpdate();
510 fhcnt+=fhinc;
511 }
512
c62d2810 513 if(PCMIRQCount>0)
514 {
515 PCMIRQCount-=temp;
516 if(PCMIRQCount<=0)
517 {
518 vdis=1;
519 if((PSG[0x10]&0x80) && !(PSG[0x10]&0x40))
520 {
521 extern uint8 SIRQStat;
522 SIRQStat|=0x80;
af32b6c2 523 X6502_IRQBegin_c(FCEU_IQDPCM);
c62d2810 524 }
525 }
526 }
92e249b1 527
c0bf6f9f 528#ifdef DEBUG_ASM_6502
529 PC_prev = _PC;
530 OP_prev = b1;
531 cpu_lastval = 0;
532#endif
c62d2810 533 //printf("$%04x:$%02x\n",_PC,b1);
534 //_PC++;
535 //printf("$%02x\n",b1);
536 _PC++;
537 switch(b1)
538 {
539 #include "ops.h"
937bf65b 540 }
af32b6c2 541
542#ifdef DEBUG_ASM_6502
543 _PI=_P;
544#endif
c62d2810 545 }
546}
937bf65b 547
548