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