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