load keys again after plat init
[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 #include "dprintf.h"
30
31 #ifdef DEBUG_ASM_6502
32 #include <stdio.h>
33 #include <stdlib.h>
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(...)
41 #else
42 #define DummyRdMem RdMem
43 void FP_FASTAPASS(1) (*MapIRQHook)(int a);
44 #endif
45
46 X6502 X;
47 uint32 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
64 static 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 - 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
86 static 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
100 static 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
110 static INLINE void WrRAM(unsigned int A, uint8 V)
111 {
112  RAM[A]=V;
113 }
114
115 static INLINE void ADDCYC(int x)
116 {
117  _tcount+=x;
118  _count-=x*48;
119  timestamp+=x;
120 }
121
122 void FASTAPASS(1) X6502_AddCycles_c(int x)
123 {
124  ADDCYC(x);
125 }
126
127 static INLINE void PUSH(uint8 V)
128 {
129  WrRAM(0x100+_S,V);
130  _S--;
131 }
132
133 static INLINE uint8 POP(void)
134 {
135  _S++;
136  return(RdRAM(0x100+_S));
137 }
138
139 #if 0
140 static 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
380 static uint8 CycTable[256] =
381 {
382 /*       0 1 2 3 4 5 6 7 8 9 a b c d e f */
383 /*0x00*/ 7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,
384 /*0x10*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
385 /*0x20*/ 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,
386 /*0x30*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
387 /*0x40*/ 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,
388 /*0x50*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
389 /*0x60*/ 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,
390 /*0x70*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
391 /*0x80*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
392 /*0x90*/ 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,
393 /*0xA0*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
394 /*0xB0*/ 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,
395 /*0xC0*/ 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
396 /*0xD0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
397 /*0xE0*/ 2,6,3,8,3,3,5,5,2,2,2,2,4,4,6,6,
398 /*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
399 };
400
401 void FASTAPASS(1) X6502_IRQBegin_c(int w)
402 {
403  dprintf("IRQB %02x",w);
404  _IRQlow|=w;
405 }
406
407 void FASTAPASS(1) X6502_IRQEnd_c(int w)
408 {
409  dprintf("IRQE %02x",w);
410  _IRQlow&=~w;
411 }
412
413 void TriggerIRQ_c(void) /* This function should probably be phased out. */
414 {
415  _IRQlow|=FCEU_IQTEMP;
416 }
417
418 void TriggerNMI_c(void)
419 {
420  _IRQlow|=FCEU_IQNMI;
421 }
422
423 static void TriggerNMIReal(void)
424 {
425  if(!_jammed)
426  {
427   dprintf("NMI");
428   ADDCYC(7);
429   PUSH(_PC>>8);
430   PUSH(_PC);
431   _P&=~B_FLAG;
432   PUSH(_P|U_FLAG);
433   _PC=RdMem(0xFFFA);
434   _PC|=RdMem(0xFFFB)<<8;
435 #ifdef DEBUG_ASM_6502
436   PC_prev = _PC;
437   OP_prev = 0x100;
438 #endif
439  }
440 }
441
442 void TriggerIRQReal(void)
443 {
444  if(!(_PI&I_FLAG) && !_jammed)
445  {
446   dprintf("IRQ");
447   ADDCYC(7);
448   PUSH(_PC>>8);
449   PUSH(_PC);
450   _P&=~B_FLAG;
451   PUSH(_P|U_FLAG);
452   _P|=I_FLAG;
453   _PC=RdMem(0xFFFE);
454   _PC|=RdMem(0xFFFF)<<8;
455 #ifdef DEBUG_ASM_6502
456   PC_prev = _PC;
457   OP_prev = 0x101;
458 #endif
459  }
460 }
461
462 void X6502_Reset_c(void)
463 {
464   _PC=RdMem(0xFFFC);
465   _PC|=RdMem(0xFFFD)<<8;
466   _jammed=0;
467   _PI=_P=I_FLAG;
468 }
469
470 void X6502_Power_c(void)
471 {
472  memset((void *)&X,0,sizeof(X));
473  timestamp=0;
474  X6502_Reset_c();
475 }
476
477
478 //int asdc = 0;
479 void X6502_Run_c(void/*int32 cycles*/)
480 {
481 /*
482         if(PAL)
483          cycles*=15;          // 15*4=60
484         else
485          cycles*=16;          // 16*4=64
486
487         _count+=cycles;
488 */
489 //      if (_count <= 0) asdc++;
490
491         while(_count>0)
492         {
493          int32 temp;
494          uint8 b1;
495
496          if(_IRQlow)
497          {
498           if(_IRQlow&FCEU_IQNMI)
499            TriggerNMIReal();
500           else
501            TriggerIRQReal();
502
503           _IRQlow&=~(FCEU_IQTEMP|FCEU_IQNMI);
504           if(_count<=0)
505           {
506 #ifdef DEBUG_ASM_6502
507            if(MapIRQHook) mapirq_cyc_c = _tcount;
508            _tcount=0;
509 #endif
510            _PI=_P;
511            return; /* Should increase accuracy without a major speed hit. */
512           }
513          }
514          _PI=_P;
515 #ifdef DEBUG_ASM_6502
516          b1=RdMem(_PC++); _PC--;
517 #else
518          b1=RdMem(_PC);
519 #endif
520          ADDCYC(CycTable[b1]);
521          temp=_tcount;
522
523          temp*=48;
524
525          fhcnt-=temp;
526          if(fhcnt<=0)
527          {
528           FrameSoundUpdate();
529           fhcnt+=fhinc;
530          }
531
532          if(PCMIRQCount>0)
533          {
534           PCMIRQCount-=temp;
535           if(PCMIRQCount<=0)
536           {
537            vdis=1;
538            if((PSG[0x10]&0x80) && !(PSG[0x10]&0x40))
539            {
540             extern uint8 SIRQStat;
541             SIRQStat|=0x80;
542             X6502_IRQBegin(FCEU_IQDPCM);
543            }
544           }
545          }
546
547 #ifdef DEBUG_ASM_6502
548          PC_prev = _PC;
549          OP_prev = b1;
550 #endif
551           //printf("$%04x:$%02x\n",_PC,b1);
552          //_PC++;
553          //printf("$%02x\n",b1);
554          _PC++;
555          switch(b1)
556          {
557           #include "ops.h"
558          }
559
560          temp=_tcount; /* Gradius II (J) glitches if _tcount is not used */
561          _tcount=0;
562
563          if(MapIRQHook) {
564 #ifdef DEBUG_ASM_6502
565           mapirq_cyc_c = temp;
566 #endif
567           MapIRQHook(temp);
568          }
569
570 #ifdef DEBUG_ASM_6502
571          _PI=_P;
572 #endif
573         }
574 }
575
576