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