1 /*****************************************************************************/
5 /* CPU core for the 6502 simulator */
9 /* (C) 2002-2003 Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
56 /*****************************************************************************/
58 /*****************************************************************************/
65 /* Count the total number of cylcles */
66 unsigned Cycles; /* Cycles per insn */
67 unsigned long TotalCycles; /* Total cycles */
69 /* Allow the stack page to be changed */
70 static unsigned StackPage = 0x100;
73 int HaveNMIRequest = 0;
74 int HaveIRQRequest = 0;
78 static char BreakMsg[1024];
82 /*****************************************************************************/
83 /* Helper functions and macros */
84 /*****************************************************************************/
88 /* Return the flags as a boolean value (0/1) */
89 #define GET_CF() ((Regs.SR & CF) != 0)
90 #define GET_ZF() ((Regs.SR & ZF) != 0)
91 #define GET_IF() ((Regs.SR & IF) != 0)
92 #define GET_DF() ((Regs.SR & DF) != 0)
93 #define GET_BF() ((Regs.SR & BF) != 0)
94 #define GET_OF() ((Regs.SR & OF) != 0)
95 #define GET_SF() ((Regs.SR & SF) != 0)
97 /* Set the flags. The parameter is a boolean flag that says if the flag should be
100 #define SET_CF(f) do { if (f) { Regs.SR |= CF; } else { Regs.SR &= ~CF; } } while (0)
101 #define SET_ZF(f) do { if (f) { Regs.SR |= ZF; } else { Regs.SR &= ~ZF; } } while (0)
102 #define SET_IF(f) do { if (f) { Regs.SR |= IF; } else { Regs.SR &= ~IF; } } while (0)
103 #define SET_DF(f) do { if (f) { Regs.SR |= DF; } else { Regs.SR &= ~DF; } } while (0)
104 #define SET_BF(f) do { if (f) { Regs.SR |= BF; } else { Regs.SR &= ~BF; } } while (0)
105 #define SET_OF(f) do { if (f) { Regs.SR |= OF; } else { Regs.SR &= ~OF; } } while (0)
106 #define SET_SF(f) do { if (f) { Regs.SR |= SF; } else { Regs.SR &= ~SF; } } while (0)
108 /* Special test and set macros. The meaning of the parameter depends on the
109 * actual flag that should be set or reset.
111 #define TEST_ZF(v) SET_ZF (((v) & 0xFF) == 0)
112 #define TEST_SF(v) SET_SF (((v) & 0x80) != 0)
113 #define TEST_CF(v) SET_CF (((v) & 0xFF00) != 0)
115 /* Program counter halves */
116 #define PCL (Regs.PC & 0xFF)
117 #define PCH ((Regs.PC >> 8) & 0xFF)
119 /* Stack operations */
120 #define PUSH(Val) MemWriteByte (StackPage + Regs.SP--, Val)
121 #define POP() MemReadByte (StackPage + ++Regs.SP)
123 /* Test for page cross */
124 #define PAGE_CROSS(addr,offs) ((((addr) & 0xFF) + offs) >= 0x100)
127 #define AC_OP_IMM(op) \
129 Regs.AC = Regs.AC op MemReadByte (Regs.PC+1); \
135 #define AC_OP_ZP(op) \
137 Regs.AC = Regs.AC op MemReadByte (MemReadByte (Regs.PC+1)); \
143 #define AC_OP_ZPX(op) \
144 unsigned char ZPAddr; \
146 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; \
147 Regs.AC = Regs.AC op MemReadByte (ZPAddr); \
153 #define AC_OP_ZPY(op) \
154 unsigned char ZPAddr; \
156 ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR; \
157 Regs.AC = Regs.AC op MemReadByte (ZPAddr); \
163 #define AC_OP_ABS(op) \
166 Addr = MemReadWord (Regs.PC+1); \
167 Regs.AC = Regs.AC op MemReadByte (Addr); \
173 #define AC_OP_ABSX(op) \
176 Addr = MemReadWord (Regs.PC+1); \
177 if (PAGE_CROSS (Addr, Regs.XR)) { \
180 Regs.AC = Regs.AC op MemReadByte (Addr + Regs.XR); \
186 #define AC_OP_ABSY(op) \
189 Addr = MemReadWord (Regs.PC+1); \
190 if (PAGE_CROSS (Addr, Regs.YR)) { \
193 Regs.AC = Regs.AC op MemReadByte (Addr + Regs.YR); \
199 #define AC_OP_ZPXIND(op) \
200 unsigned char ZPAddr; \
203 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; \
204 Addr = MemReadZPWord (ZPAddr); \
205 Regs.AC = Regs.AC op MemReadByte (Addr); \
211 #define AC_OP_ZPINDY(op) \
212 unsigned char ZPAddr; \
215 ZPAddr = MemReadByte (Regs.PC+1); \
216 Addr = MemReadZPWord (ZPAddr) + Regs.YR; \
217 Regs.AC = Regs.AC op MemReadByte (Addr); \
225 Warning ("Decimal mode not available"); \
227 unsigned old = Regs.AC; \
228 unsigned rhs = (v & 0xFF); \
229 Regs.AC += rhs + GET_CF (); \
233 SET_OF (!((old ^ rhs) & 0x80) && \
234 ((old ^ Regs.AC) & 0x80)); \
239 #define BRANCH(cond) \
243 unsigned char OldPCH; \
245 Offs = (signed char) MemReadByte (Regs.PC+1); \
247 Regs.PC += 2 + (int) Offs; \
248 if (PCH != OldPCH) { \
258 unsigned Result = v1 - v2; \
259 TEST_ZF (Result & 0xFF); \
261 SET_CF (Result <= 0xFF); \
280 SET_CF (Val & 0x01); \
288 Warning ("Decimal mode not available"); \
290 unsigned old = Regs.AC; \
291 unsigned rhs = (v & 0xFF); \
292 Regs.AC -= rhs - (!GET_CF ()); \
295 SET_CF (Regs.AC <= 0xFF); \
296 SET_OF (((old^rhs) & (old^Regs.AC) & 0x80)); \
302 /*****************************************************************************/
303 /* Helper functions */
304 /*****************************************************************************/
308 static void OPC_Illegal (void)
310 Warning ("Illegal opcode $%02X at address $%04X\n", MemReadByte (Regs.PC), Regs.PC);
315 /*****************************************************************************/
317 /*****************************************************************************/
321 static void OPC_6502_00 (void)
322 /* Opcode $00: BRK */
331 Regs.PC = MemReadWord (0xFFFE);
337 static void OPC_6502_01 (void)
338 /* Opcode $01: ORA (ind,x) */
345 static void OPC_6502_05 (void)
346 /* Opcode $05: ORA zp */
353 static void OPC_6502_06 (void)
354 /* Opcode $06: ASL zp */
356 unsigned char ZPAddr;
359 ZPAddr = MemReadByte (Regs.PC+1);
360 Val = MemReadByte (ZPAddr) << 1;
361 MemWriteByte (ZPAddr, (unsigned char) Val);
362 TEST_ZF (Val & 0xFF);
364 SET_CF (Val & 0x100);
370 static void OPC_6502_08 (void)
371 /* Opcode $08: PHP */
374 PUSH (Regs.SR & ~BF);
380 static void OPC_6502_09 (void)
381 /* Opcode $09: ORA #imm */
388 static void OPC_6502_0A (void)
389 /* Opcode $0A: ASL a */
393 TEST_ZF (Regs.AC & 0xFF);
395 SET_CF (Regs.AC & 0x100);
402 static void OPC_6502_0D (void)
403 /* Opcode $0D: ORA abs */
410 static void OPC_6502_0E (void)
411 /* Opcode $0E: ALS abs */
416 Addr = MemReadWord (Regs.PC+1);
417 Val = MemReadByte (Addr) << 1;
418 MemWriteByte (Addr, (unsigned char) Val);
419 TEST_ZF (Val & 0xFF);
421 SET_CF (Val & 0x100);
427 static void OPC_6502_10 (void)
428 /* Opcode $10: BPL */
435 static void OPC_6502_11 (void)
436 /* Opcode $11: ORA (zp),y */
443 static void OPC_6502_15 (void)
444 /* Opcode $15: ORA zp,x */
451 static void OPC_6502_16 (void)
452 /* Opcode $16: ASL zp,x */
454 unsigned char ZPAddr;
457 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
458 Val = MemReadByte (ZPAddr) << 1;
459 MemWriteByte (ZPAddr, (unsigned char) Val);
460 TEST_ZF (Val & 0xFF);
462 SET_CF (Val & 0x100);
468 static void OPC_6502_18 (void)
469 /* Opcode $18: CLC */
478 static void OPC_6502_19 (void)
479 /* Opcode $19: ORA abs,y */
486 static void OPC_6502_1D (void)
487 /* Opcode $1D: ORA abs,x */
494 static void OPC_6502_1E (void)
495 /* Opcode $1E: ASL abs,x */
500 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
501 Val = MemReadByte (Addr) << 1;
502 MemWriteByte (Addr, (unsigned char) Val);
503 TEST_ZF (Val & 0xFF);
505 SET_CF (Val & 0x100);
511 static void OPC_6502_20 (void)
512 /* Opcode $20: JSR */
516 Addr = MemReadWord (Regs.PC+1);
525 static void OPC_6502_21 (void)
526 /* Opcode $21: AND (zp,x) */
533 static void OPC_6502_24 (void)
534 /* Opcode $24: BIT zp */
536 unsigned char ZPAddr;
539 ZPAddr = MemReadByte (Regs.PC+1);
540 Val = MemReadByte (ZPAddr);
543 SET_ZF ((Val & Regs.AC) == 0);
549 static void OPC_6502_25 (void)
550 /* Opcode $25: AND zp */
557 static void OPC_6502_26 (void)
558 /* Opcode $26: ROL zp */
560 unsigned char ZPAddr;
563 ZPAddr = MemReadByte (Regs.PC+1);
564 Val = MemReadByte (ZPAddr);
566 MemWriteByte (ZPAddr, Val);
572 static void OPC_6502_28 (void)
573 /* Opcode $28: PLP */
576 Regs.SR = (POP () & ~BF);
582 static void OPC_6502_29 (void)
583 /* Opcode $29: AND #imm */
590 static void OPC_6502_2A (void)
591 /* Opcode $2A: ROL a */
601 static void OPC_6502_2C (void)
602 /* Opcode $2C: BIT abs */
607 Addr = MemReadByte (Regs.PC+1);
608 Val = MemReadByte (Addr);
611 SET_ZF ((Val & Regs.AC) == 0);
617 static void OPC_6502_2D (void)
618 /* Opcode $2D: AND abs */
625 static void OPC_6502_2E (void)
626 /* Opcode $2E: ROL abs */
631 Addr = MemReadWord (Regs.PC+1);
632 Val = MemReadByte (Addr);
634 MemWriteByte (Addr, Val);
640 static void OPC_6502_30 (void)
641 /* Opcode $30: BMI */
648 static void OPC_6502_31 (void)
649 /* Opcode $31: AND (zp),y */
656 static void OPC_6502_35 (void)
657 /* Opcode $35: AND zp,x */
664 static void OPC_6502_36 (void)
665 /* Opcode $36: ROL zp,x */
667 unsigned char ZPAddr;
670 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
671 Val = MemReadByte (ZPAddr);
673 MemWriteByte (ZPAddr, Val);
679 static void OPC_6502_38 (void)
680 /* Opcode $38: SEC */
689 static void OPC_6502_39 (void)
690 /* Opcode $39: AND abs,y */
697 static void OPC_6502_3D (void)
698 /* Opcode $3D: AND abs,x */
705 static void OPC_6502_3E (void)
706 /* Opcode $3E: ROL abs,x */
711 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
712 Val = MemReadByte (Addr);
714 MemWriteByte (Addr, Val);
720 static void OPC_6502_40 (void)
721 /* Opcode $40: RTI */
725 Regs.PC = POP (); /* PCL */
726 Regs.PC |= (POP () << 8); /* PCH */
731 static void OPC_6502_41 (void)
732 /* Opcode $41: EOR (zp,x) */
739 static void OPC_6502_45 (void)
740 /* Opcode $45: EOR zp */
747 static void OPC_6502_46 (void)
748 /* Opcode $46: LSR zp */
750 unsigned char ZPAddr;
753 ZPAddr = MemReadByte (Regs.PC+1);
754 Val = MemReadByte (ZPAddr);
757 MemWriteByte (ZPAddr, Val);
765 static void OPC_6502_48 (void)
766 /* Opcode $48: PHA */
775 static void OPC_6502_49 (void)
776 /* Opcode $49: EOR #imm */
783 static void OPC_6502_4A (void)
784 /* Opcode $4A: LSR a */
787 SET_CF (Regs.AC & 0x01);
796 static void OPC_6502_4C (void)
797 /* Opcode $4C: JMP abs */
800 Regs.PC = MemReadWord (Regs.PC+1);
805 static void OPC_6502_4D (void)
806 /* Opcode $4D: EOR abs */
813 static void OPC_6502_4E (void)
814 /* Opcode $4E: LSR abs */
819 Addr = MemReadWord (Regs.PC+1);
820 Val = MemReadByte (Addr);
823 MemWriteByte (Addr, Val);
831 static void OPC_6502_50 (void)
832 /* Opcode $50: BVC */
839 static void OPC_6502_51 (void)
840 /* Opcode $51: EOR (zp),y */
847 static void OPC_6502_55 (void)
848 /* Opcode $55: EOR zp,x */
855 static void OPC_6502_56 (void)
856 /* Opcode $56: LSR zp,x */
858 unsigned char ZPAddr;
861 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
862 Val = MemReadByte (ZPAddr);
865 MemWriteByte (ZPAddr, Val);
873 static void OPC_6502_58 (void)
874 /* Opcode $58: CLI */
883 static void OPC_6502_59 (void)
884 /* Opcode $59: EOR abs,y */
891 static void OPC_6502_5D (void)
892 /* Opcode $5D: EOR abs,x */
899 static void OPC_6502_5E (void)
900 /* Opcode $5E: LSR abs,x */
905 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
906 Val = MemReadByte (Addr);
909 MemWriteByte (Addr, Val);
917 static void OPC_6502_60 (void)
918 /* Opcode $60: RTS */
921 Regs.PC = POP (); /* PCL */
922 Regs.PC |= (POP () << 8); /* PCH */
928 static void OPC_6502_61 (void)
929 /* Opcode $61: ADC (zp,x) */
931 unsigned char ZPAddr;
934 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
935 Addr = MemReadZPWord (ZPAddr);
936 ADC (MemReadByte (Addr));
942 static void OPC_6502_65 (void)
943 /* Opcode $65: ADC zp */
945 unsigned char ZPAddr;
947 ZPAddr = MemReadByte (Regs.PC+1);
948 ADC (MemReadByte (ZPAddr));
954 static void OPC_6502_66 (void)
955 /* Opcode $66: ROR zp */
957 unsigned char ZPAddr;
960 ZPAddr = MemReadByte (Regs.PC+1);
961 Val = MemReadByte (ZPAddr);
963 MemWriteByte (ZPAddr, Val);
969 static void OPC_6502_68 (void)
970 /* Opcode $68: PLA */
981 static void OPC_6502_69 (void)
982 /* Opcode $69: ADC #imm */
985 ADC (MemReadByte (Regs.PC+1));
991 static void OPC_6502_6A (void)
992 /* Opcode $6A: ROR a */
1001 static void OPC_6502_6C (void)
1002 /* Opcode $6C: JMP (ind) */
1006 Addr = MemReadWord (Regs.PC+1);
1007 if (CPU == CPU_6502) {
1008 /* Emulate the 6502 bug */
1009 Regs.PC = MemReadByte (Addr);
1010 Addr = (Addr & 0xFF00) | ((Addr + 1) & 0xFF);
1011 Regs.PC |= (MemReadByte (Addr) << 8);
1013 /* 65C02 and above have this bug fixed */
1014 Regs.PC = MemReadWord (Addr);
1020 static void OPC_6502_6D (void)
1021 /* Opcode $6D: ADC abs */
1025 Addr = MemReadWord (Regs.PC+1);
1026 ADC (MemReadByte (Addr));
1032 static void OPC_6502_6E (void)
1033 /* Opcode $6E: ROR abs */
1038 Addr = MemReadWord (Regs.PC+1);
1039 Val = MemReadByte (Addr);
1041 MemWriteByte (Addr, Val);
1047 static void OPC_6502_70 (void)
1048 /* Opcode $70: BVS */
1055 static void OPC_6502_71 (void)
1056 /* Opcode $71: ADC (zp),y */
1058 unsigned char ZPAddr;
1061 ZPAddr = MemReadByte (Regs.PC+1);
1062 Addr = MemReadZPWord (ZPAddr);
1063 if (PAGE_CROSS (Addr, Regs.YR)) {
1066 ADC (MemReadByte (Addr + Regs.YR));
1072 static void OPC_6502_75 (void)
1073 /* Opcode $75: ADC zp,x */
1075 unsigned char ZPAddr;
1077 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1078 ADC (MemReadByte (ZPAddr));
1084 static void OPC_6502_76 (void)
1085 /* Opcode $76: ROR zp,x */
1087 unsigned char ZPAddr;
1090 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1091 Val = MemReadByte (ZPAddr);
1093 MemWriteByte (ZPAddr, Val);
1099 static void OPC_6502_78 (void)
1100 /* Opcode $78: SEI */
1109 static void OPC_6502_79 (void)
1110 /* Opcode $79: ADC abs,y */
1114 Addr = MemReadWord (Regs.PC+1);
1115 if (PAGE_CROSS (Addr, Regs.YR)) {
1118 ADC (MemReadByte (Addr + Regs.YR));
1124 static void OPC_6502_7D (void)
1125 /* Opcode $7D: ADC abs,x */
1129 Addr = MemReadWord (Regs.PC+1);
1130 if (PAGE_CROSS (Addr, Regs.XR)) {
1133 ADC (MemReadByte (Addr + Regs.XR));
1139 static void OPC_6502_7E (void)
1140 /* Opcode $7E: ROR abs,x */
1145 Addr = MemReadByte (Regs.PC+1) + Regs.XR;
1146 Val = MemReadByte (Addr);
1148 MemWriteByte (Addr, Val);
1154 static void OPC_6502_81 (void)
1155 /* Opcode $81: STA (zp,x) */
1157 unsigned char ZPAddr;
1160 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1161 Addr = MemReadZPWord (ZPAddr);
1162 MemWriteByte (Addr, Regs.AC);
1168 static void OPC_6502_84 (void)
1169 /* Opcode $84: STY zp */
1171 unsigned char ZPAddr;
1173 ZPAddr = MemReadByte (Regs.PC+1);
1174 MemWriteByte (ZPAddr, Regs.YR);
1180 static void OPC_6502_85 (void)
1181 /* Opcode $85: STA zp */
1183 unsigned char ZPAddr;
1185 ZPAddr = MemReadByte (Regs.PC+1);
1186 MemWriteByte (ZPAddr, Regs.AC);
1192 static void OPC_6502_86 (void)
1193 /* Opcode $86: STX zp */
1195 unsigned char ZPAddr;
1197 ZPAddr = MemReadByte (Regs.PC+1);
1198 MemWriteByte (ZPAddr, Regs.XR);
1204 static void OPC_6502_88 (void)
1205 /* Opcode $88: DEY */
1208 Regs.YR = (Regs.YR - 1) & 0xFF;
1216 static void OPC_6502_8A (void)
1217 /* Opcode $8A: TXA */
1228 static void OPC_6502_8C (void)
1229 /* Opcode $8C: STY abs */
1233 Addr = MemReadWord (Regs.PC+1);
1234 MemWriteByte (Addr, Regs.YR);
1240 static void OPC_6502_8D (void)
1241 /* Opcode $8D: STA abs */
1245 Addr = MemReadWord (Regs.PC+1);
1246 MemWriteByte (Addr, Regs.AC);
1252 static void OPC_6502_8E (void)
1253 /* Opcode $8E: STX abs */
1257 Addr = MemReadWord (Regs.PC+1);
1258 MemWriteByte (Addr, Regs.XR);
1264 static void OPC_6502_90 (void)
1265 /* Opcode $90: BCC */
1267 BRANCH (!GET_CF ());
1272 static void OPC_6502_91 (void)
1273 /* Opcode $91: sta (zp),y */
1275 unsigned char ZPAddr;
1278 ZPAddr = MemReadByte (Regs.PC+1);
1279 Addr = MemReadZPWord (ZPAddr) + Regs.YR;
1280 MemWriteByte (Addr, Regs.AC);
1286 static void OPC_6502_94 (void)
1287 /* Opcode $94: STY zp,x */
1289 unsigned char ZPAddr;
1291 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1292 MemWriteByte (ZPAddr, Regs.YR);
1298 static void OPC_6502_95 (void)
1299 /* Opcode $95: STA zp,x */
1301 unsigned char ZPAddr;
1303 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1304 MemWriteByte (ZPAddr, Regs.AC);
1310 static void OPC_6502_96 (void)
1311 /* Opcode $96: stx zp,y */
1313 unsigned char ZPAddr;
1315 ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR;
1316 MemWriteByte (ZPAddr, Regs.XR);
1322 static void OPC_6502_98 (void)
1323 /* Opcode $98: TYA */
1334 static void OPC_6502_99 (void)
1335 /* Opcode $99: STA abs,y */
1339 Addr = MemReadWord (Regs.PC+1) + Regs.YR;
1340 MemWriteByte (Addr, Regs.AC);
1346 static void OPC_6502_9A (void)
1347 /* Opcode $9A: TXS */
1356 static void OPC_6502_9D (void)
1357 /* Opcode $9D: STA abs,x */
1361 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
1362 MemWriteByte (Addr, Regs.AC);
1368 static void OPC_6502_A0 (void)
1369 /* Opcode $A0: LDY #imm */
1372 Regs.YR = MemReadByte (Regs.PC+1);
1380 static void OPC_6502_A1 (void)
1381 /* Opcode $A1: LDA (zp,x) */
1383 unsigned char ZPAddr;
1386 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1387 Addr = MemReadZPWord (ZPAddr);
1388 Regs.AC = MemReadByte (Addr);
1396 static void OPC_6502_A2 (void)
1397 /* Opcode $A2: LDX #imm */
1400 Regs.XR = MemReadByte (Regs.PC+1);
1408 static void OPC_6502_A4 (void)
1409 /* Opcode $A4: LDY zp */
1411 unsigned char ZPAddr;
1413 ZPAddr = MemReadByte (Regs.PC+1);
1414 Regs.YR = MemReadByte (ZPAddr);
1422 static void OPC_6502_A5 (void)
1423 /* Opcode $A5: LDA zp */
1425 unsigned char ZPAddr;
1427 ZPAddr = MemReadByte (Regs.PC+1);
1428 Regs.AC = MemReadByte (ZPAddr);
1436 static void OPC_6502_A6 (void)
1437 /* Opcode $A6: LDX zp */
1439 unsigned char ZPAddr;
1441 ZPAddr = MemReadByte (Regs.PC+1);
1442 Regs.XR = MemReadByte (ZPAddr);
1450 static void OPC_6502_A8 (void)
1451 /* Opcode $A8: TAY */
1462 static void OPC_6502_A9 (void)
1463 /* Opcode $A9: LDA #imm */
1466 Regs.AC = MemReadByte (Regs.PC+1);
1474 static void OPC_6502_AA (void)
1475 /* Opcode $AA: TAX */
1486 static void OPC_6502_AC (void)
1487 /* Opcode $Regs.AC: LDY abs */
1491 Addr = MemReadWord (Regs.PC+1);
1492 Regs.YR = MemReadByte (Addr);
1500 static void OPC_6502_AD (void)
1501 /* Opcode $AD: LDA abs */
1505 Addr = MemReadWord (Regs.PC+1);
1506 Regs.AC = MemReadByte (Addr);
1514 static void OPC_6502_AE (void)
1515 /* Opcode $AE: LDX abs */
1519 Addr = MemReadWord (Regs.PC+1);
1520 Regs.XR = MemReadByte (Addr);
1528 static void OPC_6502_B0 (void)
1529 /* Opcode $B0: BCS */
1536 static void OPC_6502_B1 (void)
1537 /* Opcode $B1: LDA (zp),y */
1539 unsigned char ZPAddr;
1542 ZPAddr = MemReadByte (Regs.PC+1);
1543 Addr = MemReadZPWord (ZPAddr);
1544 if (PAGE_CROSS (Addr, Regs.YR)) {
1547 Regs.AC = MemReadByte (Addr + Regs.YR);
1555 static void OPC_6502_B4 (void)
1556 /* Opcode $B4: LDY zp,x */
1558 unsigned char ZPAddr;
1560 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1561 Regs.YR = MemReadByte (ZPAddr);
1569 static void OPC_6502_B5 (void)
1570 /* Opcode $B5: LDA zp,x */
1572 unsigned char ZPAddr;
1574 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1575 Regs.AC = MemReadByte (ZPAddr);
1583 static void OPC_6502_B6 (void)
1584 /* Opcode $B6: LDX zp,y */
1586 unsigned char ZPAddr;
1588 ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR;
1589 Regs.XR = MemReadByte (ZPAddr);
1597 static void OPC_6502_B8 (void)
1598 /* Opcode $B8: CLV */
1607 static void OPC_6502_B9 (void)
1608 /* Opcode $B9: LDA abs,y */
1612 Addr = MemReadWord (Regs.PC+1);
1613 if (PAGE_CROSS (Addr, Regs.YR)) {
1616 Regs.AC = MemReadByte (Addr + Regs.YR);
1624 static void OPC_6502_BA (void)
1625 /* Opcode $BA: TSX */
1636 static void OPC_6502_BC (void)
1637 /* Opcode $BC: LDY abs,x */
1641 Addr = MemReadWord (Regs.PC+1);
1642 if (PAGE_CROSS (Addr, Regs.XR)) {
1645 Regs.YR = MemReadByte (Addr + Regs.XR);
1653 static void OPC_6502_BD (void)
1654 /* Opcode $BD: LDA abs,x */
1658 Addr = MemReadWord (Regs.PC+1);
1659 if (PAGE_CROSS (Addr, Regs.XR)) {
1662 Regs.AC = MemReadByte (Addr + Regs.XR);
1670 static void OPC_6502_BE (void)
1671 /* Opcode $BE: LDX abs,y */
1675 Addr = MemReadWord (Regs.PC+1);
1676 if (PAGE_CROSS (Addr, Regs.YR)) {
1679 Regs.XR = MemReadByte (Addr + Regs.YR);
1687 static void OPC_6502_C0 (void)
1688 /* Opcode $C0: CPY #imm */
1691 CMP (Regs.YR, MemReadByte (Regs.PC+1));
1697 static void OPC_6502_C1 (void)
1698 /* Opcode $C1: CMP (zp,x) */
1700 unsigned char ZPAddr;
1703 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1704 Addr = MemReadZPWord (ZPAddr);
1705 CMP (Regs.AC, MemReadByte (Addr));
1711 static void OPC_6502_C4 (void)
1712 /* Opcode $C4: CPY zp */
1714 unsigned char ZPAddr;
1716 ZPAddr = MemReadByte (Regs.PC+1);
1717 CMP (Regs.YR, MemReadByte (ZPAddr));
1723 static void OPC_6502_C5 (void)
1724 /* Opcode $C5: CMP zp */
1726 unsigned char ZPAddr;
1728 ZPAddr = MemReadByte (Regs.PC+1);
1729 CMP (Regs.AC, MemReadByte (ZPAddr));
1735 static void OPC_6502_C6 (void)
1736 /* Opcode $C6: DEC zp */
1738 unsigned char ZPAddr;
1741 ZPAddr = MemReadByte (Regs.PC+1);
1742 Val = MemReadByte (ZPAddr) - 1;
1743 MemWriteByte (ZPAddr, Val);
1751 static void OPC_6502_C8 (void)
1752 /* Opcode $C8: INY */
1755 Regs.YR = (Regs.YR + 1) & 0xFF;
1763 static void OPC_6502_C9 (void)
1764 /* Opcode $C9: CMP #imm */
1767 CMP (Regs.AC, MemReadByte (Regs.PC+1));
1773 static void OPC_6502_CA (void)
1774 /* Opcode $CA: DEX */
1777 Regs.XR = (Regs.XR - 1) & 0xFF;
1785 static void OPC_6502_CC (void)
1786 /* Opcode $CC: CPY abs */
1790 Addr = MemReadWord (Regs.PC+1);
1791 CMP (Regs.YR, MemReadByte (Addr));
1797 static void OPC_6502_CD (void)
1798 /* Opcode $CD: CMP abs */
1802 Addr = MemReadWord (Regs.PC+1);
1803 CMP (Regs.AC, MemReadByte (Addr));
1809 static void OPC_6502_CE (void)
1810 /* Opcode $CE: DEC abs */
1815 Addr = MemReadWord (Regs.PC+1);
1816 Val = MemReadByte (Addr) - 1;
1817 MemWriteByte (Addr, Val);
1825 static void OPC_6502_D0 (void)
1826 /* Opcode $D0: BNE */
1828 BRANCH (!GET_ZF ());
1833 static void OPC_6502_D1 (void)
1834 /* Opcode $D1: CMP (zp),y */
1839 ZPAddr = MemReadByte (Regs.PC+1);
1840 Addr = MemReadWord (ZPAddr);
1841 if (PAGE_CROSS (Addr, Regs.YR)) {
1844 CMP (Regs.AC, MemReadByte (Addr + Regs.YR));
1850 static void OPC_6502_D5 (void)
1851 /* Opcode $D5: CMP zp,x */
1853 unsigned char ZPAddr;
1855 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1856 CMP (Regs.AC, MemReadByte (ZPAddr));
1862 static void OPC_6502_D6 (void)
1863 /* Opcode $D6: DEC zp,x */
1865 unsigned char ZPAddr;
1868 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1869 Val = MemReadByte (ZPAddr) - 1;
1870 MemWriteByte (ZPAddr, Val);
1878 static void OPC_6502_D8 (void)
1879 /* Opcode $D8: CLD */
1888 static void OPC_6502_D9 (void)
1889 /* Opcode $D9: CMP abs,y */
1893 Addr = MemReadWord (Regs.PC+1);
1894 if (PAGE_CROSS (Addr, Regs.YR)) {
1897 CMP (Regs.AC, MemReadByte (Addr + Regs.YR));
1903 static void OPC_6502_DD (void)
1904 /* Opcode $DD: CMP abs,x */
1908 Addr = MemReadWord (Regs.PC+1);
1909 if (PAGE_CROSS (Addr, Regs.XR)) {
1912 CMP (Regs.AC, MemReadByte (Addr + Regs.XR));
1918 static void OPC_6502_DE (void)
1919 /* Opcode $DE: DEC abs,x */
1924 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
1925 Val = MemReadByte (Addr) - 1;
1926 MemWriteByte (Addr, Val);
1934 static void OPC_6502_E0 (void)
1935 /* Opcode $E0: CPX #imm */
1938 CMP (Regs.XR, MemReadByte (Regs.PC+1));
1944 static void OPC_6502_E1 (void)
1945 /* Opcode $E1: SBC (zp,x) */
1947 unsigned char ZPAddr;
1950 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1951 Addr = MemReadZPWord (ZPAddr);
1952 SBC (MemReadByte (Addr));
1958 static void OPC_6502_E4 (void)
1959 /* Opcode $E4: CPX zp */
1961 unsigned char ZPAddr;
1963 ZPAddr = MemReadByte (Regs.PC+1);
1964 CMP (Regs.XR, MemReadByte (ZPAddr));
1970 static void OPC_6502_E5 (void)
1971 /* Opcode $E5: SBC zp */
1973 unsigned char ZPAddr;
1975 ZPAddr = MemReadByte (Regs.PC+1);
1976 SBC (MemReadByte (ZPAddr));
1982 static void OPC_6502_E6 (void)
1983 /* Opcode $E6: INC zp */
1985 unsigned char ZPAddr;
1988 ZPAddr = MemReadByte (Regs.PC+1);
1989 Val = MemReadByte (ZPAddr) + 1;
1990 MemWriteByte (ZPAddr, Val);
1998 static void OPC_6502_E8 (void)
1999 /* Opcode $E8: INX */
2002 Regs.XR = (Regs.XR + 1) & 0xFF;
2010 static void OPC_6502_E9 (void)
2011 /* Opcode $E9: SBC #imm */
2014 SBC (MemReadByte (Regs.PC+1));
2020 static void OPC_6502_EA (void)
2021 /* Opcode $EA: NOP */
2023 /* This one is easy... */
2030 static void OPC_6502_EC (void)
2031 /* Opcode $EC: CPX abs */
2035 Addr = MemReadWord (Regs.PC+1);
2036 CMP (Regs.XR, MemReadByte (Addr));
2042 static void OPC_6502_ED (void)
2043 /* Opcode $ED: SBC abs */
2047 Addr = MemReadWord (Regs.PC+1);
2048 SBC (MemReadByte (Addr));
2054 static void OPC_6502_EE (void)
2055 /* Opcode $EE: INC abs */
2060 Addr = MemReadWord (Regs.PC+1);
2061 Val = MemReadByte (Addr) + 1;
2062 MemWriteByte (Addr, Val);
2070 static void OPC_6502_F0 (void)
2071 /* Opcode $F0: BEQ */
2078 static void OPC_6502_F1 (void)
2079 /* Opcode $F1: SBC (zp),y */
2081 unsigned char ZPAddr;
2084 ZPAddr = MemReadByte (Regs.PC+1);
2085 Addr = MemReadZPWord (ZPAddr);
2086 if (PAGE_CROSS (Addr, Regs.YR)) {
2089 SBC (MemReadByte (Addr + Regs.YR));
2095 static void OPC_6502_F5 (void)
2096 /* Opcode $F5: SBC zp,x */
2098 unsigned char ZPAddr;
2100 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
2101 SBC (MemReadByte (ZPAddr));
2107 static void OPC_6502_F6 (void)
2108 /* Opcode $F6: INC zp,x */
2110 unsigned char ZPAddr;
2113 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
2114 Val = MemReadByte (ZPAddr) + 1;
2115 MemWriteByte (ZPAddr, Val);
2123 static void OPC_6502_F8 (void)
2124 /* Opcode $F8: SED */
2131 static void OPC_6502_F9 (void)
2132 /* Opcode $F9: SBC abs,y */
2136 Addr = MemReadWord (Regs.PC+1);
2137 if (PAGE_CROSS (Addr, Regs.YR)) {
2140 SBC (MemReadByte (Addr + Regs.YR));
2146 static void OPC_6502_FD (void)
2147 /* Opcode $FD: SBC abs,x */
2151 Addr = MemReadWord (Regs.PC+1);
2152 if (PAGE_CROSS (Addr, Regs.XR)) {
2155 SBC (MemReadByte (Addr + Regs.XR));
2161 static void OPC_6502_FE (void)
2162 /* Opcode $FE: INC abs,x */
2167 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
2168 Val = MemReadByte (Addr) + 1;
2169 MemWriteByte (Addr, Val);
2177 /*****************************************************************************/
2179 /*****************************************************************************/
2183 /* Opcode handler table */
2184 typedef void (*OPCFunc) (void);
2185 static OPCFunc OPCTable[256] = {
2446 /*****************************************************************************/
2448 /*****************************************************************************/
2453 /* Initialize the CPU */
2460 void IRQRequest (void)
2461 /* Generate an IRQ */
2468 void NMIRequest (void)
2469 /* Generate an NMI */
2477 /* Generate a CPU RESET */
2479 CPUHalted = HaveIRQRequest = HaveNMIRequest = 0;
2480 Regs.PC = MemReadWord (0xFFFC);
2485 void Break (const char* Format, ...)
2486 /* Stop running and display the given message */
2490 va_start (ap, Format);
2491 xvsprintf (BreakMsg, sizeof (BreakMsg), Format, ap);
2499 /* Run one CPU instruction */
2501 /* If the CPU is halted, do nothing */
2506 /* If we have an NMI request, handle it */
2507 if (HaveNMIRequest) {
2514 Regs.PC = MemReadWord (0xFFFA);
2517 } else if (HaveIRQRequest && GET_IF () == 0) {
2524 Regs.PC = MemReadWord (0xFFFE);
2529 /* Normal instruction - read the next opcode */
2530 unsigned char OPC = MemReadByte (Regs.PC);
2538 TotalCycles += Cycles;
2541 printf ("%s\n", BreakMsg);
2549 if ((++I & 0xFF) == 0)
2550 printf ("%9lu %06X %02X A=%02X X=%02X Y=%02X %c%c%c%c%c%c%c\n",
2551 TotalCycles, Regs.PC, OPC, Regs.AC, Regs.XR, Regs.YR,
2552 GET_SF()? 'S' : '-',
2553 GET_ZF()? 'Z' : '-',
2554 GET_CF()? 'C' : '-',
2555 GET_IF()? 'I' : '-',
2556 GET_BF()? 'B' : '-',
2557 GET_DF()? 'D' : '-',
2558 GET_OF()? 'V' : '-');