Page[] mappings in mapper code, X.DB update for games with no controls
[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 && A != _PC - 1 && 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 /*0x00*/ 7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,
383 /*0x10*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
384 /*0x20*/ 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,
385 /*0x30*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
386 /*0x40*/ 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,
387 /*0x50*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
388 /*0x60*/ 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,
389 /*0x70*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
390 /*0x80*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
391 /*0x90*/ 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,
392 /*0xA0*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
393 /*0xB0*/ 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,
394 /*0xC0*/ 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
395 /*0xD0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
396 /*0xE0*/ 2,6,3,8,3,3,5,5,2,2,2,2,4,4,6,6,
397 /*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
398 };
399
400 void FASTAPASS(1) X6502_IRQBegin_c(int w)
401 {
402  dprintf("IRQB %02x",w);
403  _IRQlow|=w;
404 }
405
406 void FASTAPASS(1) X6502_IRQEnd_c(int w)
407 {
408  dprintf("IRQE %02x",w);
409  _IRQlow&=~w;
410 }
411
412 void TriggerIRQ_c(void) /* This function should probably be phased out. */
413 {
414  _IRQlow|=FCEU_IQTEMP;
415 }
416
417 void TriggerNMINSF_c(void)
418 {
419  ADDCYC(7);
420  PUSH(_PC>>8);
421  PUSH(_PC);
422  PUSH((_P&~B_FLAG)|(U_FLAG));
423  _PC=0x3800;
424 }
425
426 void TriggerNMI_c(void)
427 {
428  _IRQlow|=FCEU_IQNMI;
429 }
430
431 static void TriggerNMIReal(void)
432 {
433  if(!_jammed)
434  {
435   dprintf("NMI");
436   ADDCYC(7);
437   PUSH(_PC>>8);
438   PUSH(_PC);
439   _P&=~B_FLAG;
440   PUSH(_P|U_FLAG);
441   _PC=RdMem(0xFFFA);
442   _PC|=RdMem(0xFFFB)<<8;
443 #ifdef DEBUG_ASM_6502
444   PC_prev = _PC;
445   OP_prev = 0x100;
446 #endif
447  }
448 }
449
450 void TriggerIRQReal(void)
451 {
452  if(!(_PI&I_FLAG) && !_jammed)
453  {
454   dprintf("IRQ");
455   ADDCYC(7);
456   PUSH(_PC>>8);
457   PUSH(_PC);
458   _P&=~B_FLAG;
459   PUSH(_P|U_FLAG);
460   _P|=I_FLAG;
461   _PC=RdMem(0xFFFE);
462   _PC|=RdMem(0xFFFF)<<8;
463 #ifdef DEBUG_ASM_6502
464   PC_prev = _PC;
465   OP_prev = 0x101;
466 #endif
467  }
468 }
469
470 void X6502_Reset_c(void)
471 {
472   _PC=RdMem(0xFFFC);
473   _PC|=RdMem(0xFFFD)<<8;
474   _jammed=0;
475   _PI=_P=I_FLAG;
476 }
477
478 void X6502_Power_c(void)
479 {
480  memset((void *)&X,0,sizeof(X));
481  timestamp=0;
482  X6502_Reset_c();
483 }
484
485
486 //int asdc = 0;
487 void X6502_Run_c(void/*int32 cycles*/)
488 {
489 /*
490         if(PAL)
491          cycles*=15;          // 15*4=60
492         else
493          cycles*=16;          // 16*4=64
494
495         _count+=cycles;
496 */
497 //      if (_count <= 0) asdc++;
498
499         while(_count>0)
500         {
501          int32 temp;
502          uint8 b1;
503
504          if(_IRQlow)
505          {
506           if(_IRQlow&FCEU_IQNMI)
507            TriggerNMIReal();
508           else
509            TriggerIRQReal();
510
511           _IRQlow&=~(FCEU_IQTEMP|FCEU_IQNMI);
512           if(_count<=0)
513           {
514 #ifdef DEBUG_ASM_6502
515            if(MapIRQHook) mapirq_cyc_c = _tcount;
516            _tcount=0;
517 #endif
518            _PI=_P;
519            return; /* Should increase accuracy without a major speed hit. */
520           }
521          }
522          _PI=_P;
523          b1=RdMem(_PC);
524          ADDCYC(CycTable[b1]);
525          temp=_tcount;
526
527          temp*=48;
528
529          fhcnt-=temp;
530          if(fhcnt<=0)
531          {
532           FrameSoundUpdate();
533           fhcnt+=fhinc;
534          }
535
536          if(PCMIRQCount>0)
537          {
538           PCMIRQCount-=temp;
539           if(PCMIRQCount<=0)
540           {
541            vdis=1;
542            if((PSG[0x10]&0x80) && !(PSG[0x10]&0x40))
543            {
544             extern uint8 SIRQStat;
545             SIRQStat|=0x80;
546             X6502_IRQBegin_c(FCEU_IQDPCM);
547            }
548           }
549          }
550
551 #ifdef DEBUG_ASM_6502
552          PC_prev = _PC;
553          OP_prev = b1;
554 #endif
555           //printf("$%04x:$%02x\n",_PC,b1);
556          //_PC++;
557          //printf("$%02x\n",b1);
558          _PC++;
559          switch(b1)
560          {
561           #include "ops.h"
562          }
563
564          temp=_tcount; /* Gradius II (J) glitches if _tcount is not used */
565          _tcount=0;
566
567          if(MapIRQHook) {
568 #ifdef DEBUG_ASM_6502
569           mapirq_cyc_c = temp;
570 #endif
571           MapIRQHook(temp);
572          }
573
574 #ifdef DEBUG_ASM_6502
575          _PI=_P;
576 #endif
577         }
578 }
579
580