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