1 /*****************************************************************************/
5 /* CPU core for the 6502 */
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 /*****************************************************************************/
43 /*****************************************************************************/
45 /*****************************************************************************/
52 /* Type of an opcode handler function */
53 typedef void (*OPFunc) (void);
55 /* The CPU registers */
58 /* Cycles for the current insn */
59 static unsigned Cycles;
61 /* Total number of CPU cycles exec'd */
62 static unsigned long TotalCycles;
64 /* NMI request active */
65 static unsigned HaveNMIRequest;
67 /* IRQ request active */
68 static unsigned HaveIRQRequest;
70 /* flag to print cycles at program termination */
74 /*****************************************************************************/
75 /* Helper functions and macros */
76 /*****************************************************************************/
80 /* Return the flags as a boolean value (0/1) */
81 #define GET_CF() ((Regs.SR & CF) != 0)
82 #define GET_ZF() ((Regs.SR & ZF) != 0)
83 #define GET_IF() ((Regs.SR & IF) != 0)
84 #define GET_DF() ((Regs.SR & DF) != 0)
85 #define GET_BF() ((Regs.SR & BF) != 0)
86 #define GET_OF() ((Regs.SR & OF) != 0)
87 #define GET_SF() ((Regs.SR & SF) != 0)
89 /* Set the flags. The parameter is a boolean flag that says if the flag should be
92 #define SET_CF(f) do { if (f) { Regs.SR |= CF; } else { Regs.SR &= ~CF; } } while (0)
93 #define SET_ZF(f) do { if (f) { Regs.SR |= ZF; } else { Regs.SR &= ~ZF; } } while (0)
94 #define SET_IF(f) do { if (f) { Regs.SR |= IF; } else { Regs.SR &= ~IF; } } while (0)
95 #define SET_DF(f) do { if (f) { Regs.SR |= DF; } else { Regs.SR &= ~DF; } } while (0)
96 #define SET_BF(f) do { if (f) { Regs.SR |= BF; } else { Regs.SR &= ~BF; } } while (0)
97 #define SET_OF(f) do { if (f) { Regs.SR |= OF; } else { Regs.SR &= ~OF; } } while (0)
98 #define SET_SF(f) do { if (f) { Regs.SR |= SF; } else { Regs.SR &= ~SF; } } while (0)
100 /* Special test and set macros. The meaning of the parameter depends on the
101 ** actual flag that should be set or reset.
103 #define TEST_ZF(v) SET_ZF (((v) & 0xFF) == 0)
104 #define TEST_SF(v) SET_SF (((v) & 0x80) != 0)
105 #define TEST_CF(v) SET_CF (((v) & 0xFF00) != 0)
107 /* Program counter halves */
108 #define PCL (Regs.PC & 0xFF)
109 #define PCH ((Regs.PC >> 8) & 0xFF)
111 /* Stack operations */
112 #define PUSH(Val) MemWriteByte (0x0100 + Regs.SP--, Val)
113 #define POP() MemReadByte (0x0100 + ++Regs.SP)
115 /* Test for page cross */
116 #define PAGE_CROSS(addr,offs) ((((addr) & 0xFF) + offs) >= 0x100)
119 #define AC_OP_IMM(op) \
121 Regs.AC = Regs.AC op MemReadByte (Regs.PC+1); \
127 #define AC_OP_ZP(op) \
129 Regs.AC = Regs.AC op MemReadByte (MemReadByte (Regs.PC+1)); \
135 #define AC_OP_ZPX(op) \
136 unsigned char ZPAddr; \
138 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; \
139 Regs.AC = Regs.AC op MemReadByte (ZPAddr); \
145 #define AC_OP_ZPY(op) \
146 unsigned char ZPAddr; \
148 ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR; \
149 Regs.AC = Regs.AC op MemReadByte (ZPAddr); \
155 #define AC_OP_ABS(op) \
158 Addr = MemReadWord (Regs.PC+1); \
159 Regs.AC = Regs.AC op MemReadByte (Addr); \
165 #define AC_OP_ABSX(op) \
168 Addr = MemReadWord (Regs.PC+1); \
169 if (PAGE_CROSS (Addr, Regs.XR)) { \
172 Regs.AC = Regs.AC op MemReadByte (Addr + Regs.XR); \
178 #define AC_OP_ABSY(op) \
181 Addr = MemReadWord (Regs.PC+1); \
182 if (PAGE_CROSS (Addr, Regs.YR)) { \
185 Regs.AC = Regs.AC op MemReadByte (Addr + Regs.YR); \
191 #define AC_OP_ZPXIND(op) \
192 unsigned char ZPAddr; \
195 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; \
196 Addr = MemReadZPWord (ZPAddr); \
197 Regs.AC = Regs.AC op MemReadByte (Addr); \
203 #define AC_OP_ZPINDY(op) \
204 unsigned char ZPAddr; \
207 ZPAddr = MemReadByte (Regs.PC+1); \
208 Addr = MemReadZPWord (ZPAddr) + Regs.YR; \
209 Regs.AC = Regs.AC op MemReadByte (Addr); \
217 unsigned old = Regs.AC; \
218 unsigned rhs = (v & 0xFF); \
222 lo = (old & 0x0F) + (rhs & 0x0F) + GET_CF (); \
224 lo = ((lo + 0x06) & 0x0F) + 0x10; \
226 Regs.AC = (old & 0xF0) + (rhs & 0xF0) + lo; \
227 res = (signed char)(old & 0xF0) + \
228 (signed char)(rhs & 0xF0) + \
230 TEST_ZF (old + rhs + GET_CF ()); \
232 if (Regs.AC >= 0xA0) { \
236 SET_OF ((res < -128) || (res > 127)); \
238 Regs.AC += rhs + GET_CF (); \
242 SET_OF (!((old ^ rhs) & 0x80) && \
243 ((old ^ Regs.AC) & 0x80)); \
249 #define BRANCH(cond) \
253 unsigned char OldPCH; \
255 Offs = (signed char) MemReadByte (Regs.PC+1); \
257 Regs.PC += 2 + (int) Offs; \
258 if (PCH != OldPCH) { \
266 #define CMP(v1, v2) \
268 unsigned Result = v1 - v2; \
269 TEST_ZF (Result & 0xFF); \
271 SET_CF (Result <= 0xFF); \
290 SET_CF (Val & 0x01); \
298 unsigned old = Regs.AC; \
299 unsigned rhs = (v & 0xFF); \
303 lo = (old & 0x0F) - (rhs & 0x0F) + GET_CF () - 1; \
305 lo = ((lo - 0x06) & 0x0F) - 0x10; \
307 Regs.AC = (old & 0xF0) - (rhs & 0xF0) + lo; \
308 if (Regs.AC & 0x80) { \
311 res = Regs.AC - rhs + (!GET_CF ()); \
314 SET_CF (res <= 0xFF); \
315 SET_OF (((old^rhs) & (old^res) & 0x80)); \
317 Regs.AC -= rhs + (!GET_CF ()); \
320 SET_CF (Regs.AC <= 0xFF); \
321 SET_OF (((old^rhs) & (old^Regs.AC) & 0x80)); \
328 /*****************************************************************************/
329 /* Opcode handling functions */
330 /*****************************************************************************/
334 static void OPC_Illegal (void)
336 Error ("Illegal opcode $%02X at address $%04X",
337 MemReadByte (Regs.PC), Regs.PC);
342 static void OPC_6502_00 (void)
343 /* Opcode $00: BRK */
352 Regs.PC = MemReadWord (0xFFFE);
357 static void OPC_6502_01 (void)
358 /* Opcode $01: ORA (ind,x) */
365 static void OPC_6502_05 (void)
366 /* Opcode $05: ORA zp */
373 static void OPC_6502_06 (void)
374 /* Opcode $06: ASL zp */
376 unsigned char ZPAddr;
379 ZPAddr = MemReadByte (Regs.PC+1);
380 Val = MemReadByte (ZPAddr) << 1;
381 MemWriteByte (ZPAddr, (unsigned char) Val);
382 TEST_ZF (Val & 0xFF);
384 SET_CF (Val & 0x100);
390 static void OPC_6502_08 (void)
391 /* Opcode $08: PHP */
394 PUSH (Regs.SR & ~BF);
400 static void OPC_6502_09 (void)
401 /* Opcode $09: ORA #imm */
408 static void OPC_6502_0A (void)
409 /* Opcode $0A: ASL a */
413 TEST_ZF (Regs.AC & 0xFF);
415 SET_CF (Regs.AC & 0x100);
422 static void OPC_6502_0D (void)
423 /* Opcode $0D: ORA abs */
430 static void OPC_6502_0E (void)
431 /* Opcode $0E: ALS abs */
436 Addr = MemReadWord (Regs.PC+1);
437 Val = MemReadByte (Addr) << 1;
438 MemWriteByte (Addr, (unsigned char) Val);
439 TEST_ZF (Val & 0xFF);
441 SET_CF (Val & 0x100);
447 static void OPC_6502_10 (void)
448 /* Opcode $10: BPL */
455 static void OPC_6502_11 (void)
456 /* Opcode $11: ORA (zp),y */
463 static void OPC_6502_15 (void)
464 /* Opcode $15: ORA zp,x */
471 static void OPC_6502_16 (void)
472 /* Opcode $16: ASL zp,x */
474 unsigned char ZPAddr;
477 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
478 Val = MemReadByte (ZPAddr) << 1;
479 MemWriteByte (ZPAddr, (unsigned char) Val);
480 TEST_ZF (Val & 0xFF);
482 SET_CF (Val & 0x100);
488 static void OPC_6502_18 (void)
489 /* Opcode $18: CLC */
498 static void OPC_6502_19 (void)
499 /* Opcode $19: ORA abs,y */
506 static void OPC_6502_1D (void)
507 /* Opcode $1D: ORA abs,x */
514 static void OPC_6502_1E (void)
515 /* Opcode $1E: ASL abs,x */
520 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
521 Val = MemReadByte (Addr) << 1;
522 MemWriteByte (Addr, (unsigned char) Val);
523 TEST_ZF (Val & 0xFF);
525 SET_CF (Val & 0x100);
531 static void OPC_6502_20 (void)
532 /* Opcode $20: JSR */
536 Addr = MemReadWord (Regs.PC+1);
542 ParaVirtHooks (&Regs);
547 static void OPC_6502_21 (void)
548 /* Opcode $21: AND (zp,x) */
555 static void OPC_6502_24 (void)
556 /* Opcode $24: BIT zp */
558 unsigned char ZPAddr;
561 ZPAddr = MemReadByte (Regs.PC+1);
562 Val = MemReadByte (ZPAddr);
565 SET_ZF ((Val & Regs.AC) == 0);
571 static void OPC_6502_25 (void)
572 /* Opcode $25: AND zp */
579 static void OPC_6502_26 (void)
580 /* Opcode $26: ROL zp */
582 unsigned char ZPAddr;
585 ZPAddr = MemReadByte (Regs.PC+1);
586 Val = MemReadByte (ZPAddr);
588 MemWriteByte (ZPAddr, Val);
594 static void OPC_6502_28 (void)
595 /* Opcode $28: PLP */
598 Regs.SR = (POP () & ~BF);
604 static void OPC_6502_29 (void)
605 /* Opcode $29: AND #imm */
612 static void OPC_6502_2A (void)
613 /* Opcode $2A: ROL a */
623 static void OPC_6502_2C (void)
624 /* Opcode $2C: BIT abs */
629 Addr = MemReadByte (Regs.PC+1);
630 Val = MemReadByte (Addr);
633 SET_ZF ((Val & Regs.AC) == 0);
639 static void OPC_6502_2D (void)
640 /* Opcode $2D: AND abs */
647 static void OPC_6502_2E (void)
648 /* Opcode $2E: ROL abs */
653 Addr = MemReadWord (Regs.PC+1);
654 Val = MemReadByte (Addr);
656 MemWriteByte (Addr, Val);
662 static void OPC_6502_30 (void)
663 /* Opcode $30: BMI */
670 static void OPC_6502_31 (void)
671 /* Opcode $31: AND (zp),y */
678 static void OPC_6502_35 (void)
679 /* Opcode $35: AND zp,x */
686 static void OPC_6502_36 (void)
687 /* Opcode $36: ROL zp,x */
689 unsigned char ZPAddr;
692 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
693 Val = MemReadByte (ZPAddr);
695 MemWriteByte (ZPAddr, Val);
701 static void OPC_6502_38 (void)
702 /* Opcode $38: SEC */
711 static void OPC_6502_39 (void)
712 /* Opcode $39: AND abs,y */
719 static void OPC_6502_3D (void)
720 /* Opcode $3D: AND abs,x */
727 static void OPC_6502_3E (void)
728 /* Opcode $3E: ROL abs,x */
733 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
734 Val = MemReadByte (Addr);
736 MemWriteByte (Addr, Val);
742 static void OPC_6502_40 (void)
743 /* Opcode $40: RTI */
747 Regs.PC = POP (); /* PCL */
748 Regs.PC |= (POP () << 8); /* PCH */
753 static void OPC_6502_41 (void)
754 /* Opcode $41: EOR (zp,x) */
761 static void OPC_6502_45 (void)
762 /* Opcode $45: EOR zp */
769 static void OPC_6502_46 (void)
770 /* Opcode $46: LSR zp */
772 unsigned char ZPAddr;
775 ZPAddr = MemReadByte (Regs.PC+1);
776 Val = MemReadByte (ZPAddr);
779 MemWriteByte (ZPAddr, Val);
787 static void OPC_6502_48 (void)
788 /* Opcode $48: PHA */
797 static void OPC_6502_49 (void)
798 /* Opcode $49: EOR #imm */
805 static void OPC_6502_4A (void)
806 /* Opcode $4A: LSR a */
809 SET_CF (Regs.AC & 0x01);
818 static void OPC_6502_4C (void)
819 /* Opcode $4C: JMP abs */
822 Regs.PC = MemReadWord (Regs.PC+1);
824 ParaVirtHooks (&Regs);
829 static void OPC_6502_4D (void)
830 /* Opcode $4D: EOR abs */
837 static void OPC_6502_4E (void)
838 /* Opcode $4E: LSR abs */
843 Addr = MemReadWord (Regs.PC+1);
844 Val = MemReadByte (Addr);
847 MemWriteByte (Addr, Val);
855 static void OPC_6502_50 (void)
856 /* Opcode $50: BVC */
863 static void OPC_6502_51 (void)
864 /* Opcode $51: EOR (zp),y */
871 static void OPC_6502_55 (void)
872 /* Opcode $55: EOR zp,x */
879 static void OPC_6502_56 (void)
880 /* Opcode $56: LSR zp,x */
882 unsigned char ZPAddr;
885 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
886 Val = MemReadByte (ZPAddr);
889 MemWriteByte (ZPAddr, Val);
897 static void OPC_6502_58 (void)
898 /* Opcode $58: CLI */
907 static void OPC_6502_59 (void)
908 /* Opcode $59: EOR abs,y */
915 static void OPC_6502_5D (void)
916 /* Opcode $5D: EOR abs,x */
923 static void OPC_6502_5E (void)
924 /* Opcode $5E: LSR abs,x */
929 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
930 Val = MemReadByte (Addr);
933 MemWriteByte (Addr, Val);
941 static void OPC_6502_60 (void)
942 /* Opcode $60: RTS */
945 Regs.PC = POP (); /* PCL */
946 Regs.PC |= (POP () << 8); /* PCH */
952 static void OPC_6502_61 (void)
953 /* Opcode $61: ADC (zp,x) */
955 unsigned char ZPAddr;
958 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
959 Addr = MemReadZPWord (ZPAddr);
960 ADC (MemReadByte (Addr));
966 static void OPC_6502_65 (void)
967 /* Opcode $65: ADC zp */
969 unsigned char ZPAddr;
971 ZPAddr = MemReadByte (Regs.PC+1);
972 ADC (MemReadByte (ZPAddr));
978 static void OPC_6502_66 (void)
979 /* Opcode $66: ROR zp */
981 unsigned char ZPAddr;
984 ZPAddr = MemReadByte (Regs.PC+1);
985 Val = MemReadByte (ZPAddr);
987 MemWriteByte (ZPAddr, Val);
993 static void OPC_6502_68 (void)
994 /* Opcode $68: PLA */
1005 static void OPC_6502_69 (void)
1006 /* Opcode $69: ADC #imm */
1009 ADC (MemReadByte (Regs.PC+1));
1015 static void OPC_6502_6A (void)
1016 /* Opcode $6A: ROR a */
1025 static void OPC_6502_6C (void)
1026 /* Opcode $6C: JMP (ind) */
1028 unsigned PC, Lo, Hi;
1031 Lo = MemReadWord (PC+1);
1033 /* Emulate the 6502 bug */
1034 Regs.PC = MemReadByte (Lo);
1035 Hi = (Lo & 0xFF00) | ((Lo + 1) & 0xFF);
1036 Regs.PC |= (MemReadByte (Hi) << 8);
1038 /* Output a warning if the bug is triggered */
1040 Warning ("6502 indirect jump bug triggered at $%04X, ind addr = $%04X",
1047 static void OPC_65C02_6C (void)
1048 /* Opcode $6C: JMP (ind) */
1050 /* 6502 bug fixed here */
1052 Regs.PC = MemReadWord (MemReadWord (Regs.PC+1));
1057 static void OPC_6502_6D (void)
1058 /* Opcode $6D: ADC abs */
1062 Addr = MemReadWord (Regs.PC+1);
1063 ADC (MemReadByte (Addr));
1069 static void OPC_6502_6E (void)
1070 /* Opcode $6E: ROR abs */
1075 Addr = MemReadWord (Regs.PC+1);
1076 Val = MemReadByte (Addr);
1078 MemWriteByte (Addr, Val);
1084 static void OPC_6502_70 (void)
1085 /* Opcode $70: BVS */
1092 static void OPC_6502_71 (void)
1093 /* Opcode $71: ADC (zp),y */
1095 unsigned char ZPAddr;
1098 ZPAddr = MemReadByte (Regs.PC+1);
1099 Addr = MemReadZPWord (ZPAddr);
1100 if (PAGE_CROSS (Addr, Regs.YR)) {
1103 ADC (MemReadByte (Addr + Regs.YR));
1109 static void OPC_6502_75 (void)
1110 /* Opcode $75: ADC zp,x */
1112 unsigned char ZPAddr;
1114 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1115 ADC (MemReadByte (ZPAddr));
1121 static void OPC_6502_76 (void)
1122 /* Opcode $76: ROR zp,x */
1124 unsigned char ZPAddr;
1127 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1128 Val = MemReadByte (ZPAddr);
1130 MemWriteByte (ZPAddr, Val);
1136 static void OPC_6502_78 (void)
1137 /* Opcode $78: SEI */
1146 static void OPC_6502_79 (void)
1147 /* Opcode $79: ADC abs,y */
1151 Addr = MemReadWord (Regs.PC+1);
1152 if (PAGE_CROSS (Addr, Regs.YR)) {
1155 ADC (MemReadByte (Addr + Regs.YR));
1161 static void OPC_6502_7D (void)
1162 /* Opcode $7D: ADC abs,x */
1166 Addr = MemReadWord (Regs.PC+1);
1167 if (PAGE_CROSS (Addr, Regs.XR)) {
1170 ADC (MemReadByte (Addr + Regs.XR));
1176 static void OPC_6502_7E (void)
1177 /* Opcode $7E: ROR abs,x */
1182 Addr = MemReadByte (Regs.PC+1) + Regs.XR;
1183 Val = MemReadByte (Addr);
1185 MemWriteByte (Addr, Val);
1191 static void OPC_6502_81 (void)
1192 /* Opcode $81: STA (zp,x) */
1194 unsigned char ZPAddr;
1197 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1198 Addr = MemReadZPWord (ZPAddr);
1199 MemWriteByte (Addr, Regs.AC);
1205 static void OPC_6502_84 (void)
1206 /* Opcode $84: STY zp */
1208 unsigned char ZPAddr;
1210 ZPAddr = MemReadByte (Regs.PC+1);
1211 MemWriteByte (ZPAddr, Regs.YR);
1217 static void OPC_6502_85 (void)
1218 /* Opcode $85: STA zp */
1220 unsigned char ZPAddr;
1222 ZPAddr = MemReadByte (Regs.PC+1);
1223 MemWriteByte (ZPAddr, Regs.AC);
1229 static void OPC_6502_86 (void)
1230 /* Opcode $86: STX zp */
1232 unsigned char ZPAddr;
1234 ZPAddr = MemReadByte (Regs.PC+1);
1235 MemWriteByte (ZPAddr, Regs.XR);
1241 static void OPC_6502_88 (void)
1242 /* Opcode $88: DEY */
1245 Regs.YR = (Regs.YR - 1) & 0xFF;
1253 static void OPC_6502_8A (void)
1254 /* Opcode $8A: TXA */
1265 static void OPC_6502_8C (void)
1266 /* Opcode $8C: STY abs */
1270 Addr = MemReadWord (Regs.PC+1);
1271 MemWriteByte (Addr, Regs.YR);
1277 static void OPC_6502_8D (void)
1278 /* Opcode $8D: STA abs */
1282 Addr = MemReadWord (Regs.PC+1);
1283 MemWriteByte (Addr, Regs.AC);
1289 static void OPC_6502_8E (void)
1290 /* Opcode $8E: STX abs */
1294 Addr = MemReadWord (Regs.PC+1);
1295 MemWriteByte (Addr, Regs.XR);
1301 static void OPC_6502_90 (void)
1302 /* Opcode $90: BCC */
1304 BRANCH (!GET_CF ());
1309 static void OPC_6502_91 (void)
1310 /* Opcode $91: sta (zp),y */
1312 unsigned char ZPAddr;
1315 ZPAddr = MemReadByte (Regs.PC+1);
1316 Addr = MemReadZPWord (ZPAddr) + Regs.YR;
1317 MemWriteByte (Addr, Regs.AC);
1323 static void OPC_6502_94 (void)
1324 /* Opcode $94: STY zp,x */
1326 unsigned char ZPAddr;
1328 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1329 MemWriteByte (ZPAddr, Regs.YR);
1335 static void OPC_6502_95 (void)
1336 /* Opcode $95: STA zp,x */
1338 unsigned char ZPAddr;
1340 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1341 MemWriteByte (ZPAddr, Regs.AC);
1347 static void OPC_6502_96 (void)
1348 /* Opcode $96: stx zp,y */
1350 unsigned char ZPAddr;
1352 ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR;
1353 MemWriteByte (ZPAddr, Regs.XR);
1359 static void OPC_6502_98 (void)
1360 /* Opcode $98: TYA */
1371 static void OPC_6502_99 (void)
1372 /* Opcode $99: STA abs,y */
1376 Addr = MemReadWord (Regs.PC+1) + Regs.YR;
1377 MemWriteByte (Addr, Regs.AC);
1383 static void OPC_6502_9A (void)
1384 /* Opcode $9A: TXS */
1393 static void OPC_6502_9D (void)
1394 /* Opcode $9D: STA abs,x */
1398 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
1399 MemWriteByte (Addr, Regs.AC);
1405 static void OPC_6502_A0 (void)
1406 /* Opcode $A0: LDY #imm */
1409 Regs.YR = MemReadByte (Regs.PC+1);
1417 static void OPC_6502_A1 (void)
1418 /* Opcode $A1: LDA (zp,x) */
1420 unsigned char ZPAddr;
1423 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1424 Addr = MemReadZPWord (ZPAddr);
1425 Regs.AC = MemReadByte (Addr);
1433 static void OPC_6502_A2 (void)
1434 /* Opcode $A2: LDX #imm */
1437 Regs.XR = MemReadByte (Regs.PC+1);
1445 static void OPC_6502_A4 (void)
1446 /* Opcode $A4: LDY zp */
1448 unsigned char ZPAddr;
1450 ZPAddr = MemReadByte (Regs.PC+1);
1451 Regs.YR = MemReadByte (ZPAddr);
1459 static void OPC_6502_A5 (void)
1460 /* Opcode $A5: LDA zp */
1462 unsigned char ZPAddr;
1464 ZPAddr = MemReadByte (Regs.PC+1);
1465 Regs.AC = MemReadByte (ZPAddr);
1473 static void OPC_6502_A6 (void)
1474 /* Opcode $A6: LDX zp */
1476 unsigned char ZPAddr;
1478 ZPAddr = MemReadByte (Regs.PC+1);
1479 Regs.XR = MemReadByte (ZPAddr);
1487 static void OPC_6502_A8 (void)
1488 /* Opcode $A8: TAY */
1499 static void OPC_6502_A9 (void)
1500 /* Opcode $A9: LDA #imm */
1503 Regs.AC = MemReadByte (Regs.PC+1);
1511 static void OPC_6502_AA (void)
1512 /* Opcode $AA: TAX */
1523 static void OPC_6502_AC (void)
1524 /* Opcode $Regs.AC: LDY abs */
1528 Addr = MemReadWord (Regs.PC+1);
1529 Regs.YR = MemReadByte (Addr);
1537 static void OPC_6502_AD (void)
1538 /* Opcode $AD: LDA abs */
1542 Addr = MemReadWord (Regs.PC+1);
1543 Regs.AC = MemReadByte (Addr);
1551 static void OPC_6502_AE (void)
1552 /* Opcode $AE: LDX abs */
1556 Addr = MemReadWord (Regs.PC+1);
1557 Regs.XR = MemReadByte (Addr);
1565 static void OPC_6502_B0 (void)
1566 /* Opcode $B0: BCS */
1573 static void OPC_6502_B1 (void)
1574 /* Opcode $B1: LDA (zp),y */
1576 unsigned char ZPAddr;
1579 ZPAddr = MemReadByte (Regs.PC+1);
1580 Addr = MemReadZPWord (ZPAddr);
1581 if (PAGE_CROSS (Addr, Regs.YR)) {
1584 Regs.AC = MemReadByte (Addr + Regs.YR);
1592 static void OPC_6502_B4 (void)
1593 /* Opcode $B4: LDY zp,x */
1595 unsigned char ZPAddr;
1597 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1598 Regs.YR = MemReadByte (ZPAddr);
1606 static void OPC_6502_B5 (void)
1607 /* Opcode $B5: LDA zp,x */
1609 unsigned char ZPAddr;
1611 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1612 Regs.AC = MemReadByte (ZPAddr);
1620 static void OPC_6502_B6 (void)
1621 /* Opcode $B6: LDX zp,y */
1623 unsigned char ZPAddr;
1625 ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR;
1626 Regs.XR = MemReadByte (ZPAddr);
1634 static void OPC_6502_B8 (void)
1635 /* Opcode $B8: CLV */
1644 static void OPC_6502_B9 (void)
1645 /* Opcode $B9: LDA abs,y */
1649 Addr = MemReadWord (Regs.PC+1);
1650 if (PAGE_CROSS (Addr, Regs.YR)) {
1653 Regs.AC = MemReadByte (Addr + Regs.YR);
1661 static void OPC_6502_BA (void)
1662 /* Opcode $BA: TSX */
1673 static void OPC_6502_BC (void)
1674 /* Opcode $BC: LDY abs,x */
1678 Addr = MemReadWord (Regs.PC+1);
1679 if (PAGE_CROSS (Addr, Regs.XR)) {
1682 Regs.YR = MemReadByte (Addr + Regs.XR);
1690 static void OPC_6502_BD (void)
1691 /* Opcode $BD: LDA abs,x */
1695 Addr = MemReadWord (Regs.PC+1);
1696 if (PAGE_CROSS (Addr, Regs.XR)) {
1699 Regs.AC = MemReadByte (Addr + Regs.XR);
1707 static void OPC_6502_BE (void)
1708 /* Opcode $BE: LDX abs,y */
1712 Addr = MemReadWord (Regs.PC+1);
1713 if (PAGE_CROSS (Addr, Regs.YR)) {
1716 Regs.XR = MemReadByte (Addr + Regs.YR);
1724 static void OPC_6502_C0 (void)
1725 /* Opcode $C0: CPY #imm */
1728 CMP (Regs.YR, MemReadByte (Regs.PC+1));
1734 static void OPC_6502_C1 (void)
1735 /* Opcode $C1: CMP (zp,x) */
1737 unsigned char ZPAddr;
1740 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1741 Addr = MemReadZPWord (ZPAddr);
1742 CMP (Regs.AC, MemReadByte (Addr));
1748 static void OPC_6502_C4 (void)
1749 /* Opcode $C4: CPY zp */
1751 unsigned char ZPAddr;
1753 ZPAddr = MemReadByte (Regs.PC+1);
1754 CMP (Regs.YR, MemReadByte (ZPAddr));
1760 static void OPC_6502_C5 (void)
1761 /* Opcode $C5: CMP zp */
1763 unsigned char ZPAddr;
1765 ZPAddr = MemReadByte (Regs.PC+1);
1766 CMP (Regs.AC, MemReadByte (ZPAddr));
1772 static void OPC_6502_C6 (void)
1773 /* Opcode $C6: DEC zp */
1775 unsigned char ZPAddr;
1778 ZPAddr = MemReadByte (Regs.PC+1);
1779 Val = MemReadByte (ZPAddr) - 1;
1780 MemWriteByte (ZPAddr, Val);
1788 static void OPC_6502_C8 (void)
1789 /* Opcode $C8: INY */
1792 Regs.YR = (Regs.YR + 1) & 0xFF;
1800 static void OPC_6502_C9 (void)
1801 /* Opcode $C9: CMP #imm */
1804 CMP (Regs.AC, MemReadByte (Regs.PC+1));
1810 static void OPC_6502_CA (void)
1811 /* Opcode $CA: DEX */
1814 Regs.XR = (Regs.XR - 1) & 0xFF;
1822 static void OPC_6502_CC (void)
1823 /* Opcode $CC: CPY abs */
1827 Addr = MemReadWord (Regs.PC+1);
1828 CMP (Regs.YR, MemReadByte (Addr));
1834 static void OPC_6502_CD (void)
1835 /* Opcode $CD: CMP abs */
1839 Addr = MemReadWord (Regs.PC+1);
1840 CMP (Regs.AC, MemReadByte (Addr));
1846 static void OPC_6502_CE (void)
1847 /* Opcode $CE: DEC abs */
1852 Addr = MemReadWord (Regs.PC+1);
1853 Val = MemReadByte (Addr) - 1;
1854 MemWriteByte (Addr, Val);
1862 static void OPC_6502_D0 (void)
1863 /* Opcode $D0: BNE */
1865 BRANCH (!GET_ZF ());
1870 static void OPC_6502_D1 (void)
1871 /* Opcode $D1: CMP (zp),y */
1876 ZPAddr = MemReadByte (Regs.PC+1);
1877 Addr = MemReadWord (ZPAddr);
1878 if (PAGE_CROSS (Addr, Regs.YR)) {
1881 CMP (Regs.AC, MemReadByte (Addr + Regs.YR));
1887 static void OPC_6502_D5 (void)
1888 /* Opcode $D5: CMP zp,x */
1890 unsigned char ZPAddr;
1892 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1893 CMP (Regs.AC, MemReadByte (ZPAddr));
1899 static void OPC_6502_D6 (void)
1900 /* Opcode $D6: DEC zp,x */
1902 unsigned char ZPAddr;
1905 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1906 Val = MemReadByte (ZPAddr) - 1;
1907 MemWriteByte (ZPAddr, Val);
1915 static void OPC_6502_D8 (void)
1916 /* Opcode $D8: CLD */
1925 static void OPC_6502_D9 (void)
1926 /* Opcode $D9: CMP abs,y */
1930 Addr = MemReadWord (Regs.PC+1);
1931 if (PAGE_CROSS (Addr, Regs.YR)) {
1934 CMP (Regs.AC, MemReadByte (Addr + Regs.YR));
1940 static void OPC_6502_DD (void)
1941 /* Opcode $DD: CMP abs,x */
1945 Addr = MemReadWord (Regs.PC+1);
1946 if (PAGE_CROSS (Addr, Regs.XR)) {
1949 CMP (Regs.AC, MemReadByte (Addr + Regs.XR));
1955 static void OPC_6502_DE (void)
1956 /* Opcode $DE: DEC abs,x */
1961 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
1962 Val = MemReadByte (Addr) - 1;
1963 MemWriteByte (Addr, Val);
1971 static void OPC_6502_E0 (void)
1972 /* Opcode $E0: CPX #imm */
1975 CMP (Regs.XR, MemReadByte (Regs.PC+1));
1981 static void OPC_6502_E1 (void)
1982 /* Opcode $E1: SBC (zp,x) */
1984 unsigned char ZPAddr;
1987 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1988 Addr = MemReadZPWord (ZPAddr);
1989 SBC (MemReadByte (Addr));
1995 static void OPC_6502_E4 (void)
1996 /* Opcode $E4: CPX zp */
1998 unsigned char ZPAddr;
2000 ZPAddr = MemReadByte (Regs.PC+1);
2001 CMP (Regs.XR, MemReadByte (ZPAddr));
2007 static void OPC_6502_E5 (void)
2008 /* Opcode $E5: SBC zp */
2010 unsigned char ZPAddr;
2012 ZPAddr = MemReadByte (Regs.PC+1);
2013 SBC (MemReadByte (ZPAddr));
2019 static void OPC_6502_E6 (void)
2020 /* Opcode $E6: INC zp */
2022 unsigned char ZPAddr;
2025 ZPAddr = MemReadByte (Regs.PC+1);
2026 Val = MemReadByte (ZPAddr) + 1;
2027 MemWriteByte (ZPAddr, Val);
2035 static void OPC_6502_E8 (void)
2036 /* Opcode $E8: INX */
2039 Regs.XR = (Regs.XR + 1) & 0xFF;
2047 static void OPC_6502_E9 (void)
2048 /* Opcode $E9: SBC #imm */
2051 SBC (MemReadByte (Regs.PC+1));
2057 static void OPC_6502_EA (void)
2058 /* Opcode $EA: NOP */
2060 /* This one is easy... */
2067 static void OPC_6502_EC (void)
2068 /* Opcode $EC: CPX abs */
2072 Addr = MemReadWord (Regs.PC+1);
2073 CMP (Regs.XR, MemReadByte (Addr));
2079 static void OPC_6502_ED (void)
2080 /* Opcode $ED: SBC abs */
2084 Addr = MemReadWord (Regs.PC+1);
2085 SBC (MemReadByte (Addr));
2091 static void OPC_6502_EE (void)
2092 /* Opcode $EE: INC abs */
2097 Addr = MemReadWord (Regs.PC+1);
2098 Val = MemReadByte (Addr) + 1;
2099 MemWriteByte (Addr, Val);
2107 static void OPC_6502_F0 (void)
2108 /* Opcode $F0: BEQ */
2115 static void OPC_6502_F1 (void)
2116 /* Opcode $F1: SBC (zp),y */
2118 unsigned char ZPAddr;
2121 ZPAddr = MemReadByte (Regs.PC+1);
2122 Addr = MemReadZPWord (ZPAddr);
2123 if (PAGE_CROSS (Addr, Regs.YR)) {
2126 SBC (MemReadByte (Addr + Regs.YR));
2132 static void OPC_6502_F5 (void)
2133 /* Opcode $F5: SBC zp,x */
2135 unsigned char ZPAddr;
2137 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
2138 SBC (MemReadByte (ZPAddr));
2144 static void OPC_6502_F6 (void)
2145 /* Opcode $F6: INC zp,x */
2147 unsigned char ZPAddr;
2150 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
2151 Val = MemReadByte (ZPAddr) + 1;
2152 MemWriteByte (ZPAddr, Val);
2160 static void OPC_6502_F8 (void)
2161 /* Opcode $F8: SED */
2168 static void OPC_6502_F9 (void)
2169 /* Opcode $F9: SBC abs,y */
2173 Addr = MemReadWord (Regs.PC+1);
2174 if (PAGE_CROSS (Addr, Regs.YR)) {
2177 SBC (MemReadByte (Addr + Regs.YR));
2183 static void OPC_6502_FD (void)
2184 /* Opcode $FD: SBC abs,x */
2188 Addr = MemReadWord (Regs.PC+1);
2189 if (PAGE_CROSS (Addr, Regs.XR)) {
2192 SBC (MemReadByte (Addr + Regs.XR));
2198 static void OPC_6502_FE (void)
2199 /* Opcode $FE: INC abs,x */
2204 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
2205 Val = MemReadByte (Addr) + 1;
2206 MemWriteByte (Addr, Val);
2214 /*****************************************************************************/
2215 /* Opcode handler tables */
2216 /*****************************************************************************/
2220 /* Opcode handler table for the 6502 */
2221 static const OPFunc OP6502Table[256] = {
2482 /* Opcode handler table for the 65C02 */
2483 static const OPFunc OP65C02Table[256] = {
2744 /* Tables with opcode handlers */
2745 static const OPFunc* Handlers[2] = {OP6502Table, OP65C02Table};
2749 /*****************************************************************************/
2751 /*****************************************************************************/
2755 void IRQRequest (void)
2756 /* Generate an IRQ */
2758 /* Remember the request */
2764 void NMIRequest (void)
2765 /* Generate an NMI */
2767 /* Remember the request */
2774 /* Generate a CPU RESET */
2780 Regs.PC = MemReadWord (0xFFFC);
2785 unsigned ExecuteInsn (void)
2786 /* Execute one CPU instruction */
2788 /* If we have an NMI request, handle it */
2789 if (HaveNMIRequest) {
2796 Regs.PC = MemReadWord (0xFFFA);
2799 } else if (HaveIRQRequest && GET_IF () == 0) {
2806 Regs.PC = MemReadWord (0xFFFE);
2811 /* Normal instruction - read the next opcode */
2812 unsigned char OPC = MemReadByte (Regs.PC);
2815 Handlers[CPU][OPC] ();
2819 TotalCycles += Cycles;
2821 /* Return the number of clock cycles needed by this insn */
2827 unsigned long GetCycles (void)
2828 /* Return the total number of cycles executed */
2830 /* Return the total number of cycles */