1 /*****************************************************************************/
5 /* CPU core for the 6502 simulator */
9 /* (C) 2003-2012, Ullrich von Bassewitz */
10 /* Roemerstrasse 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 StrBuf BreakMsg = STATIC_STRBUF_INITIALIZER;
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 unsigned old = Regs.AC; \
226 unsigned rhs = (v & 0xFF); \
230 lo = (old & 0x0F) + (rhs & 0x0F) + GET_CF (); \
232 lo = ((lo + 0x06) & 0x0F) + 0x10; \
234 Regs.AC = (old & 0xF0) + (rhs & 0xF0) + lo; \
235 res = (signed char)(old & 0xF0) + \
236 (signed char)(rhs & 0xF0) + \
238 TEST_ZF (old + rhs + GET_CF ()); \
240 if (Regs.AC >= 0xA0) { \
244 SET_OF ((res < -128) || (res > 127)); \
246 Regs.AC += rhs + GET_CF (); \
250 SET_OF (!((old ^ rhs) & 0x80) && \
251 ((old ^ Regs.AC) & 0x80)); \
257 #define BRANCH(cond) \
261 unsigned char OldPCH; \
263 Offs = (signed char) MemReadByte (Regs.PC+1); \
265 Regs.PC += 2 + (int) Offs; \
266 if (PCH != OldPCH) { \
276 unsigned Result = v1 - v2; \
277 TEST_ZF (Result & 0xFF); \
279 SET_CF (Result <= 0xFF); \
298 SET_CF (Val & 0x01); \
306 unsigned old = Regs.AC; \
307 unsigned rhs = (v & 0xFF); \
311 lo = (old & 0x0F) - (rhs & 0x0F) + GET_CF () - 1; \
313 lo = ((lo - 0x06) & 0x0F) - 0x10; \
315 Regs.AC = (old & 0xF0) - (rhs & 0xF0) + lo; \
316 if (Regs.AC & 0x80) { \
319 res = Regs.AC - rhs + (!GET_CF ()); \
322 SET_CF (res <= 0xFF); \
323 SET_OF (((old^rhs) & (old^res) & 0x80)); \
325 Regs.AC -= rhs - (!GET_CF ()); \
328 SET_CF (Regs.AC <= 0xFF); \
329 SET_OF (((old^rhs) & (old^Regs.AC) & 0x80)); \
335 /*****************************************************************************/
336 /* Helper functions */
337 /*****************************************************************************/
341 static void OPC_Illegal (void)
343 Warning ("Illegal opcode $%02X at address $%04X\n", MemReadByte (Regs.PC), Regs.PC);
348 /*****************************************************************************/
350 /*****************************************************************************/
354 static void OPC_6502_00 (void)
355 /* Opcode $00: BRK */
364 Regs.PC = MemReadWord (0xFFFE);
370 static void OPC_6502_01 (void)
371 /* Opcode $01: ORA (ind,x) */
378 static void OPC_6502_05 (void)
379 /* Opcode $05: ORA zp */
386 static void OPC_6502_06 (void)
387 /* Opcode $06: ASL zp */
389 unsigned char ZPAddr;
392 ZPAddr = MemReadByte (Regs.PC+1);
393 Val = MemReadByte (ZPAddr) << 1;
394 MemWriteByte (ZPAddr, (unsigned char) Val);
395 TEST_ZF (Val & 0xFF);
397 SET_CF (Val & 0x100);
403 static void OPC_6502_08 (void)
404 /* Opcode $08: PHP */
407 PUSH (Regs.SR & ~BF);
413 static void OPC_6502_09 (void)
414 /* Opcode $09: ORA #imm */
421 static void OPC_6502_0A (void)
422 /* Opcode $0A: ASL a */
426 TEST_ZF (Regs.AC & 0xFF);
428 SET_CF (Regs.AC & 0x100);
435 static void OPC_6502_0D (void)
436 /* Opcode $0D: ORA abs */
443 static void OPC_6502_0E (void)
444 /* Opcode $0E: ALS abs */
449 Addr = MemReadWord (Regs.PC+1);
450 Val = MemReadByte (Addr) << 1;
451 MemWriteByte (Addr, (unsigned char) Val);
452 TEST_ZF (Val & 0xFF);
454 SET_CF (Val & 0x100);
460 static void OPC_6502_10 (void)
461 /* Opcode $10: BPL */
468 static void OPC_6502_11 (void)
469 /* Opcode $11: ORA (zp),y */
476 static void OPC_6502_15 (void)
477 /* Opcode $15: ORA zp,x */
484 static void OPC_6502_16 (void)
485 /* Opcode $16: ASL zp,x */
487 unsigned char ZPAddr;
490 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
491 Val = MemReadByte (ZPAddr) << 1;
492 MemWriteByte (ZPAddr, (unsigned char) Val);
493 TEST_ZF (Val & 0xFF);
495 SET_CF (Val & 0x100);
501 static void OPC_6502_18 (void)
502 /* Opcode $18: CLC */
511 static void OPC_6502_19 (void)
512 /* Opcode $19: ORA abs,y */
519 static void OPC_6502_1D (void)
520 /* Opcode $1D: ORA abs,x */
527 static void OPC_6502_1E (void)
528 /* Opcode $1E: ASL abs,x */
533 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
534 Val = MemReadByte (Addr) << 1;
535 MemWriteByte (Addr, (unsigned char) Val);
536 TEST_ZF (Val & 0xFF);
538 SET_CF (Val & 0x100);
544 static void OPC_6502_20 (void)
545 /* Opcode $20: JSR */
549 Addr = MemReadWord (Regs.PC+1);
558 static void OPC_6502_21 (void)
559 /* Opcode $21: AND (zp,x) */
566 static void OPC_6502_24 (void)
567 /* Opcode $24: BIT zp */
569 unsigned char ZPAddr;
572 ZPAddr = MemReadByte (Regs.PC+1);
573 Val = MemReadByte (ZPAddr);
576 SET_ZF ((Val & Regs.AC) == 0);
582 static void OPC_6502_25 (void)
583 /* Opcode $25: AND zp */
590 static void OPC_6502_26 (void)
591 /* Opcode $26: ROL zp */
593 unsigned char ZPAddr;
596 ZPAddr = MemReadByte (Regs.PC+1);
597 Val = MemReadByte (ZPAddr);
599 MemWriteByte (ZPAddr, Val);
605 static void OPC_6502_28 (void)
606 /* Opcode $28: PLP */
609 Regs.SR = (POP () & ~BF);
615 static void OPC_6502_29 (void)
616 /* Opcode $29: AND #imm */
623 static void OPC_6502_2A (void)
624 /* Opcode $2A: ROL a */
634 static void OPC_6502_2C (void)
635 /* Opcode $2C: BIT abs */
640 Addr = MemReadByte (Regs.PC+1);
641 Val = MemReadByte (Addr);
644 SET_ZF ((Val & Regs.AC) == 0);
650 static void OPC_6502_2D (void)
651 /* Opcode $2D: AND abs */
658 static void OPC_6502_2E (void)
659 /* Opcode $2E: ROL abs */
664 Addr = MemReadWord (Regs.PC+1);
665 Val = MemReadByte (Addr);
667 MemWriteByte (Addr, Val);
673 static void OPC_6502_30 (void)
674 /* Opcode $30: BMI */
681 static void OPC_6502_31 (void)
682 /* Opcode $31: AND (zp),y */
689 static void OPC_6502_35 (void)
690 /* Opcode $35: AND zp,x */
697 static void OPC_6502_36 (void)
698 /* Opcode $36: ROL zp,x */
700 unsigned char ZPAddr;
703 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
704 Val = MemReadByte (ZPAddr);
706 MemWriteByte (ZPAddr, Val);
712 static void OPC_6502_38 (void)
713 /* Opcode $38: SEC */
722 static void OPC_6502_39 (void)
723 /* Opcode $39: AND abs,y */
730 static void OPC_6502_3D (void)
731 /* Opcode $3D: AND abs,x */
738 static void OPC_6502_3E (void)
739 /* Opcode $3E: ROL abs,x */
744 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
745 Val = MemReadByte (Addr);
747 MemWriteByte (Addr, Val);
753 static void OPC_6502_40 (void)
754 /* Opcode $40: RTI */
758 Regs.PC = POP (); /* PCL */
759 Regs.PC |= (POP () << 8); /* PCH */
764 static void OPC_6502_41 (void)
765 /* Opcode $41: EOR (zp,x) */
772 static void OPC_6502_45 (void)
773 /* Opcode $45: EOR zp */
780 static void OPC_6502_46 (void)
781 /* Opcode $46: LSR zp */
783 unsigned char ZPAddr;
786 ZPAddr = MemReadByte (Regs.PC+1);
787 Val = MemReadByte (ZPAddr);
790 MemWriteByte (ZPAddr, Val);
798 static void OPC_6502_48 (void)
799 /* Opcode $48: PHA */
808 static void OPC_6502_49 (void)
809 /* Opcode $49: EOR #imm */
816 static void OPC_6502_4A (void)
817 /* Opcode $4A: LSR a */
820 SET_CF (Regs.AC & 0x01);
829 static void OPC_6502_4C (void)
830 /* Opcode $4C: JMP abs */
833 Regs.PC = MemReadWord (Regs.PC+1);
838 static void OPC_6502_4D (void)
839 /* Opcode $4D: EOR abs */
846 static void OPC_6502_4E (void)
847 /* Opcode $4E: LSR abs */
852 Addr = MemReadWord (Regs.PC+1);
853 Val = MemReadByte (Addr);
856 MemWriteByte (Addr, Val);
864 static void OPC_6502_50 (void)
865 /* Opcode $50: BVC */
872 static void OPC_6502_51 (void)
873 /* Opcode $51: EOR (zp),y */
880 static void OPC_6502_55 (void)
881 /* Opcode $55: EOR zp,x */
888 static void OPC_6502_56 (void)
889 /* Opcode $56: LSR zp,x */
891 unsigned char ZPAddr;
894 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
895 Val = MemReadByte (ZPAddr);
898 MemWriteByte (ZPAddr, Val);
906 static void OPC_6502_58 (void)
907 /* Opcode $58: CLI */
916 static void OPC_6502_59 (void)
917 /* Opcode $59: EOR abs,y */
924 static void OPC_6502_5D (void)
925 /* Opcode $5D: EOR abs,x */
932 static void OPC_6502_5E (void)
933 /* Opcode $5E: LSR abs,x */
938 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
939 Val = MemReadByte (Addr);
942 MemWriteByte (Addr, Val);
950 static void OPC_6502_60 (void)
951 /* Opcode $60: RTS */
954 Regs.PC = POP (); /* PCL */
955 Regs.PC |= (POP () << 8); /* PCH */
961 static void OPC_6502_61 (void)
962 /* Opcode $61: ADC (zp,x) */
964 unsigned char ZPAddr;
967 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
968 Addr = MemReadZPWord (ZPAddr);
969 ADC (MemReadByte (Addr));
975 static void OPC_6502_65 (void)
976 /* Opcode $65: ADC zp */
978 unsigned char ZPAddr;
980 ZPAddr = MemReadByte (Regs.PC+1);
981 ADC (MemReadByte (ZPAddr));
987 static void OPC_6502_66 (void)
988 /* Opcode $66: ROR zp */
990 unsigned char ZPAddr;
993 ZPAddr = MemReadByte (Regs.PC+1);
994 Val = MemReadByte (ZPAddr);
996 MemWriteByte (ZPAddr, Val);
1002 static void OPC_6502_68 (void)
1003 /* Opcode $68: PLA */
1014 static void OPC_6502_69 (void)
1015 /* Opcode $69: ADC #imm */
1018 ADC (MemReadByte (Regs.PC+1));
1024 static void OPC_6502_6A (void)
1025 /* Opcode $6A: ROR a */
1034 static void OPC_6502_6C (void)
1035 /* Opcode $6C: JMP (ind) */
1039 Addr = MemReadWord (Regs.PC+1);
1040 if (CPU == CPU_6502) {
1041 /* Emulate the 6502 bug */
1042 Regs.PC = MemReadByte (Addr);
1043 Addr = (Addr & 0xFF00) | ((Addr + 1) & 0xFF);
1044 Regs.PC |= (MemReadByte (Addr) << 8);
1046 /* 65C02 and above have this bug fixed */
1047 Regs.PC = MemReadWord (Addr);
1053 static void OPC_6502_6D (void)
1054 /* Opcode $6D: ADC abs */
1058 Addr = MemReadWord (Regs.PC+1);
1059 ADC (MemReadByte (Addr));
1065 static void OPC_6502_6E (void)
1066 /* Opcode $6E: ROR abs */
1071 Addr = MemReadWord (Regs.PC+1);
1072 Val = MemReadByte (Addr);
1074 MemWriteByte (Addr, Val);
1080 static void OPC_6502_70 (void)
1081 /* Opcode $70: BVS */
1088 static void OPC_6502_71 (void)
1089 /* Opcode $71: ADC (zp),y */
1091 unsigned char ZPAddr;
1094 ZPAddr = MemReadByte (Regs.PC+1);
1095 Addr = MemReadZPWord (ZPAddr);
1096 if (PAGE_CROSS (Addr, Regs.YR)) {
1099 ADC (MemReadByte (Addr + Regs.YR));
1105 static void OPC_6502_75 (void)
1106 /* Opcode $75: ADC zp,x */
1108 unsigned char ZPAddr;
1110 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1111 ADC (MemReadByte (ZPAddr));
1117 static void OPC_6502_76 (void)
1118 /* Opcode $76: ROR zp,x */
1120 unsigned char ZPAddr;
1123 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1124 Val = MemReadByte (ZPAddr);
1126 MemWriteByte (ZPAddr, Val);
1132 static void OPC_6502_78 (void)
1133 /* Opcode $78: SEI */
1142 static void OPC_6502_79 (void)
1143 /* Opcode $79: ADC abs,y */
1147 Addr = MemReadWord (Regs.PC+1);
1148 if (PAGE_CROSS (Addr, Regs.YR)) {
1151 ADC (MemReadByte (Addr + Regs.YR));
1157 static void OPC_6502_7D (void)
1158 /* Opcode $7D: ADC abs,x */
1162 Addr = MemReadWord (Regs.PC+1);
1163 if (PAGE_CROSS (Addr, Regs.XR)) {
1166 ADC (MemReadByte (Addr + Regs.XR));
1172 static void OPC_6502_7E (void)
1173 /* Opcode $7E: ROR abs,x */
1178 Addr = MemReadByte (Regs.PC+1) + Regs.XR;
1179 Val = MemReadByte (Addr);
1181 MemWriteByte (Addr, Val);
1187 static void OPC_6502_81 (void)
1188 /* Opcode $81: STA (zp,x) */
1190 unsigned char ZPAddr;
1193 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1194 Addr = MemReadZPWord (ZPAddr);
1195 MemWriteByte (Addr, Regs.AC);
1201 static void OPC_6502_84 (void)
1202 /* Opcode $84: STY zp */
1204 unsigned char ZPAddr;
1206 ZPAddr = MemReadByte (Regs.PC+1);
1207 MemWriteByte (ZPAddr, Regs.YR);
1213 static void OPC_6502_85 (void)
1214 /* Opcode $85: STA zp */
1216 unsigned char ZPAddr;
1218 ZPAddr = MemReadByte (Regs.PC+1);
1219 MemWriteByte (ZPAddr, Regs.AC);
1225 static void OPC_6502_86 (void)
1226 /* Opcode $86: STX zp */
1228 unsigned char ZPAddr;
1230 ZPAddr = MemReadByte (Regs.PC+1);
1231 MemWriteByte (ZPAddr, Regs.XR);
1237 static void OPC_6502_88 (void)
1238 /* Opcode $88: DEY */
1241 Regs.YR = (Regs.YR - 1) & 0xFF;
1249 static void OPC_6502_8A (void)
1250 /* Opcode $8A: TXA */
1261 static void OPC_6502_8C (void)
1262 /* Opcode $8C: STY abs */
1266 Addr = MemReadWord (Regs.PC+1);
1267 MemWriteByte (Addr, Regs.YR);
1273 static void OPC_6502_8D (void)
1274 /* Opcode $8D: STA abs */
1278 Addr = MemReadWord (Regs.PC+1);
1279 MemWriteByte (Addr, Regs.AC);
1285 static void OPC_6502_8E (void)
1286 /* Opcode $8E: STX abs */
1290 Addr = MemReadWord (Regs.PC+1);
1291 MemWriteByte (Addr, Regs.XR);
1297 static void OPC_6502_90 (void)
1298 /* Opcode $90: BCC */
1300 BRANCH (!GET_CF ());
1305 static void OPC_6502_91 (void)
1306 /* Opcode $91: sta (zp),y */
1308 unsigned char ZPAddr;
1311 ZPAddr = MemReadByte (Regs.PC+1);
1312 Addr = MemReadZPWord (ZPAddr) + Regs.YR;
1313 MemWriteByte (Addr, Regs.AC);
1319 static void OPC_6502_94 (void)
1320 /* Opcode $94: STY zp,x */
1322 unsigned char ZPAddr;
1324 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1325 MemWriteByte (ZPAddr, Regs.YR);
1331 static void OPC_6502_95 (void)
1332 /* Opcode $95: STA zp,x */
1334 unsigned char ZPAddr;
1336 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1337 MemWriteByte (ZPAddr, Regs.AC);
1343 static void OPC_6502_96 (void)
1344 /* Opcode $96: stx zp,y */
1346 unsigned char ZPAddr;
1348 ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR;
1349 MemWriteByte (ZPAddr, Regs.XR);
1355 static void OPC_6502_98 (void)
1356 /* Opcode $98: TYA */
1367 static void OPC_6502_99 (void)
1368 /* Opcode $99: STA abs,y */
1372 Addr = MemReadWord (Regs.PC+1) + Regs.YR;
1373 MemWriteByte (Addr, Regs.AC);
1379 static void OPC_6502_9A (void)
1380 /* Opcode $9A: TXS */
1389 static void OPC_6502_9D (void)
1390 /* Opcode $9D: STA abs,x */
1394 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
1395 MemWriteByte (Addr, Regs.AC);
1401 static void OPC_6502_A0 (void)
1402 /* Opcode $A0: LDY #imm */
1405 Regs.YR = MemReadByte (Regs.PC+1);
1413 static void OPC_6502_A1 (void)
1414 /* Opcode $A1: LDA (zp,x) */
1416 unsigned char ZPAddr;
1419 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1420 Addr = MemReadZPWord (ZPAddr);
1421 Regs.AC = MemReadByte (Addr);
1429 static void OPC_6502_A2 (void)
1430 /* Opcode $A2: LDX #imm */
1433 Regs.XR = MemReadByte (Regs.PC+1);
1441 static void OPC_6502_A4 (void)
1442 /* Opcode $A4: LDY zp */
1444 unsigned char ZPAddr;
1446 ZPAddr = MemReadByte (Regs.PC+1);
1447 Regs.YR = MemReadByte (ZPAddr);
1455 static void OPC_6502_A5 (void)
1456 /* Opcode $A5: LDA zp */
1458 unsigned char ZPAddr;
1460 ZPAddr = MemReadByte (Regs.PC+1);
1461 Regs.AC = MemReadByte (ZPAddr);
1469 static void OPC_6502_A6 (void)
1470 /* Opcode $A6: LDX zp */
1472 unsigned char ZPAddr;
1474 ZPAddr = MemReadByte (Regs.PC+1);
1475 Regs.XR = MemReadByte (ZPAddr);
1483 static void OPC_6502_A8 (void)
1484 /* Opcode $A8: TAY */
1495 static void OPC_6502_A9 (void)
1496 /* Opcode $A9: LDA #imm */
1499 Regs.AC = MemReadByte (Regs.PC+1);
1507 static void OPC_6502_AA (void)
1508 /* Opcode $AA: TAX */
1519 static void OPC_6502_AC (void)
1520 /* Opcode $Regs.AC: LDY abs */
1524 Addr = MemReadWord (Regs.PC+1);
1525 Regs.YR = MemReadByte (Addr);
1533 static void OPC_6502_AD (void)
1534 /* Opcode $AD: LDA abs */
1538 Addr = MemReadWord (Regs.PC+1);
1539 Regs.AC = MemReadByte (Addr);
1547 static void OPC_6502_AE (void)
1548 /* Opcode $AE: LDX abs */
1552 Addr = MemReadWord (Regs.PC+1);
1553 Regs.XR = MemReadByte (Addr);
1561 static void OPC_6502_B0 (void)
1562 /* Opcode $B0: BCS */
1569 static void OPC_6502_B1 (void)
1570 /* Opcode $B1: LDA (zp),y */
1572 unsigned char ZPAddr;
1575 ZPAddr = MemReadByte (Regs.PC+1);
1576 Addr = MemReadZPWord (ZPAddr);
1577 if (PAGE_CROSS (Addr, Regs.YR)) {
1580 Regs.AC = MemReadByte (Addr + Regs.YR);
1588 static void OPC_6502_B4 (void)
1589 /* Opcode $B4: LDY zp,x */
1591 unsigned char ZPAddr;
1593 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1594 Regs.YR = MemReadByte (ZPAddr);
1602 static void OPC_6502_B5 (void)
1603 /* Opcode $B5: LDA zp,x */
1605 unsigned char ZPAddr;
1607 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1608 Regs.AC = MemReadByte (ZPAddr);
1616 static void OPC_6502_B6 (void)
1617 /* Opcode $B6: LDX zp,y */
1619 unsigned char ZPAddr;
1621 ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR;
1622 Regs.XR = MemReadByte (ZPAddr);
1630 static void OPC_6502_B8 (void)
1631 /* Opcode $B8: CLV */
1640 static void OPC_6502_B9 (void)
1641 /* Opcode $B9: LDA abs,y */
1645 Addr = MemReadWord (Regs.PC+1);
1646 if (PAGE_CROSS (Addr, Regs.YR)) {
1649 Regs.AC = MemReadByte (Addr + Regs.YR);
1657 static void OPC_6502_BA (void)
1658 /* Opcode $BA: TSX */
1669 static void OPC_6502_BC (void)
1670 /* Opcode $BC: LDY abs,x */
1674 Addr = MemReadWord (Regs.PC+1);
1675 if (PAGE_CROSS (Addr, Regs.XR)) {
1678 Regs.YR = MemReadByte (Addr + Regs.XR);
1686 static void OPC_6502_BD (void)
1687 /* Opcode $BD: LDA abs,x */
1691 Addr = MemReadWord (Regs.PC+1);
1692 if (PAGE_CROSS (Addr, Regs.XR)) {
1695 Regs.AC = MemReadByte (Addr + Regs.XR);
1703 static void OPC_6502_BE (void)
1704 /* Opcode $BE: LDX abs,y */
1708 Addr = MemReadWord (Regs.PC+1);
1709 if (PAGE_CROSS (Addr, Regs.YR)) {
1712 Regs.XR = MemReadByte (Addr + Regs.YR);
1720 static void OPC_6502_C0 (void)
1721 /* Opcode $C0: CPY #imm */
1724 CMP (Regs.YR, MemReadByte (Regs.PC+1));
1730 static void OPC_6502_C1 (void)
1731 /* Opcode $C1: CMP (zp,x) */
1733 unsigned char ZPAddr;
1736 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1737 Addr = MemReadZPWord (ZPAddr);
1738 CMP (Regs.AC, MemReadByte (Addr));
1744 static void OPC_6502_C4 (void)
1745 /* Opcode $C4: CPY zp */
1747 unsigned char ZPAddr;
1749 ZPAddr = MemReadByte (Regs.PC+1);
1750 CMP (Regs.YR, MemReadByte (ZPAddr));
1756 static void OPC_6502_C5 (void)
1757 /* Opcode $C5: CMP zp */
1759 unsigned char ZPAddr;
1761 ZPAddr = MemReadByte (Regs.PC+1);
1762 CMP (Regs.AC, MemReadByte (ZPAddr));
1768 static void OPC_6502_C6 (void)
1769 /* Opcode $C6: DEC zp */
1771 unsigned char ZPAddr;
1774 ZPAddr = MemReadByte (Regs.PC+1);
1775 Val = MemReadByte (ZPAddr) - 1;
1776 MemWriteByte (ZPAddr, Val);
1784 static void OPC_6502_C8 (void)
1785 /* Opcode $C8: INY */
1788 Regs.YR = (Regs.YR + 1) & 0xFF;
1796 static void OPC_6502_C9 (void)
1797 /* Opcode $C9: CMP #imm */
1800 CMP (Regs.AC, MemReadByte (Regs.PC+1));
1806 static void OPC_6502_CA (void)
1807 /* Opcode $CA: DEX */
1810 Regs.XR = (Regs.XR - 1) & 0xFF;
1818 static void OPC_6502_CC (void)
1819 /* Opcode $CC: CPY abs */
1823 Addr = MemReadWord (Regs.PC+1);
1824 CMP (Regs.YR, MemReadByte (Addr));
1830 static void OPC_6502_CD (void)
1831 /* Opcode $CD: CMP abs */
1835 Addr = MemReadWord (Regs.PC+1);
1836 CMP (Regs.AC, MemReadByte (Addr));
1842 static void OPC_6502_CE (void)
1843 /* Opcode $CE: DEC abs */
1848 Addr = MemReadWord (Regs.PC+1);
1849 Val = MemReadByte (Addr) - 1;
1850 MemWriteByte (Addr, Val);
1858 static void OPC_6502_D0 (void)
1859 /* Opcode $D0: BNE */
1861 BRANCH (!GET_ZF ());
1866 static void OPC_6502_D1 (void)
1867 /* Opcode $D1: CMP (zp),y */
1872 ZPAddr = MemReadByte (Regs.PC+1);
1873 Addr = MemReadWord (ZPAddr);
1874 if (PAGE_CROSS (Addr, Regs.YR)) {
1877 CMP (Regs.AC, MemReadByte (Addr + Regs.YR));
1883 static void OPC_6502_D5 (void)
1884 /* Opcode $D5: CMP zp,x */
1886 unsigned char ZPAddr;
1888 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1889 CMP (Regs.AC, MemReadByte (ZPAddr));
1895 static void OPC_6502_D6 (void)
1896 /* Opcode $D6: DEC zp,x */
1898 unsigned char ZPAddr;
1901 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1902 Val = MemReadByte (ZPAddr) - 1;
1903 MemWriteByte (ZPAddr, Val);
1911 static void OPC_6502_D8 (void)
1912 /* Opcode $D8: CLD */
1921 static void OPC_6502_D9 (void)
1922 /* Opcode $D9: CMP abs,y */
1926 Addr = MemReadWord (Regs.PC+1);
1927 if (PAGE_CROSS (Addr, Regs.YR)) {
1930 CMP (Regs.AC, MemReadByte (Addr + Regs.YR));
1936 static void OPC_6502_DD (void)
1937 /* Opcode $DD: CMP abs,x */
1941 Addr = MemReadWord (Regs.PC+1);
1942 if (PAGE_CROSS (Addr, Regs.XR)) {
1945 CMP (Regs.AC, MemReadByte (Addr + Regs.XR));
1951 static void OPC_6502_DE (void)
1952 /* Opcode $DE: DEC abs,x */
1957 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
1958 Val = MemReadByte (Addr) - 1;
1959 MemWriteByte (Addr, Val);
1967 static void OPC_6502_E0 (void)
1968 /* Opcode $E0: CPX #imm */
1971 CMP (Regs.XR, MemReadByte (Regs.PC+1));
1977 static void OPC_6502_E1 (void)
1978 /* Opcode $E1: SBC (zp,x) */
1980 unsigned char ZPAddr;
1983 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1984 Addr = MemReadZPWord (ZPAddr);
1985 SBC (MemReadByte (Addr));
1991 static void OPC_6502_E4 (void)
1992 /* Opcode $E4: CPX zp */
1994 unsigned char ZPAddr;
1996 ZPAddr = MemReadByte (Regs.PC+1);
1997 CMP (Regs.XR, MemReadByte (ZPAddr));
2003 static void OPC_6502_E5 (void)
2004 /* Opcode $E5: SBC zp */
2006 unsigned char ZPAddr;
2008 ZPAddr = MemReadByte (Regs.PC+1);
2009 SBC (MemReadByte (ZPAddr));
2015 static void OPC_6502_E6 (void)
2016 /* Opcode $E6: INC zp */
2018 unsigned char ZPAddr;
2021 ZPAddr = MemReadByte (Regs.PC+1);
2022 Val = MemReadByte (ZPAddr) + 1;
2023 MemWriteByte (ZPAddr, Val);
2031 static void OPC_6502_E8 (void)
2032 /* Opcode $E8: INX */
2035 Regs.XR = (Regs.XR + 1) & 0xFF;
2043 static void OPC_6502_E9 (void)
2044 /* Opcode $E9: SBC #imm */
2047 SBC (MemReadByte (Regs.PC+1));
2053 static void OPC_6502_EA (void)
2054 /* Opcode $EA: NOP */
2056 /* This one is easy... */
2063 static void OPC_6502_EC (void)
2064 /* Opcode $EC: CPX abs */
2068 Addr = MemReadWord (Regs.PC+1);
2069 CMP (Regs.XR, MemReadByte (Addr));
2075 static void OPC_6502_ED (void)
2076 /* Opcode $ED: SBC abs */
2080 Addr = MemReadWord (Regs.PC+1);
2081 SBC (MemReadByte (Addr));
2087 static void OPC_6502_EE (void)
2088 /* Opcode $EE: INC abs */
2093 Addr = MemReadWord (Regs.PC+1);
2094 Val = MemReadByte (Addr) + 1;
2095 MemWriteByte (Addr, Val);
2103 static void OPC_6502_F0 (void)
2104 /* Opcode $F0: BEQ */
2111 static void OPC_6502_F1 (void)
2112 /* Opcode $F1: SBC (zp),y */
2114 unsigned char ZPAddr;
2117 ZPAddr = MemReadByte (Regs.PC+1);
2118 Addr = MemReadZPWord (ZPAddr);
2119 if (PAGE_CROSS (Addr, Regs.YR)) {
2122 SBC (MemReadByte (Addr + Regs.YR));
2128 static void OPC_6502_F5 (void)
2129 /* Opcode $F5: SBC zp,x */
2131 unsigned char ZPAddr;
2133 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
2134 SBC (MemReadByte (ZPAddr));
2140 static void OPC_6502_F6 (void)
2141 /* Opcode $F6: INC zp,x */
2143 unsigned char ZPAddr;
2146 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
2147 Val = MemReadByte (ZPAddr) + 1;
2148 MemWriteByte (ZPAddr, Val);
2156 static void OPC_6502_F8 (void)
2157 /* Opcode $F8: SED */
2164 static void OPC_6502_F9 (void)
2165 /* Opcode $F9: SBC abs,y */
2169 Addr = MemReadWord (Regs.PC+1);
2170 if (PAGE_CROSS (Addr, Regs.YR)) {
2173 SBC (MemReadByte (Addr + Regs.YR));
2179 static void OPC_6502_FD (void)
2180 /* Opcode $FD: SBC abs,x */
2184 Addr = MemReadWord (Regs.PC+1);
2185 if (PAGE_CROSS (Addr, Regs.XR)) {
2188 SBC (MemReadByte (Addr + Regs.XR));
2194 static void OPC_6502_FE (void)
2195 /* Opcode $FE: INC abs,x */
2200 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
2201 Val = MemReadByte (Addr) + 1;
2202 MemWriteByte (Addr, Val);
2210 /*****************************************************************************/
2212 /*****************************************************************************/
2216 /* Opcode handler table */
2217 typedef void (*OPCFunc) (void);
2218 static OPCFunc OPCTable[256] = {
2479 /*****************************************************************************/
2481 /*****************************************************************************/
2486 /* Initialize the CPU */
2493 void IRQRequest (void)
2494 /* Generate an IRQ */
2501 void NMIRequest (void)
2502 /* Generate an NMI */
2510 /* Generate a CPU RESET */
2512 CPUHalted = HaveIRQRequest = HaveNMIRequest = 0;
2513 Regs.PC = MemReadWord (0xFFFC);
2518 void Break (const char* Format, ...)
2519 /* Stop running and display the given message */
2522 va_start (ap, Format);
2523 SB_VPrintf (&BreakMsg, Format, ap);
2530 /* Run one CPU instruction */
2532 /* If the CPU is halted, do nothing */
2537 /* If we have an NMI request, handle it */
2538 if (HaveNMIRequest) {
2545 Regs.PC = MemReadWord (0xFFFA);
2548 } else if (HaveIRQRequest && GET_IF () == 0) {
2555 Regs.PC = MemReadWord (0xFFFE);
2560 /* Normal instruction - read the next opcode */
2561 unsigned char OPC = MemReadByte (Regs.PC);
2569 TotalCycles += Cycles;
2571 if (SB_GetLen (&BreakMsg) > 0) {
2572 printf ("%.*s\n", SB_GetLen (&BreakMsg), SB_GetConstBuf (&BreakMsg));
2573 SB_Clear (&BreakMsg);
2580 if ((++I & 0xFF) == 0)
2581 printf ("%9lu %06X %02X A=%02X X=%02X Y=%02X %c%c%c%c%c%c%c\n",
2582 TotalCycles, Regs.PC, OPC, Regs.AC, Regs.XR, Regs.YR,
2583 GET_SF()? 'S' : '-',
2584 GET_ZF()? 'Z' : '-',
2585 GET_CF()? 'C' : '-',
2586 GET_IF()? 'I' : '-',
2587 GET_BF()? 'B' : '-',
2588 GET_DF()? 'D' : '-',
2589 GET_OF()? 'V' : '-');