2 // Virtual 65C02 Emulator v1.0
5 // (c) 2005 Underground Software
7 // JLH = James L. Hammons <jlhamm@acm.org>
10 // --- ---------- ------------------------------------------------------------
11 // JLH 01/04/2006 Added changelog ;-)
14 //OK, the wraparound bug exists in both the Apple and Atari versions of Ultima II.
15 //However, the Atari version *does* occassionally pick strength while the Apple
16 //versions do not--which would seem to indicate a bug either in the RNG algorithm,
17 //the 65C02 core, or the Apple hardware. Need to investigate all three!
18 //[As it turns out, it was a problem with the Apple RNG written by Origin. Bad Origin!]
21 //#define __DEBUGMON__
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))
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)
49 //Small problem with the EA_ macros: ABS macros don't increment the PC!!! !!! FIX !!!
50 #define EA_IMM regs.pc++
51 #define EA_ZP regs.RdMem(regs.pc++)
52 #define EA_ZP_X (regs.RdMem(regs.pc++) + regs.x) & 0xFF
53 #define EA_ZP_Y (regs.RdMem(regs.pc++) + regs.y) & 0xFF
54 #define EA_ABS RdMemW(regs.pc)
55 #define EA_ABS_X RdMemW(regs.pc) + regs.x
56 #define EA_ABS_Y RdMemW(regs.pc) + regs.y
57 #define EA_IND_ZP_X RdMemW((regs.RdMem(regs.pc++) + regs.x) & 0xFF)
58 #define EA_IND_ZP_Y RdMemW(regs.RdMem(regs.pc++)) + regs.y
59 #define EA_IND_ZP RdMemW(regs.RdMem(regs.pc++))
61 #define READ_IMM regs.RdMem(EA_IMM)
62 #define READ_ZP regs.RdMem(EA_ZP)
63 #define READ_ZP_X regs.RdMem(EA_ZP_X)
64 #define READ_ZP_Y regs.RdMem(EA_ZP_Y)
65 #define READ_ABS regs.RdMem(EA_ABS); regs.pc += 2
66 #define READ_ABS_X regs.RdMem(EA_ABS_X); regs.pc += 2
67 #define READ_ABS_Y regs.RdMem(EA_ABS_Y); regs.pc += 2
68 #define READ_IND_ZP_X regs.RdMem(EA_IND_ZP_X)
69 #define READ_IND_ZP_Y regs.RdMem(EA_IND_ZP_Y)
70 #define READ_IND_ZP regs.RdMem(EA_IND_ZP)
72 #define READ_IMM_WB(v) uint16 addr = EA_IMM; v = regs.RdMem(addr)
73 #define READ_ZP_WB(v) uint16 addr = EA_ZP; v = regs.RdMem(addr)
74 #define READ_ZP_X_WB(v) uint16 addr = EA_ZP_X; v = regs.RdMem(addr)
75 #define READ_ABS_WB(v) uint16 addr = EA_ABS; v = regs.RdMem(addr); regs.pc += 2
76 #define READ_ABS_X_WB(v) uint16 addr = EA_ABS_X; v = regs.RdMem(addr); regs.pc += 2
77 #define READ_ABS_Y_WB(v) uint16 addr = EA_ABS_Y; v = regs.RdMem(addr); regs.pc += 2
78 #define READ_IND_ZP_X_WB(v) uint16 addr = EA_IND_ZP_X; v = regs.RdMem(addr)
79 #define READ_IND_ZP_Y_WB(v) uint16 addr = EA_IND_ZP_Y; v = regs.RdMem(addr)
80 #define READ_IND_ZP_WB(v) uint16 addr = EA_IND_ZP; v = regs.RdMem(addr)
82 #define WRITE_BACK(d) regs.WrMem(addr, (d))
84 // Private global variables
86 static V65C02REGS regs;
88 //This is probably incorrect, at least WRT to the $x7 and $xF opcodes... !!! FIX !!!
89 //Also this doesn't take into account the extra cycle it takes when an indirect fetch
90 //(ABS, ABS X/Y, ZP) crosses a page boundary, or extra cycle for BCD add/subtract...
91 #warning Cycle counts are not accurate--!!! FIX !!!
92 static uint8 CPUCycles[256] = {
93 7, 6, 1, 1, 5, 3, 5, 1, 3, 2, 2, 1, 6, 4, 6, 1,
94 2, 5, 5, 1, 5, 4, 6, 1, 2, 4, 2, 1, 6, 4, 6, 1,
95 6, 6, 1, 1, 3, 3, 5, 1, 4, 2, 2, 1, 4, 4, 6, 1,
96 2, 5, 5, 1, 4, 4, 6, 1, 2, 4, 2, 1, 4, 4, 6, 1,
97 6, 6, 1, 1, 1, 3, 5, 1, 3, 2, 2, 1, 3, 4, 6, 1,
98 2, 5, 5, 1, 1, 4, 6, 1, 2, 4, 3, 1, 1, 4, 6, 1,
99 6, 6, 1, 1, 3, 3, 5, 1, 4, 2, 2, 1, 6, 4, 6, 1,
100 2, 5, 5, 1, 4, 4, 6, 1, 2, 4, 4, 1, 6, 4, 6, 1,
101 2, 6, 1, 1, 3, 3, 3, 1, 2, 2, 2, 1, 4, 4, 4, 1,
102 2, 6, 5, 1, 4, 4, 4, 1, 2, 5, 2, 1, 4, 5, 5, 1,
103 2, 6, 2, 1, 3, 3, 3, 1, 2, 2, 2, 1, 4, 4, 4, 1,
104 2, 5, 5, 1, 4, 4, 4, 1, 2, 4, 2, 1, 4, 4, 4, 1,
105 2, 6, 1, 1, 3, 3, 5, 1, 2, 2, 2, 1, 4, 4, 6, 1,
106 2, 5, 5, 1, 1, 4, 6, 1, 2, 4, 3, 1, 1, 4, 6, 1,
107 2, 6, 1, 1, 3, 3, 5, 1, 2, 2, 2, 1, 4, 4, 6, 1,
108 2, 5, 5, 1, 1, 4, 6, 1, 2, 4, 4, 1, 1, 4, 6, 1 };
110 // Private function prototypes
112 static uint16 RdMemW(uint16);
115 // Read a uint16 out of 65C02 memory (big endian format)
117 static uint16 RdMemW(uint16 address)
119 return (uint16)(regs.RdMem(address + 1) << 8) | regs.RdMem(address + 0);
124 // 65C02 OPCODE IMPLEMENTATION
126 // NOTE: Lots of macros are used here to save a LOT of typing. Also
127 // helps speed the debugging process. :-) Because of this, combining
128 // certain lines may look like a good idea but would end in disaster.
129 // You have been warned! ;-)
133 Mnemonic Addressing mode Form Opcode Size Timing
135 ADC Immediate ADC #Oper 69 2 2
136 Zero Page ADC Zpg 65 2 3
137 Zero Page,X ADC Zpg,X 75 2 4
138 Absolute ADC Abs 6D 3 4
139 Absolute,X ADC Abs,X 7D 3 4
140 Absolute,Y ADC Abs,Y 79 3 4
141 (Zero Page,X) ADC (Zpg,X) 61 2 6
142 (Zero Page),Y ADC (Zpg),Y 71 2 5
143 (Zero Page) ADC (Zpg) 72 2 5
148 //This is non-optimal, but it works--optimize later. :-)
149 #define OP_ADC_HANDLER(m) \
150 uint16 sum = (uint16)regs.a + (m) + (uint16)(regs.cc & FLAG_C); \
152 if (regs.cc & FLAG_D) \
154 if ((sum & 0x0F) > 0x09) \
157 if ((sum & 0xF0) > 0x90) \
161 regs.cc = (regs.cc & ~FLAG_C) | (sum >> 8); \
162 regs.cc = (~(regs.a ^ (m)) & (regs.a ^ sum) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V); \
163 regs.a = sum & 0xFF; \
166 //OLD V detection: regs.cc = ((regs.a ^ (m) ^ sum ^ (regs.cc << 7)) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V);
168 static void Op69(void) // ADC #
174 static void Op65(void) // ADC ZP
180 static void Op75(void) // ADC ZP, X
182 uint16 m = READ_ZP_X;
186 static void Op6D(void) // ADC ABS
192 static void Op7D(void) // ADC ABS, X
194 uint16 m = READ_ABS_X;
198 static void Op79(void) // ADC ABS, Y
200 uint16 m = READ_ABS_Y;
204 static void Op61(void) // ADC (ZP, X)
206 uint16 m = READ_IND_ZP_X;
210 static void Op71(void) // ADC (ZP), Y
212 uint16 m = READ_IND_ZP_Y;
216 static void Op72(void) // ADC (ZP)
218 uint16 m = READ_IND_ZP;
223 AND Immediate AND #Oper 29 2 2
224 Zero Page AND Zpg 25 2 3
225 Zero Page,X AND Zpg,X 35 2 4
226 Absolute AND Abs 2D 3 4
227 Absolute,X AND Abs,X 3D 3 4
228 Absolute,Y AND Abs,Y 39 3 4
229 (Zero Page,X) AND (Zpg,X) 21 2 6
230 (Zero Page),Y AND (Zpg),Y 31 2 5
231 (Zero Page) AND (Zpg) 32 2 5
236 #define OP_AND_HANDLER(m) \
240 static void Op29(void) // AND #
246 static void Op25(void) // AND ZP
252 static void Op35(void) // AND ZP, X
258 static void Op2D(void) // AND ABS
264 static void Op3D(void) // AND ABS, X
266 uint8 m = READ_ABS_X;
270 static void Op39(void) // AND ABS, Y
272 uint8 m = READ_ABS_Y;
276 static void Op21(void) // AND (ZP, X)
278 uint8 m = READ_IND_ZP_X;
282 static void Op31(void) // AND (ZP), Y
284 uint8 m = READ_IND_ZP_Y;
288 static void Op32(void) // AND (ZP)
290 uint8 m = READ_IND_ZP;
295 ASL Accumulator ASL A 0A 1 2
296 Zero Page ASL Zpg 06 2 5
297 Zero Page,X ASL Zpg,X 16 2 6
298 Absolute ASL Abs 0E 3 6
299 Absolute,X ASL Abs,X 1E 3 7
302 /*static void Op78(void) // LSL ABS
304 uint8 tmp; uint16 addr;
306 tmp = regs.RdMem(addr);
307 (tmp&0x80 ? regs.cc |= 0x01 : regs.cc &= 0xFE); // Shift hi bit into Carry
309 regs.WrMem(addr, tmp);
310 (tmp == 0 ? regs.cc |= 0x04 : regs.cc &= 0xFB); // Adjust Zero flag
311 (tmp&0x80 ? regs.cc |= 0x08 : regs.cc &= 0xF7); // Adjust Negative flag
316 #define OP_ASL_HANDLER(m) \
317 regs.cc = ((m) & 0x80 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
321 static void Op0A(void) // ASL A
323 OP_ASL_HANDLER(regs.a);
326 static void Op06(void) // ASL ZP
334 static void Op16(void) // ASL ZP, X
342 static void Op0E(void) // ASL ABS
350 static void Op1E(void) // ASL ABS, X
359 BBR0 Relative BBR0 Oper 0F 2 2
360 BBR1 Relative BBR1 Oper 1F 2 2
361 BBR2 Relative BBR2 Oper 2F 2 2
362 BBR3 Relative BBR3 Oper 3F 2 2
363 BBR4 Relative BBR4 Oper 4F 2 2
364 BBR5 Relative BBR5 Oper 5F 2 2
365 BBR6 Relative BBR6 Oper 6F 2 2
366 BBR7 Relative BBR7 Oper 7F 2 2
367 BBS0 Relative BBS0 Oper 8F 2 2
368 BBS1 Relative BBS1 Oper 9F 2 2
369 BBS2 Relative BBS2 Oper AF 2 2
370 BBS3 Relative BBS3 Oper BF 2 2
371 BBS4 Relative BBS4 Oper CF 2 2
372 BBS5 Relative BBS5 Oper DF 2 2
373 BBS6 Relative BBS6 Oper EF 2 2
374 BBS7 Relative BBS7 Oper FF 2 2
379 static void Op0F(void) // BBR0
381 int16 m = (int16)(int8)READ_IMM;
383 if (!(regs.a & 0x01))
387 static void Op1F(void) // BBR1
389 int16 m = (int16)(int8)READ_IMM;
391 if (!(regs.a & 0x02))
395 static void Op2F(void) // BBR2
397 int16 m = (int16)(int8)READ_IMM;
399 if (!(regs.a & 0x04))
403 static void Op3F(void) // BBR3
405 int16 m = (int16)(int8)READ_IMM;
407 if (!(regs.a & 0x08))
411 static void Op4F(void) // BBR4
413 int16 m = (int16)(int8)READ_IMM;
415 if (!(regs.a & 0x10))
419 static void Op5F(void) // BBR5
421 int16 m = (int16)(int8)READ_IMM;
423 if (!(regs.a & 0x20))
427 static void Op6F(void) // BBR6
429 int16 m = (int16)(int8)READ_IMM;
431 if (!(regs.a & 0x40))
435 static void Op7F(void) // BBR7
437 int16 m = (int16)(int8)READ_IMM;
439 if (!(regs.a & 0x80))
443 static void Op8F(void) // BBS0
445 int16 m = (int16)(int8)READ_IMM;
451 static void Op9F(void) // BBS1
453 int16 m = (int16)(int8)READ_IMM;
459 static void OpAF(void) // BBS2
461 int16 m = (int16)(int8)READ_IMM;
467 static void OpBF(void) // BBS3
469 int16 m = (int16)(int8)READ_IMM;
475 static void OpCF(void) // BBS4
477 int16 m = (int16)(int8)READ_IMM;
483 static void OpDF(void) // BBS5
485 int16 m = (int16)(int8)READ_IMM;
491 static void OpEF(void) // BBS6
493 int16 m = (int16)(int8)READ_IMM;
499 static void OpFF(void) // BBS7
501 int16 m = (int16)(int8)READ_IMM;
508 BCC Relative BCC Oper 90 2 2
509 BCS Relative BCS Oper B0 2 2
510 BEQ Relative BEQ Oper F0 2 2
515 static void Op90(void) // BCC
517 int16 m = (int16)(int8)READ_IMM;
519 if (!(regs.cc & FLAG_C))
523 static void OpB0(void) // BCS
525 int16 m = (int16)(int8)READ_IMM;
527 if (regs.cc & FLAG_C)
531 static void OpF0(void) // BEQ
533 int16 m = (int16)(int8)READ_IMM;
535 if (regs.cc & FLAG_Z)
540 BIT Immediate BIT #Oper 89 2 2
541 Zero Page BIT Zpg 24 2 3
542 Zero Page,X BIT Zpg,X 34 2 4
543 Absolute BIT Abs 2C 3 4
544 Absolute,X BIT Abs,X 3C 3 4
549 /* 1. The BIT instruction copies bit 6 to the V flag, and bit 7 to the N flag (except in immediate
550 addressing mode where V & N are untouched.) The accumulator and the operand are ANDed and the
551 Z flag is set appropriately. */
553 #define OP_BIT_HANDLER(m) \
554 int8 result = regs.a & (m); \
555 regs.cc &= ~(FLAG_N | FLAG_V); \
556 regs.cc |= ((m) & 0xC0); \
559 static void Op89(void) // BIT #
562 int8 result = regs.a & m;
566 static void Op24(void) // BIT ZP
572 static void Op34(void) // BIT ZP, X
578 static void Op2C(void) // BIT ABS
584 static void Op3C(void) // BIT ABS, X
586 uint8 m = READ_ABS_X;
591 BMI Relative BMI Oper 30 2 2
592 BNE Relative BNE Oper D0 2 2
593 BPL Relative BPL Oper 10 2 2
594 BRA Relative BRA Oper 80 2 3
597 // More branch opcodes
599 static void Op30(void) // BMI
601 int16 m = (int16)(int8)READ_IMM;
603 if (regs.cc & FLAG_N)
607 static void OpD0(void) // BNE
609 int16 m = (int16)(int8)READ_IMM;
611 if (!(regs.cc & FLAG_Z))
615 static void Op10(void) // BPL
617 int16 m = (int16)(int8)READ_IMM;
619 if (!(regs.cc & FLAG_N))
623 static void Op80(void) // BRA
625 int16 m = (int16)(int8)READ_IMM;
630 BRK Implied BRK 00 1 7
633 static void Op00(void) // BRK
635 regs.cc |= FLAG_B; // Set B
636 regs.pc++; // RTI comes back to the instruction one byte after the BRK
637 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8); // Save PC and CC
638 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
639 regs.WrMem(0x0100 + regs.sp--, regs.cc);
640 regs.cc |= FLAG_I; // Set I
641 regs.cc &= ~FLAG_D; // & clear D
642 regs.pc = RdMemW(0xFFFE); // Grab the IRQ vector & go...
646 BVC Relative BVC Oper 50 2 2
647 BVS Relative BVS Oper 70 2 2
650 // Even more branch opcodes
652 static void Op50(void) // BVC
654 int16 m = (int16)(int8)READ_IMM;
656 if (!(regs.cc & FLAG_V))
660 static void Op70(void) // BVS
662 int16 m = (int16)(int8)READ_IMM;
664 if (regs.cc & FLAG_V)
669 CLC Implied CLC 18 1 2
672 static void Op18(void) // CLC
678 CLD Implied CLD D8 1 2
681 static void OpD8(void) // CLD
687 CLI Implied CLI 58 1 2
690 static void Op58(void) // CLI
696 CLV Implied CLV B8 1 2
699 static void OpB8(void) // CLV
705 CMP Immediate CMP #Oper C9 2 2
706 Zero Page CMP Zpg C5 2 3
707 Zero Page,X CMP Zpg D5 2 4
708 Absolute CMP Abs CD 3 4
709 Absolute,X CMP Abs,X DD 3 4
710 Absolute,Y CMP Abs,Y D9 3 4
711 (Zero Page,X) CMP (Zpg,X) C1 2 6
712 (Zero Page),Y CMP (Zpg),Y D1 2 5
713 (Zero Page) CMP (Zpg) D2 2 5
719 Here's the latest: The CMP is NOT generating the Z flag when A=$C0!
721 FABA: A0 07 LDY #$07 [PC=FABC, SP=01FF, CC=---B-IZ-, A=00, X=00, Y=07]
722 FABC: C6 01 DEC $01 [PC=FABE, SP=01FF, CC=N--B-I--, A=00, X=00, Y=07]
723 FABE: A5 01 LDA $01 [PC=FAC0, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
724 FAC0: C9 C0 CMP #$C0 [PC=FAC2, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
725 FAC2: F0 D7 BEQ $FA9B [PC=FAC4, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
726 FAC4: 8D F8 07 STA $07F8 [PC=FAC7, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
727 FAC7: B1 00 LDA ($00),Y
728 *** Read at I/O address C007
729 [PC=FAC9, SP=01FF, CC=---B-IZ-, A=00, X=00, Y=07]
730 FAC9: D9 01 FB CMP $FB01,Y [PC=FACC, SP=01FF, CC=---B-I--, A=00, X=00, Y=07]
731 FACC: D0 EC BNE $FABA [PC=FABA, SP=01FF, CC=---B-I--, A=00, X=00, Y=07]
733 Should be fixed now... (was adding instead of subtracting!)
735 Small problem here... First two should set the carry while the last one should clear it. !!! FIX !!! [DONE]
737 FDF0: C9 A0 CMP #$A0 [PC=FDF2, SP=01F1, CC=---B-IZ-, A=A0, X=02, Y=03]
738 FD7E: C9 E0 CMP #$E0 [PC=FD80, SP=01F4, CC=N--B-I--, A=A0, X=02, Y=03]
739 FD38: C9 9B CMP #$9B [PC=FD3A, SP=01F2, CC=---B-I-C, A=A0, X=02, Y=03]
741 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.
744 #define OP_CMP_HANDLER(m) \
745 uint8 result = regs.a - (m); \
746 SET_ZNC_CMP(m, regs.a, result)
748 static void OpC9(void) // CMP #
754 static void OpC5(void) // CMP ZP
760 static void OpD5(void) // CMP ZP, X
766 static void OpCD(void) // CMP ABS
772 static void OpDD(void) // CMP ABS, X
774 uint8 m = READ_ABS_X;
778 static void OpD9(void) // CMP ABS, Y
780 uint8 m = READ_ABS_Y;
784 static void OpC1(void) // CMP (ZP, X)
786 uint8 m = READ_IND_ZP_X;
790 static void OpD1(void) // CMP (ZP), Y
792 uint8 m = READ_IND_ZP_Y;
796 static void OpD2(void) // CMP (ZP)
798 uint8 m = READ_IND_ZP;
803 CPX Immediate CPX #Oper E0 2 2
804 Zero Page CPX Zpg E4 2 3
805 Absolute CPX Abs EC 3 4
810 #define OP_CPX_HANDLER(m) \
811 uint8 result = regs.x - (m); \
812 SET_ZNC_CMP(m, regs.x, result)
814 static void OpE0(void) // CPX #
820 static void OpE4(void) // CPX ZP
826 static void OpEC(void) // CPX ABS
833 CPY Immediate CPY #Oper C0 2 2
834 Zero Page CPY Zpg C4 2 3
835 Absolute CPY Abs CC 3 4
840 #define OP_CPY_HANDLER(m) \
841 uint8 result = regs.y - (m); \
842 SET_ZNC_CMP(m, regs.y, result)
844 static void OpC0(void) // CPY #
850 static void OpC4(void) // CPY ZP
856 static void OpCC(void) // CPY ABS
863 DEA Accumulator DEA 3A 1 2
866 static void Op3A(void) // DEA
873 DEC Zero Page DEC Zpg C6 2 5
874 Zero Page,X DEC Zpg,X D6 2 6
875 Absolute DEC Abs CE 3 6
876 Absolute,X DEC Abs,X DE 3 7
881 #define OP_DEC_HANDLER(m) \
885 static void OpC6(void) // DEC ZP
893 static void OpD6(void) // DEC ZP, X
901 static void OpCE(void) // DEC ABS
909 static void OpDE(void) // DEC ABS, X
918 Here's one problem: DEX is setting the N flag!
920 D3EE: A2 09 LDX #$09 [PC=D3F0, SP=01F7, CC=---B-I-C, A=01, X=09, Y=08]
921 D3F0: 98 TYA [PC=D3F1, SP=01F7, CC=N--B-I-C, A=08, X=09, Y=08]
922 D3F1: 48 PHA [PC=D3F2, SP=01F6, CC=N--B-I-C, A=08, X=09, Y=08]
923 D3F2: B5 93 LDA $93,X [PC=D3F4, SP=01F6, CC=---B-IZC, A=00, X=09, Y=08]
924 D3F4: CA DEX [PC=D3F5, SP=01F6, CC=N--B-I-C, A=00, X=08, Y=08]
925 D3F5: 10 FA BPL $D3F1 [PC=D3F7, SP=01F6, CC=N--B-I-C, A=00, X=08, Y=08]
926 D3F7: 20 84 E4 JSR $E484 [PC=E484, SP=01F4, CC=N--B-I-C, A=00, X=08, Y=08]
928 should be fixed now...
932 DEX Implied DEX CA 1 2
935 static void OpCA(void) // DEX
942 DEY Implied DEY 88 1 2
945 static void Op88(void) // DEY
952 EOR Immediate EOR #Oper 49 2 2
953 Zero Page EOR Zpg 45 2 3
954 Zero Page,X EOR Zpg,X 55 2 4
955 Absolute EOR Abs 4D 3 4
956 Absolute,X EOR Abs,X 5D 3 4
957 Absolute,Y EOR Abs,Y 59 3 4
958 (Zero Page,X) EOR (Zpg,X) 41 2 6
959 (Zero Page),Y EOR (Zpg),Y 51 2 5
960 (Zero Page) EOR (Zpg) 52 2 5
965 #define OP_EOR_HANDLER(m) \
969 static void Op49(void) // EOR #
975 static void Op45(void) // EOR ZP
981 static void Op55(void) // EOR ZP, X
987 static void Op4D(void) // EOR ABS
993 static void Op5D(void) // EOR ABS, X
995 uint8 m = READ_ABS_X;
999 static void Op59(void) // EOR ABS, Y
1001 uint8 m = READ_ABS_Y;
1005 static void Op41(void) // EOR (ZP, X)
1007 uint8 m = READ_IND_ZP_X;
1011 static void Op51(void) // EOR (ZP), Y
1013 uint8 m = READ_IND_ZP_Y;
1017 static void Op52(void) // EOR (ZP)
1019 uint8 m = READ_IND_ZP;
1024 INA Accumulator INA 1A 1 2
1027 static void Op1A(void) // INA
1034 INC Zero Page INC Zpg E6 2 5
1035 Zero Page,X INC Zpg,X F6 2 6
1036 Absolute INC Abs EE 3 6
1037 Absolute,X INC Abs,X FE 3 7
1042 #define OP_INC_HANDLER(m) \
1046 static void OpE6(void) // INC ZP
1054 static void OpF6(void) // INC ZP, X
1062 static void OpEE(void) // INC ABS
1070 static void OpFE(void) // INC ABS, X
1079 INX Implied INX E8 1 2
1082 static void OpE8(void) // INX
1089 INY Implied INY C8 1 2
1092 static void OpC8(void) // INY
1099 JMP Absolute JMP Abs 4C 3 3
1100 (Absolute) JMP (Abs) 6C 3 5
1101 (Absolute,X) JMP (Abs,X) 7C 3 6
1106 static void Op4C(void) // JMP ABS
1108 regs.pc = RdMemW(regs.pc);
1111 static void Op6C(void) // JMP (ABS)
1113 // uint16 addr = RdMemW(regs.pc);
1115 //WriteLog("\n[JMP ABS]: addr fetched = %04X, bytes at %04X = %02X %02X (RdMemw=%04X)\n",
1116 // addr, addr, regs.RdMem(addr), regs.RdMem(addr+1), RdMemW(addr));
1118 // addr = RdMemW(addr);
1119 regs.pc = RdMemW(RdMemW(regs.pc));
1122 static void Op7C(void) // JMP (ABS, X)
1124 regs.pc = RdMemW(RdMemW(regs.pc) + regs.x);
1128 JSR Absolute JSR Abs 20 3 6
1131 //This is not jumping to the correct address... !!! FIX !!! [DONE]
1132 static void Op20(void) // JSR
1134 // The whole ret - 1 probably stems from a fetch/push/fetch/push sequence...
1135 uint16 addr = RdMemW(regs.pc);
1136 regs.pc++; // Since it pushes return address - 1...
1137 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8);
1138 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
1143 LDA Immediate LDA #Oper A9 2 2
1144 Zero Page LDA Zpg A5 2 3
1145 Zero Page,X LDA Zpg,X B5 2 4
1146 Absolute LDA Abs AD 3 4
1147 Absolute,X LDA Abs,X BD 3 4
1148 Absolute,Y LDA Abs,Y B9 3 4
1149 (Zero Page,X) LDA (Zpg,X) A1 2 6
1150 (Zero Page),Y LDA (Zpg),Y B1 2 5
1151 (Zero Page) LDA (Zpg) B2 2 5
1156 #define OP_LDA_HANDLER(m) \
1160 static void OpA9(void) // LDA #
1166 static void OpA5(void) // LDA ZP
1172 static void OpB5(void) // LDA ZP, X
1174 uint8 m = READ_ZP_X;
1178 static void OpAD(void) // LDA ABS
1184 static void OpBD(void) // LDA ABS, X
1186 uint8 m = READ_ABS_X;
1190 static void OpB9(void) // LDA ABS, Y
1192 uint8 m = READ_ABS_Y;
1196 static void OpA1(void) // LDA (ZP, X)
1198 uint8 m = READ_IND_ZP_X;
1202 static void OpB1(void) // LDA (ZP), Y
1204 uint8 m = READ_IND_ZP_Y;
1208 static void OpB2(void) // LDA (ZP)
1210 uint8 m = READ_IND_ZP;
1215 LDX Immediate LDX #Oper A2 2 2
1216 Zero Page LDX Zpg A6 2 3
1217 Zero Page,Y LDX Zpg,Y B6 2 4
1218 Absolute LDX Abs AE 3 4
1219 Absolute,Y LDX Abs,Y BE 3 4
1224 #define OP_LDX_HANDLER(m) \
1228 static void OpA2(void) // LDX #
1234 static void OpA6(void) // LDX ZP
1240 static void OpB6(void) // LDX ZP, Y
1242 uint8 m = READ_ZP_Y;
1246 static void OpAE(void) // LDX ABS
1252 static void OpBE(void) // LDX ABS, Y
1254 uint8 m = READ_ABS_Y;
1259 LDY Immediate LDY #Oper A0 2 2
1260 Zero Page LDY Zpg A4 2 3
1261 Zero Page,Y LDY Zpg,X B4 2 4
1262 Absolute LDY Abs AC 3 4
1263 Absolute,Y LDY Abs,X BC 3 4
1268 #define OP_LDY_HANDLER(m) \
1272 static void OpA0(void) // LDY #
1278 static void OpA4(void) // LDY ZP
1284 static void OpB4(void) // LDY ZP, X
1286 uint8 m = READ_ZP_X;
1290 static void OpAC(void) // LDY ABS
1296 static void OpBC(void) // LDY ABS, X
1298 uint8 m = READ_ABS_X;
1303 LSR Accumulator LSR A 4A 1 2
1304 Zero Page LSR Zpg 46 2 5
1305 Zero Page,X LSR Zpg,X 56 2 6
1306 Absolute LSR Abs 4E 3 6
1307 Absolute,X LSR Abs,X 5E 3 7
1312 #define OP_LSR_HANDLER(m) \
1313 regs.cc = ((m) & 0x01 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
1317 static void Op4A(void) // LSR A
1319 OP_LSR_HANDLER(regs.a);
1322 static void Op46(void) // LSR ZP
1330 static void Op56(void) // LSR ZP, X
1338 static void Op4E(void) // LSR ABS
1346 static void Op5E(void) // LSR ABS, X
1355 NOP Implied NOP EA 1 2
1358 static void OpEA(void) // NOP
1363 ORA Immediate ORA #Oper 09 2 2
1364 Zero Page ORA Zpg 05 2 3
1365 Zero Page,X ORA Zpg,X 15 2 4
1366 Absolute ORA Abs 0D 3 4
1367 Absolute,X ORA Abs,X 1D 3 4
1368 Absolute,Y ORA Abs,Y 19 3 4
1369 (Zero Page,X) ORA (Zpg,X) 01 2 6
1370 (Zero Page),Y ORA (Zpg),Y 11 2 5
1371 (Zero Page) ORA (Zpg) 12 2 5
1376 #define OP_ORA_HANDLER(m) \
1380 static void Op09(void) // ORA #
1386 static void Op05(void) // ORA ZP
1392 static void Op15(void) // ORA ZP, X
1394 uint8 m = READ_ZP_X;
1398 static void Op0D(void) // ORA ABS
1404 static void Op1D(void) // ORA ABS, X
1406 uint8 m = READ_ABS_X;
1410 static void Op19(void) // ORA ABS, Y
1412 uint8 m = READ_ABS_Y;
1416 static void Op01(void) // ORA (ZP, X)
1418 uint8 m = READ_IND_ZP_X;
1422 static void Op11(void) // ORA (ZP), Y
1424 uint8 m = READ_IND_ZP_Y;
1428 static void Op12(void) // ORA (ZP)
1430 uint8 m = READ_IND_ZP;
1435 PHA Implied PHA 48 1 3
1438 static void Op48(void) // PHA
1440 regs.WrMem(0x0100 + regs.sp--, regs.a);
1443 static void Op08(void) // PHP
1445 regs.cc |= FLAG_UNK; // Make sure that the unused bit is always set
1446 regs.WrMem(0x0100 + regs.sp--, regs.cc);
1450 PHX Implied PHX DA 1 3
1453 static void OpDA(void) // PHX
1455 regs.WrMem(0x0100 + regs.sp--, regs.x);
1459 PHY Implied PHY 5A 1 3
1462 static void Op5A(void) // PHY
1464 regs.WrMem(0x0100 + regs.sp--, regs.y);
1468 PLA Implied PLA 68 1 4
1471 static void Op68(void) // PLA
1473 regs.a = regs.RdMem(0x0100 + ++regs.sp);
1477 static void Op28(void) // PLP
1479 regs.cc = regs.RdMem(0x0100 + ++regs.sp);
1483 PLX Implied PLX FA 1 4
1486 static void OpFA(void) // PLX
1488 regs.x = regs.RdMem(0x0100 + ++regs.sp);
1493 PLY Implied PLY 7A 1 4
1496 static void Op7A(void) // PLY
1498 regs.y = regs.RdMem(0x0100 + ++regs.sp);
1503 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.
1504 RMB0 RMB1 RMB2 RMB3 RMB4 RMB5 RMB6 RMB7
1505 zp 07 17 27 37 47 57 67 77
1506 SMB0 SMB1 SMB2 SMB3 SMB4 SMB5 SMB6 SMB7
1507 zp 87 97 A7 B7 C7 D7 E7 F7
1512 static void Op07(void) // RMB0 ZP
1520 static void Op17(void) // RMB1 ZP
1528 static void Op27(void) // RMB2 ZP
1536 static void Op37(void) // RMB3 ZP
1544 static void Op47(void) // RMB4 ZP
1552 static void Op57(void) // RMB5 ZP
1560 static void Op67(void) // RMB6 ZP
1568 static void Op77(void) // RMB7 ZP
1577 ROL Accumulator ROL A 2A 1 2
1578 Zero Page ROL Zpg 26 2 5
1579 Zero Page,X ROL Zpg,X 36 2 6
1580 Absolute ROL Abs 2E 3 6
1581 Absolute,X ROL Abs,X 3E 3 7
1586 #define OP_ROL_HANDLER(m) \
1587 uint8 tmp = regs.cc & 0x01; \
1588 regs.cc = ((m) & 0x80 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
1589 (m) = ((m) << 1) | tmp; \
1592 static void Op2A(void) // ROL A
1594 OP_ROL_HANDLER(regs.a);
1597 static void Op26(void) // ROL ZP
1605 static void Op36(void) // ROL ZP, X
1613 static void Op2E(void) // ROL ABS
1621 static void Op3E(void) // ROL ABS, X
1630 ROR Accumulator ROR A 6A 1 2
1631 Zero Page ROR Zpg 66 2 5
1632 Zero Page,X ROR Zpg,X 76 2 6
1633 Absolute ROR Abs 6E 3 6
1634 Absolute,X ROR Abs,X 7E 3 7
1639 #define OP_ROR_HANDLER(m) \
1640 uint8 tmp = (regs.cc & 0x01) << 7; \
1641 regs.cc = ((m) & 0x01 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
1642 (m) = ((m) >> 1) | tmp; \
1645 static void Op6A(void) // ROR A
1647 OP_ROR_HANDLER(regs.a);
1650 static void Op66(void) // ROR ZP
1658 static void Op76(void) // ROR ZP, X
1666 static void Op6E(void) // ROR ABS
1674 static void Op7E(void) // ROR ABS, X
1683 RTI Implied RTI 40 1 6
1686 static void Op40(void) // RTI
1688 regs.cc = regs.RdMem(0x0100 + ++regs.sp);
1689 regs.pc = regs.RdMem(0x0100 + ++regs.sp);
1690 regs.pc |= (uint16)(regs.RdMem(0x0100 + ++regs.sp)) << 8;
1694 RTS Implied RTS 60 1 6
1697 static void Op60(void) // RTS
1699 regs.pc = regs.RdMem(0x0100 + ++regs.sp);
1700 regs.pc |= (uint16)(regs.RdMem(0x0100 + ++regs.sp)) << 8;
1701 regs.pc++; // Since it pushes return address - 1...
1702 //printf("*** RTS: PC = $%04X, SP= $1%02X\n", regs.pc, regs.sp);
1707 SBC Immediate SBC #Oper E9 2 2
1708 Zero Page SBC Zpg E5 2 3
1709 Zero Page,X SBC Zpg,X F5 2 4
1710 Absolute SBC Abs ED 3 4
1711 Absolute,X SBC Abs,X FD 3 4
1712 Absolute,Y SBC Abs,Y F9 3 4
1713 (Zero Page,X) SBC (Zpg,X) E1 2 6
1714 (Zero Page),Y SBC (Zpg),Y F1 2 5
1715 (Zero Page) SBC (Zpg) F2 2 5
1720 //This is non-optimal, but it works--optimize later. :-)
1721 //This is correct except for the BCD handling... !!! FIX !!! [Possibly DONE]
1722 #define OP_SBC_HANDLER(m) \
1723 uint16 sum = (uint16)regs.a - (m) - (uint16)((regs.cc & FLAG_C) ^ 0x01); \
1725 if (regs.cc & FLAG_D) \
1727 if ((sum & 0x0F) > 0x09) \
1730 if ((sum & 0xF0) > 0x90) \
1734 regs.cc = (regs.cc & ~FLAG_C) | (((sum >> 8) ^ 0x01) & FLAG_C); \
1735 regs.cc = ((regs.a ^ (m)) & (regs.a ^ sum) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V); \
1736 regs.a = sum & 0xFF; \
1740 D5AF: 38 SEC [PC=D5B0, SP=01F6, CC=---B-I-C, A=4C, X=00, Y=06]
1742 *** HERE'S where it sets the D flag on a subtract... Arg!
1744 D5B0: F1 9D SBC ($9D),Y [PC=D5B2, SP=01F6, CC=N--BDI--, A=FE, X=00, Y=06]
1749 //OLD V detection: regs.cc = ((regs.a ^ (m) ^ sum ^ (regs.cc << 7)) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V);
1751 static void OpE9(void) // SBC #
1753 uint16 m = READ_IMM;
1757 static void OpE5(void) // SBC ZP
1763 static void OpF5(void) // SBC ZP, X
1765 uint16 m = READ_ZP_X;
1769 static void OpED(void) // SBC ABS
1771 uint16 m = READ_ABS;
1775 static void OpFD(void) // SBC ABS, X
1777 uint16 m = READ_ABS_X;
1781 static void OpF9(void) // SBC ABS, Y
1783 uint16 m = READ_ABS_Y;
1787 static void OpE1(void) // SBC (ZP, X)
1789 uint16 m = READ_IND_ZP_X;
1793 static void OpF1(void) // SBC (ZP), Y
1795 uint16 m = READ_IND_ZP_Y;
1799 static void OpF2(void) // SBC (ZP)
1801 uint16 m = READ_IND_ZP;
1806 SEC Implied SEC 38 1 2
1809 static void Op38(void) // SEC
1815 SED Implied SED F8 1 2
1818 static void OpF8(void) // SED
1824 SEI Implied SEI 78 1 2
1827 static void Op78(void) // SEI
1833 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.
1834 RMB0 RMB1 RMB2 RMB3 RMB4 RMB5 RMB6 RMB7
1835 zp 07 17 27 37 47 57 67 77
1836 SMB0 SMB1 SMB2 SMB3 SMB4 SMB5 SMB6 SMB7
1837 zp 87 97 A7 B7 C7 D7 E7 F7
1842 static void Op87(void) // SMB0 ZP
1850 static void Op97(void) // SMB1 ZP
1858 static void OpA7(void) // SMB2 ZP
1866 static void OpB7(void) // SMB3 ZP
1874 static void OpC7(void) // SMB4 ZP
1882 static void OpD7(void) // SMB5 ZP
1890 static void OpE7(void) // SMB6 ZP
1898 static void OpF7(void) // SMB7 ZP
1907 STA Zero Page STA Zpg 85 2 3
1908 Zero Page,X STA Zpg,X 95 2 4
1909 Absolute STA Abs 8D 3 4
1910 Absolute,X STA Abs,X 9D 3 5
1911 Absolute,Y STA Abs,Y 99 3 5
1912 (Zero Page,X) STA (Zpg,X) 81 2 6
1913 (Zero Page),Y STA (Zpg),Y 91 2 6
1914 (Zero Page) STA (Zpg) 92 2 5
1919 static void Op85(void)
1921 regs.WrMem(EA_ZP, regs.a);
1924 static void Op95(void)
1926 regs.WrMem(EA_ZP_X, regs.a);
1929 static void Op8D(void)
1931 regs.WrMem(EA_ABS, regs.a);
1935 static void Op9D(void)
1937 regs.WrMem(EA_ABS_X, regs.a);
1941 static void Op99(void)
1943 regs.WrMem(EA_ABS_Y, regs.a);
1947 static void Op81(void)
1949 regs.WrMem(EA_IND_ZP_X, regs.a);
1952 static void Op91(void)
1954 regs.WrMem(EA_IND_ZP_Y, regs.a);
1957 static void Op92(void)
1959 regs.WrMem(EA_IND_ZP, regs.a);
1963 STX Zero Page STX Zpg 86 2 3
1964 Zero Page,Y STX Zpg,Y 96 2 4
1965 Absolute STX Abs 8E 3 4
1970 static void Op86(void)
1972 regs.WrMem(EA_ZP, regs.x);
1975 static void Op96(void)
1977 regs.WrMem(EA_ZP_X, regs.x);
1980 static void Op8E(void)
1982 regs.WrMem(EA_ABS, regs.x);
1987 STY Zero Page STY Zpg 84 2 3
1988 Zero Page,X STY Zpg,X 94 2 4
1989 Absolute STY Abs 8C 3 4
1994 static void Op84(void)
1996 regs.WrMem(EA_ZP, regs.y);
1999 static void Op94(void)
2001 regs.WrMem(EA_ZP_X, regs.y);
2004 static void Op8C(void)
2006 regs.WrMem(EA_ABS, regs.y);
2011 STZ Zero Page STZ Zpg 64 2 3
2012 Zero Page,X STZ Zpg,X 74 2 4
2013 Absolute STZ Abs 9C 3 4
2014 Absolute,X STZ Abs,X 9E 3 5
2019 static void Op64(void)
2021 regs.WrMem(EA_ZP, 0x00);
2024 static void Op74(void)
2026 regs.WrMem(EA_ZP_X, 0x00);
2029 static void Op9C(void)
2031 regs.WrMem(EA_ABS, 0x00);
2035 static void Op9E(void)
2037 regs.WrMem(EA_ABS_X, 0x00);
2042 TAX Implied TAX AA 1 2
2045 static void OpAA(void) // TAX
2052 TAY Implied TAY A8 1 2
2055 static void OpA8(void) // TAY
2062 TRB Zero Page TRB Zpg 14 2 5
2063 Absolute TRB Abs 1C 3 6
2068 #define OP_TRB_HANDLER(m) \
2069 SET_Z(m & regs.a); \
2072 static void Op14(void) // TRB ZP
2080 static void Op1C(void) // TRB ABS
2089 TSB Zero Page TSB Zpg 04 2 5
2090 Absolute TSB Abs 0C 3 6
2095 #define OP_TSB_HANDLER(m) \
2096 SET_Z(m & regs.a); \
2099 static void Op04(void) // TSB ZP
2107 static void Op0C(void) // TSB ABS
2116 TSX Implied TSX BA 1 2
2119 static void OpBA(void) // TSX
2126 TXA Implied TXA 8A 1 2
2129 static void Op8A(void) // TXA
2136 TXS Implied TXS 9A 1 2
2139 static void Op9A(void) // TXS
2145 TYA Implied TYA 98 1 2
2147 static void Op98(void) // TYA
2153 static void Op__(void)
2155 regs.cpuFlags |= V65C02_STATE_ILLEGAL_INST;
2160 // Ok, the exec_op[] array is globally defined here basically to save
2161 // a LOT of unnecessary typing. Sure it's ugly, but hey, it works!
2163 void (* exec_op[256])() = {
2164 Op00, Op01, Op__, Op__, Op04, Op05, Op06, Op07, Op08, Op09, Op0A, Op__, Op0C, Op0D, Op0E, Op0F,
2165 Op10, Op11, Op12, Op__, Op14, Op15, Op16, Op17, Op18, Op19, Op1A, Op__, Op1C, Op1D, Op1E, Op1F,
2166 Op20, Op21, Op__, Op__, Op24, Op25, Op26, Op27, Op28, Op29, Op2A, Op__, Op2C, Op2D, Op2E, Op2F,
2167 Op30, Op31, Op32, Op__, Op34, Op35, Op36, Op37, Op38, Op39, Op3A, Op__, Op3C, Op3D, Op3E, Op3F,
2168 Op40, Op41, Op__, Op__, Op__, Op45, Op46, Op47, Op48, Op49, Op4A, Op__, Op4C, Op4D, Op4E, Op4F,
2169 Op50, Op51, Op52, Op__, Op__, Op55, Op56, Op57, Op58, Op59, Op5A, Op__, Op__, Op5D, Op5E, Op5F,
2170 Op60, Op61, Op__, Op__, Op64, Op65, Op66, Op67, Op68, Op69, Op6A, Op__, Op6C, Op6D, Op6E, Op6F,
2171 Op70, Op71, Op72, Op__, Op74, Op75, Op76, Op77, Op78, Op79, Op7A, Op__, Op7C, Op7D, Op7E, Op7F,
2172 Op80, Op81, Op__, Op__, Op84, Op85, Op86, Op87, Op88, Op89, Op8A, Op__, Op8C, Op8D, Op8E, Op8F,
2173 Op90, Op91, Op92, Op__, Op94, Op95, Op96, Op97, Op98, Op99, Op9A, Op__, Op9C, Op9D, Op9E, Op9F,
2174 OpA0, OpA1, OpA2, Op__, OpA4, OpA5, OpA6, OpA7, OpA8, OpA9, OpAA, Op__, OpAC, OpAD, OpAE, OpAF,
2175 OpB0, OpB1, OpB2, Op__, OpB4, OpB5, OpB6, OpB7, OpB8, OpB9, OpBA, Op__, OpBC, OpBD, OpBE, OpBF,
2176 OpC0, OpC1, Op__, Op__, OpC4, OpC5, OpC6, OpC7, OpC8, OpC9, OpCA, Op__, OpCC, OpCD, OpCE, OpCF,
2177 OpD0, OpD1, OpD2, Op__, Op__, OpD5, OpD6, OpD7, OpD8, OpD9, OpDA, Op__, Op__, OpDD, OpDE, OpDF,
2178 OpE0, OpE1, Op__, Op__, OpE4, OpE5, OpE6, OpE7, OpE8, OpE9, OpEA, Op__, OpEC, OpED, OpEE, OpEF,
2179 OpF0, OpF1, OpF2, Op__, Op__, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, Op__, Op__, OpFD, OpFE, OpFF
2183 // Internal "memcpy" (so we don't have to link with any external libraries!)
2185 static void myMemcpy(void * dst, void * src, uint32 size)
2187 uint8 * d = (uint8 *)dst, * s = (uint8 *)src;
2189 for(uint32 i=0; i<size; i++)
2194 FCA8: 38 698 WAIT SEC
2195 FCA9: 48 699 WAIT2 PHA
2196 FCAA: E9 01 700 WAIT3 SBC #$01
2197 FCAC: D0 FC 701 BNE WAIT3 ;1.0204 USEC
2198 FCAE: 68 702 PLA ;(13+27/2*A+5/2*A*A)
2199 FCAF: E9 01 703 SBC #$01
2200 FCB1: D0 F6 704 BNE WAIT2
2203 FBD9: C9 87 592 BELL1 CMP #$87 ;BELL CHAR? (CNTRL-G)
2204 FBDB: D0 12 593 BNE RTS2B ; NO, RETURN
2205 FBDD: A9 40 594 LDA #$40 ;DELAY .01 SECONDS
2206 FBDF: 20 A8 FC 595 JSR WAIT
2207 FBE2: A0 C0 596 LDY #$C0
2208 FBE4: A9 0C 597 BELL2 LDA #$0C ;TOGGLE SPEAKER AT
2209 FBE6: 20 A8 FC 598 JSR WAIT ; 1 KHZ FOR .1 SEC.
2210 FBE9: AD 30 C0 599 LDA SPKR
2212 FBED: D0 F5 601 BNE BELL2
2213 FBEF: 60 602 RTS2B RTS
2215 //int instCount[256];
2217 bool dumpDis = false;
2220 // Function to execute 6808 for "cycles" cycles
2222 void Execute65C02(V65C02REGS * context, uint32 cycles)
2224 myMemcpy(®s, context, sizeof(V65C02REGS));
2227 while (regs.clock < cycles)
2230 /*if (regs.pc == 0x4007)
2234 if (regs.pc == 0x444B)
2236 WriteLog("\n*** End of wait...\n\n");
2239 if (regs.pc == 0x444E)
2241 WriteLog("\n*** Start of wait...\n\n");
2247 //WAIT is commented out here because it's called by BELL1...
2248 if (regs.pc == 0xFCA8)
2250 WriteLog("\n*** WAIT subroutine...\n\n");
2253 if (regs.pc == 0xFBD9)
2255 WriteLog("\n*** BELL1 subroutine...\n\n");
2258 if (regs.pc == 0xFC58)
2260 WriteLog("\n*** HOME subroutine...\n\n");
2263 if (regs.pc == 0xFDED)
2265 WriteLog("\n*** COUT subroutine...\n\n");
2272 Decode65C02(regs.pc);
2274 uint8 opcode = regs.RdMem(regs.pc++);
2276 //if (!(regs.cpuFlags & V65C02_STATE_ILLEGAL_INST))
2277 //instCount[opcode]++;
2279 exec_op[opcode](); // Execute that opcode...
2280 regs.clock += CPUCycles[opcode];
2283 WriteLog(" [PC=%04X, SP=%04X, CC=%s%s-%s%s%s%s%s, A=%02X, X=%02X, Y=%02X]\n",
2284 regs.pc, 0x0100 + regs.sp,
2285 (regs.cc & FLAG_N ? "N" : "-"), (regs.cc & FLAG_V ? "V" : "-"),
2286 (regs.cc & FLAG_B ? "B" : "-"), (regs.cc & FLAG_D ? "D" : "-"),
2287 (regs.cc & FLAG_I ? "I" : "-"), (regs.cc & FLAG_Z ? "Z" : "-"),
2288 (regs.cc & FLAG_C ? "C" : "-"), regs.a, regs.x, regs.y);
2292 if (regs.pc == 0xFCB3) // WAIT exit point
2296 /*if (regs.pc == 0xFBEF) // BELL1 exit point
2300 /*if (regs.pc == 0xFC22) // HOME exit point
2304 if (regs.pc == 0xFDFF) // COUT exit point
2308 if (regs.pc == 0xFBD8)
2310 WriteLog("\n*** BASCALC set BASL/H = $%04X\n\n", RdMemW(0x0028));
2314 //These should be correct now...
2315 if (regs.cpuFlags & V65C02_ASSERT_LINE_RESET)
2318 WriteLog("\n*** RESET ***\n\n");
2320 // Not sure about this...
2322 regs.cc = FLAG_B | FLAG_I; // Reset the CC register
2323 regs.pc = RdMemW(0xFFFC); // And load PC with the RESET vector
2325 context->cpuFlags &= ~V65C02_ASSERT_LINE_RESET;
2326 regs.cpuFlags &= ~V65C02_ASSERT_LINE_RESET;
2328 else if (regs.cpuFlags & V65C02_ASSERT_LINE_NMI)
2331 WriteLog("\n*** NMI ***\n\n");
2333 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8); // Save PC and CC
2334 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
2335 regs.WrMem(0x0100 + regs.sp--, regs.cc);
2336 regs.cc |= FLAG_I; // Set I
2337 regs.cc &= ~FLAG_D; // & clear D
2338 regs.pc = RdMemW(0xFFFA); // And do it!
2341 context->cpuFlags &= ~V65C02_ASSERT_LINE_NMI;// Reset the asserted line (NMI)...
2342 regs.cpuFlags &= ~V65C02_ASSERT_LINE_NMI; // Reset the asserted line (NMI)...
2344 else if (regs.cpuFlags & V65C02_ASSERT_LINE_IRQ)
2346 if (!(regs.cc & FLAG_I)) // Process an interrupt (I=0)?
2349 WriteLog("\n*** IRQ ***\n\n");
2351 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8); // Save PC and CC
2352 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
2353 regs.WrMem(0x0100 + regs.sp--, regs.cc);
2354 regs.cc |= FLAG_I; // Set I
2355 regs.cc &= ~FLAG_D; // & clear D
2356 regs.pc = RdMemW(0xFFFE); // And do it!
2359 context->cpuFlags &= ~V65C02_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
2360 regs.cpuFlags &= ~V65C02_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
2365 myMemcpy(context, ®s, sizeof(V65C02REGS));
2369 // Get the clock of the currently executing CPU
2371 uint32 GetCurrentV65C02Clock(void)