]> Shamusworld >> Repos - apple2/blob - src/v65c02.cpp
05acaed04cc2cbc4c7af3bbe636ae46efba34cc0
[apple2] / src / v65c02.cpp
1 //
2 // Virtual 65C02 Emulator v1.1
3 //
4 // by James Hammons
5 // (c) 2005-2018 Underground Software
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
10 // ---  ----------  -----------------------------------------------------------
11 // JLH  01/04/2006  Added changelog ;-)
12 // JLH  01/18/2009  Fixed EA_ABS_* macros
13 //
14
15 //OK, the wraparound bug exists in both the Apple and Atari versions of Ultima
16 //II. However, the Atari version *does* occassionally pick strength while the
17 //Apple versions do not--which would seem to indicate a bug either in the RNG
18 //algorithm, the 65C02 core, or the Apple hardware. Need to investigate all
19 //three!
20 //N.B.: There were some lingering bugs in the BCD portions of the ADC and SBC
21 //      opcodes; need to test to see if that clears up the problem.
22
23 #define __DEBUG__
24 //#define __DEBUGMON__
25
26 #include "v65c02.h"
27
28 #ifdef __DEBUG__
29 #include <string.h>
30 #include "dis65c02.h"
31 #include "log.h"
32 #endif
33
34
35 // Various helper macros
36
37 #define CLR_Z                           (regs->cc &= ~FLAG_Z)
38 #define CLR_ZN                          (regs->cc &= ~(FLAG_Z | FLAG_N))
39 #define CLR_ZNC                         (regs->cc &= ~(FLAG_Z | FLAG_N | FLAG_C))
40 #define CLR_V                           (regs->cc &= ~FLAG_V)
41 #define CLR_N                           (regs->cc &= ~FLAG_N)
42 #define CLR_D                           (regs->cc &= ~FLAG_D)
43 #define SET_Z(r)                        (regs->cc = ((r) == 0 ? regs->cc | FLAG_Z : regs->cc & ~FLAG_Z))
44 #define SET_N(r)                        (regs->cc = ((r) & 0x80 ? regs->cc | FLAG_N : regs->cc & ~FLAG_N))
45 #define SET_I                           (regs->cc |= FLAG_I)
46
47 //Not sure that this code is computing the carry correctly... Investigate! [Seems to be]
48 /*
49 Not 100% sure (for SET_C_CMP), when we have things like this:
50 D0BE: AC 6F D3  LDY  $D36F     [SP=01EC, CC=--.--IZ-, A=AA, X=60, Y=00]
51 D0C1: CC 5A D3  CPY  $D35A     [SP=01EC, CC=--.--IZC, A=AA, X=60, Y=00]
52 D0C4: F0 0F     BEQ  $D0D5     [SP=01EC, CC=--.--IZC, A=AA, X=60, Y=00]
53 D0D5: AD 6E D3  LDA  $D36E     [SP=01EC, CC=--.--I-C, A=0A, X=60, Y=00]
54
55 Which shows that $D35A has to be 0 since the Z flag is set.  Why would the carry flag be set on a comparison where the compared items are equal?
56 */
57 #define SET_C_ADD(a,b)          (regs->cc = ((uint8_t)(b) > (uint8_t)(~(a)) ? regs->cc | FLAG_C : regs->cc & ~FLAG_C))
58 #define SET_C_CMP(a,b)          (regs->cc = ((uint8_t)(b) >= (uint8_t)(a) ? regs->cc | FLAG_C : regs->cc & ~FLAG_C))
59 #define SET_ZN(r)                       SET_N(r); SET_Z(r)
60 #define SET_ZNC_ADD(a,b,r)      SET_N(r); SET_Z(r); SET_C_ADD(a,b)
61 #define SET_ZNC_CMP(a,b,r)      SET_N(r); SET_Z(r); SET_C_CMP(a,b)
62
63 #define EA_IMM                          regs->pc++
64 #define EA_ZP                           regs->RdMem(regs->pc++)
65 #define EA_ZP_X                         (regs->RdMem(regs->pc++) + regs->x) & 0xFF
66 #define EA_ZP_Y                         (regs->RdMem(regs->pc++) + regs->y) & 0xFF
67 #define EA_ABS                          FetchMemW(regs->pc)
68 #define EA_ABS_X                        FetchMemW(regs->pc) + regs->x
69 #define EA_ABS_Y                        FetchMemW(regs->pc) + regs->y
70 #define EA_IND_ZP_X                     RdMemWZP((regs->RdMem(regs->pc++) + regs->x) & 0xFF)
71 #define EA_IND_ZP_Y                     RdMemWZP(regs->RdMem(regs->pc++)) + regs->y
72 #define EA_IND_ZP                       RdMemWZP(regs->RdMem(regs->pc++))
73
74 #define READ_IMM                        regs->RdMem(EA_IMM)
75 #define READ_ZP                         regs->RdMem(EA_ZP)
76 #define READ_ZP_X                       regs->RdMem(EA_ZP_X)
77 #define READ_ZP_Y                       regs->RdMem(EA_ZP_Y)
78 #define READ_ABS                        regs->RdMem(EA_ABS)
79 #define READ_ABS_X                      regs->RdMem(EA_ABS_X)
80 #define READ_ABS_Y                      regs->RdMem(EA_ABS_Y)
81 #define READ_IND_ZP_X           regs->RdMem(EA_IND_ZP_X)
82 #define READ_IND_ZP_Y           regs->RdMem(EA_IND_ZP_Y)
83 #define READ_IND_ZP                     regs->RdMem(EA_IND_ZP)
84
85 #define READ_IMM_WB(v)          uint16_t addr = EA_IMM;      v = regs->RdMem(addr)
86 #define READ_ZP_WB(v)           uint16_t addr = EA_ZP;       v = regs->RdMem(addr)
87 #define READ_ZP_X_WB(v)         uint16_t addr = EA_ZP_X;     v = regs->RdMem(addr)
88 #define READ_ABS_WB(v)          uint16_t addr = EA_ABS;      v = regs->RdMem(addr)
89 #define READ_ABS_X_WB(v)        uint16_t addr = EA_ABS_X;    v = regs->RdMem(addr)
90 #define READ_ABS_Y_WB(v)        uint16_t addr = EA_ABS_Y;    v = regs->RdMem(addr)
91 #define READ_IND_ZP_X_WB(v)     uint16_t addr = EA_IND_ZP_X; v = regs->RdMem(addr)
92 #define READ_IND_ZP_Y_WB(v)     uint16_t addr = EA_IND_ZP_Y; v = regs->RdMem(addr)
93 #define READ_IND_ZP_WB(v)       uint16_t addr = EA_IND_ZP;   v = regs->RdMem(addr)
94
95 #define WRITE_BACK(d)           regs->WrMem(addr, (d))
96
97
98 // Private global variables
99
100 static V65C02REGS * regs;
101
102 // Cycle counts should be correct for the the Rockwell version of the 65C02.
103 // Extra cycles for page crossing or BCD mode are accounted for in their
104 // respective opcode handlers.
105 static uint8_t CPUCycles[256] = {
106         7, 6, 2, 2, 5, 3, 5, 5, 3, 2, 2, 2, 6, 4, 6, 5,
107         2, 5, 5, 2, 5, 4, 6, 5, 2, 4, 2, 2, 6, 4, 6, 5,
108         6, 6, 2, 2, 3, 3, 5, 5, 4, 2, 2, 2, 4, 2, 6, 5,
109         2, 5, 5, 2, 4, 4, 6, 5, 2, 4, 2, 2, 4, 4, 6, 5,
110         6, 6, 2, 2, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 5,
111         2, 5, 5, 2, 4, 4, 6, 5, 2, 4, 3, 2, 8, 4, 6, 5,
112         6, 6, 2, 2, 3, 3, 5, 5, 4, 2, 2, 2, 6, 4, 6, 5,
113         2, 5, 5, 2, 4, 4, 6, 5, 2, 4, 4, 2, 6, 4, 6, 5,
114         2, 6, 2, 2, 3, 3, 3, 5, 2, 2, 2, 2, 4, 4, 4, 5,
115         2, 6, 5, 2, 4, 4, 4, 5, 2, 5, 2, 2, 4, 5, 5, 5,
116         2, 6, 2, 2, 3, 3, 3, 5, 2, 2, 2, 2, 4, 4, 4, 5,
117         2, 5, 5, 2, 4, 4, 4, 5, 2, 4, 2, 2, 4, 4, 4, 5,
118         2, 6, 2, 2, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 5, 5,
119         2, 5, 5, 2, 4, 4, 6, 5, 2, 4, 3, 2, 4, 4, 6, 5,
120         2, 6, 2, 2, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 5,
121         2, 5, 5, 2, 4, 4, 6, 5, 2, 4, 4, 2, 4, 4, 6, 5 };
122
123
124 //
125 // Read a uint16_t out of 65C02 memory (big endian format)
126 //
127 static inline uint16_t RdMemW(uint16_t address)
128 {
129         return (uint16_t)(regs->RdMem(address + 1) << 8)
130                 | regs->RdMem(address + 0);
131 }
132
133
134 //
135 // Read a uint16_t out of 65C02 memory (big endian format), wrapping on page 0
136 //
137 static inline uint16_t RdMemWZP(uint16_t address)
138 {
139         return (uint16_t)(regs->RdMem((address + 1) & 0xFF) << 8)
140                 | regs->RdMem(address + 0);
141 }
142
143
144 //
145 // Read a uint16_t out of 65C02 memory (big endian format) and increment PC
146 //
147 static inline uint16_t FetchMemW(uint16_t address)
148 {
149         regs->pc += 2;
150         return (uint16_t)(regs->RdMem(address + 1) << 8)
151                 | regs->RdMem(address + 0);
152 }
153
154
155 //
156 // 65C02 OPCODE IMPLEMENTATION
157 //
158 // NOTE: Lots of macros are used here to save a LOT of typing.  Also
159 //       helps speed the debugging process.  :-)  Because of this, combining
160 //       certain lines may look like a good idea but would end in disaster.
161 //       You have been warned!  ;-)
162 //
163
164 // Page crossing macros.  These catch the cases where access of a certain type
165 // will incur a one cycle penalty when crossing a page boundary.
166
167 #define HANDLE_PAGE_CROSSING_IND_Y \
168         uint16_t addressLo = regs->RdMem(regs->RdMem(regs->pc)); \
169 \
170         if ((addressLo + regs->y) > 0xFF) \
171                 regs->clock++;
172
173 #define HANDLE_PAGE_CROSSING_ABS_X \
174         uint16_t addressLo = regs->RdMem(regs->pc); \
175 \
176         if ((addressLo + regs->x) > 0xFF) \
177                 regs->clock++;
178
179 #define HANDLE_PAGE_CROSSING_ABS_Y \
180         uint16_t addressLo = regs->RdMem(regs->pc); \
181 \
182         if ((addressLo + regs->y) > 0xFF) \
183                 regs->clock++;
184
185 // Branch taken adds a cycle, crossing page adds one more
186
187 #define HANDLE_BRANCH_TAKEN(m)       \
188 {                                    \
189         uint16_t oldpc = regs->pc;       \
190         regs->pc += m;                   \
191         regs->clock++;                   \
192                                      \
193         if ((oldpc ^ regs->pc) & 0xFF00) \
194                 regs->clock++;               \
195 }
196
197 /*
198 Mnemonic        Addressing mode Form            Opcode  Size    Timing
199
200 ADC                     Immediate               ADC #Oper       69              2               2
201                         Zero Page               ADC Zpg         65              2               3
202                         Zero Page,X             ADC Zpg,X       75              2               4
203                         Absolute                ADC Abs         6D              3               4
204                         Absolute,X              ADC Abs,X       7D              3               4
205                         Absolute,Y              ADC Abs,Y       79              3               4
206                         (Zero Page,X)   ADC (Zpg,X)     61              2               6
207                         (Zero Page),Y   ADC (Zpg),Y     71              2               5
208                         (Zero Page)             ADC (Zpg)       72              2               5
209 */
210
211 // ADC opcodes
212
213 //This is non-optimal, but it works--optimize later. :-)
214 //N.B.: We have to pull the low nybble from each part of the sum in order to
215 //      check BCD addition of the low nybble correctly.  It doesn't work to
216 //      look at the sum after summing the bytes.  Also, Decimal mode incurs a
217 //      one cycle penalty (for the decimal correction).
218 #define OP_ADC_HANDLER(m) \
219         uint16_t sum = (uint16_t)regs->a + (m) + (uint16_t)(regs->cc & FLAG_C); \
220 \
221         if (regs->cc & FLAG_D) \
222         { \
223                 uint8_t an = regs->a & 0x0F, mn = (m) & 0x0F, cn = (uint8_t)(regs->cc & FLAG_C); \
224 \
225                 if ((an + mn + cn) > 9) \
226                         sum += 0x06; \
227 \
228                 if ((sum & 0x1F0) > 0x90) \
229                         sum += 0x60; \
230 \
231                 regs->clock++;\
232         } \
233 \
234         regs->cc = (regs->cc & ~FLAG_C) | (sum >> 8); \
235         regs->cc = (~(regs->a ^ (m)) & (regs->a ^ sum) & 0x80 ? regs->cc | FLAG_V : regs->cc & ~FLAG_V); \
236         regs->a = sum & 0xFF; \
237         SET_ZN(regs->a)
238
239 static void Op69(void)                                                  // ADC #
240 {
241         uint16_t m = READ_IMM;
242         OP_ADC_HANDLER(m);
243 }
244
245 static void Op65(void)                                                  // ADC ZP
246 {
247         uint16_t m = READ_ZP;
248         OP_ADC_HANDLER(m);
249 }
250
251 static void Op75(void)                                                  // ADC ZP, X
252 {
253         uint16_t m = READ_ZP_X;
254         OP_ADC_HANDLER(m);
255 }
256
257 static void Op6D(void)                                                  // ADC ABS
258 {
259         uint16_t m = READ_ABS;
260         OP_ADC_HANDLER(m);
261 }
262
263 static void Op7D(void)                                                  // ADC ABS, X
264 {
265         HANDLE_PAGE_CROSSING_ABS_X;
266         uint16_t m = READ_ABS_X;
267         OP_ADC_HANDLER(m);
268 }
269
270 static void Op79(void)                                                  // ADC ABS, Y
271 {
272         HANDLE_PAGE_CROSSING_ABS_Y;
273         uint16_t m = READ_ABS_Y;
274         OP_ADC_HANDLER(m);
275 }
276
277 static void Op61(void)                                                  // ADC (ZP, X)
278 {
279         uint16_t m = READ_IND_ZP_X;
280         OP_ADC_HANDLER(m);
281 }
282
283 static void Op71(void)                                                  // ADC (ZP), Y
284 {
285         HANDLE_PAGE_CROSSING_IND_Y;
286         uint16_t m = READ_IND_ZP_Y;
287         OP_ADC_HANDLER(m);
288 }
289
290 static void Op72(void)                                                  // ADC (ZP)
291 {
292         uint16_t m = READ_IND_ZP;
293         OP_ADC_HANDLER(m);
294 }
295
296 /*
297 AND     Immediate       AND #Oper       29      2       2
298 Zero Page               AND Zpg         25      2       3
299 Zero Page,X             AND Zpg,X       35      2       4
300 Absolute                AND Abs         2D      3       4
301 Absolute,X              AND Abs,X       3D      3       4
302 Absolute,Y              AND Abs,Y       39      3       4
303 (Zero Page,X)   AND (Zpg,X)     21      2       6
304 (Zero Page),Y   AND (Zpg),Y     31      2       5
305 (Zero Page)             AND (Zpg)       32      2       5
306 */
307
308 // AND opcodes
309
310 #define OP_AND_HANDLER(m) \
311         regs->a &= m; \
312         SET_ZN(regs->a)
313
314 static void Op29(void)                                                  // AND #
315 {
316         uint8_t m = READ_IMM;
317         OP_AND_HANDLER(m);
318 }
319
320 static void Op25(void)                                                  // AND ZP
321 {
322         uint8_t m = READ_ZP;
323         OP_AND_HANDLER(m);
324 }
325
326 static void Op35(void)                                                  // AND ZP, X
327 {
328         uint8_t m = READ_ZP_X;
329         OP_AND_HANDLER(m);
330 }
331
332 static void Op2D(void)                                                  // AND ABS
333 {
334         uint8_t m = READ_ABS;
335         OP_AND_HANDLER(m);
336 }
337
338 static void Op3D(void)                                                  // AND ABS, X
339 {
340         HANDLE_PAGE_CROSSING_ABS_X;
341         uint8_t m = READ_ABS_X;
342         OP_AND_HANDLER(m);
343 }
344
345 static void Op39(void)                                                  // AND ABS, Y
346 {
347         HANDLE_PAGE_CROSSING_ABS_Y;
348         uint8_t m = READ_ABS_Y;
349         OP_AND_HANDLER(m);
350 }
351
352 static void Op21(void)                                                  // AND (ZP, X)
353 {
354         uint8_t m = READ_IND_ZP_X;
355         OP_AND_HANDLER(m);
356 }
357
358 static void Op31(void)                                                  // AND (ZP), Y
359 {
360         HANDLE_PAGE_CROSSING_IND_Y;
361         uint8_t m = READ_IND_ZP_Y;
362         OP_AND_HANDLER(m);
363 }
364
365 static void Op32(void)                                                  // AND (ZP)
366 {
367         uint8_t m = READ_IND_ZP;
368         OP_AND_HANDLER(m);
369 }
370
371 /*
372 ASL     Accumulator     ASL A           0A      1       2
373 Zero Page               ASL Zpg         06      2       5
374 Zero Page,X             ASL Zpg,X       16      2       6
375 Absolute                ASL Abs         0E      3       6
376 Absolute,X              ASL Abs,X       1E      3       7
377 */
378
379 // ASL opcodes
380
381 #define OP_ASL_HANDLER(m) \
382         regs->cc = ((m) & 0x80 ? regs->cc | FLAG_C : regs->cc & ~FLAG_C); \
383         (m) <<= 1; \
384         SET_ZN((m))
385
386 static void Op0A(void)                                                  // ASL A
387 {
388         OP_ASL_HANDLER(regs->a);
389 }
390
391 static void Op06(void)                                                  // ASL ZP
392 {
393         uint8_t m;
394         READ_ZP_WB(m);
395         OP_ASL_HANDLER(m);
396         WRITE_BACK(m);
397 }
398
399 static void Op16(void)                                                  // ASL ZP, X
400 {
401         uint8_t m;
402         READ_ZP_X_WB(m);
403         OP_ASL_HANDLER(m);
404         WRITE_BACK(m);
405 }
406
407 static void Op0E(void)                                                  // ASL ABS
408 {
409         uint8_t m;
410         READ_ABS_WB(m);
411         OP_ASL_HANDLER(m);
412         WRITE_BACK(m);
413 }
414
415 static void Op1E(void)                                                  // ASL ABS, X
416 {
417         HANDLE_PAGE_CROSSING_ABS_X;
418         uint8_t m;
419         READ_ABS_X_WB(m);
420         OP_ASL_HANDLER(m);
421         WRITE_BACK(m);
422 }
423
424 /*
425 BBR0    ZP, Relative    BBR0 Oper       0F      3       5
426 BBR1    ZP, Relative    BBR1 Oper       1F      3       5
427 BBR2    ZP, Relative    BBR2 Oper       2F      3       5
428 BBR3    ZP, Relative    BBR3 Oper       3F      3       5
429 BBR4    ZP, Relative    BBR4 Oper       4F      3       5
430 BBR5    ZP, Relative    BBR5 Oper       5F      3       5
431 BBR6    ZP, Relative    BBR6 Oper       6F      3       5
432 BBR7    ZP, Relative    BBR7 Oper       7F      3       5
433 BBS0    ZP, Relative    BBS0 Oper       8F      3       5
434 BBS1    ZP, Relative    BBS1 Oper       9F      3       5
435 BBS2    ZP, Relative    BBS2 Oper       AF      3       5
436 BBS3    ZP, Relative    BBS3 Oper       BF      3       5
437 BBS4    ZP, Relative    BBS4 Oper       CF      3       5
438 BBS5    ZP, Relative    BBS5 Oper       DF      3       5
439 BBS6    ZP, Relative    BBS6 Oper       EF      3       5
440 BBS7    ZP, Relative    BBS7 Oper       FF      3       5
441 */
442
443 // BBR/Sn opcodes
444
445 static void Op0F(void)                                                  // BBR0
446 {
447         uint8_t b = READ_ZP;
448         int16_t m = (int16_t)(int8_t)READ_IMM;
449
450         if (!(b & 0x01))
451                 HANDLE_BRANCH_TAKEN(m);
452 }
453
454 static void Op1F(void)                                                  // BBR1
455 {
456         uint8_t b = READ_ZP;
457         int16_t m = (int16_t)(int8_t)READ_IMM;
458
459         if (!(b & 0x02))
460                 HANDLE_BRANCH_TAKEN(m);
461 }
462
463 static void Op2F(void)                                                  // BBR2
464 {
465         uint8_t b = READ_ZP;
466         int16_t m = (int16_t)(int8_t)READ_IMM;
467
468         if (!(b & 0x04))
469                 HANDLE_BRANCH_TAKEN(m);
470 }
471
472 static void Op3F(void)                                                  // BBR3
473 {
474         uint8_t b = READ_ZP;
475         int16_t m = (int16_t)(int8_t)READ_IMM;
476
477         if (!(b & 0x08))
478                 HANDLE_BRANCH_TAKEN(m);
479 }
480
481 static void Op4F(void)                                                  // BBR4
482 {
483         uint8_t b = READ_ZP;
484         int16_t m = (int16_t)(int8_t)READ_IMM;
485
486         if (!(b & 0x10))
487                 HANDLE_BRANCH_TAKEN(m);
488 }
489
490 static void Op5F(void)                                                  // BBR5
491 {
492         uint8_t b = READ_ZP;
493         int16_t m = (int16_t)(int8_t)READ_IMM;
494
495         if (!(b & 0x20))
496                 HANDLE_BRANCH_TAKEN(m);
497 }
498
499 static void Op6F(void)                                                  // BBR6
500 {
501         uint8_t b = READ_ZP;
502         int16_t m = (int16_t)(int8_t)READ_IMM;
503
504         if (!(b & 0x40))
505                 HANDLE_BRANCH_TAKEN(m);
506 }
507
508 static void Op7F(void)                                                  // BBR7
509 {
510         uint8_t b = READ_ZP;
511         int16_t m = (int16_t)(int8_t)READ_IMM;
512
513         if (!(b & 0x80))
514                 HANDLE_BRANCH_TAKEN(m);
515 }
516
517 static void Op8F(void)                                                  // BBS0
518 {
519         uint8_t b = READ_ZP;
520         int16_t m = (int16_t)(int8_t)READ_IMM;
521
522         if (b & 0x01)
523                 HANDLE_BRANCH_TAKEN(m);
524 }
525
526 static void Op9F(void)                                                  // BBS1
527 {
528         uint8_t b = READ_ZP;
529         int16_t m = (int16_t)(int8_t)READ_IMM;
530
531         if (b & 0x02)
532                 HANDLE_BRANCH_TAKEN(m);
533 }
534
535 static void OpAF(void)                                                  // BBS2
536 {
537         uint8_t b = READ_ZP;
538         int16_t m = (int16_t)(int8_t)READ_IMM;
539
540         if (b & 0x04)
541                 HANDLE_BRANCH_TAKEN(m);
542 }
543
544 static void OpBF(void)                                                  // BBS3
545 {
546         uint8_t b = READ_ZP;
547         int16_t m = (int16_t)(int8_t)READ_IMM;
548
549         if (b & 0x08)
550                 HANDLE_BRANCH_TAKEN(m);
551 }
552
553 static void OpCF(void)                                                  // BBS4
554 {
555         uint8_t b = READ_ZP;
556         int16_t m = (int16_t)(int8_t)READ_IMM;
557
558         if (b & 0x10)
559                 HANDLE_BRANCH_TAKEN(m);
560 }
561
562 static void OpDF(void)                                                  // BBS5
563 {
564         uint8_t b = READ_ZP;
565         int16_t m = (int16_t)(int8_t)READ_IMM;
566
567         if (b & 0x20)
568                 HANDLE_BRANCH_TAKEN(m);
569 }
570
571 static void OpEF(void)                                                  // BBS6
572 {
573         uint8_t b = READ_ZP;
574         int16_t m = (int16_t)(int8_t)READ_IMM;
575
576         if (b & 0x40)
577                 HANDLE_BRANCH_TAKEN(m);
578 }
579
580 static void OpFF(void)                                                  // BBS7
581 {
582         uint8_t b = READ_ZP;
583         int16_t m = (int16_t)(int8_t)READ_IMM;
584
585         if (b & 0x80)
586                 HANDLE_BRANCH_TAKEN(m);
587 }
588
589 /*
590 BCC     Relative        BCC Oper        90      2       2
591 BCS     Relative        BCS Oper        B0      2       2
592 BEQ     Relative        BEQ Oper        F0      2       2
593 */
594
595 // Branch opcodes
596
597 static void Op90(void)                                                  // BCC
598 {
599         int16_t m = (int16_t)(int8_t)READ_IMM;
600
601         if (!(regs->cc & FLAG_C))
602                 HANDLE_BRANCH_TAKEN(m)
603 }
604
605 static void OpB0(void)                                                  // BCS
606 {
607         int16_t m = (int16_t)(int8_t)READ_IMM;
608
609         if (regs->cc & FLAG_C)
610                 HANDLE_BRANCH_TAKEN(m)
611 }
612
613 static void OpF0(void)                                                  // BEQ
614 {
615         int16_t m = (int16_t)(int8_t)READ_IMM;
616
617         if (regs->cc & FLAG_Z)
618                 HANDLE_BRANCH_TAKEN(m)
619 }
620
621 /*
622 BIT     Immediate       BIT #Oper       89      2       2
623 Zero Page               BIT Zpg         24      2       3
624 Zero Page,X             BIT Zpg,X       34      2       4
625 Absolute                BIT Abs         2C      3       4
626 Absolute,X              BIT Abs,X       3C      3       4
627 */
628
629 // BIT opcodes
630
631 /* 1. The BIT instruction copies bit 6 to the V flag, and bit 7 to the N flag
632       (except in immediate addressing mode where V & N are untouched.) The
633       accumulator and the operand are ANDed and the Z flag is set
634       appropriately. */
635
636 #define OP_BIT_HANDLER(m) \
637         int8_t result = regs->a & (m); \
638         regs->cc &= ~(FLAG_N | FLAG_V); \
639         regs->cc |= ((m) & 0xC0); \
640         SET_Z(result)
641
642 static void Op89(void)                                                  // BIT #
643 {
644         int8_t m = READ_IMM;
645         int8_t result = regs->a & m;
646         SET_Z(result);
647 }
648
649 static void Op24(void)                                                  // BIT ZP
650 {
651         int8_t m = READ_ZP;
652         OP_BIT_HANDLER(m);
653 }
654
655 static void Op34(void)                                                  // BIT ZP, X
656 {
657         uint8_t m = READ_ZP_X;
658         OP_BIT_HANDLER(m);
659 }
660
661 static void Op2C(void)                                                  // BIT ABS
662 {
663         uint8_t m = READ_ABS;
664         OP_BIT_HANDLER(m);
665 }
666
667 static void Op3C(void)                                                  // BIT ABS, X
668 {
669         HANDLE_PAGE_CROSSING_ABS_X;
670         uint8_t m = READ_ABS_X;
671         OP_BIT_HANDLER(m);
672 }
673
674 /*
675 BMI     Relative        BMI Oper        30      2       2
676 BNE     Relative        BNE Oper        D0      2       2
677 BPL     Relative        BPL Oper        10      2       2
678 BRA     Relative        BRA Oper        80      2       3
679 */
680
681 // More branch opcodes
682
683 static void Op30(void)                                                  // BMI
684 {
685         int16_t m = (int16_t)(int8_t)READ_IMM;
686
687         if (regs->cc & FLAG_N)
688                 HANDLE_BRANCH_TAKEN(m)
689 }
690
691 static void OpD0(void)                                                  // BNE
692 {
693         int16_t m = (int16_t)(int8_t)READ_IMM;
694
695         if (!(regs->cc & FLAG_Z))
696                 HANDLE_BRANCH_TAKEN(m)
697 }
698
699 static void Op10(void)                                                  // BPL
700 {
701         int16_t m = (int16_t)(int8_t)READ_IMM;
702
703         if (!(regs->cc & FLAG_N))
704                 HANDLE_BRANCH_TAKEN(m)
705 }
706
707 static void Op80(void)                                                  // BRA
708 {
709         int16_t m = (int16_t)(int8_t)READ_IMM;
710         HANDLE_BRANCH_TAKEN(m)
711 }
712
713 /*
714 BRK     Implied         BRK                     00      1       7
715 */
716
717 static void Op00(void)                                                  // BRK
718 {
719 //#ifdef __DEBUG__
720 #if 1
721 WriteLog("\n*** BRK ***\n\n");
722 WriteLog(" [PC=%04X, SP=%04X, CC=%s%s.%s%s%s%s%s, A=%02X, X=%02X, Y=%02X]\n",
723         regs->pc, 0x0100 + regs->sp,
724         (regs->cc & FLAG_N ? "N" : "-"), (regs->cc & FLAG_V ? "V" : "-"),
725         (regs->cc & FLAG_B ? "B" : "-"), (regs->cc & FLAG_D ? "D" : "-"),
726         (regs->cc & FLAG_I ? "I" : "-"), (regs->cc & FLAG_Z ? "Z" : "-"),
727         (regs->cc & FLAG_C ? "C" : "-"), regs->a, regs->x, regs->y);
728 #endif
729         regs->cc |= FLAG_B;                                                     // Set B
730         regs->pc++;                                                                     // RTI comes back to the instruction one byte after the BRK
731         regs->WrMem(0x0100 + regs->sp--, regs->pc >> 8);        // Save PC and CC
732         regs->WrMem(0x0100 + regs->sp--, regs->pc & 0xFF);
733         regs->WrMem(0x0100 + regs->sp--, regs->cc);
734         regs->cc |= FLAG_I;                                                     // Set I
735         regs->cc &= ~FLAG_D;                                                    // & clear D
736         regs->pc = RdMemW(0xFFFE);                                      // Grab the IRQ vector & go...
737 }
738
739 /*
740 BVC     Relative        BVC Oper        50      2       2
741 BVS     Relative        BVS Oper        70      2       2
742 */
743
744 // Even more branch opcodes
745
746 static void Op50(void)                                                  // BVC
747 {
748         int16_t m = (int16_t)(int8_t)READ_IMM;
749
750         if (!(regs->cc & FLAG_V))
751                 HANDLE_BRANCH_TAKEN(m)
752 }
753
754 static void Op70(void)                                                  // BVS
755 {
756         int16_t m = (int16_t)(int8_t)READ_IMM;
757
758         if (regs->cc & FLAG_V)
759                 HANDLE_BRANCH_TAKEN(m)
760 }
761
762 /*
763 CLC     Implied         CLC                     18      1       2
764 */
765
766 static void Op18(void)                                                  // CLC
767 {
768         regs->cc &= ~FLAG_C;
769 }
770
771 /*
772 CLD     Implied         CLD                     D8      1       2
773 */
774
775 static void OpD8(void)                                                  // CLD
776 {
777         CLR_D;
778 }
779
780 /*
781 CLI     Implied         CLI                     58      1       2
782 */
783
784 static void Op58(void)                                                  // CLI
785 {
786         regs->cc &= ~FLAG_I;
787 }
788
789 /*
790 CLV     Implied         CLV                     B8      1       2
791 */
792
793 static void OpB8(void)                                                  // CLV
794 {
795         regs->cc &= ~FLAG_V;
796 }
797
798 /*
799 CMP     Immediate       CMP #Oper       C9      2       2
800 Zero Page               CMP Zpg         C5      2       3
801 Zero Page,X             CMP Zpg         D5      2       4
802 Absolute                CMP Abs         CD      3       4
803 Absolute,X              CMP Abs,X       DD      3       4
804 Absolute,Y              CMP Abs,Y       D9      3       4
805 (Zero Page,X)   CMP (Zpg,X)     C1      2       6
806 (Zero Page),Y   CMP (Zpg),Y     D1      2       5
807 (Zero Page)             CMP (Zpg)       D2      2       5
808 */
809
810 // CMP opcodes
811
812 #define OP_CMP_HANDLER(m) \
813         uint8_t result = regs->a - (m); \
814         SET_ZNC_CMP(m, regs->a, result)
815
816 static void OpC9(void)                                                  // CMP #
817 {
818         uint8_t m = READ_IMM;
819         OP_CMP_HANDLER(m);
820 }
821
822 static void OpC5(void)                                                  // CMP ZP
823 {
824         uint8_t m = READ_ZP;
825         OP_CMP_HANDLER(m);
826 }
827
828 static void OpD5(void)                                                  // CMP ZP, X
829 {
830         uint8_t m = READ_ZP_X;
831         OP_CMP_HANDLER(m);
832 }
833
834 static void OpCD(void)                                                  // CMP ABS
835 {
836         uint8_t m = READ_ABS;
837         OP_CMP_HANDLER(m);
838 }
839
840 static void OpDD(void)                                                  // CMP ABS, X
841 {
842         HANDLE_PAGE_CROSSING_ABS_X;
843         uint8_t m = READ_ABS_X;
844         OP_CMP_HANDLER(m);
845 }
846
847 static void OpD9(void)                                                  // CMP ABS, Y
848 {
849         HANDLE_PAGE_CROSSING_ABS_Y;
850         uint8_t m = READ_ABS_Y;
851         OP_CMP_HANDLER(m);
852 }
853
854 static void OpC1(void)                                                  // CMP (ZP, X)
855 {
856         uint8_t m = READ_IND_ZP_X;
857         OP_CMP_HANDLER(m);
858 }
859
860 static void OpD1(void)                                                  // CMP (ZP), Y
861 {
862         HANDLE_PAGE_CROSSING_IND_Y;
863         uint8_t m = READ_IND_ZP_Y;
864         OP_CMP_HANDLER(m);
865 }
866
867 static void OpD2(void)                                                  // CMP (ZP)
868 {
869         uint8_t m = READ_IND_ZP;
870         OP_CMP_HANDLER(m);
871 }
872
873 /*
874 CPX     Immediate       CPX #Oper       E0      2       2
875 Zero Page               CPX Zpg         E4      2       3
876 Absolute                CPX Abs         EC      3       4
877 */
878
879 // CPX opcodes
880
881 #define OP_CPX_HANDLER(m) \
882         uint8_t result = regs->x - (m); \
883         SET_ZNC_CMP(m, regs->x, result)
884
885 static void OpE0(void)                                                  // CPX #
886 {
887         uint8_t m = READ_IMM;
888         OP_CPX_HANDLER(m);
889 }
890
891 static void OpE4(void)                                                  // CPX ZP
892 {
893         uint8_t m = READ_ZP;
894         OP_CPX_HANDLER(m);
895 }
896
897 static void OpEC(void)                                                  // CPX ABS
898 {
899         uint8_t m = READ_ABS;
900         OP_CPX_HANDLER(m);
901 }
902
903 /*
904 CPY     Immediate       CPY #Oper       C0      2       2
905 Zero Page               CPY Zpg         C4      2       3
906 Absolute                CPY Abs         CC      3       4
907 */
908
909 // CPY opcodes
910
911 #define OP_CPY_HANDLER(m) \
912         uint8_t result = regs->y - (m); \
913         SET_ZNC_CMP(m, regs->y, result)
914
915 static void OpC0(void)                                                  // CPY #
916 {
917         uint8_t m = READ_IMM;
918         OP_CPY_HANDLER(m);
919 }
920
921 static void OpC4(void)                                                  // CPY ZP
922 {
923         uint8_t m = READ_ZP;
924         OP_CPY_HANDLER(m);
925 }
926
927 static void OpCC(void)                                                  // CPY ABS
928 {
929         uint8_t m = READ_ABS;
930         OP_CPY_HANDLER(m);
931 }
932
933 /*
934 DEA     Accumulator     DEA                     3A      1       2
935 */
936
937 static void Op3A(void)                                                  // DEA
938 {
939         regs->a--;
940         SET_ZN(regs->a);
941 }
942
943 /*
944 DEC     Zero Page       DEC Zpg         C6      2       5
945 Zero Page,X             DEC Zpg,X       D6      2       6
946 Absolute                DEC Abs         CE      3       6
947 Absolute,X              DEC Abs,X       DE      3       7
948 */
949
950 // DEC opcodes
951
952 #define OP_DEC_HANDLER(m) \
953         m--; \
954         SET_ZN(m)
955
956 static void OpC6(void)                                                  // DEC ZP
957 {
958         uint8_t m;
959         READ_ZP_WB(m);
960         OP_DEC_HANDLER(m);
961         WRITE_BACK(m);
962 }
963
964 static void OpD6(void)                                                  // DEC ZP, X
965 {
966         uint8_t m;
967         READ_ZP_X_WB(m);
968         OP_DEC_HANDLER(m);
969         WRITE_BACK(m);
970 }
971
972 static void OpCE(void)                                                  // DEC ABS
973 {
974         uint8_t m;
975         READ_ABS_WB(m);
976         OP_DEC_HANDLER(m);
977         WRITE_BACK(m);
978 }
979
980 static void OpDE(void)                                                  // DEC ABS, X
981 {
982         HANDLE_PAGE_CROSSING_ABS_X;
983         uint8_t m;
984         READ_ABS_X_WB(m);
985         OP_DEC_HANDLER(m);
986         WRITE_BACK(m);
987 }
988
989 /*
990 DEX     Implied         DEX                     CA      1       2
991 */
992
993 static void OpCA(void)                                                  // DEX
994 {
995         regs->x--;
996         SET_ZN(regs->x);
997 }
998
999 /*
1000 DEY     Implied         DEY                     88      1       2
1001 */
1002
1003 static void Op88(void)                                                  // DEY
1004 {
1005         regs->y--;
1006         SET_ZN(regs->y);
1007 }
1008
1009 /*
1010 EOR     Immediate       EOR #Oper       49      2       2
1011 Zero Page               EOR Zpg         45      2       3
1012 Zero Page,X             EOR Zpg,X       55      2       4
1013 Absolute                EOR Abs         4D      3       4
1014 Absolute,X              EOR Abs,X       5D      3       4
1015 Absolute,Y              EOR Abs,Y       59      3       4
1016 (Zero Page,X)   EOR (Zpg,X)     41      2       6
1017 (Zero Page),Y   EOR (Zpg),Y     51      2       5
1018 (Zero Page)             EOR (Zpg)       52      2       5
1019 */
1020
1021 // EOR opcodes
1022
1023 #define OP_EOR_HANDLER(m) \
1024         regs->a ^= m; \
1025         SET_ZN(regs->a)
1026
1027 static void Op49(void)                                                  // EOR #
1028 {
1029         uint8_t m = READ_IMM;
1030         OP_EOR_HANDLER(m);
1031 }
1032
1033 static void Op45(void)                                                  // EOR ZP
1034 {
1035         uint8_t m = READ_ZP;
1036         OP_EOR_HANDLER(m);
1037 }
1038
1039 static void Op55(void)                                                  // EOR ZP, X
1040 {
1041         uint8_t m = READ_ZP_X;
1042         OP_EOR_HANDLER(m);
1043 }
1044
1045 static void Op4D(void)                                                  // EOR ABS
1046 {
1047         uint8_t m = READ_ABS;
1048         OP_EOR_HANDLER(m);
1049 }
1050
1051 static void Op5D(void)                                                  // EOR ABS, X
1052 {
1053         HANDLE_PAGE_CROSSING_ABS_X;
1054         uint8_t m = READ_ABS_X;
1055         OP_EOR_HANDLER(m);
1056 }
1057
1058 static void Op59(void)                                                  // EOR ABS, Y
1059 {
1060         HANDLE_PAGE_CROSSING_ABS_Y;
1061         uint8_t m = READ_ABS_Y;
1062         OP_EOR_HANDLER(m);
1063 }
1064
1065 static void Op41(void)                                                  // EOR (ZP, X)
1066 {
1067         uint8_t m = READ_IND_ZP_X;
1068         OP_EOR_HANDLER(m);
1069 }
1070
1071 static void Op51(void)                                                  // EOR (ZP), Y
1072 {
1073         HANDLE_PAGE_CROSSING_IND_Y;
1074         uint8_t m = READ_IND_ZP_Y;
1075         OP_EOR_HANDLER(m);
1076 }
1077
1078 static void Op52(void)                                                  // EOR (ZP)
1079 {
1080         uint8_t m = READ_IND_ZP;
1081         OP_EOR_HANDLER(m);
1082 }
1083
1084 /*
1085 INA     Accumulator     INA                     1A      1       2
1086 */
1087
1088 static void Op1A(void)                                                  // INA
1089 {
1090         regs->a++;
1091         SET_ZN(regs->a);
1092 }
1093
1094 /*
1095 INC     Zero Page       INC Zpg         E6      2       5
1096 Zero Page,X             INC Zpg,X       F6      2       6
1097 Absolute                INC Abs         EE      3       6
1098 Absolute,X              INC Abs,X       FE      3       7
1099 */
1100
1101 // INC opcodes
1102
1103 #define OP_INC_HANDLER(m) \
1104         m++; \
1105         SET_ZN(m)
1106
1107 static void OpE6(void)                                                  // INC ZP
1108 {
1109         uint8_t m;
1110         READ_ZP_WB(m);
1111         OP_INC_HANDLER(m);
1112         WRITE_BACK(m);
1113 }
1114
1115 static void OpF6(void)                                                  // INC ZP, X
1116 {
1117         uint8_t m;
1118         READ_ZP_X_WB(m);
1119         OP_INC_HANDLER(m);
1120         WRITE_BACK(m);
1121 }
1122
1123 static void OpEE(void)                                                  // INC ABS
1124 {
1125         uint8_t m;
1126         READ_ABS_WB(m);
1127         OP_INC_HANDLER(m);
1128         WRITE_BACK(m);
1129 }
1130
1131 static void OpFE(void)                                                  // INC ABS, X
1132 {
1133         HANDLE_PAGE_CROSSING_ABS_X;
1134         uint8_t m;
1135         READ_ABS_X_WB(m);
1136         OP_INC_HANDLER(m);
1137         WRITE_BACK(m);
1138 }
1139
1140 /*
1141 INX     Implied         INX                     E8      1       2
1142 */
1143
1144 static void OpE8(void)                                                  // INX
1145 {
1146         regs->x++;
1147         SET_ZN(regs->x);
1148 }
1149
1150 /*
1151 INY     Implied         INY                     C8      1       2
1152 */
1153
1154 static void OpC8(void)                                                  // INY
1155 {
1156         regs->y++;
1157         SET_ZN(regs->y);
1158 }
1159
1160 /*
1161 JMP     Absolute        JMP Abs         4C      3       3
1162 (Absolute)              JMP (Abs)       6C      3       5
1163 (Absolute,X)    JMP (Abs,X)     7C      3       6
1164 */
1165
1166 // JMP opcodes
1167
1168 static void Op4C(void)                                                  // JMP ABS
1169 {
1170         regs->pc = RdMemW(regs->pc);
1171 }
1172
1173 static void Op6C(void)                                                  // JMP (ABS)
1174 {
1175         // Check for page crossing
1176         uint16_t addressLo = regs->RdMem(regs->pc);
1177
1178         if (addressLo == 0xFF)
1179                 regs->clock++;
1180
1181         regs->pc = RdMemW(RdMemW(regs->pc));
1182 }
1183
1184 static void Op7C(void)                                                  // JMP (ABS, X)
1185 {
1186         regs->pc = RdMemW(RdMemW(regs->pc) + regs->x);
1187 }
1188
1189 /*
1190 JSR     Absolute        JSR Abs         20      3       6
1191 */
1192
1193 static void Op20(void)                                                  // JSR
1194 {
1195         uint16_t addr = RdMemW(regs->pc);
1196         regs->pc++;                                                                     // Since it pushes return address - 1...
1197         regs->WrMem(0x0100 + regs->sp--, regs->pc >> 8);
1198         regs->WrMem(0x0100 + regs->sp--, regs->pc & 0xFF);
1199         regs->pc = addr;
1200 }
1201
1202 /*
1203 LDA     Immediate       LDA #Oper       A9      2       2
1204 Zero Page               LDA Zpg         A5      2       3
1205 Zero Page,X             LDA Zpg,X       B5      2       4
1206 Absolute                LDA Abs         AD      3       4
1207 Absolute,X              LDA Abs,X       BD      3       4
1208 Absolute,Y              LDA Abs,Y       B9      3       4
1209 (Zero Page,X)   LDA (Zpg,X)     A1      2       6
1210 (Zero Page),Y   LDA (Zpg),Y     B1      2       5
1211 (Zero Page)             LDA (Zpg)       B2      2       5
1212 */
1213
1214 // LDA opcodes
1215
1216 #define OP_LDA_HANDLER(m) \
1217         regs->a = m; \
1218         SET_ZN(regs->a)
1219
1220 static void OpA9(void)                                                  // LDA #
1221 {
1222         uint8_t m = READ_IMM;
1223         OP_LDA_HANDLER(m);
1224 }
1225
1226 static void OpA5(void)                                                  // LDA ZP
1227 {
1228         uint8_t m = READ_ZP;
1229         OP_LDA_HANDLER(m);
1230 }
1231
1232 static void OpB5(void)                                                  // LDA ZP, X
1233 {
1234         uint8_t m = READ_ZP_X;
1235         OP_LDA_HANDLER(m);
1236 }
1237
1238 static void OpAD(void)                                                  // LDA ABS
1239 {
1240         uint8_t m = READ_ABS;
1241         OP_LDA_HANDLER(m);
1242 }
1243
1244 static void OpBD(void)                                                  // LDA ABS, X
1245 {
1246         HANDLE_PAGE_CROSSING_ABS_X;
1247         uint8_t m = READ_ABS_X;
1248         OP_LDA_HANDLER(m);
1249 }
1250
1251 static void OpB9(void)                                                  // LDA ABS, Y
1252 {
1253         HANDLE_PAGE_CROSSING_ABS_Y;
1254         uint8_t m = READ_ABS_Y;
1255         OP_LDA_HANDLER(m);
1256 }
1257
1258 static void OpA1(void)                                                  // LDA (ZP, X)
1259 {
1260         uint8_t m = READ_IND_ZP_X;
1261         OP_LDA_HANDLER(m);
1262 }
1263
1264 static void OpB1(void)                                                  // LDA (ZP), Y
1265 {
1266         HANDLE_PAGE_CROSSING_IND_Y;
1267         uint8_t m = READ_IND_ZP_Y;
1268         OP_LDA_HANDLER(m);
1269 }
1270
1271 static void OpB2(void)                                                  // LDA (ZP)
1272 {
1273         uint8_t m = READ_IND_ZP;
1274         OP_LDA_HANDLER(m);
1275 }
1276
1277 /*
1278 LDX     Immediate       LDX #Oper       A2      2       2
1279 Zero Page               LDX Zpg         A6      2       3
1280 Zero Page,Y             LDX Zpg,Y       B6      2       4
1281 Absolute                LDX Abs         AE      3       4
1282 Absolute,Y              LDX Abs,Y       BE      3       4
1283 */
1284
1285 // LDX opcodes
1286
1287 #define OP_LDX_HANDLER(m) \
1288         regs->x = m; \
1289         SET_ZN(regs->x)
1290
1291 static void OpA2(void)                                                  // LDX #
1292 {
1293         uint8_t m = READ_IMM;
1294         OP_LDX_HANDLER(m);
1295 }
1296
1297 static void OpA6(void)                                                  // LDX ZP
1298 {
1299         uint8_t m = READ_ZP;
1300         OP_LDX_HANDLER(m);
1301 }
1302
1303 static void OpB6(void)                                                  // LDX ZP, Y
1304 {
1305         uint8_t m = READ_ZP_Y;
1306         OP_LDX_HANDLER(m);
1307 }
1308
1309 static void OpAE(void)                                                  // LDX ABS
1310 {
1311         uint8_t m = READ_ABS;
1312         OP_LDX_HANDLER(m);
1313 }
1314
1315 static void OpBE(void)                                                  // LDX ABS, Y
1316 {
1317         HANDLE_PAGE_CROSSING_ABS_Y;
1318         uint8_t m = READ_ABS_Y;
1319         OP_LDX_HANDLER(m);
1320 }
1321
1322 /*
1323 LDY     Immediate       LDY #Oper       A0      2       2
1324 Zero Page               LDY Zpg         A4      2       3
1325 Zero Page,X             LDY Zpg,X       B4      2       4
1326 Absolute                LDY Abs         AC      3       4
1327 Absolute,X              LDY Abs,X       BC      3       4
1328 */
1329
1330 // LDY opcodes
1331
1332 #define OP_LDY_HANDLER(m) \
1333         regs->y = m; \
1334         SET_ZN(regs->y)
1335
1336 static void OpA0(void)                                                  // LDY #
1337 {
1338         uint8_t m = READ_IMM;
1339         OP_LDY_HANDLER(m);
1340 }
1341
1342 static void OpA4(void)                                                  // LDY ZP
1343 {
1344         uint8_t m = READ_ZP;
1345         OP_LDY_HANDLER(m);
1346 }
1347
1348 static void OpB4(void)                                                  // LDY ZP, X
1349 {
1350         uint8_t m = READ_ZP_X;
1351         OP_LDY_HANDLER(m);
1352 }
1353
1354 static void OpAC(void)                                                  // LDY ABS
1355 {
1356         uint8_t m = READ_ABS;
1357         OP_LDY_HANDLER(m);
1358 }
1359
1360 static void OpBC(void)                                                  // LDY ABS, X
1361 {
1362         HANDLE_PAGE_CROSSING_ABS_X;
1363         uint8_t m = READ_ABS_X;
1364         OP_LDY_HANDLER(m);
1365 }
1366
1367 /*
1368 LSR     Accumulator     LSR A           4A      1       2
1369 Zero Page               LSR Zpg         46      2       5
1370 Zero Page,X             LSR Zpg,X       56      2       6
1371 Absolute                LSR Abs         4E      3       6
1372 Absolute,X              LSR Abs,X       5E      3       7
1373 */
1374
1375 // LSR opcodes
1376
1377 #define OP_LSR_HANDLER(m) \
1378         regs->cc = ((m) & 0x01 ? regs->cc | FLAG_C : regs->cc & ~FLAG_C); \
1379         (m) >>= 1; \
1380         CLR_N; SET_Z((m))
1381
1382 static void Op4A(void)                                                  // LSR A
1383 {
1384         OP_LSR_HANDLER(regs->a);
1385 }
1386
1387 static void Op46(void)                                                  // LSR ZP
1388 {
1389         uint8_t m;
1390         READ_ZP_WB(m);
1391         OP_LSR_HANDLER(m);
1392         WRITE_BACK(m);
1393 }
1394
1395 static void Op56(void)                                                  // LSR ZP, X
1396 {
1397         uint8_t m;
1398         READ_ZP_X_WB(m);
1399         OP_LSR_HANDLER(m);
1400         WRITE_BACK(m);
1401 }
1402
1403 static void Op4E(void)                                                  // LSR ABS
1404 {
1405         uint8_t m;
1406         READ_ABS_WB(m);
1407         OP_LSR_HANDLER(m);
1408         WRITE_BACK(m);
1409 }
1410
1411 static void Op5E(void)                                                  // LSR ABS, X
1412 {
1413         HANDLE_PAGE_CROSSING_ABS_X;
1414         uint8_t m;
1415         READ_ABS_X_WB(m);
1416         OP_LSR_HANDLER(m);
1417         WRITE_BACK(m);
1418 }
1419
1420 /*
1421 NOP     Implied         NOP                     EA      1       2
1422 */
1423
1424 static void OpEA(void)                                                  // NOP
1425 {
1426 }
1427
1428 /*
1429 ORA     Immediate       ORA #Oper       09      2       2
1430 Zero Page               ORA Zpg         05      2       3
1431 Zero Page,X             ORA Zpg,X       15      2       4
1432 Absolute                ORA Abs         0D      3       4
1433 Absolute,X              ORA Abs,X       1D      3       4
1434 Absolute,Y              ORA Abs,Y       19      3       4
1435 (Zero Page,X)   ORA (Zpg,X)     01      2       6
1436 (Zero Page),Y   ORA (Zpg),Y     11      2       5
1437 (Zero Page)             ORA (Zpg)       12      2       5
1438 */
1439
1440 // ORA opcodes
1441
1442 #define OP_ORA_HANDLER(m) \
1443         regs->a |= m; \
1444         SET_ZN(regs->a)
1445
1446 static void Op09(void)                                                  // ORA #
1447 {
1448         uint8_t m = READ_IMM;
1449         OP_ORA_HANDLER(m);
1450 }
1451
1452 static void Op05(void)                                                  // ORA ZP
1453 {
1454         uint8_t m = READ_ZP;
1455         OP_ORA_HANDLER(m);
1456 }
1457
1458 static void Op15(void)                                                  // ORA ZP, X
1459 {
1460         uint8_t m = READ_ZP_X;
1461         OP_ORA_HANDLER(m);
1462 }
1463
1464 static void Op0D(void)                                                  // ORA ABS
1465 {
1466         uint8_t m = READ_ABS;
1467         OP_ORA_HANDLER(m);
1468 }
1469
1470 static void Op1D(void)                                                  // ORA ABS, X
1471 {
1472         HANDLE_PAGE_CROSSING_ABS_X;
1473         uint8_t m = READ_ABS_X;
1474         OP_ORA_HANDLER(m);
1475 }
1476
1477 static void Op19(void)                                                  // ORA ABS, Y
1478 {
1479         HANDLE_PAGE_CROSSING_ABS_Y;
1480         uint8_t m = READ_ABS_Y;
1481         OP_ORA_HANDLER(m);
1482 }
1483
1484 static void Op01(void)                                                  // ORA (ZP, X)
1485 {
1486         uint8_t m = READ_IND_ZP_X;
1487         OP_ORA_HANDLER(m);
1488 }
1489
1490 static void Op11(void)                                                  // ORA (ZP), Y
1491 {
1492         HANDLE_PAGE_CROSSING_IND_Y;
1493         uint8_t m = READ_IND_ZP_Y;
1494         OP_ORA_HANDLER(m);
1495 }
1496
1497 static void Op12(void)                                                  // ORA (ZP)
1498 {
1499         uint8_t m = READ_IND_ZP;
1500         OP_ORA_HANDLER(m);
1501 }
1502
1503 /*
1504 PHA     Implied         PHA                     48      1       3
1505 */
1506
1507 static void Op48(void)                                                  // PHA
1508 {
1509         regs->WrMem(0x0100 + regs->sp--, regs->a);
1510 }
1511
1512 static void Op08(void)                                                  // PHP
1513 {
1514         regs->cc |= FLAG_UNK;                                           // Make sure that the unused bit is always set
1515         regs->WrMem(0x0100 + regs->sp--, regs->cc);
1516 }
1517
1518 /*
1519 PHX     Implied         PHX                     DA      1       3
1520 */
1521
1522 static void OpDA(void)                                                  // PHX
1523 {
1524         regs->WrMem(0x0100 + regs->sp--, regs->x);
1525 }
1526
1527 /*
1528 PHY     Implied         PHY                     5A      1       3
1529 */
1530
1531 static void Op5A(void)                                                  // PHY
1532 {
1533         regs->WrMem(0x0100 + regs->sp--, regs->y);
1534 }
1535
1536 /*
1537 PLA     Implied         PLA                     68      1       4
1538 */
1539
1540 static void Op68(void)                                                  // PLA
1541 {
1542         regs->a = regs->RdMem(0x0100 + ++regs->sp);
1543         SET_ZN(regs->a);
1544 }
1545
1546 static void Op28(void)                                                  // PLP
1547 {
1548         regs->cc = regs->RdMem(0x0100 + ++regs->sp);
1549 }
1550
1551 /*
1552 PLX     Implied         PLX                     FA      1       4
1553 */
1554
1555 static void OpFA(void)                                                  // PLX
1556 {
1557         regs->x = regs->RdMem(0x0100 + ++regs->sp);
1558         SET_ZN(regs->x);
1559 }
1560
1561 /*
1562 PLY     Implied         PLY                     7A      1       4
1563 */
1564
1565 static void Op7A(void)                                                  // PLY
1566 {
1567         regs->y = regs->RdMem(0x0100 + ++regs->sp);
1568         SET_ZN(regs->y);
1569 }
1570
1571 /*
1572 The bit set and clear instructions have the form xyyy0111, where x is 0 to clear a bit or 1 to set it, and yyy is which bit at the memory location to set or clear.
1573    RMB0  RMB1  RMB2  RMB3  RMB4  RMB5  RMB6  RMB7
1574   zp  07  17  27  37  47  57  67  77
1575      SMB0  SMB1  SMB2  SMB3  SMB4  SMB5  SMB6  SMB7
1576   zp  87  97  A7  B7  C7  D7  E7  F7
1577 */
1578
1579 // RMB opcodes
1580
1581 static void Op07(void)                                                  // RMB0 ZP
1582 {
1583         uint8_t m;
1584         READ_ZP_WB(m);
1585         m &= 0xFE;
1586         WRITE_BACK(m);
1587 }
1588
1589 static void Op17(void)                                                  // RMB1 ZP
1590 {
1591         uint8_t m;
1592         READ_ZP_WB(m);
1593         m &= 0xFD;
1594         WRITE_BACK(m);
1595 }
1596
1597 static void Op27(void)                                                  // RMB2 ZP
1598 {
1599         uint8_t m;
1600         READ_ZP_WB(m);
1601         m &= 0xFB;
1602         WRITE_BACK(m);
1603 }
1604
1605 static void Op37(void)                                                  // RMB3 ZP
1606 {
1607         uint8_t m;
1608         READ_ZP_WB(m);
1609         m &= 0xF7;
1610         WRITE_BACK(m);
1611 }
1612
1613 static void Op47(void)                                                  // RMB4 ZP
1614 {
1615         uint8_t m;
1616         READ_ZP_WB(m);
1617         m &= 0xEF;
1618         WRITE_BACK(m);
1619 }
1620
1621 static void Op57(void)                                                  // RMB5 ZP
1622 {
1623         uint8_t m;
1624         READ_ZP_WB(m);
1625         m &= 0xDF;
1626         WRITE_BACK(m);
1627 }
1628
1629 static void Op67(void)                                                  // RMB6 ZP
1630 {
1631         uint8_t m;
1632         READ_ZP_WB(m);
1633         m &= 0xBF;
1634         WRITE_BACK(m);
1635 }
1636
1637 static void Op77(void)                                                  // RMB7 ZP
1638 {
1639         uint8_t m;
1640         READ_ZP_WB(m);
1641         m &= 0x7F;
1642         WRITE_BACK(m);
1643 }
1644
1645 /*
1646 ROL     Accumulator     ROL A           2A      1       2
1647 Zero Page               ROL Zpg         26      2       5
1648 Zero Page,X             ROL Zpg,X       36      2       6
1649 Absolute                ROL Abs         2E      3       6
1650 Absolute,X              ROL Abs,X       3E      3       7
1651 */
1652
1653 // ROL opcodes
1654
1655 #define OP_ROL_HANDLER(m) \
1656         uint8_t tmp = regs->cc & 0x01; \
1657         regs->cc = ((m) & 0x80 ? regs->cc | FLAG_C : regs->cc & ~FLAG_C); \
1658         (m) = ((m) << 1) | tmp; \
1659         SET_ZN((m))
1660
1661 static void Op2A(void)                                                  // ROL A
1662 {
1663         OP_ROL_HANDLER(regs->a);
1664 }
1665
1666 static void Op26(void)                                                  // ROL ZP
1667 {
1668         uint8_t m;
1669         READ_ZP_WB(m);
1670         OP_ROL_HANDLER(m);
1671         WRITE_BACK(m);
1672 }
1673
1674 static void Op36(void)                                                  // ROL ZP, X
1675 {
1676         uint8_t m;
1677         READ_ZP_X_WB(m);
1678         OP_ROL_HANDLER(m);
1679         WRITE_BACK(m);
1680 }
1681
1682 static void Op2E(void)                                                  // ROL ABS
1683 {
1684         uint8_t m;
1685         READ_ABS_WB(m);
1686         OP_ROL_HANDLER(m);
1687         WRITE_BACK(m);
1688 }
1689
1690 static void Op3E(void)                                                  // ROL ABS, X
1691 {
1692         HANDLE_PAGE_CROSSING_ABS_X;
1693         uint8_t m;
1694         READ_ABS_X_WB(m);
1695         OP_ROL_HANDLER(m);
1696         WRITE_BACK(m);
1697 }
1698
1699 /*
1700 ROR     Accumulator     ROR A           6A      1       2
1701 Zero Page               ROR Zpg         66      2       5
1702 Zero Page,X             ROR Zpg,X       76      2       6
1703 Absolute                ROR Abs         6E      3       6
1704 Absolute,X              ROR Abs,X       7E      3       7
1705 */
1706
1707 // ROR opcodes
1708
1709 #define OP_ROR_HANDLER(m) \
1710         uint8_t tmp = (regs->cc & 0x01) << 7; \
1711         regs->cc = ((m) & 0x01 ? regs->cc | FLAG_C : regs->cc & ~FLAG_C); \
1712         (m) = ((m) >> 1) | tmp; \
1713         SET_ZN((m))
1714
1715 static void Op6A(void)                                                  // ROR A
1716 {
1717         OP_ROR_HANDLER(regs->a);
1718 }
1719
1720 static void Op66(void)                                                  // ROR ZP
1721 {
1722         uint8_t m;
1723         READ_ZP_WB(m);
1724         OP_ROR_HANDLER(m);
1725         WRITE_BACK(m);
1726 }
1727
1728 static void Op76(void)                                                  // ROR ZP, X
1729 {
1730         uint8_t m;
1731         READ_ZP_X_WB(m);
1732         OP_ROR_HANDLER(m);
1733         WRITE_BACK(m);
1734 }
1735
1736 static void Op6E(void)                                                  // ROR ABS
1737 {
1738         uint8_t m;
1739         READ_ABS_WB(m);
1740         OP_ROR_HANDLER(m);
1741         WRITE_BACK(m);
1742 }
1743
1744 static void Op7E(void)                                                  // ROR ABS, X
1745 {
1746         HANDLE_PAGE_CROSSING_ABS_X;
1747         uint8_t m;
1748         READ_ABS_X_WB(m);
1749         OP_ROR_HANDLER(m);
1750         WRITE_BACK(m);
1751 }
1752
1753 /*
1754 RTI     Implied         RTI                     40      1       6
1755 */
1756
1757 static void Op40(void)                                                  // RTI
1758 {
1759         regs->cc = regs->RdMem(0x0100 + ++regs->sp);
1760         regs->pc = regs->RdMem(0x0100 + ++regs->sp);
1761         regs->pc |= (uint16_t)(regs->RdMem(0x0100 + ++regs->sp)) << 8;
1762 }
1763
1764 /*
1765 RTS     Implied         RTS                     60      1       6
1766 */
1767
1768 static void Op60(void)                                                  // RTS
1769 {
1770         regs->pc = regs->RdMem(0x0100 + ++regs->sp);
1771         regs->pc |= (uint16_t)(regs->RdMem(0x0100 + ++regs->sp)) << 8;
1772         regs->pc++;                                                                     // Since it pushes return address - 1...
1773 }
1774
1775 /*
1776 SBC     Immediate       SBC #Oper       E9      2       2
1777 Zero Page               SBC Zpg         E5      2       3
1778 Zero Page,X             SBC Zpg,X       F5      2       4
1779 Absolute                SBC Abs         ED      3       4
1780 Absolute,X              SBC Abs,X       FD      3       4
1781 Absolute,Y              SBC Abs,Y       F9      3       4
1782 (Zero Page,X)   SBC (Zpg,X)     E1      2       6
1783 (Zero Page),Y   SBC (Zpg),Y     F1      2       5
1784 (Zero Page)             SBC (Zpg)       F2      2       5
1785 */
1786
1787 // SBC opcodes
1788
1789 //This is non-optimal, but it works--optimize later. :-)
1790 // We do the BCD subtraction one nybble at a time to ensure a correct result.
1791 // 9 - m is a "Nine's Complement".  We do the BCD subtraction as a 9s
1792 // complement addition because it's easier and it works.  :-)  Also, Decimal
1793 // mode incurs a once cycle penalty (for the decimal correction).
1794 #define OP_SBC_HANDLER(m) \
1795         uint16_t sum = (uint16_t)regs->a - (m) - (uint16_t)((regs->cc & FLAG_C) ^ 0x01); \
1796 \
1797         if (regs->cc & FLAG_D) \
1798         { \
1799                 sum = (regs->a & 0x0F) + (9 - ((m) & 0x0F)) + (uint16_t)(regs->cc & FLAG_C); \
1800 \
1801                 if (sum > 0x09) \
1802                         sum += 0x06; \
1803 \
1804                 sum += (regs->a & 0xF0) + (0x90 - ((m) & 0xF0)); \
1805 \
1806                 if (sum > 0x99) \
1807                         sum += 0x60; \
1808 \
1809                 sum ^= 0x100; /* Invert carry, for active low borrow */ \
1810                 regs->clock++;\
1811         } \
1812 \
1813         regs->cc = (regs->cc & ~FLAG_C) | (((sum >> 8) ^ 0x01) & FLAG_C); \
1814         regs->cc = ((regs->a ^ (m)) & (regs->a ^ sum) & 0x80 ? regs->cc | FLAG_V : regs->cc & ~FLAG_V); \
1815         regs->a = sum & 0xFF; \
1816         SET_ZN(regs->a)
1817
1818 static void OpE9(void)                                                  // SBC #
1819 {
1820         uint16_t m = READ_IMM;
1821         OP_SBC_HANDLER(m);
1822 }
1823
1824 static void OpE5(void)                                                  // SBC ZP
1825 {
1826         uint16_t m = READ_ZP;
1827         OP_SBC_HANDLER(m);
1828 }
1829
1830 static void OpF5(void)                                                  // SBC ZP, X
1831 {
1832         uint16_t m = READ_ZP_X;
1833         OP_SBC_HANDLER(m);
1834 }
1835
1836 static void OpED(void)                                                  // SBC ABS
1837 {
1838         uint16_t m = READ_ABS;
1839         OP_SBC_HANDLER(m);
1840 }
1841
1842 static void OpFD(void)                                                  // SBC ABS, X
1843 {
1844         HANDLE_PAGE_CROSSING_ABS_X;
1845         uint16_t m = READ_ABS_X;
1846         OP_SBC_HANDLER(m);
1847 }
1848
1849 static void OpF9(void)                                                  // SBC ABS, Y
1850 {
1851         HANDLE_PAGE_CROSSING_ABS_Y;
1852         uint16_t m = READ_ABS_Y;
1853         OP_SBC_HANDLER(m);
1854 }
1855
1856 static void OpE1(void)                                                  // SBC (ZP, X)
1857 {
1858         uint16_t m = READ_IND_ZP_X;
1859         OP_SBC_HANDLER(m);
1860 }
1861
1862 static void OpF1(void)                                                  // SBC (ZP), Y
1863 {
1864         HANDLE_PAGE_CROSSING_IND_Y;
1865         uint16_t m = READ_IND_ZP_Y;
1866         OP_SBC_HANDLER(m);
1867 }
1868
1869 static void OpF2(void)                                                  // SBC (ZP)
1870 {
1871         uint16_t m = READ_IND_ZP;
1872         OP_SBC_HANDLER(m);
1873 }
1874
1875 /*
1876 SEC     Implied         SEC                     38      1       2
1877 */
1878
1879 static void Op38(void)                                                  // SEC
1880 {
1881         regs->cc |= FLAG_C;
1882 }
1883
1884 /*
1885 SED     Implied         SED                     F8      1       2
1886 */
1887
1888 static void OpF8(void)                                                  // SED
1889 {
1890         regs->cc |= FLAG_D;
1891 }
1892
1893 /*
1894 SEI     Implied         SEI                     78      1       2
1895 */
1896
1897 static void Op78(void)                                                  // SEI
1898 {
1899         SET_I;
1900 }
1901
1902 /*
1903 The bit set and clear instructions have the form xyyy0111, where x is 0 to clear a bit or 1 to set it, and yyy is which bit at the memory location to set or clear.
1904    RMB0  RMB1  RMB2  RMB3  RMB4  RMB5  RMB6  RMB7
1905   zp  07  17  27  37  47  57  67  77
1906      SMB0  SMB1  SMB2  SMB3  SMB4  SMB5  SMB6  SMB7
1907   zp  87  97  A7  B7  C7  D7  E7  F7
1908 */
1909
1910 // SMB opcodes
1911
1912 static void Op87(void)                                                  // SMB0 ZP
1913 {
1914         uint8_t m;
1915         READ_ZP_WB(m);
1916         m |= 0x01;
1917         WRITE_BACK(m);
1918 }
1919
1920 static void Op97(void)                                                  // SMB1 ZP
1921 {
1922         uint8_t m;
1923         READ_ZP_WB(m);
1924         m |= 0x02;
1925         WRITE_BACK(m);
1926 }
1927
1928 static void OpA7(void)                                                  // SMB2 ZP
1929 {
1930         uint8_t m;
1931         READ_ZP_WB(m);
1932         m |= 0x04;
1933         WRITE_BACK(m);
1934 }
1935
1936 static void OpB7(void)                                                  // SMB3 ZP
1937 {
1938         uint8_t m;
1939         READ_ZP_WB(m);
1940         m |= 0x08;
1941         WRITE_BACK(m);
1942 }
1943
1944 static void OpC7(void)                                                  // SMB4 ZP
1945 {
1946         uint8_t m;
1947         READ_ZP_WB(m);
1948         m |= 0x10;
1949         WRITE_BACK(m);
1950 }
1951
1952 static void OpD7(void)                                                  // SMB5 ZP
1953 {
1954         uint8_t m;
1955         READ_ZP_WB(m);
1956         m |= 0x20;
1957         WRITE_BACK(m);
1958 }
1959
1960 static void OpE7(void)                                                  // SMB6 ZP
1961 {
1962         uint8_t m;
1963         READ_ZP_WB(m);
1964         m |= 0x40;
1965         WRITE_BACK(m);
1966 }
1967
1968 static void OpF7(void)                                                  // SMB7 ZP
1969 {
1970         uint8_t m;
1971         READ_ZP_WB(m);
1972         m |= 0x80;
1973         WRITE_BACK(m);
1974 }
1975
1976 /*
1977 STA     Zero Page       STA Zpg         85      2       3
1978 Zero Page,X             STA Zpg,X       95      2       4
1979 Absolute                STA Abs         8D      3       4
1980 Absolute,X              STA Abs,X       9D      3       5
1981 Absolute,Y              STA Abs,Y       99      3       5
1982 (Zero Page,X)   STA (Zpg,X)     81      2       6
1983 (Zero Page),Y   STA (Zpg),Y     91      2       6
1984 (Zero Page)             STA (Zpg)       92      2       5
1985 */
1986
1987 // STA opcodes
1988
1989 static void Op85(void)
1990 {
1991         regs->WrMem(EA_ZP, regs->a);
1992 }
1993
1994 static void Op95(void)
1995 {
1996         regs->WrMem(EA_ZP_X, regs->a);
1997 }
1998
1999 static void Op8D(void)
2000 {
2001         regs->WrMem(EA_ABS, regs->a);
2002 }
2003
2004 static void Op9D(void)
2005 {
2006         regs->WrMem(EA_ABS_X, regs->a);
2007 }
2008
2009 static void Op99(void)
2010 {
2011         regs->WrMem(EA_ABS_Y, regs->a);
2012 }
2013
2014 static void Op81(void)
2015 {
2016         regs->WrMem(EA_IND_ZP_X, regs->a);
2017 }
2018
2019 static void Op91(void)
2020 {
2021         regs->WrMem(EA_IND_ZP_Y, regs->a);
2022 }
2023
2024 static void Op92(void)
2025 {
2026         regs->WrMem(EA_IND_ZP, regs->a);
2027 }
2028
2029 /*
2030 STX     Zero Page       STX Zpg         86      2       3
2031 Zero Page,Y             STX Zpg,Y       96      2       4
2032 Absolute                STX Abs         8E      3       4
2033 */
2034
2035 // STX opcodes
2036
2037 static void Op86(void)
2038 {
2039         regs->WrMem(EA_ZP, regs->x);
2040 }
2041
2042 static void Op96(void)
2043 {
2044         regs->WrMem(EA_ZP_Y, regs->x);
2045 }
2046
2047 static void Op8E(void)
2048 {
2049         regs->WrMem(EA_ABS, regs->x);
2050 }
2051
2052 /*
2053 STY     Zero Page       STY Zpg         84      2       3
2054 Zero Page,X             STY Zpg,X       94      2       4
2055 Absolute                STY Abs         8C      3       4
2056 */
2057
2058 // STY opcodes
2059
2060 static void Op84(void)
2061 {
2062         regs->WrMem(EA_ZP, regs->y);
2063 }
2064
2065 static void Op94(void)
2066 {
2067         regs->WrMem(EA_ZP_X, regs->y);
2068 }
2069
2070 static void Op8C(void)
2071 {
2072         regs->WrMem(EA_ABS, regs->y);
2073 }
2074
2075 /*
2076 STZ     Zero Page       STZ Zpg         64      2       3
2077 Zero Page,X             STZ Zpg,X       74      2       4
2078 Absolute                STZ Abs         9C      3       4
2079 Absolute,X              STZ Abs,X       9E      3       5
2080 */
2081
2082 // STZ opcodes
2083
2084 static void Op64(void)
2085 {
2086         regs->WrMem(EA_ZP, 0x00);
2087 }
2088
2089 static void Op74(void)
2090 {
2091         regs->WrMem(EA_ZP_X, 0x00);
2092 }
2093
2094 static void Op9C(void)
2095 {
2096         regs->WrMem(EA_ABS, 0x00);
2097 }
2098
2099 static void Op9E(void)
2100 {
2101         regs->WrMem(EA_ABS_X, 0x00);
2102 }
2103
2104 /*
2105 TAX     Implied         TAX                     AA      1       2
2106 */
2107
2108 static void OpAA(void)                                                  // TAX
2109 {
2110         regs->x = regs->a;
2111         SET_ZN(regs->x);
2112 }
2113
2114 /*
2115 TAY     Implied         TAY                     A8      1       2
2116 */
2117
2118 static void OpA8(void)                                                  // TAY
2119 {
2120         regs->y = regs->a;
2121         SET_ZN(regs->y);
2122 }
2123
2124 /*
2125 TRB     Zero Page       TRB Zpg         14      2       5
2126 Absolute                TRB Abs         1C      3       6
2127 */
2128
2129 // TRB opcodes
2130
2131 #define OP_TRB_HANDLER(m) \
2132         SET_Z(m & regs->a); \
2133         m &= ~regs->a
2134
2135 static void Op14(void)                                                  // TRB ZP
2136 {
2137         uint8_t m;
2138         READ_ZP_WB(m);
2139         OP_TRB_HANDLER(m);
2140         WRITE_BACK(m);
2141 }
2142
2143 static void Op1C(void)                                                  // TRB ABS
2144 {
2145         uint8_t m;
2146         READ_ABS_WB(m);
2147         OP_TRB_HANDLER(m);
2148         WRITE_BACK(m);
2149 }
2150
2151 /*
2152 TSB     Zero Page       TSB Zpg         04      2       5
2153 Absolute                TSB Abs         0C      3       6
2154 */
2155
2156 // TSB opcodes
2157
2158 #define OP_TSB_HANDLER(m) \
2159         SET_Z(m & regs->a); \
2160         m |= regs->a
2161
2162 static void Op04(void)                                                  // TSB ZP
2163 {
2164         uint8_t m;
2165         READ_ZP_WB(m);
2166         OP_TSB_HANDLER(m);
2167         WRITE_BACK(m);
2168 }
2169
2170 static void Op0C(void)                                                  // TSB ABS
2171 {
2172         uint8_t m;
2173         READ_ABS_WB(m);
2174         OP_TSB_HANDLER(m);
2175         WRITE_BACK(m);
2176 }
2177
2178 /*
2179 TSX     Implied         TSX                     BA      1       2
2180 */
2181
2182 static void OpBA(void)                                                  // TSX
2183 {
2184         regs->x = regs->sp;
2185         SET_ZN(regs->x);
2186 }
2187
2188 /*
2189 TXA     Implied         TXA                     8A      1       2
2190 */
2191
2192 static void Op8A(void)                                                  // TXA
2193 {
2194         regs->a = regs->x;
2195         SET_ZN(regs->a);
2196 }
2197
2198 /*
2199 TXS     Implied         TXS                     9A      1       2
2200 */
2201
2202 static void Op9A(void)                                                  // TXS
2203 {
2204         regs->sp = regs->x;
2205 }
2206
2207 /*
2208 TYA     Implied         TYA                     98      1       2
2209 */
2210 static void Op98(void)                                                  // TYA
2211 {
2212         regs->a = regs->y;
2213         SET_ZN(regs->a);
2214 }
2215
2216 static void Op__(void)
2217 {
2218         regs->cpuFlags |= V65C02_STATE_ILLEGAL_INST;
2219 }
2220
2221
2222 //
2223 // Ok, the exec_op[] array is globally defined here basically to save
2224 // a LOT of unnecessary typing.  Sure it's ugly, but hey, it works!
2225 //
2226 static void (* exec_op[256])() = {
2227         Op00, Op01, Op__, Op__, Op04, Op05, Op06, Op07, Op08, Op09, Op0A, Op__, Op0C, Op0D, Op0E, Op0F,
2228         Op10, Op11, Op12, Op__, Op14, Op15, Op16, Op17, Op18, Op19, Op1A, Op__, Op1C, Op1D, Op1E, Op1F,
2229         Op20, Op21, Op__, Op__, Op24, Op25, Op26, Op27, Op28, Op29, Op2A, Op__, Op2C, Op2D, Op2E, Op2F,
2230         Op30, Op31, Op32, Op__, Op34, Op35, Op36, Op37, Op38, Op39, Op3A, Op__, Op3C, Op3D, Op3E, Op3F,
2231         Op40, Op41, Op__, Op__, Op__, Op45, Op46, Op47, Op48, Op49, Op4A, Op__, Op4C, Op4D, Op4E, Op4F,
2232         Op50, Op51, Op52, Op__, Op__, Op55, Op56, Op57, Op58, Op59, Op5A, Op__, Op__, Op5D, Op5E, Op5F,
2233         Op60, Op61, Op__, Op__, Op64, Op65, Op66, Op67, Op68, Op69, Op6A, Op__, Op6C, Op6D, Op6E, Op6F,
2234         Op70, Op71, Op72, Op__, Op74, Op75, Op76, Op77, Op78, Op79, Op7A, Op__, Op7C, Op7D, Op7E, Op7F,
2235         Op80, Op81, Op__, Op__, Op84, Op85, Op86, Op87, Op88, Op89, Op8A, Op__, Op8C, Op8D, Op8E, Op8F,
2236         Op90, Op91, Op92, Op__, Op94, Op95, Op96, Op97, Op98, Op99, Op9A, Op__, Op9C, Op9D, Op9E, Op9F,
2237         OpA0, OpA1, OpA2, Op__, OpA4, OpA5, OpA6, OpA7, OpA8, OpA9, OpAA, Op__, OpAC, OpAD, OpAE, OpAF,
2238         OpB0, OpB1, OpB2, Op__, OpB4, OpB5, OpB6, OpB7, OpB8, OpB9, OpBA, Op__, OpBC, OpBD, OpBE, OpBF,
2239         OpC0, OpC1, Op__, Op__, OpC4, OpC5, OpC6, OpC7, OpC8, OpC9, OpCA, Op__, OpCC, OpCD, OpCE, OpCF,
2240         OpD0, OpD1, OpD2, Op__, Op__, OpD5, OpD6, OpD7, OpD8, OpD9, OpDA, Op__, Op__, OpDD, OpDE, OpDF,
2241         OpE0, OpE1, Op__, Op__, OpE4, OpE5, OpE6, OpE7, OpE8, OpE9, OpEA, Op__, OpEC, OpED, OpEE, OpEF,
2242         OpF0, OpF1, OpF2, Op__, Op__, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, Op__, Op__, OpFD, OpFE, OpFF
2243 };
2244
2245
2246 /*
2247 FCA8: 38        698  WAIT     SEC
2248 FCA9: 48        699  WAIT2    PHA
2249 FCAA: E9 01     700  WAIT3    SBC   #$01
2250 FCAC: D0 FC     701           BNE   WAIT3      ;1.0204 USEC
2251 FCAE: 68        702           PLA              ;(13+27/2*A+5/2*A*A)
2252 FCAF: E9 01     703           SBC   #$01
2253 FCB1: D0 F6     704           BNE   WAIT2
2254 FCB3: 60        705           RTS
2255
2256 FBD9: C9 87     592  BELL1    CMP   #$87       ;BELL CHAR? (CNTRL-G)
2257 FBDB: D0 12     593           BNE   RTS2B      ;  NO, RETURN
2258 FBDD: A9 40     594           LDA   #$40       ;DELAY .01 SECONDS
2259 FBDF: 20 A8 FC  595           JSR   WAIT
2260 FBE2: A0 C0     596           LDY   #$C0
2261 FBE4: A9 0C     597  BELL2    LDA   #$0C       ;TOGGLE SPEAKER AT
2262 FBE6: 20 A8 FC  598           JSR   WAIT       ;  1 KHZ FOR .1 SEC.
2263 FBE9: AD 30 C0  599           LDA   SPKR
2264 FBEC: 88        600           DEY
2265 FBED: D0 F5     601           BNE   BELL2
2266 FBEF: 60        602  RTS2B    RTS
2267 */
2268 //int instCount[256];
2269 #ifdef __DEBUG__
2270 bool dumpDis = false;
2271 //bool dumpDis = true;
2272 #endif
2273
2274 /*
2275 On //e, $FCAA is the delay routine. (seems to not have changed from ][+)
2276 */
2277
2278 #define DO_BACKTRACE
2279 #ifdef DO_BACKTRACE
2280 #define BACKTRACE_SIZE 16384
2281 uint32_t btQueuePtr = 0;
2282 V65C02REGS btQueue[BACKTRACE_SIZE];
2283 uint8_t btQueueInst[BACKTRACE_SIZE][4];
2284 #endif
2285
2286
2287 //
2288 // Function to execute 65C02 for "cycles" cycles
2289 //
2290 //static bool first = true;
2291 void Execute65C02(V65C02REGS * context, uint32_t cycles)
2292 {
2293         regs = context;
2294
2295         // Calculate number of clock cycles to run for
2296         uint64_t endCycles = regs->clock + (uint64_t)cycles - regs->overflow;
2297
2298         while (regs->clock < endCycles)
2299         {
2300 // Hard disk debugging
2301 #if 0
2302 if (first && (regs->pc == 0x801))
2303 {
2304         regs->WrMem(0x42, 1);
2305         regs->WrMem(0x44, 0);
2306         first = false;
2307 }
2308 else if (regs->pc == 0x869)
2309 {
2310 /*      regs->WrMem(0x42, 1);
2311         first = false;//*/
2312 /*      static char disbuf[80];
2313         uint16_t pc=0x801;
2314         while (pc < 0xA00)
2315         {
2316                 pc += Decode65C02(regs, disbuf, pc);
2317                 WriteLog("%s\n", disbuf);
2318         }*/
2319 /*      dumpDis = true;
2320         WriteLog("\n>>> $42-7: %02X %02X %02X %02X %02X %02X\n\n", regs->RdMem(0x42), regs->RdMem(0x43), regs->RdMem(0x44), regs->RdMem(0x45), regs->RdMem(0x46), regs->RdMem(0x47));//*/
2321 }
2322 #endif
2323 #if 0
2324 //Epoch
2325 if (regs->pc == 0x0518)
2326 {
2327         dumpDis = true;
2328 }
2329 else if (regs->pc == 0x051E)
2330 {
2331         uint16_t c1 = regs->RdMem(0xFF);
2332         uint16_t c2 = regs->RdMem(0x00);
2333         WriteLog("$FF/$00 = $%02X $%02X\n", c1, c2);
2334         WriteLog("--> $%02X\n", regs->RdMem((c2 << 8) | c1));
2335 }
2336 else if (regs->pc == 0x0522)
2337 {
2338         uint16_t c1 = regs->RdMem(0xFF);
2339         uint16_t c2 = regs->RdMem(0x00);
2340         WriteLog("$FF/$00 = $%02X $%02X\n", c1, c2);
2341         WriteLog("--> $%02X\n", regs->RdMem(((c2 << 8) | c1) + 1));
2342 }
2343 #endif
2344 #if 0
2345 // Up N Down testing
2346 // Now Ankh testing...
2347 static bool inDelay = false;
2348 static bool inBell = false;
2349 static bool inReadSector = false;
2350 if (regs->pc == 0xFCA8 && !inBell && !inReadSector)
2351 {
2352         dumpDis = false;
2353         inDelay = true;
2354         WriteLog("*** DELAY\n");
2355 }
2356 else if (regs->pc == 0xFCB3 && inDelay && !inBell && !inReadSector)
2357 {
2358         dumpDis = true;
2359         inDelay = false;
2360 }
2361 if (regs->pc == 0xFBD9)
2362 {
2363         dumpDis = false;
2364         inBell = true;
2365         WriteLog("*** BELL1\n");
2366 }
2367 else if (regs->pc == 0xFBEF && inBell)
2368 {
2369         dumpDis = true;
2370         inBell = false;
2371 }
2372 else if (regs->pc == 0xC600)
2373 {
2374         dumpDis = false;
2375         WriteLog("*** DISK @ $C600\n");
2376 }
2377 else if (regs->pc == 0x801)
2378 {
2379         WriteLog("*** DISK @ $801\n");
2380         dumpDis = true;
2381 }
2382 else if (regs->pc == 0xC119)
2383 {
2384         dumpDis = false;
2385         WriteLog("*** BIOS @ $C119\n");
2386 }
2387 else if (regs->pc == 0xC117)
2388 {
2389         dumpDis = true;
2390 }
2391 else if (regs->pc == 0x843)
2392 {
2393         dumpDis = false;
2394         inReadSector = true;
2395         uint16_t lo = regs->RdMem(0x26);
2396         uint16_t hi = regs->RdMem(0x27);
2397         WriteLog("\n*** DISK Read sector ($26=$%04X)...\n\n", (hi << 8) | lo);
2398 }
2399 else if (regs->pc == 0x8FC)
2400 {
2401         dumpDis = true;
2402         inReadSector = false;
2403 }
2404 else if (regs->pc == 0xA8A8 || regs->pc == 0xC100)
2405 {
2406         dumpDis = false;
2407 }
2408 else if (regs->pc == 0x8FD)
2409 {
2410 //      regs->WrMem(0x827, 3);
2411 //      regs->WrMem(0x82A, 0);
2412 //1 doesn't work, but 2 does (only with WOZ, not with DSK; DSK needs 4)...
2413 //      regs->WrMem(0x0D, 4);
2414 }
2415
2416 #endif
2417 #if 0
2418 static bool inDelay = false;
2419 static bool inMLI = false;
2420 static uint16_t mliReturnAddr = 0;
2421 static uint8_t mliCmd = 0;
2422 if (regs->pc == 0x160B && dumpDis)
2423 {
2424         inDelay = true;
2425         dumpDis = false;
2426         WriteLog("*** DELAY\n");
2427 }
2428 else if (regs->pc == 0x1616 && inDelay)
2429 {
2430         inDelay = false;
2431         dumpDis = true;
2432 }
2433 else if (regs->pc == 0xD385 && dumpDis)
2434 {
2435         inDelay = true;
2436         dumpDis = false;
2437         WriteLog("*** DELAY\n");
2438 }
2439 else if (regs->pc == 0xD397 && inDelay)
2440 {
2441         inDelay = false;
2442         dumpDis = true;
2443 }
2444 else if (regs->pc == 0xBF00 && dumpDis)
2445 {
2446         uint16_t lo = regs->RdMem(regs->sp + 0x101);
2447         uint16_t hi = regs->RdMem(regs->sp + 0x102);
2448         mliReturnAddr = ((hi << 8) | lo) + 1;
2449         mliCmd = regs->RdMem(mliReturnAddr);
2450         WriteLog("*** Calling ProDOS MLI with params: %02X %04X\n", mliCmd, RdMemW(mliReturnAddr + 1));
2451         mliReturnAddr += 3;
2452         inMLI = true;
2453
2454         // We want to see what's going on in the WRITE BLOCK command... :-P
2455 //      if (mliCmd != 0x81)
2456 //              dumpDis = false;
2457 }
2458 else if (regs->pc == mliReturnAddr && inMLI)
2459 {
2460 //extern bool stopWriting;
2461 //Stop writing to disk after the first block is done
2462 //      if (mliCmd == 0x81)
2463 //              stopWriting = true;
2464
2465         inMLI = false;
2466         dumpDis = true;
2467 }
2468 else if (regs->pc == 0xAB3A && dumpDis && !inDelay)
2469 {
2470         dumpDis = false;
2471         inDelay = true;
2472         WriteLog("\n*** DELAY (A=$%02X)\n\n", regs->a);
2473 }
2474 else if (regs->pc == 0xAB4A && inDelay)
2475 {
2476         dumpDis = true;
2477         inDelay = false;
2478 }
2479
2480 if (regs->pc == 0xA80B)
2481         dumpDis = true;
2482
2483 #endif
2484 #if 0
2485 static bool weGo = false;
2486 static bool inDelay = false;
2487 if (regs->pc == 0x92BA)
2488 {
2489         dumpDis = true;
2490         weGo = true;
2491 }
2492 else if (regs->pc == 0xAB3A && weGo && !inDelay)
2493 {
2494         dumpDis = false;
2495         inDelay = true;
2496         WriteLog("\n*** DELAY (A=$%02X)\n\n", regs->a);
2497 }
2498 else if (regs->pc == 0xAB4A && weGo)
2499 {
2500         dumpDis = true;
2501         inDelay = false;
2502 }
2503 else if (regs->pc == 0xA8B5 && weGo)
2504 {
2505         WriteLog("\n$D4=%02X, $AC1F=%02X, $AC20=%02X\n\n", regs->RdMem(0xD4), regs->RdMem(0xAC1F), regs->RdMem(0xAC20));
2506 }
2507 /*else if (regs->pc == 0xA8C4 && weGo)
2508 {
2509         WriteLog("Cheating... (clearing Carry flag)\n");
2510         regs->cc &= ~FLAG_C;
2511 }*/
2512 #endif
2513 #if 0
2514 static bool weGo = false;
2515 if (regs->pc == 0x80AE)
2516 {
2517         dumpDis = true;
2518         weGo = true;
2519 }
2520 else if (regs->pc == 0xFCA8 && weGo)
2521 {
2522         dumpDis = false;
2523         WriteLog("\n*** DELAY (A=$%02X)\n\n", regs->a);
2524 }
2525 else if (regs->pc == 0xFCB3 && weGo)
2526 {
2527         dumpDis = true;
2528 }
2529 #endif
2530 #if 0
2531 /*if (regs->pc == 0x4007)
2532 {
2533         dumpDis = true;
2534 }//*/
2535 if (regs->pc == 0x444B)
2536 {
2537         WriteLog("\n*** End of wait...\n\n");
2538         dumpDis = true;
2539 }//*/
2540 if (regs->pc == 0x444E)
2541 {
2542         WriteLog("\n*** Start of wait...\n\n");
2543         dumpDis = false;
2544 }//*/
2545 #endif
2546 /*if (regs->pc >= 0xC600 && regs->pc <=0xC6FF)
2547 {
2548         dumpDis = true;
2549 }
2550 else
2551         dumpDis = false;//*/
2552 /*if (regs->pc == 0xE039)
2553 {
2554         dumpDis = true;
2555 }//*/
2556
2557 #if 0
2558 /*if (regs->pc == 0x0801)
2559 {
2560         WriteLog("\n*** DISK BOOT subroutine...\n\n");
2561         dumpDis = true;
2562 }//*/
2563 if (regs->pc == 0xE000)
2564 {
2565 #if 0
2566         WriteLog("\n*** Dump of $E000 routine ***\n\n");
2567
2568         for(uint32_t addr=0xE000; addr<0xF000;)
2569         {
2570                 addr += Decode65C02(addr);
2571                 WriteLog("\n");
2572         }
2573 #endif
2574         WriteLog("\n*** DISK part II subroutine...\n\n");
2575         dumpDis = true;
2576 }//*/
2577 if (regs->pc == 0xD000)
2578 {
2579         WriteLog("\n*** CUSTOM DISK READ subroutine...\n\n");
2580         dumpDis = false;
2581 }//*/
2582 if (regs->pc == 0xD1BE)
2583 {
2584 //      WriteLog("\n*** DISK part II subroutine...\n\n");
2585         dumpDis = true;
2586 }//*/
2587 if (regs->pc == 0xD200)
2588 {
2589         WriteLog("\n*** CUSTOM SCREEN subroutine...\n\n");
2590         dumpDis = false;
2591 }//*/
2592 if (regs->pc == 0xD269)
2593 {
2594 //      WriteLog("\n*** DISK part II subroutine...\n\n");
2595         dumpDis = true;
2596 }//*/
2597 #endif
2598 //if (regs->pc == 0xE08E)
2599 /*if (regs->pc == 0xAD33)
2600 {
2601         WriteLog("\n*** After loader ***\n\n");
2602         dumpDis = true;
2603 }//*/
2604 /*if (regs->pc == 0x0418)
2605 {
2606         WriteLog("\n*** CUSTOM DISK READ subroutine...\n\n");
2607         dumpDis = false;
2608 }
2609 if (regs->pc == 0x0)
2610 {
2611         dumpDis = true;
2612 }//*/
2613 #ifdef __DEBUGMON__
2614 //WAIT is commented out here because it's called by BELL1...
2615 if (regs->pc == 0xFCA8)
2616 {
2617         WriteLog("\n*** WAIT subroutine...\n\n");
2618         dumpDis = false;
2619 }//*/
2620 if (regs->pc == 0xFBD9)
2621 {
2622         WriteLog("\n*** BELL1 subroutine...\n\n");
2623 //      dumpDis = false;
2624 }//*/
2625 if (regs->pc == 0xFC58)
2626 {
2627         WriteLog("\n*** HOME subroutine...\n\n");
2628 //      dumpDis = false;
2629 }//*/
2630 if (regs->pc == 0xFDED)
2631 {
2632         WriteLog("\n*** COUT subroutine...\n\n");
2633         dumpDis = false;
2634 }
2635 #endif
2636 #if 0
2637 // ProDOS debugging
2638 if (regs->pc == 0x2000)
2639         dumpDis = true;
2640 #endif
2641
2642 #ifdef __DEBUG__
2643 #ifdef DO_BACKTRACE
2644 //uint32_t btQueuePtr = 0;
2645 //V65C02REGS btQueue[BACKTRACE_SIZE];
2646 //uint8_t btQueueInst[BACKTRACE_SIZE][4];
2647 memcpy(&btQueue[btQueuePtr], regs, sizeof(V65C02REGS));
2648 btQueuePtr = (btQueuePtr + 1) % BACKTRACE_SIZE;
2649 #endif
2650 #endif
2651 #ifdef __DEBUG__
2652 static char disbuf[80];
2653 if (dumpDis)
2654 {
2655         Decode65C02(regs, disbuf, regs->pc);
2656         WriteLog("%s", disbuf);
2657 }
2658 #endif
2659                 uint8_t opcode = regs->RdMem(regs->pc++);
2660
2661 #if 0
2662 if (opcode == 0)
2663 {
2664         static char disbuf[80];
2665         uint32_t btStart = btQueuePtr - 12 + (btQueuePtr < 12 ? BACKTRACE_SIZE : 0);
2666
2667         for(uint32_t i=btStart; i<btQueuePtr; i++)
2668         {
2669                 Decode65C02(regs, disbuf, btQueue[i].pc);
2670                 WriteLog("%s\n", disbuf);
2671         }
2672 }
2673 #endif
2674 //if (!(regs->cpuFlags & V65C02_STATE_ILLEGAL_INST))
2675 //instCount[opcode]++;
2676
2677                 // We need this because the opcode function could add 1 or 2 cycles
2678                 // which aren't accounted for in CPUCycles[].
2679                 uint64_t clockSave = regs->clock;
2680
2681                 // Execute that opcode...
2682                 exec_op[opcode]();
2683                 regs->clock += CPUCycles[opcode];
2684
2685                 // Tell the timer function (if any) how many PHI2s have elapsed...
2686                 if (regs->Timer)
2687                         regs->Timer(regs->clock - clockSave);
2688
2689 #ifdef __DEBUG__
2690 if (dumpDis)
2691         WriteLog(" [SP=01%02X, CC=%s%s.%s%s%s%s%s, A=%02X, X=%02X, Y=%02X](%d)\n",
2692                 regs->sp,
2693                 (regs->cc & FLAG_N ? "N" : "-"), (regs->cc & FLAG_V ? "V" : "-"),
2694                 (regs->cc & FLAG_B ? "B" : "-"), (regs->cc & FLAG_D ? "D" : "-"),
2695                 (regs->cc & FLAG_I ? "I" : "-"), (regs->cc & FLAG_Z ? "Z" : "-"),
2696                 (regs->cc & FLAG_C ? "C" : "-"), regs->a, regs->x, regs->y, regs->clock - clockSave);
2697 #endif
2698
2699 #ifdef __DEBUGMON__
2700 if (regs->pc == 0xFCB3) // WAIT exit point
2701 {
2702         dumpDis = true;
2703 }//*/
2704 /*if (regs->pc == 0xFBEF)       // BELL1 exit point
2705 {
2706         dumpDis = true;
2707 }//*/
2708 /*if (regs->pc == 0xFC22)       // HOME exit point
2709 {
2710         dumpDis = true;
2711 }//*/
2712 if (regs->pc == 0xFDFF) // COUT exit point
2713 {
2714         dumpDis = true;
2715 }
2716 if (regs->pc == 0xFBD8)
2717 {
2718         WriteLog("\n*** BASCALC set BASL/H = $%04X\n\n", RdMemW(0x0028));
2719 }//*/
2720 #endif
2721
2722 //These should be correct now...
2723                 if (regs->cpuFlags & V65C02_ASSERT_LINE_RESET)
2724                 {
2725                         // Not sure about this...
2726                         regs->sp = 0xFF;
2727                         regs->cc = FLAG_I;                              // Reset the CC register
2728                         regs->pc = RdMemW(0xFFFC);              // And load PC with RESET vector
2729
2730                         regs->cpuFlags = 0;                             // Clear CPU flags...
2731 #ifdef __DEBUG__
2732 WriteLog("\n*** RESET *** (PC = $%04X)\n\n", regs->pc);
2733 #endif
2734                 }
2735                 else if (regs->cpuFlags & V65C02_ASSERT_LINE_NMI)
2736                 {
2737 #ifdef __DEBUG__
2738 WriteLog("\n*** NMI ***\n\n");
2739 #endif
2740                         regs->WrMem(0x0100 + regs->sp--, regs->pc >> 8);        // Save PC & CC
2741                         regs->WrMem(0x0100 + regs->sp--, regs->pc & 0xFF);
2742                         regs->WrMem(0x0100 + regs->sp--, regs->cc);
2743                         SET_I;
2744                         CLR_D;
2745                         regs->pc = RdMemW(0xFFFA);              // Jump to NMI vector
2746
2747                         regs->clock += 7;
2748                         regs->cpuFlags &= ~V65C02_ASSERT_LINE_NMI;      // Reset NMI line
2749                 }
2750                 else if ((regs->cpuFlags & V65C02_ASSERT_LINE_IRQ)
2751                         // IRQs are maskable, so check if the I flag is clear
2752                         && (!(regs->cc & FLAG_I)))
2753                 {
2754 #ifdef __DEBUG__
2755 WriteLog("\n*** IRQ ***\n\n");
2756 WriteLog("Clock=$%X\n", regs->clock);
2757 //dumpDis = true;
2758 #endif
2759                         regs->WrMem(0x0100 + regs->sp--, regs->pc >> 8);        // Save PC & CC
2760                         regs->WrMem(0x0100 + regs->sp--, regs->pc & 0xFF);
2761                         regs->WrMem(0x0100 + regs->sp--, regs->cc);
2762                         SET_I;
2763                         CLR_D;
2764                         regs->pc = RdMemW(0xFFFE);              // Jump to IRQ vector
2765
2766                         regs->clock += 7;
2767                         regs->cpuFlags &= ~V65C02_ASSERT_LINE_IRQ;      // Reset IRQ line
2768                 }
2769         }
2770
2771         // If we went longer than the passed in cycles, make a note of it so we can
2772         // subtract it out from a subsequent run.  It's guaranteed to be non-
2773         // negative, because the condition that exits the main loop above is
2774         // written such that regs->clock has to be equal or larger than endCycles
2775         // to exit from it.
2776         regs->overflow = regs->clock - endCycles;
2777 }
2778