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