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