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