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