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