smb3 and addams family hacks
[fceu.git] / x6502.c
... / ...
CommitLineData
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"
27#include "cart.h"
28
29#include "dprintf.h"
30
31#ifdef DEBUG_ASM_6502
32#include <stdio.h>
33#include <stdlib.h>
34extern uint32 PC_prev, OP_prev;
35extern uint8 dreads[4];
36extern uint32 dwrites_c[2];
37extern int dread_count_c, dwrite_count_c;
38extern int mapirq_cyc_c;
39extern void (*MapIRQHook)(int a);
40#define DummyRdMem(...)
41#else
42#define DummyRdMem RdMem
43void FP_FASTAPASS(1) (*MapIRQHook)(int a);
44#endif
45
46X6502 X;
47uint32 timestamp;
48
49#define _PC X.PC
50#define _A X.A
51#define _X X.X
52#define _Y X.Y
53#define _S X.S
54#define _P X.P
55#define _PI X.mooPI
56//#define _PZ X.PZ // unused?
57#define _DB X.DB
58#define _count X.count
59#define _tcount X.tcount
60#define _IRQlow X.IRQlow
61#define _jammed X.jammed
62
63
64static INLINE uint8 RdMem(unsigned int A)
65{
66 int _DB1=ARead[A](A);
67#ifdef DEBUG_ASM_6502
68 //_DB=_DB1;
69 //printf("a == %x, pc == %x\n", A, _PC);
70 if (A >= 0x2000) {
71 if (A == _PC || A == _PC - 1 || A == _PC + 1) {
72 //printf("fr: %02x\n", _DB1);
73 }
74 _DB=_DB1;
75 }
76 if (A >= 0x2000 && A != _PC && A != _PC - 1 && A != _PC + 1) {
77 dreads[dread_count_c++] = _DB1;
78 if (dread_count_c > 4) { printf("dread_count out of range\n"); exit(1); }
79 }
80#else
81 _DB=_DB1;
82#endif
83 return _DB1;
84}
85
86static INLINE void WrMem(unsigned int A, uint8 V)
87{
88 //printf("w [%04x] %02x\n", A, V);
89 if ((A&0xe000) == 0) { // RAM area (always 0-0x1fff)
90 RAM[A&0x7FF] = V;
91 return;
92 }
93 BWrite[A](A,V);
94#ifdef DEBUG_ASM_6502
95 dwrites_c[dwrite_count_c++] = (A<<8)|V;
96 if (dwrite_count_c > 2) { printf("dwrite_count_c out of range\n"); exit(1); }
97#endif
98}
99
100static INLINE uint8 RdRAM(unsigned int A)
101{
102 //return((_DB=RAM[A]));
103 int _DB1=RAM[A];
104#ifndef DEBUG_ASM_6502
105 _DB=_DB1;
106#endif
107 return _DB1;
108}
109
110static INLINE void WrRAM(unsigned int A, uint8 V)
111{
112 RAM[A]=V;
113}
114
115static INLINE void ADDCYC(int x)
116{
117 _tcount+=x;
118 _count-=x*48;
119 timestamp+=x;
120}
121
122void FASTAPASS(1) X6502_AddCycles_c(int x)
123{
124 ADDCYC(x);
125}
126
127static INLINE void PUSH(uint8 V)
128{
129 WrRAM(0x100+_S,V);
130 _S--;
131}
132
133static INLINE uint8 POP(void)
134{
135 _S++;
136 return(RdRAM(0x100+_S));
137}
138
139#if 0
140static uint8 ZNTable[256] = {
141 Z_FLAG,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 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
148 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
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,
155 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,
156 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};
158#endif
159/* Some of these operations will only make sense if you know what the flag
160 constants are. */
161//#define X_ZN(zort) _P&=~(Z_FLAG|N_FLAG);_P|=ZNTable[zort]
162//#define X_ZNT(zort) _P|=ZNTable[zort]
163#define X_ZN(zort) _P&=~(Z_FLAG|N_FLAG);if(!zort) _P|=Z_FLAG;else _P|=zort&N_FLAG
164#define X_ZNT(zort) if(!zort) _P|=Z_FLAG;else _P|=(zort&N_FLAG)
165
166/* Care must be taken if you want to turn this into a macro. Use { and }. */
167#define JR(); \
168{ \
169 uint32 tmp; \
170 int8 disp; \
171 disp=RdMem(_PC++); \
172 ADDCYC(1); \
173 tmp=_PC; \
174 _PC+=disp; \
175 if((tmp^_PC)&0x100) \
176 ADDCYC(1); \
177}
178
179#define LDA _A=x;X_ZN(_A)
180#define LDX _X=x;X_ZN(_X)
181#define LDY _Y=x;X_ZN(_Y)
182
183/* All of the freaky arithmetic operations. */
184#define AND _A&=x;X_ZN(_A)
185//#define BIT _P&=~(Z_FLAG|V_FLAG|N_FLAG);_P|=ZNTable[x&_A]&Z_FLAG;_P|=x&(V_FLAG|N_FLAG)
186#define BIT _P&=~(Z_FLAG|V_FLAG|N_FLAG);if(!(x&_A)) _P|=Z_FLAG;_P|=x&(V_FLAG|N_FLAG)
187#define EOR _A^=x;X_ZN(_A)
188#define ORA _A|=x;X_ZN(_A)
189
190#define ADC { \
191 uint32 l=_A+x+(_P&1); \
192 _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \
193 _P|=((((_A^x)&0x80)^0x80) & ((_A^l)&0x80))>>1; \
194 _P|=(l>>8)&C_FLAG; \
195 _A=l; \
196 X_ZNT(_A); \
197 }
198#define SBC { \
199 uint32 l=_A-x-((_P&1)^1); \
200 _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \
201 _P|=((_A^l)&(_A^x)&0x80)>>1; \
202 _P|=((l>>8)&C_FLAG)^C_FLAG; \
203 _A=l; \
204 X_ZNT(_A); \
205 }
206
207#define CMPL(a1,a2) { \
208 uint32 t=a1-a2; \
209 X_ZN(t&0xFF); \
210 _P&=~C_FLAG; \
211 _P|=((t>>8)&C_FLAG)^C_FLAG; \
212 }
213
214/* Special undocumented operation. Very similar to CMP. */
215#define AXS { \
216 uint32 t=(_A&_X)-x; \
217 X_ZN(t&0xFF); \
218 _P&=~C_FLAG; \
219 _P|=((t>>8)&C_FLAG)^C_FLAG; \
220 _X=t; \
221 }
222
223#define CMP CMPL(_A,x)
224#define CPX CMPL(_X,x)
225#define CPY CMPL(_Y,x)
226
227/* The following operations modify the byte being worked on. */
228#define DEC x--;X_ZN(x)
229#define INC x++;X_ZN(x)
230
231#define ASL _P&=~C_FLAG;_P|=x>>7;x<<=1;X_ZN(x)
232#define LSR _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=x&1;x>>=1;X_ZNT(x)
233
234/* For undocumented instructions, maybe for other things later... */
235#define LSRA _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=_A&1;_A>>=1;X_ZNT(_A)
236
237#define ROL { \
238 uint8 l=x>>7; \
239 x<<=1; \
240 x|=_P&C_FLAG; \
241 _P&=~(Z_FLAG|N_FLAG|C_FLAG); \
242 _P|=l; \
243 X_ZNT(x); \
244 }
245#define ROR { \
246 uint8 l=x&1; \
247 x>>=1; \
248 x|=(_P&C_FLAG)<<7; \
249 _P&=~(Z_FLAG|N_FLAG|C_FLAG); \
250 _P|=l; \
251 X_ZNT(x); \
252 }
253
254/* Icky icky thing for some undocumented instructions. Can easily be
255 broken if names of local variables are changed.
256*/
257
258/* Absolute */
259#define GetAB(target) \
260{ \
261 target=RdMem(_PC++); \
262 target|=RdMem(_PC++)<<8; \
263}
264
265/* Absolute Indexed(for reads) */
266#define GetABIRD(target, i) \
267{ \
268 unsigned int tmp; \
269 GetAB(tmp); \
270 target=tmp; \
271 target+=i; \
272 if((target^tmp)&0x100) \
273 { \
274 target&=0xFFFF; \
275 DummyRdMem(target^0x100); \
276 ADDCYC(1); \
277 } \
278}
279
280/* Absolute Indexed(for writes and rmws) */
281#define GetABIWR(target, i) \
282{ \
283 unsigned int rt; \
284 GetAB(rt); \
285 target=rt; \
286 target+=i; \
287 target&=0xFFFF; \
288 DummyRdMem((target&0x00FF)|(rt&0xFF00)); \
289}
290
291/* Zero Page */
292#define GetZP(target) \
293{ \
294 target=RdMem(_PC++); \
295}
296
297/* Zero Page Indexed */
298#define GetZPI(target,i) \
299{ \
300 target=i+RdMem(_PC++); \
301}
302
303/* Indexed Indirect */
304#define GetIX(target) \
305{ \
306 uint8 tmp; \
307 tmp=RdMem(_PC++); \
308 tmp+=_X; \
309 target=RdRAM(tmp++); \
310 target|=RdRAM(tmp)<<8; \
311}
312
313/* Indirect Indexed(for reads) */
314#define GetIYRD(target) \
315{ \
316 unsigned int rt; \
317 uint8 tmp; \
318 tmp=RdMem(_PC++); \
319 rt=RdRAM(tmp++); \
320 rt|=RdRAM(tmp)<<8; \
321 target=rt; \
322 target+=_Y; \
323 if((target^rt)&0x100) \
324 { \
325 target&=0xFFFF; \
326 DummyRdMem(target^0x100); \
327 ADDCYC(1); \
328 } \
329}
330
331/* Indirect Indexed(for writes and rmws) */
332#define GetIYWR(target) \
333{ \
334 unsigned int rt; \
335 uint8 tmp; \
336 tmp=RdMem(_PC++); \
337 rt=RdRAM(tmp++); \
338 rt|=RdRAM(tmp)<<8; \
339 target=rt; \
340 target+=_Y; \
341 DummyRdMem((target&0x00FF)|(rt&0xFF00)); \
342}
343
344/* Now come the macros to wrap up all of the above stuff addressing mode functions
345 and operation macros. Note that operation macros will always operate(redundant
346 redundant) on the variable "x".
347*/
348
349#define RMW_A(op) {uint8 x=_A; op; _A=x; break; } /* Meh... */
350#define RMW_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
351#define RMW_ABI(reg,op) {unsigned int A; uint8 x; GetABIWR(A,reg); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
352#define RMW_ABX(op) RMW_ABI(_X,op)
353#define RMW_ABY(op) RMW_ABI(_Y,op)
354#define RMW_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
355#define RMW_IY(op) {unsigned int A; uint8 x; GetIYWR(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
356#define RMW_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; WrRAM(A,x); break; }
357#define RMW_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; WrRAM(A,x); break;}
358
359#define LD_IM(op) {uint8 x; x=RdMem(_PC++); op; break;}
360#define LD_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; break;}
361#define LD_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; break;}
362#define LD_ZPY(op) {uint8 A; uint8 x; GetZPI(A,_Y); x=RdRAM(A); op; break;}
363#define LD_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); op; break; }
364#define LD_ABI(reg,op) {unsigned int A; uint8 x; GetABIRD(A,reg); x=RdMem(A); op; break;}
365#define LD_ABX(op) LD_ABI(_X,op)
366#define LD_ABY(op) LD_ABI(_Y,op)
367#define LD_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); op; break;}
368#define LD_IY(op) {unsigned int A; uint8 x; GetIYRD(A); x=RdMem(A); op; break;}
369
370#define ST_ZP(r) {uint8 A; GetZP(A); WrRAM(A,r); break;}
371#define ST_ZPX(r) {uint8 A; GetZPI(A,_X); WrRAM(A,r); break;}
372#define ST_ZPY(r) {uint8 A; GetZPI(A,_Y); WrRAM(A,r); break;}
373#define ST_AB(r) {unsigned int A; GetAB(A); WrMem(A,r); break;}
374#define ST_ABI(reg,r) {unsigned int A; GetABIWR(A,reg); WrMem(A,r); break; }
375#define ST_ABX(r) ST_ABI(_X,r)
376#define ST_ABY(r) ST_ABI(_Y,r)
377#define ST_IX(r) {unsigned int A; GetIX(A); WrMem(A,r); break; }
378#define ST_IY(r) {unsigned int A; GetIYWR(A); WrMem(A,r); break; }
379
380static uint8 CycTable[256] =
381{
382/*0x00*/ 7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,
383/*0x10*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
384/*0x20*/ 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,
385/*0x30*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
386/*0x40*/ 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,
387/*0x50*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
388/*0x60*/ 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,
389/*0x70*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
390/*0x80*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
391/*0x90*/ 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,
392/*0xA0*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
393/*0xB0*/ 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,
394/*0xC0*/ 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
395/*0xD0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
396/*0xE0*/ 2,6,3,8,3,3,5,5,2,2,2,2,4,4,6,6,
397/*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
398};
399
400void FASTAPASS(1) X6502_IRQBegin_c(int w)
401{
402 dprintf("IRQB %02x",w);
403 _IRQlow|=w;
404}
405
406void FASTAPASS(1) X6502_IRQEnd_c(int w)
407{
408 dprintf("IRQE %02x",w);
409 _IRQlow&=~w;
410}
411
412void TriggerIRQ_c(void) /* This function should probably be phased out. */
413{
414 _IRQlow|=FCEU_IQTEMP;
415}
416
417void TriggerNMINSF_c(void)
418{
419 ADDCYC(7);
420 PUSH(_PC>>8);
421 PUSH(_PC);
422 PUSH((_P&~B_FLAG)|(U_FLAG));
423 _PC=0x3800;
424}
425
426void TriggerNMI_c(void)
427{
428 _IRQlow|=FCEU_IQNMI;
429}
430
431static void TriggerNMIReal(void)
432{
433 if(!_jammed)
434 {
435 dprintf("NMI");
436 ADDCYC(7);
437 PUSH(_PC>>8);
438 PUSH(_PC);
439 _P&=~B_FLAG;
440 PUSH(_P|U_FLAG);
441 _PC=RdMem(0xFFFA);
442 _PC|=RdMem(0xFFFB)<<8;
443#ifdef DEBUG_ASM_6502
444 PC_prev = _PC;
445 OP_prev = 0x100;
446#endif
447 }
448}
449
450void TriggerIRQReal(void)
451{
452 if(!(_PI&I_FLAG) && !_jammed)
453 {
454 dprintf("IRQ");
455 ADDCYC(7);
456 PUSH(_PC>>8);
457 PUSH(_PC);
458 _P&=~B_FLAG;
459 PUSH(_P|U_FLAG);
460 _P|=I_FLAG;
461 _PC=RdMem(0xFFFE);
462 _PC|=RdMem(0xFFFF)<<8;
463#ifdef DEBUG_ASM_6502
464 PC_prev = _PC;
465 OP_prev = 0x101;
466#endif
467 }
468}
469
470void X6502_Reset_c(void)
471{
472 _PC=RdMem(0xFFFC);
473 _PC|=RdMem(0xFFFD)<<8;
474 _jammed=0;
475 _PI=_P=I_FLAG;
476}
477
478void X6502_Power_c(void)
479{
480 memset((void *)&X,0,sizeof(X));
481 timestamp=0;
482 X6502_Reset_c();
483}
484
485
486//int asdc = 0;
487void X6502_Run_c(void/*int32 cycles*/)
488{
489/*
490 if(PAL)
491 cycles*=15; // 15*4=60
492 else
493 cycles*=16; // 16*4=64
494
495 _count+=cycles;
496*/
497// if (_count <= 0) asdc++;
498
499 while(_count>0)
500 {
501 int32 temp;
502 uint8 b1;
503
504 if(_IRQlow)
505 {
506 if(_IRQlow&FCEU_IQNMI)
507 TriggerNMIReal();
508 else
509 TriggerIRQReal();
510
511 _IRQlow&=~(FCEU_IQTEMP|FCEU_IQNMI);
512 if(_count<=0)
513 {
514#ifdef DEBUG_ASM_6502
515 if(MapIRQHook) mapirq_cyc_c = _tcount;
516 _tcount=0;
517#endif
518 _PI=_P;
519 return; /* Should increase accuracy without a major speed hit. */
520 }
521 }
522 _PI=_P;
523 b1=RdMem(_PC);
524 ADDCYC(CycTable[b1]);
525 temp=_tcount;
526
527 temp*=48;
528
529 fhcnt-=temp;
530 if(fhcnt<=0)
531 {
532 FrameSoundUpdate();
533 fhcnt+=fhinc;
534 }
535
536 if(PCMIRQCount>0)
537 {
538 PCMIRQCount-=temp;
539 if(PCMIRQCount<=0)
540 {
541 vdis=1;
542 if((PSG[0x10]&0x80) && !(PSG[0x10]&0x40))
543 {
544 extern uint8 SIRQStat;
545 SIRQStat|=0x80;
546 X6502_IRQBegin(FCEU_IQDPCM);
547 }
548 }
549 }
550
551#ifdef DEBUG_ASM_6502
552 PC_prev = _PC;
553 OP_prev = b1;
554#endif
555 //printf("$%04x:$%02x\n",_PC,b1);
556 //_PC++;
557 //printf("$%02x\n",b1);
558 _PC++;
559 switch(b1)
560 {
561 #include "ops.h"
562 }
563
564 temp=_tcount; /* Gradius II (J) glitches if _tcount is not used */
565 _tcount=0;
566
567 if(MapIRQHook) {
568#ifdef DEBUG_ASM_6502
569 mapirq_cyc_c = temp;
570#endif
571 MapIRQHook(temp);
572 }
573
574#ifdef DEBUG_ASM_6502
575 _PI=_P;
576#endif
577 }
578}
579
580