2 // Virtual 65C02 Emulator v1.0
\r
4 // by James L. Hammons
\r
5 // (c) 2005 Underground Software
\r
7 // JLH = James L. Hammons <jlhamm@acm.org>
\r
10 // --- ---------- ------------------------------------------------------------
\r
11 // JLH 01/04/2006 Added changelog ;-)
\r
14 //OK, the wraparound bug exists in both the Apple and Atari versions of Ultima II.
\r
15 //However, the Atari version *does* occassionally pick strength while the Apple
\r
16 //versions do not--which would seem to indicate a bug either in the RNG algorithm,
\r
17 //the 65C02 core, or the Apple hardware. Need to investigate all three!
\r
20 //#define __DEBUGMON__
\r
25 #include "dis65c02.h"
\r
31 #define CLR_Z (regs.cc &= ~FLAG_Z)
\r
32 #define CLR_ZN (regs.cc &= ~(FLAG_Z | FLAG_N))
\r
33 #define CLR_ZNC (regs.cc &= ~(FLAG_Z | FLAG_N | FLAG_C))
\r
34 #define CLR_V (regs.cc &= ~FLAG_V)
\r
35 #define CLR_N (regs.cc &= ~FLAG_N)
\r
36 #define SET_Z(r) (regs.cc = ((r) == 0 ? regs.cc | FLAG_Z : regs.cc & ~FLAG_Z))
\r
37 #define SET_N(r) (regs.cc = ((r) & 0x80 ? regs.cc | FLAG_N : regs.cc & ~FLAG_N))
\r
39 //Not sure that this code is computing the carry correctly... Investigate! [Seems to be]
\r
40 #define SET_C_ADD(a,b) (regs.cc = ((uint8)(b) > (uint8)(~(a)) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
\r
41 //#define SET_C_SUB(a,b) (regs.cc = ((uint8)(b) >= (uint8)(a) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
\r
42 #define SET_C_CMP(a,b) (regs.cc = ((uint8)(b) >= (uint8)(a) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
\r
43 #define SET_ZN(r) SET_N(r); SET_Z(r)
\r
44 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
\r
45 //#define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
\r
46 #define SET_ZNC_CMP(a,b,r) SET_N(r); SET_Z(r); SET_C_CMP(a,b)
\r
48 //Small problem with the EA_ macros: ABS macros don't increment the PC!!! !!! FIX !!!
\r
49 #define EA_IMM regs.pc++
\r
50 #define EA_ZP regs.RdMem(regs.pc++)
\r
51 #define EA_ZP_X (regs.RdMem(regs.pc++) + regs.x) & 0xFF
\r
52 #define EA_ZP_Y (regs.RdMem(regs.pc++) + regs.y) & 0xFF
\r
53 #define EA_ABS RdMemW(regs.pc)
\r
54 #define EA_ABS_X RdMemW(regs.pc) + regs.x
\r
55 #define EA_ABS_Y RdMemW(regs.pc) + regs.y
\r
56 #define EA_IND_ZP_X RdMemW((regs.RdMem(regs.pc++) + regs.x) & 0xFF)
\r
57 #define EA_IND_ZP_Y RdMemW(regs.RdMem(regs.pc++)) + regs.y
\r
58 #define EA_IND_ZP RdMemW(regs.RdMem(regs.pc++))
\r
60 #define READ_IMM regs.RdMem(EA_IMM)
\r
61 #define READ_ZP regs.RdMem(EA_ZP)
\r
62 #define READ_ZP_X regs.RdMem(EA_ZP_X)
\r
63 #define READ_ZP_Y regs.RdMem(EA_ZP_Y)
\r
64 #define READ_ABS regs.RdMem(EA_ABS); regs.pc += 2
\r
65 #define READ_ABS_X regs.RdMem(EA_ABS_X); regs.pc += 2
\r
66 #define READ_ABS_Y regs.RdMem(EA_ABS_Y); regs.pc += 2
\r
67 #define READ_IND_ZP_X regs.RdMem(EA_IND_ZP_X)
\r
68 #define READ_IND_ZP_Y regs.RdMem(EA_IND_ZP_Y)
\r
69 #define READ_IND_ZP regs.RdMem(EA_IND_ZP)
\r
71 #define READ_IMM_WB(v) uint16 addr = EA_IMM; v = regs.RdMem(addr)
\r
72 #define READ_ZP_WB(v) uint16 addr = EA_ZP; v = regs.RdMem(addr)
\r
73 #define READ_ZP_X_WB(v) uint16 addr = EA_ZP_X; v = regs.RdMem(addr)
\r
74 #define READ_ABS_WB(v) uint16 addr = EA_ABS; v = regs.RdMem(addr); regs.pc += 2
\r
75 #define READ_ABS_X_WB(v) uint16 addr = EA_ABS_X; v = regs.RdMem(addr); regs.pc += 2
\r
76 #define READ_ABS_Y_WB(v) uint16 addr = EA_ABS_Y; v = regs.RdMem(addr); regs.pc += 2
\r
77 #define READ_IND_ZP_X_WB(v) uint16 addr = EA_IND_ZP_X; v = regs.RdMem(addr)
\r
78 #define READ_IND_ZP_Y_WB(v) uint16 addr = EA_IND_ZP_Y; v = regs.RdMem(addr)
\r
79 #define READ_IND_ZP_WB(v) uint16 addr = EA_IND_ZP; v = regs.RdMem(addr)
\r
81 #define WRITE_BACK(d) regs.WrMem(addr, (d))
\r
83 // Private global variables
\r
85 static V65C02REGS regs;
\r
87 //This is probably incorrect, at least WRT to the $x7 and $xF opcodes... !!! FIX !!!
\r
88 //Also this doesn't take into account the extra cycle it takes when an indirect fetch
\r
89 //(ABS, ABS X/Y, ZP) crosses a page boundary, or extra cycle for BCD add/subtract...
\r
90 #warning Cycle counts are not accurate--!!! FIX !!!
\r
91 static uint8 CPUCycles[256] = {
\r
92 7, 6, 1, 1, 5, 3, 5, 1, 3, 2, 2, 1, 6, 4, 6, 1,
\r
93 2, 5, 5, 1, 5, 4, 6, 1, 2, 4, 2, 1, 6, 4, 6, 1,
\r
94 6, 6, 1, 1, 3, 3, 5, 1, 4, 2, 2, 1, 4, 4, 6, 1,
\r
95 2, 5, 5, 1, 4, 4, 6, 1, 2, 4, 2, 1, 4, 4, 6, 1,
\r
96 6, 6, 1, 1, 1, 3, 5, 1, 3, 2, 2, 1, 3, 4, 6, 1,
\r
97 2, 5, 5, 1, 1, 4, 6, 1, 2, 4, 3, 1, 1, 4, 6, 1,
\r
98 6, 6, 1, 1, 3, 3, 5, 1, 4, 2, 2, 1, 6, 4, 6, 1,
\r
99 2, 5, 5, 1, 4, 4, 6, 1, 2, 4, 4, 1, 6, 4, 6, 1,
\r
100 2, 6, 1, 1, 3, 3, 3, 1, 2, 2, 2, 1, 4, 4, 4, 1,
\r
101 2, 6, 5, 1, 4, 4, 4, 1, 2, 5, 2, 1, 4, 5, 5, 1,
\r
102 2, 6, 2, 1, 3, 3, 3, 1, 2, 2, 2, 1, 4, 4, 4, 1,
\r
103 2, 5, 5, 1, 4, 4, 4, 1, 2, 4, 2, 1, 4, 4, 4, 1,
\r
104 2, 6, 1, 1, 3, 3, 5, 1, 2, 2, 2, 1, 4, 4, 6, 1,
\r
105 2, 5, 5, 1, 1, 4, 6, 1, 2, 4, 3, 1, 1, 4, 6, 1,
\r
106 2, 6, 1, 1, 3, 3, 5, 1, 2, 2, 2, 1, 4, 4, 6, 1,
\r
107 2, 5, 5, 1, 1, 4, 6, 1, 2, 4, 4, 1, 1, 4, 6, 1 };
\r
109 // Private function prototypes
\r
111 static uint16 RdMemW(uint16);
\r
114 // Read a uint16 out of 65C02 memory (big endian format)
\r
116 static uint16 RdMemW(uint16 address)
\r
118 return (uint16)(regs.RdMem(address + 1) << 8) | regs.RdMem(address + 0);
\r
123 // 65C02 OPCODE IMPLEMENTATION
\r
125 // NOTE: Lots of macros are used here to save a LOT of typing. Also
\r
126 // helps speed the debugging process. :-) Because of this, combining
\r
127 // certain lines may look like a good idea but would end in disaster.
\r
128 // You have been warned! ;-)
\r
132 Mnemonic Addressing mode Form Opcode Size Timing
\r
134 ADC Immediate ADC #Oper 69 2 2
\r
135 Zero Page ADC Zpg 65 2 3
\r
136 Zero Page,X ADC Zpg,X 75 2 4
\r
137 Absolute ADC Abs 6D 3 4
\r
138 Absolute,X ADC Abs,X 7D 3 4
\r
139 Absolute,Y ADC Abs,Y 79 3 4
\r
140 (Zero Page,X) ADC (Zpg,X) 61 2 6
\r
141 (Zero Page),Y ADC (Zpg),Y 71 2 5
\r
142 (Zero Page) ADC (Zpg) 72 2 5
\r
147 //This is non-optimal, but it works--optimize later. :-)
\r
148 #define OP_ADC_HANDLER(m) \
\r
149 uint16 sum = (uint16)regs.a + (m) + (uint16)(regs.cc & FLAG_C); \
\r
151 if (regs.cc & FLAG_D) \
\r
153 if ((sum & 0x0F) > 0x09) \
\r
156 if ((sum & 0xF0) > 0x90) \
\r
160 regs.cc = (regs.cc & ~FLAG_C) | (sum >> 8); \
\r
161 regs.cc = (~(regs.a ^ (m)) & (regs.a ^ sum) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V); \
\r
162 regs.a = sum & 0xFF; \
\r
165 //OLD V detection: regs.cc = ((regs.a ^ (m) ^ sum ^ (regs.cc << 7)) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V);
\r
167 static void Op69(void) // ADC #
\r
169 uint16 m = READ_IMM;
\r
173 static void Op65(void) // ADC ZP
\r
175 uint16 m = READ_ZP;
\r
179 static void Op75(void) // ADC ZP, X
\r
181 uint16 m = READ_ZP_X;
\r
185 static void Op6D(void) // ADC ABS
\r
187 uint16 m = READ_ABS;
\r
191 static void Op7D(void) // ADC ABS, X
\r
193 uint16 m = READ_ABS_X;
\r
197 static void Op79(void) // ADC ABS, Y
\r
199 uint16 m = READ_ABS_Y;
\r
203 static void Op61(void) // ADC (ZP, X)
\r
205 uint16 m = READ_IND_ZP_X;
\r
209 static void Op71(void) // ADC (ZP), Y
\r
211 uint16 m = READ_IND_ZP_Y;
\r
215 static void Op72(void) // ADC (ZP)
\r
217 uint16 m = READ_IND_ZP;
\r
222 AND Immediate AND #Oper 29 2 2
\r
223 Zero Page AND Zpg 25 2 3
\r
224 Zero Page,X AND Zpg,X 35 2 4
\r
225 Absolute AND Abs 2D 3 4
\r
226 Absolute,X AND Abs,X 3D 3 4
\r
227 Absolute,Y AND Abs,Y 39 3 4
\r
228 (Zero Page,X) AND (Zpg,X) 21 2 6
\r
229 (Zero Page),Y AND (Zpg),Y 31 2 5
\r
230 (Zero Page) AND (Zpg) 32 2 5
\r
235 #define OP_AND_HANDLER(m) \
\r
239 static void Op29(void) // AND #
\r
241 uint8 m = READ_IMM;
\r
245 static void Op25(void) // AND ZP
\r
251 static void Op35(void) // AND ZP, X
\r
253 uint8 m = READ_ZP_X;
\r
257 static void Op2D(void) // AND ABS
\r
259 uint8 m = READ_ABS;
\r
263 static void Op3D(void) // AND ABS, X
\r
265 uint8 m = READ_ABS_X;
\r
269 static void Op39(void) // AND ABS, Y
\r
271 uint8 m = READ_ABS_Y;
\r
275 static void Op21(void) // AND (ZP, X)
\r
277 uint8 m = READ_IND_ZP_X;
\r
281 static void Op31(void) // AND (ZP), Y
\r
283 uint8 m = READ_IND_ZP_Y;
\r
287 static void Op32(void) // AND (ZP)
\r
289 uint8 m = READ_IND_ZP;
\r
294 ASL Accumulator ASL A 0A 1 2
\r
295 Zero Page ASL Zpg 06 2 5
\r
296 Zero Page,X ASL Zpg,X 16 2 6
\r
297 Absolute ASL Abs 0E 3 6
\r
298 Absolute,X ASL Abs,X 1E 3 7
\r
301 /*static void Op78(void) // LSL ABS
\r
303 uint8 tmp; uint16 addr;
\r
305 tmp = regs.RdMem(addr);
\r
306 (tmp&0x80 ? regs.cc |= 0x01 : regs.cc &= 0xFE); // Shift hi bit into Carry
\r
308 regs.WrMem(addr, tmp);
\r
309 (tmp == 0 ? regs.cc |= 0x04 : regs.cc &= 0xFB); // Adjust Zero flag
\r
310 (tmp&0x80 ? regs.cc |= 0x08 : regs.cc &= 0xF7); // Adjust Negative flag
\r
315 #define OP_ASL_HANDLER(m) \
\r
316 regs.cc = ((m) & 0x80 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
\r
320 static void Op0A(void) // ASL A
\r
322 OP_ASL_HANDLER(regs.a);
\r
325 static void Op06(void) // ASL ZP
\r
333 static void Op16(void) // ASL ZP, X
\r
341 static void Op0E(void) // ASL ABS
\r
349 static void Op1E(void) // ASL ABS, X
\r
358 BBR0 Relative BBR0 Oper 0F 2 2
\r
359 BBR1 Relative BBR1 Oper 1F 2 2
\r
360 BBR2 Relative BBR2 Oper 2F 2 2
\r
361 BBR3 Relative BBR3 Oper 3F 2 2
\r
362 BBR4 Relative BBR4 Oper 4F 2 2
\r
363 BBR5 Relative BBR5 Oper 5F 2 2
\r
364 BBR6 Relative BBR6 Oper 6F 2 2
\r
365 BBR7 Relative BBR7 Oper 7F 2 2
\r
366 BBS0 Relative BBS0 Oper 8F 2 2
\r
367 BBS1 Relative BBS1 Oper 9F 2 2
\r
368 BBS2 Relative BBS2 Oper AF 2 2
\r
369 BBS3 Relative BBS3 Oper BF 2 2
\r
370 BBS4 Relative BBS4 Oper CF 2 2
\r
371 BBS5 Relative BBS5 Oper DF 2 2
\r
372 BBS6 Relative BBS6 Oper EF 2 2
\r
373 BBS7 Relative BBS7 Oper FF 2 2
\r
378 static void Op0F(void) // BBR0
\r
380 int16 m = (int16)(int8)READ_IMM;
\r
382 if (!(regs.a & 0x01))
\r
386 static void Op1F(void) // BBR1
\r
388 int16 m = (int16)(int8)READ_IMM;
\r
390 if (!(regs.a & 0x02))
\r
394 static void Op2F(void) // BBR2
\r
396 int16 m = (int16)(int8)READ_IMM;
\r
398 if (!(regs.a & 0x04))
\r
402 static void Op3F(void) // BBR3
\r
404 int16 m = (int16)(int8)READ_IMM;
\r
406 if (!(regs.a & 0x08))
\r
410 static void Op4F(void) // BBR4
\r
412 int16 m = (int16)(int8)READ_IMM;
\r
414 if (!(regs.a & 0x10))
\r
418 static void Op5F(void) // BBR5
\r
420 int16 m = (int16)(int8)READ_IMM;
\r
422 if (!(regs.a & 0x20))
\r
426 static void Op6F(void) // BBR6
\r
428 int16 m = (int16)(int8)READ_IMM;
\r
430 if (!(regs.a & 0x40))
\r
434 static void Op7F(void) // BBR7
\r
436 int16 m = (int16)(int8)READ_IMM;
\r
438 if (!(regs.a & 0x80))
\r
442 static void Op8F(void) // BBS0
\r
444 int16 m = (int16)(int8)READ_IMM;
\r
450 static void Op9F(void) // BBS1
\r
452 int16 m = (int16)(int8)READ_IMM;
\r
458 static void OpAF(void) // BBS2
\r
460 int16 m = (int16)(int8)READ_IMM;
\r
466 static void OpBF(void) // BBS3
\r
468 int16 m = (int16)(int8)READ_IMM;
\r
474 static void OpCF(void) // BBS4
\r
476 int16 m = (int16)(int8)READ_IMM;
\r
482 static void OpDF(void) // BBS5
\r
484 int16 m = (int16)(int8)READ_IMM;
\r
490 static void OpEF(void) // BBS6
\r
492 int16 m = (int16)(int8)READ_IMM;
\r
498 static void OpFF(void) // BBS7
\r
500 int16 m = (int16)(int8)READ_IMM;
\r
507 BCC Relative BCC Oper 90 2 2
\r
508 BCS Relative BCS Oper B0 2 2
\r
509 BEQ Relative BEQ Oper F0 2 2
\r
514 static void Op90(void) // BCC
\r
516 int16 m = (int16)(int8)READ_IMM;
\r
518 if (!(regs.cc & FLAG_C))
\r
522 static void OpB0(void) // BCS
\r
524 int16 m = (int16)(int8)READ_IMM;
\r
526 if (regs.cc & FLAG_C)
\r
530 static void OpF0(void) // BEQ
\r
532 int16 m = (int16)(int8)READ_IMM;
\r
534 if (regs.cc & FLAG_Z)
\r
539 BIT Immediate BIT #Oper 89 2 2
\r
540 Zero Page BIT Zpg 24 2 3
\r
541 Zero Page,X BIT Zpg,X 34 2 4
\r
542 Absolute BIT Abs 2C 3 4
\r
543 Absolute,X BIT Abs,X 3C 3 4
\r
548 /* 1. The BIT instruction copies bit 6 to the V flag, and bit 7 to the N flag (except in immediate
\r
549 addressing mode where V & N are untouched.) The accumulator and the operand are ANDed and the
\r
550 Z flag is set appropriately. */
\r
552 #define OP_BIT_HANDLER(m) \
\r
553 int8 result = regs.a & (m); \
\r
554 regs.cc &= ~(FLAG_N | FLAG_V); \
\r
555 regs.cc |= ((m) & 0xC0); \
\r
558 static void Op89(void) // BIT #
\r
561 int8 result = regs.a & m;
\r
565 static void Op24(void) // BIT ZP
\r
571 static void Op34(void) // BIT ZP, X
\r
573 uint8 m = READ_ZP_X;
\r
577 static void Op2C(void) // BIT ABS
\r
579 uint8 m = READ_ABS;
\r
583 static void Op3C(void) // BIT ABS, X
\r
585 uint8 m = READ_ABS_X;
\r
590 BMI Relative BMI Oper 30 2 2
\r
591 BNE Relative BNE Oper D0 2 2
\r
592 BPL Relative BPL Oper 10 2 2
\r
593 BRA Relative BRA Oper 80 2 3
\r
596 // More branch opcodes
\r
598 static void Op30(void) // BMI
\r
600 int16 m = (int16)(int8)READ_IMM;
\r
602 if (regs.cc & FLAG_N)
\r
606 static void OpD0(void) // BNE
\r
608 int16 m = (int16)(int8)READ_IMM;
\r
610 if (!(regs.cc & FLAG_Z))
\r
614 static void Op10(void) // BPL
\r
616 int16 m = (int16)(int8)READ_IMM;
\r
618 if (!(regs.cc & FLAG_N))
\r
622 static void Op80(void) // BRA
\r
624 int16 m = (int16)(int8)READ_IMM;
\r
629 BRK Implied BRK 00 1 7
\r
632 static void Op00(void) // BRK
\r
634 regs.cc |= FLAG_B; // Set B
\r
635 regs.pc++; // RTI comes back to the instruction one byte after the BRK
\r
636 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8); // Save PC and CC
\r
637 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
\r
638 regs.WrMem(0x0100 + regs.sp--, regs.cc);
\r
639 regs.cc |= FLAG_I; // Set I
\r
640 regs.cc &= ~FLAG_D; // & clear D
\r
641 regs.pc = RdMemW(0xFFFE); // Grab the IRQ vector & go...
\r
645 BVC Relative BVC Oper 50 2 2
\r
646 BVS Relative BVS Oper 70 2 2
\r
649 // Even more branch opcodes
\r
651 static void Op50(void) // BVC
\r
653 int16 m = (int16)(int8)READ_IMM;
\r
655 if (!(regs.cc & FLAG_V))
\r
659 static void Op70(void) // BVS
\r
661 int16 m = (int16)(int8)READ_IMM;
\r
663 if (regs.cc & FLAG_V)
\r
668 CLC Implied CLC 18 1 2
\r
671 static void Op18(void) // CLC
\r
673 regs.cc &= ~FLAG_C;
\r
677 CLD Implied CLD D8 1 2
\r
680 static void OpD8(void) // CLD
\r
682 regs.cc &= ~FLAG_D;
\r
686 CLI Implied CLI 58 1 2
\r
689 static void Op58(void) // CLI
\r
691 regs.cc &= ~FLAG_I;
\r
695 CLV Implied CLV B8 1 2
\r
698 static void OpB8(void) // CLV
\r
700 regs.cc &= ~FLAG_V;
\r
704 CMP Immediate CMP #Oper C9 2 2
\r
705 Zero Page CMP Zpg C5 2 3
\r
706 Zero Page,X CMP Zpg D5 2 4
\r
707 Absolute CMP Abs CD 3 4
\r
708 Absolute,X CMP Abs,X DD 3 4
\r
709 Absolute,Y CMP Abs,Y D9 3 4
\r
710 (Zero Page,X) CMP (Zpg,X) C1 2 6
\r
711 (Zero Page),Y CMP (Zpg),Y D1 2 5
\r
712 (Zero Page) CMP (Zpg) D2 2 5
\r
718 Here's the latest: The CMP is NOT generating the Z flag when A=$C0!
\r
720 FABA: A0 07 LDY #$07 [PC=FABC, SP=01FF, CC=---B-IZ-, A=00, X=00, Y=07]
\r
721 FABC: C6 01 DEC $01 [PC=FABE, SP=01FF, CC=N--B-I--, A=00, X=00, Y=07]
\r
722 FABE: A5 01 LDA $01 [PC=FAC0, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
\r
723 FAC0: C9 C0 CMP #$C0 [PC=FAC2, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
\r
724 FAC2: F0 D7 BEQ $FA9B [PC=FAC4, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
\r
725 FAC4: 8D F8 07 STA $07F8 [PC=FAC7, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
\r
726 FAC7: B1 00 LDA ($00),Y
\r
727 *** Read at I/O address C007
\r
728 [PC=FAC9, SP=01FF, CC=---B-IZ-, A=00, X=00, Y=07]
\r
729 FAC9: D9 01 FB CMP $FB01,Y [PC=FACC, SP=01FF, CC=---B-I--, A=00, X=00, Y=07]
\r
730 FACC: D0 EC BNE $FABA [PC=FABA, SP=01FF, CC=---B-I--, A=00, X=00, Y=07]
\r
732 Should be fixed now... (was adding instead of subtracting!)
\r
734 Small problem here... First two should set the carry while the last one should clear it. !!! FIX !!! [DONE]
\r
736 FDF0: C9 A0 CMP #$A0 [PC=FDF2, SP=01F1, CC=---B-IZ-, A=A0, X=02, Y=03]
\r
737 FD7E: C9 E0 CMP #$E0 [PC=FD80, SP=01F4, CC=N--B-I--, A=A0, X=02, Y=03]
\r
738 FD38: C9 9B CMP #$9B [PC=FD3A, SP=01F2, CC=---B-I-C, A=A0, X=02, Y=03]
\r
740 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.
\r
743 #define OP_CMP_HANDLER(m) \
\r
744 uint8 result = regs.a - (m); \
\r
745 SET_ZNC_CMP(m, regs.a, result)
\r
747 static void OpC9(void) // CMP #
\r
749 uint8 m = READ_IMM;
\r
753 static void OpC5(void) // CMP ZP
\r
759 static void OpD5(void) // CMP ZP, X
\r
761 uint8 m = READ_ZP_X;
\r
765 static void OpCD(void) // CMP ABS
\r
767 uint8 m = READ_ABS;
\r
771 static void OpDD(void) // CMP ABS, X
\r
773 uint8 m = READ_ABS_X;
\r
777 static void OpD9(void) // CMP ABS, Y
\r
779 uint8 m = READ_ABS_Y;
\r
783 static void OpC1(void) // CMP (ZP, X)
\r
785 uint8 m = READ_IND_ZP_X;
\r
789 static void OpD1(void) // CMP (ZP), Y
\r
791 uint8 m = READ_IND_ZP_Y;
\r
795 static void OpD2(void) // CMP (ZP)
\r
797 uint8 m = READ_IND_ZP;
\r
802 CPX Immediate CPX #Oper E0 2 2
\r
803 Zero Page CPX Zpg E4 2 3
\r
804 Absolute CPX Abs EC 3 4
\r
809 #define OP_CPX_HANDLER(m) \
\r
810 uint8 result = regs.x - (m); \
\r
811 SET_ZNC_CMP(m, regs.x, result)
\r
813 static void OpE0(void) // CPX #
\r
815 uint8 m = READ_IMM;
\r
819 static void OpE4(void) // CPX ZP
\r
825 static void OpEC(void) // CPX ABS
\r
827 uint8 m = READ_ABS;
\r
832 CPY Immediate CPY #Oper C0 2 2
\r
833 Zero Page CPY Zpg C4 2 3
\r
834 Absolute CPY Abs CC 3 4
\r
839 #define OP_CPY_HANDLER(m) \
\r
840 uint8 result = regs.y - (m); \
\r
841 SET_ZNC_CMP(m, regs.y, result)
\r
843 static void OpC0(void) // CPY #
\r
845 uint8 m = READ_IMM;
\r
849 static void OpC4(void) // CPY ZP
\r
855 static void OpCC(void) // CPY ABS
\r
857 uint8 m = READ_ABS;
\r
862 DEA Accumulator DEA 3A 1 2
\r
865 static void Op3A(void) // DEA
\r
872 DEC Zero Page DEC Zpg C6 2 5
\r
873 Zero Page,X DEC Zpg,X D6 2 6
\r
874 Absolute DEC Abs CE 3 6
\r
875 Absolute,X DEC Abs,X DE 3 7
\r
880 #define OP_DEC_HANDLER(m) \
\r
884 static void OpC6(void) // DEC ZP
\r
892 static void OpD6(void) // DEC ZP, X
\r
900 static void OpCE(void) // DEC ABS
\r
908 static void OpDE(void) // DEC ABS, X
\r
917 Here's one problem: DEX is setting the N flag!
\r
919 D3EE: A2 09 LDX #$09 [PC=D3F0, SP=01F7, CC=---B-I-C, A=01, X=09, Y=08]
\r
920 D3F0: 98 TYA [PC=D3F1, SP=01F7, CC=N--B-I-C, A=08, X=09, Y=08]
\r
921 D3F1: 48 PHA [PC=D3F2, SP=01F6, CC=N--B-I-C, A=08, X=09, Y=08]
\r
922 D3F2: B5 93 LDA $93,X [PC=D3F4, SP=01F6, CC=---B-IZC, A=00, X=09, Y=08]
\r
923 D3F4: CA DEX [PC=D3F5, SP=01F6, CC=N--B-I-C, A=00, X=08, Y=08]
\r
924 D3F5: 10 FA BPL $D3F1 [PC=D3F7, SP=01F6, CC=N--B-I-C, A=00, X=08, Y=08]
\r
925 D3F7: 20 84 E4 JSR $E484 [PC=E484, SP=01F4, CC=N--B-I-C, A=00, X=08, Y=08]
\r
927 should be fixed now...
\r
931 DEX Implied DEX CA 1 2
\r
934 static void OpCA(void) // DEX
\r
941 DEY Implied DEY 88 1 2
\r
944 static void Op88(void) // DEY
\r
951 EOR Immediate EOR #Oper 49 2 2
\r
952 Zero Page EOR Zpg 45 2 3
\r
953 Zero Page,X EOR Zpg,X 55 2 4
\r
954 Absolute EOR Abs 4D 3 4
\r
955 Absolute,X EOR Abs,X 5D 3 4
\r
956 Absolute,Y EOR Abs,Y 59 3 4
\r
957 (Zero Page,X) EOR (Zpg,X) 41 2 6
\r
958 (Zero Page),Y EOR (Zpg),Y 51 2 5
\r
959 (Zero Page) EOR (Zpg) 52 2 5
\r
964 #define OP_EOR_HANDLER(m) \
\r
968 static void Op49(void) // EOR #
\r
970 uint8 m = READ_IMM;
\r
974 static void Op45(void) // EOR ZP
\r
980 static void Op55(void) // EOR ZP, X
\r
982 uint8 m = READ_ZP_X;
\r
986 static void Op4D(void) // EOR ABS
\r
988 uint8 m = READ_ABS;
\r
992 static void Op5D(void) // EOR ABS, X
\r
994 uint8 m = READ_ABS_X;
\r
998 static void Op59(void) // EOR ABS, Y
\r
1000 uint8 m = READ_ABS_Y;
\r
1001 OP_EOR_HANDLER(m);
\r
1004 static void Op41(void) // EOR (ZP, X)
\r
1006 uint8 m = READ_IND_ZP_X;
\r
1007 OP_EOR_HANDLER(m);
\r
1010 static void Op51(void) // EOR (ZP), Y
\r
1012 uint8 m = READ_IND_ZP_Y;
\r
1013 OP_EOR_HANDLER(m);
\r
1016 static void Op52(void) // EOR (ZP)
\r
1018 uint8 m = READ_IND_ZP;
\r
1019 OP_EOR_HANDLER(m);
\r
1023 INA Accumulator INA 1A 1 2
\r
1026 static void Op1A(void) // INA
\r
1033 INC Zero Page INC Zpg E6 2 5
\r
1034 Zero Page,X INC Zpg,X F6 2 6
\r
1035 Absolute INC Abs EE 3 6
\r
1036 Absolute,X INC Abs,X FE 3 7
\r
1041 #define OP_INC_HANDLER(m) \
\r
1045 static void OpE6(void) // INC ZP
\r
1049 OP_INC_HANDLER(m);
\r
1053 static void OpF6(void) // INC ZP, X
\r
1057 OP_INC_HANDLER(m);
\r
1061 static void OpEE(void) // INC ABS
\r
1065 OP_INC_HANDLER(m);
\r
1069 static void OpFE(void) // INC ABS, X
\r
1073 OP_INC_HANDLER(m);
\r
1078 INX Implied INX E8 1 2
\r
1081 static void OpE8(void) // INX
\r
1088 INY Implied INY C8 1 2
\r
1091 static void OpC8(void) // INY
\r
1098 JMP Absolute JMP Abs 4C 3 3
\r
1099 (Absolute) JMP (Abs) 6C 3 5
\r
1100 (Absolute,X) JMP (Abs,X) 7C 3 6
\r
1105 static void Op4C(void) // JMP ABS
\r
1107 regs.pc = RdMemW(regs.pc);
\r
1110 static void Op6C(void) // JMP (ABS)
\r
1112 // uint16 addr = RdMemW(regs.pc);
\r
1113 //#ifdef __DEBUG__
\r
1114 //WriteLog("\n[JMP ABS]: addr fetched = %04X, bytes at %04X = %02X %02X (RdMemw=%04X)\n",
\r
1115 // addr, addr, regs.RdMem(addr), regs.RdMem(addr+1), RdMemW(addr));
\r
1117 // addr = RdMemW(addr);
\r
1118 regs.pc = RdMemW(RdMemW(regs.pc));
\r
1121 static void Op7C(void) // JMP (ABS, X)
\r
1123 regs.pc = RdMemW(RdMemW(regs.pc) + regs.x);
\r
1127 JSR Absolute JSR Abs 20 3 6
\r
1130 //This is not jumping to the correct address... !!! FIX !!! [DONE]
\r
1131 static void Op20(void) // JSR
\r
1133 uint16 addr = RdMemW(regs.pc);
\r
1134 regs.pc++; // Since it pushes return address - 1...
\r
1135 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8);
\r
1136 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
\r
1141 LDA Immediate LDA #Oper A9 2 2
\r
1142 Zero Page LDA Zpg A5 2 3
\r
1143 Zero Page,X LDA Zpg,X B5 2 4
\r
1144 Absolute LDA Abs AD 3 4
\r
1145 Absolute,X LDA Abs,X BD 3 4
\r
1146 Absolute,Y LDA Abs,Y B9 3 4
\r
1147 (Zero Page,X) LDA (Zpg,X) A1 2 6
\r
1148 (Zero Page),Y LDA (Zpg),Y B1 2 5
\r
1149 (Zero Page) LDA (Zpg) B2 2 5
\r
1154 #define OP_LDA_HANDLER(m) \
\r
1158 static void OpA9(void) // LDA #
\r
1160 uint8 m = READ_IMM;
\r
1161 OP_LDA_HANDLER(m);
\r
1164 static void OpA5(void) // LDA ZP
\r
1166 uint8 m = READ_ZP;
\r
1167 OP_LDA_HANDLER(m);
\r
1170 static void OpB5(void) // LDA ZP, X
\r
1172 uint8 m = READ_ZP_X;
\r
1173 OP_LDA_HANDLER(m);
\r
1176 static void OpAD(void) // LDA ABS
\r
1178 uint8 m = READ_ABS;
\r
1179 OP_LDA_HANDLER(m);
\r
1182 static void OpBD(void) // LDA ABS, X
\r
1184 uint8 m = READ_ABS_X;
\r
1185 OP_LDA_HANDLER(m);
\r
1188 static void OpB9(void) // LDA ABS, Y
\r
1190 uint8 m = READ_ABS_Y;
\r
1191 OP_LDA_HANDLER(m);
\r
1194 static void OpA1(void) // LDA (ZP, X)
\r
1196 uint8 m = READ_IND_ZP_X;
\r
1197 OP_LDA_HANDLER(m);
\r
1200 static void OpB1(void) // LDA (ZP), Y
\r
1202 uint8 m = READ_IND_ZP_Y;
\r
1203 OP_LDA_HANDLER(m);
\r
1206 static void OpB2(void) // LDA (ZP)
\r
1208 uint8 m = READ_IND_ZP;
\r
1209 OP_LDA_HANDLER(m);
\r
1213 LDX Immediate LDX #Oper A2 2 2
\r
1214 Zero Page LDX Zpg A6 2 3
\r
1215 Zero Page,Y LDX Zpg,Y B6 2 4
\r
1216 Absolute LDX Abs AE 3 4
\r
1217 Absolute,Y LDX Abs,Y BE 3 4
\r
1222 #define OP_LDX_HANDLER(m) \
\r
1226 static void OpA2(void) // LDX #
\r
1228 uint8 m = READ_IMM;
\r
1229 OP_LDX_HANDLER(m);
\r
1232 static void OpA6(void) // LDX ZP
\r
1234 uint8 m = READ_ZP;
\r
1235 OP_LDX_HANDLER(m);
\r
1238 static void OpB6(void) // LDX ZP, Y
\r
1240 uint8 m = READ_ZP_Y;
\r
1241 OP_LDX_HANDLER(m);
\r
1244 static void OpAE(void) // LDX ABS
\r
1246 uint8 m = READ_ABS;
\r
1247 OP_LDX_HANDLER(m);
\r
1250 static void OpBE(void) // LDX ABS, Y
\r
1252 uint8 m = READ_ABS_Y;
\r
1253 OP_LDX_HANDLER(m);
\r
1257 LDY Immediate LDY #Oper A0 2 2
\r
1258 Zero Page LDY Zpg A4 2 3
\r
1259 Zero Page,Y LDY Zpg,X B4 2 4
\r
1260 Absolute LDY Abs AC 3 4
\r
1261 Absolute,Y LDY Abs,X BC 3 4
\r
1266 #define OP_LDY_HANDLER(m) \
\r
1270 static void OpA0(void) // LDY #
\r
1272 uint8 m = READ_IMM;
\r
1273 OP_LDY_HANDLER(m);
\r
1276 static void OpA4(void) // LDY ZP
\r
1278 uint8 m = READ_ZP;
\r
1279 OP_LDY_HANDLER(m);
\r
1282 static void OpB4(void) // LDY ZP, X
\r
1284 uint8 m = READ_ZP_X;
\r
1285 OP_LDY_HANDLER(m);
\r
1288 static void OpAC(void) // LDY ABS
\r
1290 uint8 m = READ_ABS;
\r
1291 OP_LDY_HANDLER(m);
\r
1294 static void OpBC(void) // LDY ABS, X
\r
1296 uint8 m = READ_ABS_X;
\r
1297 OP_LDY_HANDLER(m);
\r
1301 LSR Accumulator LSR A 4A 1 2
\r
1302 Zero Page LSR Zpg 46 2 5
\r
1303 Zero Page,X LSR Zpg,X 56 2 6
\r
1304 Absolute LSR Abs 4E 3 6
\r
1305 Absolute,X LSR Abs,X 5E 3 7
\r
1310 #define OP_LSR_HANDLER(m) \
\r
1311 regs.cc = ((m) & 0x01 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
\r
1315 static void Op4A(void) // LSR A
\r
1317 OP_LSR_HANDLER(regs.a);
\r
1320 static void Op46(void) // LSR ZP
\r
1324 OP_LSR_HANDLER(m);
\r
1328 static void Op56(void) // LSR ZP, X
\r
1332 OP_LSR_HANDLER(m);
\r
1336 static void Op4E(void) // LSR ABS
\r
1340 OP_LSR_HANDLER(m);
\r
1344 static void Op5E(void) // LSR ABS, X
\r
1348 OP_LSR_HANDLER(m);
\r
1353 NOP Implied NOP EA 1 2
\r
1356 static void OpEA(void) // NOP
\r
1361 ORA Immediate ORA #Oper 09 2 2
\r
1362 Zero Page ORA Zpg 05 2 3
\r
1363 Zero Page,X ORA Zpg,X 15 2 4
\r
1364 Absolute ORA Abs 0D 3 4
\r
1365 Absolute,X ORA Abs,X 1D 3 4
\r
1366 Absolute,Y ORA Abs,Y 19 3 4
\r
1367 (Zero Page,X) ORA (Zpg,X) 01 2 6
\r
1368 (Zero Page),Y ORA (Zpg),Y 11 2 5
\r
1369 (Zero Page) ORA (Zpg) 12 2 5
\r
1374 #define OP_ORA_HANDLER(m) \
\r
1378 static void Op09(void) // ORA #
\r
1380 uint8 m = READ_IMM;
\r
1381 OP_ORA_HANDLER(m);
\r
1384 static void Op05(void) // ORA ZP
\r
1386 uint8 m = READ_ZP;
\r
1387 OP_ORA_HANDLER(m);
\r
1390 static void Op15(void) // ORA ZP, X
\r
1392 uint8 m = READ_ZP_X;
\r
1393 OP_ORA_HANDLER(m);
\r
1396 static void Op0D(void) // ORA ABS
\r
1398 uint8 m = READ_ABS;
\r
1399 OP_ORA_HANDLER(m);
\r
1402 static void Op1D(void) // ORA ABS, X
\r
1404 uint8 m = READ_ABS_X;
\r
1405 OP_ORA_HANDLER(m);
\r
1408 static void Op19(void) // ORA ABS, Y
\r
1410 uint8 m = READ_ABS_Y;
\r
1411 OP_ORA_HANDLER(m);
\r
1414 static void Op01(void) // ORA (ZP, X)
\r
1416 uint8 m = READ_IND_ZP_X;
\r
1417 OP_ORA_HANDLER(m);
\r
1420 static void Op11(void) // ORA (ZP), Y
\r
1422 uint8 m = READ_IND_ZP_Y;
\r
1423 OP_ORA_HANDLER(m);
\r
1426 static void Op12(void) // ORA (ZP)
\r
1428 uint8 m = READ_IND_ZP;
\r
1429 OP_ORA_HANDLER(m);
\r
1433 PHA Implied PHA 48 1 3
\r
1436 static void Op48(void) // PHA
\r
1438 regs.WrMem(0x0100 + regs.sp--, regs.a);
\r
1441 static void Op08(void) // PHP
\r
1443 regs.cc |= FLAG_UNK; // Make sure that the unused bit is always set
\r
1444 regs.WrMem(0x0100 + regs.sp--, regs.cc);
\r
1448 PHX Implied PHX DA 1 3
\r
1451 static void OpDA(void) // PHX
\r
1453 regs.WrMem(0x0100 + regs.sp--, regs.x);
\r
1457 PHY Implied PHY 5A 1 3
\r
1460 static void Op5A(void) // PHY
\r
1462 regs.WrMem(0x0100 + regs.sp--, regs.y);
\r
1466 PLA Implied PLA 68 1 4
\r
1469 static void Op68(void) // PLA
\r
1471 regs.a = regs.RdMem(0x0100 + ++regs.sp);
\r
1475 static void Op28(void) // PLP
\r
1477 regs.cc = regs.RdMem(0x0100 + ++regs.sp);
\r
1481 PLX Implied PLX FA 1 4
\r
1484 static void OpFA(void) // PLX
\r
1486 regs.x = regs.RdMem(0x0100 + ++regs.sp);
\r
1491 PLY Implied PLY 7A 1 4
\r
1494 static void Op7A(void) // PLY
\r
1496 regs.y = regs.RdMem(0x0100 + ++regs.sp);
\r
1501 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.
\r
1502 RMB0 RMB1 RMB2 RMB3 RMB4 RMB5 RMB6 RMB7
\r
1503 zp 07 17 27 37 47 57 67 77
\r
1504 SMB0 SMB1 SMB2 SMB3 SMB4 SMB5 SMB6 SMB7
\r
1505 zp 87 97 A7 B7 C7 D7 E7 F7
\r
1510 static void Op07(void) // RMB0 ZP
\r
1518 static void Op17(void) // RMB1 ZP
\r
1526 static void Op27(void) // RMB2 ZP
\r
1534 static void Op37(void) // RMB3 ZP
\r
1542 static void Op47(void) // RMB4 ZP
\r
1550 static void Op57(void) // RMB5 ZP
\r
1558 static void Op67(void) // RMB6 ZP
\r
1566 static void Op77(void) // RMB7 ZP
\r
1575 ROL Accumulator ROL A 2A 1 2
\r
1576 Zero Page ROL Zpg 26 2 5
\r
1577 Zero Page,X ROL Zpg,X 36 2 6
\r
1578 Absolute ROL Abs 2E 3 6
\r
1579 Absolute,X ROL Abs,X 3E 3 7
\r
1584 #define OP_ROL_HANDLER(m) \
\r
1585 uint8 tmp = regs.cc & 0x01; \
\r
1586 regs.cc = ((m) & 0x80 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
\r
1587 (m) = ((m) << 1) | tmp; \
\r
1590 static void Op2A(void) // ROL A
\r
1592 OP_ROL_HANDLER(regs.a);
\r
1595 static void Op26(void) // ROL ZP
\r
1599 OP_ROL_HANDLER(m);
\r
1603 static void Op36(void) // ROL ZP, X
\r
1607 OP_ROL_HANDLER(m);
\r
1611 static void Op2E(void) // ROL ABS
\r
1615 OP_ROL_HANDLER(m);
\r
1619 static void Op3E(void) // ROL ABS, X
\r
1623 OP_ROL_HANDLER(m);
\r
1628 ROR Accumulator ROR A 6A 1 2
\r
1629 Zero Page ROR Zpg 66 2 5
\r
1630 Zero Page,X ROR Zpg,X 76 2 6
\r
1631 Absolute ROR Abs 6E 3 6
\r
1632 Absolute,X ROR Abs,X 7E 3 7
\r
1637 #define OP_ROR_HANDLER(m) \
\r
1638 uint8 tmp = (regs.cc & 0x01) << 7; \
\r
1639 regs.cc = ((m) & 0x01 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
\r
1640 (m) = ((m) >> 1) | tmp; \
\r
1643 static void Op6A(void) // ROR A
\r
1645 OP_ROR_HANDLER(regs.a);
\r
1648 static void Op66(void) // ROR ZP
\r
1652 OP_ROR_HANDLER(m);
\r
1656 static void Op76(void) // ROR ZP, X
\r
1660 OP_ROR_HANDLER(m);
\r
1664 static void Op6E(void) // ROR ABS
\r
1668 OP_ROR_HANDLER(m);
\r
1672 static void Op7E(void) // ROR ABS, X
\r
1676 OP_ROR_HANDLER(m);
\r
1681 RTI Implied RTI 40 1 6
\r
1684 static void Op40(void) // RTI
\r
1686 regs.cc = regs.RdMem(0x0100 + ++regs.sp);
\r
1687 regs.pc = regs.RdMem(0x0100 + ++regs.sp);
\r
1688 regs.pc |= (uint16)(regs.RdMem(0x0100 + ++regs.sp)) << 8;
\r
1692 RTS Implied RTS 60 1 6
\r
1695 static void Op60(void) // RTS
\r
1697 regs.pc = regs.RdMem(0x0100 + ++regs.sp);
\r
1698 regs.pc |= (uint16)(regs.RdMem(0x0100 + ++regs.sp)) << 8;
\r
1699 regs.pc++; // Since it pushes return address - 1...
\r
1700 //printf("*** RTS: PC = $%04X, SP= $1%02X\n", regs.pc, regs.sp);
\r
1705 SBC Immediate SBC #Oper E9 2 2
\r
1706 Zero Page SBC Zpg E5 2 3
\r
1707 Zero Page,X SBC Zpg,X F5 2 4
\r
1708 Absolute SBC Abs ED 3 4
\r
1709 Absolute,X SBC Abs,X FD 3 4
\r
1710 Absolute,Y SBC Abs,Y F9 3 4
\r
1711 (Zero Page,X) SBC (Zpg,X) E1 2 6
\r
1712 (Zero Page),Y SBC (Zpg),Y F1 2 5
\r
1713 (Zero Page) SBC (Zpg) F2 2 5
\r
1718 //This is non-optimal, but it works--optimize later. :-)
\r
1719 //This is correct except for the BCD handling... !!! FIX !!! [Possibly DONE]
\r
1720 #define OP_SBC_HANDLER(m) \
\r
1721 uint16 sum = (uint16)regs.a - (m) - (uint16)((regs.cc & FLAG_C) ^ 0x01); \
\r
1723 if (regs.cc & FLAG_D) \
\r
1725 if ((sum & 0x0F) > 0x09) \
\r
1728 if ((sum & 0xF0) > 0x90) \
\r
1732 regs.cc = (regs.cc & ~FLAG_C) | (((sum >> 8) ^ 0x01) & FLAG_C); \
\r
1733 regs.cc = ((regs.a ^ (m)) & (regs.a ^ sum) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V); \
\r
1734 regs.a = sum & 0xFF; \
\r
1738 D5AF: 38 SEC [PC=D5B0, SP=01F6, CC=---B-I-C, A=4C, X=00, Y=06]
\r
1740 *** HERE'S where it sets the D flag on a subtract... Arg!
\r
1742 D5B0: F1 9D SBC ($9D),Y [PC=D5B2, SP=01F6, CC=N--BDI--, A=FE, X=00, Y=06]
\r
1747 //OLD V detection: regs.cc = ((regs.a ^ (m) ^ sum ^ (regs.cc << 7)) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V);
\r
1749 static void OpE9(void) // SBC #
\r
1751 uint16 m = READ_IMM;
\r
1752 OP_SBC_HANDLER(m);
\r
1755 static void OpE5(void) // SBC ZP
\r
1757 uint16 m = READ_ZP;
\r
1758 OP_SBC_HANDLER(m);
\r
1761 static void OpF5(void) // SBC ZP, X
\r
1763 uint16 m = READ_ZP_X;
\r
1764 OP_SBC_HANDLER(m);
\r
1767 static void OpED(void) // SBC ABS
\r
1769 uint16 m = READ_ABS;
\r
1770 OP_SBC_HANDLER(m);
\r
1773 static void OpFD(void) // SBC ABS, X
\r
1775 uint16 m = READ_ABS_X;
\r
1776 OP_SBC_HANDLER(m);
\r
1779 static void OpF9(void) // SBC ABS, Y
\r
1781 uint16 m = READ_ABS_Y;
\r
1782 OP_SBC_HANDLER(m);
\r
1785 static void OpE1(void) // SBC (ZP, X)
\r
1787 uint16 m = READ_IND_ZP_X;
\r
1788 OP_SBC_HANDLER(m);
\r
1791 static void OpF1(void) // SBC (ZP), Y
\r
1793 uint16 m = READ_IND_ZP_Y;
\r
1794 OP_SBC_HANDLER(m);
\r
1797 static void OpF2(void) // SBC (ZP)
\r
1799 uint16 m = READ_IND_ZP;
\r
1800 OP_SBC_HANDLER(m);
\r
1804 SEC Implied SEC 38 1 2
\r
1807 static void Op38(void) // SEC
\r
1809 regs.cc |= FLAG_C;
\r
1813 SED Implied SED F8 1 2
\r
1816 static void OpF8(void) // SED
\r
1818 regs.cc |= FLAG_D;
\r
1822 SEI Implied SEI 78 1 2
\r
1825 static void Op78(void) // SEI
\r
1827 regs.cc |= FLAG_I;
\r
1831 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.
\r
1832 RMB0 RMB1 RMB2 RMB3 RMB4 RMB5 RMB6 RMB7
\r
1833 zp 07 17 27 37 47 57 67 77
\r
1834 SMB0 SMB1 SMB2 SMB3 SMB4 SMB5 SMB6 SMB7
\r
1835 zp 87 97 A7 B7 C7 D7 E7 F7
\r
1840 static void Op87(void) // SMB0 ZP
\r
1848 static void Op97(void) // SMB1 ZP
\r
1856 static void OpA7(void) // SMB2 ZP
\r
1864 static void OpB7(void) // SMB3 ZP
\r
1872 static void OpC7(void) // SMB4 ZP
\r
1880 static void OpD7(void) // SMB5 ZP
\r
1888 static void OpE7(void) // SMB6 ZP
\r
1896 static void OpF7(void) // SMB7 ZP
\r
1905 STA Zero Page STA Zpg 85 2 3
\r
1906 Zero Page,X STA Zpg,X 95 2 4
\r
1907 Absolute STA Abs 8D 3 4
\r
1908 Absolute,X STA Abs,X 9D 3 5
\r
1909 Absolute,Y STA Abs,Y 99 3 5
\r
1910 (Zero Page,X) STA (Zpg,X) 81 2 6
\r
1911 (Zero Page),Y STA (Zpg),Y 91 2 6
\r
1912 (Zero Page) STA (Zpg) 92 2 5
\r
1917 static void Op85(void)
\r
1919 regs.WrMem(EA_ZP, regs.a);
\r
1922 static void Op95(void)
\r
1924 regs.WrMem(EA_ZP_X, regs.a);
\r
1927 static void Op8D(void)
\r
1929 regs.WrMem(EA_ABS, regs.a);
\r
1933 static void Op9D(void)
\r
1935 regs.WrMem(EA_ABS_X, regs.a);
\r
1939 static void Op99(void)
\r
1941 regs.WrMem(EA_ABS_Y, regs.a);
\r
1945 static void Op81(void)
\r
1947 regs.WrMem(EA_IND_ZP_X, regs.a);
\r
1950 static void Op91(void)
\r
1952 regs.WrMem(EA_IND_ZP_Y, regs.a);
\r
1955 static void Op92(void)
\r
1957 regs.WrMem(EA_IND_ZP, regs.a);
\r
1961 STX Zero Page STX Zpg 86 2 3
\r
1962 Zero Page,Y STX Zpg,Y 96 2 4
\r
1963 Absolute STX Abs 8E 3 4
\r
1968 static void Op86(void)
\r
1970 regs.WrMem(EA_ZP, regs.x);
\r
1973 static void Op96(void)
\r
1975 regs.WrMem(EA_ZP_X, regs.x);
\r
1978 static void Op8E(void)
\r
1980 regs.WrMem(EA_ABS, regs.x);
\r
1985 STY Zero Page STY Zpg 84 2 3
\r
1986 Zero Page,X STY Zpg,X 94 2 4
\r
1987 Absolute STY Abs 8C 3 4
\r
1992 static void Op84(void)
\r
1994 regs.WrMem(EA_ZP, regs.y);
\r
1997 static void Op94(void)
\r
1999 regs.WrMem(EA_ZP_X, regs.y);
\r
2002 static void Op8C(void)
\r
2004 regs.WrMem(EA_ABS, regs.y);
\r
2009 STZ Zero Page STZ Zpg 64 2 3
\r
2010 Zero Page,X STZ Zpg,X 74 2 4
\r
2011 Absolute STZ Abs 9C 3 4
\r
2012 Absolute,X STZ Abs,X 9E 3 5
\r
2017 static void Op64(void)
\r
2019 regs.WrMem(EA_ZP, 0x00);
\r
2022 static void Op74(void)
\r
2024 regs.WrMem(EA_ZP_X, 0x00);
\r
2027 static void Op9C(void)
\r
2029 regs.WrMem(EA_ABS, 0x00);
\r
2033 static void Op9E(void)
\r
2035 regs.WrMem(EA_ABS_X, 0x00);
\r
2040 TAX Implied TAX AA 1 2
\r
2043 static void OpAA(void) // TAX
\r
2050 TAY Implied TAY A8 1 2
\r
2053 static void OpA8(void) // TAY
\r
2060 TRB Zero Page TRB Zpg 14 2 5
\r
2061 Absolute TRB Abs 1C 3 6
\r
2066 #define OP_TRB_HANDLER(m) \
\r
2067 SET_Z(m & regs.a); \
\r
2070 static void Op14(void) // TRB ZP
\r
2074 OP_TRB_HANDLER(m);
\r
2078 static void Op1C(void) // TRB ABS
\r
2082 OP_TRB_HANDLER(m);
\r
2087 TSB Zero Page TSB Zpg 04 2 5
\r
2088 Absolute TSB Abs 0C 3 6
\r
2093 #define OP_TSB_HANDLER(m) \
\r
2094 SET_Z(m & regs.a); \
\r
2097 static void Op04(void) // TSB ZP
\r
2101 OP_TSB_HANDLER(m);
\r
2105 static void Op0C(void) // TSB ABS
\r
2109 OP_TSB_HANDLER(m);
\r
2114 TSX Implied TSX BA 1 2
\r
2117 static void OpBA(void) // TSX
\r
2124 TXA Implied TXA 8A 1 2
\r
2127 static void Op8A(void) // TXA
\r
2134 TXS Implied TXS 9A 1 2
\r
2137 static void Op9A(void) // TXS
\r
2143 TYA Implied TYA 98 1 2
\r
2145 static void Op98(void) // TYA
\r
2151 static void Op__(void)
\r
2153 regs.cpuFlags |= V65C02_STATE_ILLEGAL_INST;
\r
2158 // Ok, the exec_op[] array is globally defined here basically to save
\r
2159 // a LOT of unnecessary typing. Sure it's ugly, but hey, it works!
\r
2161 void (* exec_op[256])() = {
\r
2162 Op00, Op01, Op__, Op__, Op04, Op05, Op06, Op07, Op08, Op09, Op0A, Op__, Op0C, Op0D, Op0E, Op0F,
\r
2163 Op10, Op11, Op12, Op__, Op14, Op15, Op16, Op17, Op18, Op19, Op1A, Op__, Op1C, Op1D, Op1E, Op1F,
\r
2164 Op20, Op21, Op__, Op__, Op24, Op25, Op26, Op27, Op28, Op29, Op2A, Op__, Op2C, Op2D, Op2E, Op2F,
\r
2165 Op30, Op31, Op32, Op__, Op34, Op35, Op36, Op37, Op38, Op39, Op3A, Op__, Op3C, Op3D, Op3E, Op3F,
\r
2166 Op40, Op41, Op__, Op__, Op__, Op45, Op46, Op47, Op48, Op49, Op4A, Op__, Op4C, Op4D, Op4E, Op4F,
\r
2167 Op50, Op51, Op52, Op__, Op__, Op55, Op56, Op57, Op58, Op59, Op5A, Op__, Op__, Op5D, Op5E, Op5F,
\r
2168 Op60, Op61, Op__, Op__, Op64, Op65, Op66, Op67, Op68, Op69, Op6A, Op__, Op6C, Op6D, Op6E, Op6F,
\r
2169 Op70, Op71, Op72, Op__, Op74, Op75, Op76, Op77, Op78, Op79, Op7A, Op__, Op7C, Op7D, Op7E, Op7F,
\r
2170 Op80, Op81, Op__, Op__, Op84, Op85, Op86, Op87, Op88, Op89, Op8A, Op__, Op8C, Op8D, Op8E, Op8F,
\r
2171 Op90, Op91, Op92, Op__, Op94, Op95, Op96, Op97, Op98, Op99, Op9A, Op__, Op9C, Op9D, Op9E, Op9F,
\r
2172 OpA0, OpA1, OpA2, Op__, OpA4, OpA5, OpA6, OpA7, OpA8, OpA9, OpAA, Op__, OpAC, OpAD, OpAE, OpAF,
\r
2173 OpB0, OpB1, OpB2, Op__, OpB4, OpB5, OpB6, OpB7, OpB8, OpB9, OpBA, Op__, OpBC, OpBD, OpBE, OpBF,
\r
2174 OpC0, OpC1, Op__, Op__, OpC4, OpC5, OpC6, OpC7, OpC8, OpC9, OpCA, Op__, OpCC, OpCD, OpCE, OpCF,
\r
2175 OpD0, OpD1, OpD2, Op__, Op__, OpD5, OpD6, OpD7, OpD8, OpD9, OpDA, Op__, Op__, OpDD, OpDE, OpDF,
\r
2176 OpE0, OpE1, Op__, Op__, OpE4, OpE5, OpE6, OpE7, OpE8, OpE9, OpEA, Op__, OpEC, OpED, OpEE, OpEF,
\r
2177 OpF0, OpF1, OpF2, Op__, Op__, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, Op__, Op__, OpFD, OpFE, OpFF
\r
2181 // Internal "memcpy" (so we don't have to link with any external libraries!)
\r
2183 static void myMemcpy(void * dst, void * src, uint32 size)
\r
2185 uint8 * d = (uint8 *)dst, * s = (uint8 *)src;
\r
2187 for(uint32 i=0; i<size; i++)
\r
2192 FCA8: 38 698 WAIT SEC
\r
2193 FCA9: 48 699 WAIT2 PHA
\r
2194 FCAA: E9 01 700 WAIT3 SBC #$01
\r
2195 FCAC: D0 FC 701 BNE WAIT3 ;1.0204 USEC
\r
2196 FCAE: 68 702 PLA ;(13+27/2*A+5/2*A*A)
\r
2197 FCAF: E9 01 703 SBC #$01
\r
2198 FCB1: D0 F6 704 BNE WAIT2
\r
2201 FBD9: C9 87 592 BELL1 CMP #$87 ;BELL CHAR? (CNTRL-G)
\r
2202 FBDB: D0 12 593 BNE RTS2B ; NO, RETURN
\r
2203 FBDD: A9 40 594 LDA #$40 ;DELAY .01 SECONDS
\r
2204 FBDF: 20 A8 FC 595 JSR WAIT
\r
2205 FBE2: A0 C0 596 LDY #$C0
\r
2206 FBE4: A9 0C 597 BELL2 LDA #$0C ;TOGGLE SPEAKER AT
\r
2207 FBE6: 20 A8 FC 598 JSR WAIT ; 1 KHZ FOR .1 SEC.
\r
2208 FBE9: AD 30 C0 599 LDA SPKR
\r
2210 FBED: D0 F5 601 BNE BELL2
\r
2211 FBEF: 60 602 RTS2B RTS
\r
2213 //int instCount[256];
\r
2215 bool dumpDis = false;
\r
2218 // Function to execute 6808 for "cycles" cycles
\r
2220 void Execute65C02(V65C02REGS * context, uint32 cycles)
\r
2222 myMemcpy(®s, context, sizeof(V65C02REGS));
\r
2224 // Execute here...
\r
2225 while (regs.clock < cycles)
\r
2228 /*if (regs.pc == 0x4007)
\r
2232 if (regs.pc == 0x444B)
\r
2234 WriteLog("\n*** End of wait...\n\n");
\r
2237 if (regs.pc == 0x444E)
\r
2239 WriteLog("\n*** Start of wait...\n\n");
\r
2244 #ifdef __DEBUGMON__
\r
2245 //WAIT is commented out here because it's called by BELL1...
\r
2246 if (regs.pc == 0xFCA8)
\r
2248 WriteLog("\n*** WAIT subroutine...\n\n");
\r
2251 if (regs.pc == 0xFBD9)
\r
2253 WriteLog("\n*** BELL1 subroutine...\n\n");
\r
2254 // dumpDis = false;
\r
2256 if (regs.pc == 0xFC58)
\r
2258 WriteLog("\n*** HOME subroutine...\n\n");
\r
2259 // dumpDis = false;
\r
2261 if (regs.pc == 0xFDED)
\r
2263 WriteLog("\n*** COUT subroutine...\n\n");
\r
2270 Decode65C02(regs.pc);
\r
2272 uint8 opcode = regs.RdMem(regs.pc++);
\r
2274 //if (!(regs.cpuFlags & V65C02_STATE_ILLEGAL_INST))
\r
2275 //instCount[opcode]++;
\r
2277 exec_op[opcode](); // Execute that opcode...
\r
2278 regs.clock += CPUCycles[opcode];
\r
2281 WriteLog(" [PC=%04X, SP=%04X, CC=%s%s-%s%s%s%s%s, A=%02X, X=%02X, Y=%02X]\n",
\r
2282 regs.pc, 0x0100 + regs.sp,
\r
2283 (regs.cc & FLAG_N ? "N" : "-"), (regs.cc & FLAG_V ? "V" : "-"),
\r
2284 (regs.cc & FLAG_B ? "B" : "-"), (regs.cc & FLAG_D ? "D" : "-"),
\r
2285 (regs.cc & FLAG_I ? "I" : "-"), (regs.cc & FLAG_Z ? "Z" : "-"),
\r
2286 (regs.cc & FLAG_C ? "C" : "-"), regs.a, regs.x, regs.y);
\r
2289 #ifdef __DEBUGMON__
\r
2290 if (regs.pc == 0xFCB3) // WAIT exit point
\r
2294 /*if (regs.pc == 0xFBEF) // BELL1 exit point
\r
2298 /*if (regs.pc == 0xFC22) // HOME exit point
\r
2302 if (regs.pc == 0xFDFF) // COUT exit point
\r
2306 if (regs.pc == 0xFBD8)
\r
2308 WriteLog("\n*** BASCALC set BASL/H = $%04X\n\n", RdMemW(0x0028));
\r
2312 //These should be correct now...
\r
2313 if (regs.cpuFlags & V65C02_ASSERT_LINE_RESET)
\r
2316 WriteLog("\n*** RESET ***\n\n");
\r
2318 // Not sure about this...
\r
2320 regs.cc = FLAG_B | FLAG_I; // Reset the CC register
\r
2321 regs.pc = RdMemW(0xFFFC); // And load PC with the RESET vector
\r
2323 context->cpuFlags &= ~V65C02_ASSERT_LINE_RESET;
\r
2324 regs.cpuFlags &= ~V65C02_ASSERT_LINE_RESET;
\r
2326 else if (regs.cpuFlags & V65C02_ASSERT_LINE_NMI)
\r
2329 WriteLog("\n*** NMI ***\n\n");
\r
2331 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8); // Save PC and CC
\r
2332 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
\r
2333 regs.WrMem(0x0100 + regs.sp--, regs.cc);
\r
2334 regs.cc |= FLAG_I; // Set I
\r
2335 regs.cc &= ~FLAG_D; // & clear D
\r
2336 regs.pc = RdMemW(0xFFFA); // And do it!
\r
2339 context->cpuFlags &= ~V65C02_ASSERT_LINE_NMI;// Reset the asserted line (NMI)...
\r
2340 regs.cpuFlags &= ~V65C02_ASSERT_LINE_NMI; // Reset the asserted line (NMI)...
\r
2342 else if (regs.cpuFlags & V65C02_ASSERT_LINE_IRQ)
\r
2344 if (!(regs.cc & FLAG_I)) // Process an interrupt (I=0)?
\r
2347 WriteLog("\n*** IRQ ***\n\n");
\r
2349 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8); // Save PC and CC
\r
2350 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
\r
2351 regs.WrMem(0x0100 + regs.sp--, regs.cc);
\r
2352 regs.cc |= FLAG_I; // Set I
\r
2353 regs.cc &= ~FLAG_D; // & clear D
\r
2354 regs.pc = RdMemW(0xFFFE); // And do it!
\r
2357 context->cpuFlags &= ~V65C02_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
\r
2358 regs.cpuFlags &= ~V65C02_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
\r
2363 myMemcpy(context, ®s, sizeof(V65C02REGS));
\r
2367 // Get the clock of the currently executing CPU
\r
2369 uint32 GetCurrentV65C02Clock(void)
\r
2371 return regs.clock;
\r