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;
72 /*****************************************************************************/
73 /* Helper functions and macros */
74 /*****************************************************************************/
78 /* Return the flags as a boolean value (0/1) */
79 #define GET_CF() ((Regs.SR & CF) != 0)
80 #define GET_ZF() ((Regs.SR & ZF) != 0)
81 #define GET_IF() ((Regs.SR & IF) != 0)
82 #define GET_DF() ((Regs.SR & DF) != 0)
83 #define GET_BF() ((Regs.SR & BF) != 0)
84 #define GET_OF() ((Regs.SR & OF) != 0)
85 #define GET_SF() ((Regs.SR & SF) != 0)
87 /* Set the flags. The parameter is a boolean flag that says if the flag should be
90 #define SET_CF(f) do { if (f) { Regs.SR |= CF; } else { Regs.SR &= ~CF; } } while (0)
91 #define SET_ZF(f) do { if (f) { Regs.SR |= ZF; } else { Regs.SR &= ~ZF; } } while (0)
92 #define SET_IF(f) do { if (f) { Regs.SR |= IF; } else { Regs.SR &= ~IF; } } while (0)
93 #define SET_DF(f) do { if (f) { Regs.SR |= DF; } else { Regs.SR &= ~DF; } } while (0)
94 #define SET_BF(f) do { if (f) { Regs.SR |= BF; } else { Regs.SR &= ~BF; } } while (0)
95 #define SET_OF(f) do { if (f) { Regs.SR |= OF; } else { Regs.SR &= ~OF; } } while (0)
96 #define SET_SF(f) do { if (f) { Regs.SR |= SF; } else { Regs.SR &= ~SF; } } while (0)
98 /* Special test and set macros. The meaning of the parameter depends on the
99 ** actual flag that should be set or reset.
101 #define TEST_ZF(v) SET_ZF (((v) & 0xFF) == 0)
102 #define TEST_SF(v) SET_SF (((v) & 0x80) != 0)
103 #define TEST_CF(v) SET_CF (((v) & 0xFF00) != 0)
105 /* Program counter halves */
106 #define PCL (Regs.PC & 0xFF)
107 #define PCH ((Regs.PC >> 8) & 0xFF)
109 /* Stack operations */
110 #define PUSH(Val) MemWriteByte (0x0100 + Regs.SP--, Val)
111 #define POP() MemReadByte (0x0100 + ++Regs.SP)
113 /* Test for page cross */
114 #define PAGE_CROSS(addr,offs) ((((addr) & 0xFF) + offs) >= 0x100)
117 #define AC_OP_IMM(op) \
119 Regs.AC = Regs.AC op MemReadByte (Regs.PC+1); \
125 #define AC_OP_ZP(op) \
127 Regs.AC = Regs.AC op MemReadByte (MemReadByte (Regs.PC+1)); \
133 #define AC_OP_ZPX(op) \
134 unsigned char ZPAddr; \
136 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; \
137 Regs.AC = Regs.AC op MemReadByte (ZPAddr); \
143 #define AC_OP_ZPY(op) \
144 unsigned char ZPAddr; \
146 ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR; \
147 Regs.AC = Regs.AC op MemReadByte (ZPAddr); \
153 #define AC_OP_ABS(op) \
156 Addr = MemReadWord (Regs.PC+1); \
157 Regs.AC = Regs.AC op MemReadByte (Addr); \
163 #define AC_OP_ABSX(op) \
166 Addr = MemReadWord (Regs.PC+1); \
167 if (PAGE_CROSS (Addr, Regs.XR)) { \
170 Regs.AC = Regs.AC op MemReadByte (Addr + Regs.XR); \
176 #define AC_OP_ABSY(op) \
179 Addr = MemReadWord (Regs.PC+1); \
180 if (PAGE_CROSS (Addr, Regs.YR)) { \
183 Regs.AC = Regs.AC op MemReadByte (Addr + Regs.YR); \
189 #define AC_OP_ZPXIND(op) \
190 unsigned char ZPAddr; \
193 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; \
194 Addr = MemReadZPWord (ZPAddr); \
195 Regs.AC = Regs.AC op MemReadByte (Addr); \
201 #define AC_OP_ZPINDY(op) \
202 unsigned char ZPAddr; \
205 ZPAddr = MemReadByte (Regs.PC+1); \
206 Addr = MemReadZPWord (ZPAddr) + Regs.YR; \
207 Regs.AC = Regs.AC op MemReadByte (Addr); \
215 unsigned old = Regs.AC; \
216 unsigned rhs = (v & 0xFF); \
220 lo = (old & 0x0F) + (rhs & 0x0F) + GET_CF (); \
222 lo = ((lo + 0x06) & 0x0F) + 0x10; \
224 Regs.AC = (old & 0xF0) + (rhs & 0xF0) + lo; \
225 res = (signed char)(old & 0xF0) + \
226 (signed char)(rhs & 0xF0) + \
228 TEST_ZF (old + rhs + GET_CF ()); \
230 if (Regs.AC >= 0xA0) { \
234 SET_OF ((res < -128) || (res > 127)); \
236 Regs.AC += rhs + GET_CF (); \
240 SET_OF (!((old ^ rhs) & 0x80) && \
241 ((old ^ Regs.AC) & 0x80)); \
247 #define BRANCH(cond) \
251 unsigned char OldPCH; \
253 Offs = (signed char) MemReadByte (Regs.PC+1); \
255 Regs.PC += 2 + (int) Offs; \
256 if (PCH != OldPCH) { \
264 #define CMP(v1, v2) \
266 unsigned Result = v1 - v2; \
267 TEST_ZF (Result & 0xFF); \
269 SET_CF (Result <= 0xFF); \
288 SET_CF (Val & 0x01); \
296 unsigned old = Regs.AC; \
297 unsigned rhs = (v & 0xFF); \
301 lo = (old & 0x0F) - (rhs & 0x0F) + GET_CF () - 1; \
303 lo = ((lo - 0x06) & 0x0F) - 0x10; \
305 Regs.AC = (old & 0xF0) - (rhs & 0xF0) + lo; \
306 if (Regs.AC & 0x80) { \
309 res = Regs.AC - rhs + (!GET_CF ()); \
312 SET_CF (res <= 0xFF); \
313 SET_OF (((old^rhs) & (old^res) & 0x80)); \
315 Regs.AC -= rhs + (!GET_CF ()); \
318 SET_CF (Regs.AC <= 0xFF); \
319 SET_OF (((old^rhs) & (old^Regs.AC) & 0x80)); \
326 /*****************************************************************************/
327 /* Opcode handling functions */
328 /*****************************************************************************/
332 static void OPC_Illegal (void)
334 Error ("Illegal opcode $%02X at address $%04X",
335 MemReadByte (Regs.PC), Regs.PC);
340 static void OPC_6502_00 (void)
341 /* Opcode $00: BRK */
350 Regs.PC = MemReadWord (0xFFFE);
355 static void OPC_6502_01 (void)
356 /* Opcode $01: ORA (ind,x) */
363 static void OPC_6502_05 (void)
364 /* Opcode $05: ORA zp */
371 static void OPC_6502_06 (void)
372 /* Opcode $06: ASL zp */
374 unsigned char ZPAddr;
377 ZPAddr = MemReadByte (Regs.PC+1);
378 Val = MemReadByte (ZPAddr) << 1;
379 MemWriteByte (ZPAddr, (unsigned char) Val);
380 TEST_ZF (Val & 0xFF);
382 SET_CF (Val & 0x100);
388 static void OPC_6502_08 (void)
389 /* Opcode $08: PHP */
392 PUSH (Regs.SR & ~BF);
398 static void OPC_6502_09 (void)
399 /* Opcode $09: ORA #imm */
406 static void OPC_6502_0A (void)
407 /* Opcode $0A: ASL a */
411 TEST_ZF (Regs.AC & 0xFF);
413 SET_CF (Regs.AC & 0x100);
420 static void OPC_6502_0D (void)
421 /* Opcode $0D: ORA abs */
428 static void OPC_6502_0E (void)
429 /* Opcode $0E: ALS abs */
434 Addr = MemReadWord (Regs.PC+1);
435 Val = MemReadByte (Addr) << 1;
436 MemWriteByte (Addr, (unsigned char) Val);
437 TEST_ZF (Val & 0xFF);
439 SET_CF (Val & 0x100);
445 static void OPC_6502_10 (void)
446 /* Opcode $10: BPL */
453 static void OPC_6502_11 (void)
454 /* Opcode $11: ORA (zp),y */
461 static void OPC_6502_15 (void)
462 /* Opcode $15: ORA zp,x */
469 static void OPC_6502_16 (void)
470 /* Opcode $16: ASL zp,x */
472 unsigned char ZPAddr;
475 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
476 Val = MemReadByte (ZPAddr) << 1;
477 MemWriteByte (ZPAddr, (unsigned char) Val);
478 TEST_ZF (Val & 0xFF);
480 SET_CF (Val & 0x100);
486 static void OPC_6502_18 (void)
487 /* Opcode $18: CLC */
496 static void OPC_6502_19 (void)
497 /* Opcode $19: ORA abs,y */
504 static void OPC_6502_1D (void)
505 /* Opcode $1D: ORA abs,x */
512 static void OPC_6502_1E (void)
513 /* Opcode $1E: ASL abs,x */
518 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
519 Val = MemReadByte (Addr) << 1;
520 MemWriteByte (Addr, (unsigned char) Val);
521 TEST_ZF (Val & 0xFF);
523 SET_CF (Val & 0x100);
529 static void OPC_6502_20 (void)
530 /* Opcode $20: JSR */
534 Addr = MemReadWord (Regs.PC+1);
540 ParaVirtHooks (&Regs);
545 static void OPC_6502_21 (void)
546 /* Opcode $21: AND (zp,x) */
553 static void OPC_6502_24 (void)
554 /* Opcode $24: BIT zp */
556 unsigned char ZPAddr;
559 ZPAddr = MemReadByte (Regs.PC+1);
560 Val = MemReadByte (ZPAddr);
563 SET_ZF ((Val & Regs.AC) == 0);
569 static void OPC_6502_25 (void)
570 /* Opcode $25: AND zp */
577 static void OPC_6502_26 (void)
578 /* Opcode $26: ROL zp */
580 unsigned char ZPAddr;
583 ZPAddr = MemReadByte (Regs.PC+1);
584 Val = MemReadByte (ZPAddr);
586 MemWriteByte (ZPAddr, Val);
592 static void OPC_6502_28 (void)
593 /* Opcode $28: PLP */
596 Regs.SR = (POP () & ~BF);
602 static void OPC_6502_29 (void)
603 /* Opcode $29: AND #imm */
610 static void OPC_6502_2A (void)
611 /* Opcode $2A: ROL a */
621 static void OPC_6502_2C (void)
622 /* Opcode $2C: BIT abs */
627 Addr = MemReadByte (Regs.PC+1);
628 Val = MemReadByte (Addr);
631 SET_ZF ((Val & Regs.AC) == 0);
637 static void OPC_6502_2D (void)
638 /* Opcode $2D: AND abs */
645 static void OPC_6502_2E (void)
646 /* Opcode $2E: ROL abs */
651 Addr = MemReadWord (Regs.PC+1);
652 Val = MemReadByte (Addr);
654 MemWriteByte (Addr, Val);
660 static void OPC_6502_30 (void)
661 /* Opcode $30: BMI */
668 static void OPC_6502_31 (void)
669 /* Opcode $31: AND (zp),y */
676 static void OPC_6502_35 (void)
677 /* Opcode $35: AND zp,x */
684 static void OPC_6502_36 (void)
685 /* Opcode $36: ROL zp,x */
687 unsigned char ZPAddr;
690 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
691 Val = MemReadByte (ZPAddr);
693 MemWriteByte (ZPAddr, Val);
699 static void OPC_6502_38 (void)
700 /* Opcode $38: SEC */
709 static void OPC_6502_39 (void)
710 /* Opcode $39: AND abs,y */
717 static void OPC_6502_3D (void)
718 /* Opcode $3D: AND abs,x */
725 static void OPC_6502_3E (void)
726 /* Opcode $3E: ROL abs,x */
731 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
732 Val = MemReadByte (Addr);
734 MemWriteByte (Addr, Val);
740 static void OPC_6502_40 (void)
741 /* Opcode $40: RTI */
745 Regs.PC = POP (); /* PCL */
746 Regs.PC |= (POP () << 8); /* PCH */
751 static void OPC_6502_41 (void)
752 /* Opcode $41: EOR (zp,x) */
759 static void OPC_6502_45 (void)
760 /* Opcode $45: EOR zp */
767 static void OPC_6502_46 (void)
768 /* Opcode $46: LSR zp */
770 unsigned char ZPAddr;
773 ZPAddr = MemReadByte (Regs.PC+1);
774 Val = MemReadByte (ZPAddr);
777 MemWriteByte (ZPAddr, Val);
785 static void OPC_6502_48 (void)
786 /* Opcode $48: PHA */
795 static void OPC_6502_49 (void)
796 /* Opcode $49: EOR #imm */
803 static void OPC_6502_4A (void)
804 /* Opcode $4A: LSR a */
807 SET_CF (Regs.AC & 0x01);
816 static void OPC_6502_4C (void)
817 /* Opcode $4C: JMP abs */
820 Regs.PC = MemReadWord (Regs.PC+1);
822 ParaVirtHooks (&Regs);
827 static void OPC_6502_4D (void)
828 /* Opcode $4D: EOR abs */
835 static void OPC_6502_4E (void)
836 /* Opcode $4E: LSR abs */
841 Addr = MemReadWord (Regs.PC+1);
842 Val = MemReadByte (Addr);
845 MemWriteByte (Addr, Val);
853 static void OPC_6502_50 (void)
854 /* Opcode $50: BVC */
861 static void OPC_6502_51 (void)
862 /* Opcode $51: EOR (zp),y */
869 static void OPC_6502_55 (void)
870 /* Opcode $55: EOR zp,x */
877 static void OPC_6502_56 (void)
878 /* Opcode $56: LSR zp,x */
880 unsigned char ZPAddr;
883 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
884 Val = MemReadByte (ZPAddr);
887 MemWriteByte (ZPAddr, Val);
895 static void OPC_6502_58 (void)
896 /* Opcode $58: CLI */
905 static void OPC_6502_59 (void)
906 /* Opcode $59: EOR abs,y */
913 static void OPC_6502_5D (void)
914 /* Opcode $5D: EOR abs,x */
921 static void OPC_6502_5E (void)
922 /* Opcode $5E: LSR abs,x */
927 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
928 Val = MemReadByte (Addr);
931 MemWriteByte (Addr, Val);
939 static void OPC_6502_60 (void)
940 /* Opcode $60: RTS */
943 Regs.PC = POP (); /* PCL */
944 Regs.PC |= (POP () << 8); /* PCH */
950 static void OPC_6502_61 (void)
951 /* Opcode $61: ADC (zp,x) */
953 unsigned char ZPAddr;
956 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
957 Addr = MemReadZPWord (ZPAddr);
958 ADC (MemReadByte (Addr));
964 static void OPC_6502_65 (void)
965 /* Opcode $65: ADC zp */
967 unsigned char ZPAddr;
969 ZPAddr = MemReadByte (Regs.PC+1);
970 ADC (MemReadByte (ZPAddr));
976 static void OPC_6502_66 (void)
977 /* Opcode $66: ROR zp */
979 unsigned char ZPAddr;
982 ZPAddr = MemReadByte (Regs.PC+1);
983 Val = MemReadByte (ZPAddr);
985 MemWriteByte (ZPAddr, Val);
991 static void OPC_6502_68 (void)
992 /* Opcode $68: PLA */
1003 static void OPC_6502_69 (void)
1004 /* Opcode $69: ADC #imm */
1007 ADC (MemReadByte (Regs.PC+1));
1013 static void OPC_6502_6A (void)
1014 /* Opcode $6A: ROR a */
1023 static void OPC_6502_6C (void)
1024 /* Opcode $6C: JMP (ind) */
1026 unsigned PC, Lo, Hi;
1029 Lo = MemReadWord (PC+1);
1031 /* Emulate the 6502 bug */
1032 Regs.PC = MemReadByte (Lo);
1033 Hi = (Lo & 0xFF00) | ((Lo + 1) & 0xFF);
1034 Regs.PC |= (MemReadByte (Hi) << 8);
1036 /* Output a warning if the bug is triggered */
1038 Warning ("6502 indirect jump bug triggered at $%04X, ind addr = $%04X",
1045 static void OPC_65C02_6C (void)
1046 /* Opcode $6C: JMP (ind) */
1048 /* 6502 bug fixed here */
1050 Regs.PC = MemReadWord (MemReadWord (Regs.PC+1));
1055 static void OPC_6502_6D (void)
1056 /* Opcode $6D: ADC abs */
1060 Addr = MemReadWord (Regs.PC+1);
1061 ADC (MemReadByte (Addr));
1067 static void OPC_6502_6E (void)
1068 /* Opcode $6E: ROR abs */
1073 Addr = MemReadWord (Regs.PC+1);
1074 Val = MemReadByte (Addr);
1076 MemWriteByte (Addr, Val);
1082 static void OPC_6502_70 (void)
1083 /* Opcode $70: BVS */
1090 static void OPC_6502_71 (void)
1091 /* Opcode $71: ADC (zp),y */
1093 unsigned char ZPAddr;
1096 ZPAddr = MemReadByte (Regs.PC+1);
1097 Addr = MemReadZPWord (ZPAddr);
1098 if (PAGE_CROSS (Addr, Regs.YR)) {
1101 ADC (MemReadByte (Addr + Regs.YR));
1107 static void OPC_6502_75 (void)
1108 /* Opcode $75: ADC zp,x */
1110 unsigned char ZPAddr;
1112 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1113 ADC (MemReadByte (ZPAddr));
1119 static void OPC_6502_76 (void)
1120 /* Opcode $76: ROR zp,x */
1122 unsigned char ZPAddr;
1125 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1126 Val = MemReadByte (ZPAddr);
1128 MemWriteByte (ZPAddr, Val);
1134 static void OPC_6502_78 (void)
1135 /* Opcode $78: SEI */
1144 static void OPC_6502_79 (void)
1145 /* Opcode $79: ADC abs,y */
1149 Addr = MemReadWord (Regs.PC+1);
1150 if (PAGE_CROSS (Addr, Regs.YR)) {
1153 ADC (MemReadByte (Addr + Regs.YR));
1159 static void OPC_6502_7D (void)
1160 /* Opcode $7D: ADC abs,x */
1164 Addr = MemReadWord (Regs.PC+1);
1165 if (PAGE_CROSS (Addr, Regs.XR)) {
1168 ADC (MemReadByte (Addr + Regs.XR));
1174 static void OPC_6502_7E (void)
1175 /* Opcode $7E: ROR abs,x */
1180 Addr = MemReadByte (Regs.PC+1) + Regs.XR;
1181 Val = MemReadByte (Addr);
1183 MemWriteByte (Addr, Val);
1189 static void OPC_6502_81 (void)
1190 /* Opcode $81: STA (zp,x) */
1192 unsigned char ZPAddr;
1195 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1196 Addr = MemReadZPWord (ZPAddr);
1197 MemWriteByte (Addr, Regs.AC);
1203 static void OPC_6502_84 (void)
1204 /* Opcode $84: STY zp */
1206 unsigned char ZPAddr;
1208 ZPAddr = MemReadByte (Regs.PC+1);
1209 MemWriteByte (ZPAddr, Regs.YR);
1215 static void OPC_6502_85 (void)
1216 /* Opcode $85: STA zp */
1218 unsigned char ZPAddr;
1220 ZPAddr = MemReadByte (Regs.PC+1);
1221 MemWriteByte (ZPAddr, Regs.AC);
1227 static void OPC_6502_86 (void)
1228 /* Opcode $86: STX zp */
1230 unsigned char ZPAddr;
1232 ZPAddr = MemReadByte (Regs.PC+1);
1233 MemWriteByte (ZPAddr, Regs.XR);
1239 static void OPC_6502_88 (void)
1240 /* Opcode $88: DEY */
1243 Regs.YR = (Regs.YR - 1) & 0xFF;
1251 static void OPC_6502_8A (void)
1252 /* Opcode $8A: TXA */
1263 static void OPC_6502_8C (void)
1264 /* Opcode $8C: STY abs */
1268 Addr = MemReadWord (Regs.PC+1);
1269 MemWriteByte (Addr, Regs.YR);
1275 static void OPC_6502_8D (void)
1276 /* Opcode $8D: STA abs */
1280 Addr = MemReadWord (Regs.PC+1);
1281 MemWriteByte (Addr, Regs.AC);
1287 static void OPC_6502_8E (void)
1288 /* Opcode $8E: STX abs */
1292 Addr = MemReadWord (Regs.PC+1);
1293 MemWriteByte (Addr, Regs.XR);
1299 static void OPC_6502_90 (void)
1300 /* Opcode $90: BCC */
1302 BRANCH (!GET_CF ());
1307 static void OPC_6502_91 (void)
1308 /* Opcode $91: sta (zp),y */
1310 unsigned char ZPAddr;
1313 ZPAddr = MemReadByte (Regs.PC+1);
1314 Addr = MemReadZPWord (ZPAddr) + Regs.YR;
1315 MemWriteByte (Addr, Regs.AC);
1321 static void OPC_6502_94 (void)
1322 /* Opcode $94: STY zp,x */
1324 unsigned char ZPAddr;
1326 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1327 MemWriteByte (ZPAddr, Regs.YR);
1333 static void OPC_6502_95 (void)
1334 /* Opcode $95: STA zp,x */
1336 unsigned char ZPAddr;
1338 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1339 MemWriteByte (ZPAddr, Regs.AC);
1345 static void OPC_6502_96 (void)
1346 /* Opcode $96: stx zp,y */
1348 unsigned char ZPAddr;
1350 ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR;
1351 MemWriteByte (ZPAddr, Regs.XR);
1357 static void OPC_6502_98 (void)
1358 /* Opcode $98: TYA */
1369 static void OPC_6502_99 (void)
1370 /* Opcode $99: STA abs,y */
1374 Addr = MemReadWord (Regs.PC+1) + Regs.YR;
1375 MemWriteByte (Addr, Regs.AC);
1381 static void OPC_6502_9A (void)
1382 /* Opcode $9A: TXS */
1391 static void OPC_6502_9D (void)
1392 /* Opcode $9D: STA abs,x */
1396 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
1397 MemWriteByte (Addr, Regs.AC);
1403 static void OPC_6502_A0 (void)
1404 /* Opcode $A0: LDY #imm */
1407 Regs.YR = MemReadByte (Regs.PC+1);
1415 static void OPC_6502_A1 (void)
1416 /* Opcode $A1: LDA (zp,x) */
1418 unsigned char ZPAddr;
1421 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1422 Addr = MemReadZPWord (ZPAddr);
1423 Regs.AC = MemReadByte (Addr);
1431 static void OPC_6502_A2 (void)
1432 /* Opcode $A2: LDX #imm */
1435 Regs.XR = MemReadByte (Regs.PC+1);
1443 static void OPC_6502_A4 (void)
1444 /* Opcode $A4: LDY zp */
1446 unsigned char ZPAddr;
1448 ZPAddr = MemReadByte (Regs.PC+1);
1449 Regs.YR = MemReadByte (ZPAddr);
1457 static void OPC_6502_A5 (void)
1458 /* Opcode $A5: LDA zp */
1460 unsigned char ZPAddr;
1462 ZPAddr = MemReadByte (Regs.PC+1);
1463 Regs.AC = MemReadByte (ZPAddr);
1471 static void OPC_6502_A6 (void)
1472 /* Opcode $A6: LDX zp */
1474 unsigned char ZPAddr;
1476 ZPAddr = MemReadByte (Regs.PC+1);
1477 Regs.XR = MemReadByte (ZPAddr);
1485 static void OPC_6502_A8 (void)
1486 /* Opcode $A8: TAY */
1497 static void OPC_6502_A9 (void)
1498 /* Opcode $A9: LDA #imm */
1501 Regs.AC = MemReadByte (Regs.PC+1);
1509 static void OPC_6502_AA (void)
1510 /* Opcode $AA: TAX */
1521 static void OPC_6502_AC (void)
1522 /* Opcode $Regs.AC: LDY abs */
1526 Addr = MemReadWord (Regs.PC+1);
1527 Regs.YR = MemReadByte (Addr);
1535 static void OPC_6502_AD (void)
1536 /* Opcode $AD: LDA abs */
1540 Addr = MemReadWord (Regs.PC+1);
1541 Regs.AC = MemReadByte (Addr);
1549 static void OPC_6502_AE (void)
1550 /* Opcode $AE: LDX abs */
1554 Addr = MemReadWord (Regs.PC+1);
1555 Regs.XR = MemReadByte (Addr);
1563 static void OPC_6502_B0 (void)
1564 /* Opcode $B0: BCS */
1571 static void OPC_6502_B1 (void)
1572 /* Opcode $B1: LDA (zp),y */
1574 unsigned char ZPAddr;
1577 ZPAddr = MemReadByte (Regs.PC+1);
1578 Addr = MemReadZPWord (ZPAddr);
1579 if (PAGE_CROSS (Addr, Regs.YR)) {
1582 Regs.AC = MemReadByte (Addr + Regs.YR);
1590 static void OPC_6502_B4 (void)
1591 /* Opcode $B4: LDY zp,x */
1593 unsigned char ZPAddr;
1595 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1596 Regs.YR = MemReadByte (ZPAddr);
1604 static void OPC_6502_B5 (void)
1605 /* Opcode $B5: LDA zp,x */
1607 unsigned char ZPAddr;
1609 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1610 Regs.AC = MemReadByte (ZPAddr);
1618 static void OPC_6502_B6 (void)
1619 /* Opcode $B6: LDX zp,y */
1621 unsigned char ZPAddr;
1623 ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR;
1624 Regs.XR = MemReadByte (ZPAddr);
1632 static void OPC_6502_B8 (void)
1633 /* Opcode $B8: CLV */
1642 static void OPC_6502_B9 (void)
1643 /* Opcode $B9: LDA abs,y */
1647 Addr = MemReadWord (Regs.PC+1);
1648 if (PAGE_CROSS (Addr, Regs.YR)) {
1651 Regs.AC = MemReadByte (Addr + Regs.YR);
1659 static void OPC_6502_BA (void)
1660 /* Opcode $BA: TSX */
1671 static void OPC_6502_BC (void)
1672 /* Opcode $BC: LDY abs,x */
1676 Addr = MemReadWord (Regs.PC+1);
1677 if (PAGE_CROSS (Addr, Regs.XR)) {
1680 Regs.YR = MemReadByte (Addr + Regs.XR);
1688 static void OPC_6502_BD (void)
1689 /* Opcode $BD: LDA abs,x */
1693 Addr = MemReadWord (Regs.PC+1);
1694 if (PAGE_CROSS (Addr, Regs.XR)) {
1697 Regs.AC = MemReadByte (Addr + Regs.XR);
1705 static void OPC_6502_BE (void)
1706 /* Opcode $BE: LDX abs,y */
1710 Addr = MemReadWord (Regs.PC+1);
1711 if (PAGE_CROSS (Addr, Regs.YR)) {
1714 Regs.XR = MemReadByte (Addr + Regs.YR);
1722 static void OPC_6502_C0 (void)
1723 /* Opcode $C0: CPY #imm */
1726 CMP (Regs.YR, MemReadByte (Regs.PC+1));
1732 static void OPC_6502_C1 (void)
1733 /* Opcode $C1: CMP (zp,x) */
1735 unsigned char ZPAddr;
1738 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1739 Addr = MemReadZPWord (ZPAddr);
1740 CMP (Regs.AC, MemReadByte (Addr));
1746 static void OPC_6502_C4 (void)
1747 /* Opcode $C4: CPY zp */
1749 unsigned char ZPAddr;
1751 ZPAddr = MemReadByte (Regs.PC+1);
1752 CMP (Regs.YR, MemReadByte (ZPAddr));
1758 static void OPC_6502_C5 (void)
1759 /* Opcode $C5: CMP zp */
1761 unsigned char ZPAddr;
1763 ZPAddr = MemReadByte (Regs.PC+1);
1764 CMP (Regs.AC, MemReadByte (ZPAddr));
1770 static void OPC_6502_C6 (void)
1771 /* Opcode $C6: DEC zp */
1773 unsigned char ZPAddr;
1776 ZPAddr = MemReadByte (Regs.PC+1);
1777 Val = MemReadByte (ZPAddr) - 1;
1778 MemWriteByte (ZPAddr, Val);
1786 static void OPC_6502_C8 (void)
1787 /* Opcode $C8: INY */
1790 Regs.YR = (Regs.YR + 1) & 0xFF;
1798 static void OPC_6502_C9 (void)
1799 /* Opcode $C9: CMP #imm */
1802 CMP (Regs.AC, MemReadByte (Regs.PC+1));
1808 static void OPC_6502_CA (void)
1809 /* Opcode $CA: DEX */
1812 Regs.XR = (Regs.XR - 1) & 0xFF;
1820 static void OPC_6502_CC (void)
1821 /* Opcode $CC: CPY abs */
1825 Addr = MemReadWord (Regs.PC+1);
1826 CMP (Regs.YR, MemReadByte (Addr));
1832 static void OPC_6502_CD (void)
1833 /* Opcode $CD: CMP abs */
1837 Addr = MemReadWord (Regs.PC+1);
1838 CMP (Regs.AC, MemReadByte (Addr));
1844 static void OPC_6502_CE (void)
1845 /* Opcode $CE: DEC abs */
1850 Addr = MemReadWord (Regs.PC+1);
1851 Val = MemReadByte (Addr) - 1;
1852 MemWriteByte (Addr, Val);
1860 static void OPC_6502_D0 (void)
1861 /* Opcode $D0: BNE */
1863 BRANCH (!GET_ZF ());
1868 static void OPC_6502_D1 (void)
1869 /* Opcode $D1: CMP (zp),y */
1874 ZPAddr = MemReadByte (Regs.PC+1);
1875 Addr = MemReadWord (ZPAddr);
1876 if (PAGE_CROSS (Addr, Regs.YR)) {
1879 CMP (Regs.AC, MemReadByte (Addr + Regs.YR));
1885 static void OPC_6502_D5 (void)
1886 /* Opcode $D5: CMP zp,x */
1888 unsigned char ZPAddr;
1890 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1891 CMP (Regs.AC, MemReadByte (ZPAddr));
1897 static void OPC_6502_D6 (void)
1898 /* Opcode $D6: DEC zp,x */
1900 unsigned char ZPAddr;
1903 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1904 Val = MemReadByte (ZPAddr) - 1;
1905 MemWriteByte (ZPAddr, Val);
1913 static void OPC_6502_D8 (void)
1914 /* Opcode $D8: CLD */
1923 static void OPC_6502_D9 (void)
1924 /* Opcode $D9: CMP abs,y */
1928 Addr = MemReadWord (Regs.PC+1);
1929 if (PAGE_CROSS (Addr, Regs.YR)) {
1932 CMP (Regs.AC, MemReadByte (Addr + Regs.YR));
1938 static void OPC_6502_DD (void)
1939 /* Opcode $DD: CMP abs,x */
1943 Addr = MemReadWord (Regs.PC+1);
1944 if (PAGE_CROSS (Addr, Regs.XR)) {
1947 CMP (Regs.AC, MemReadByte (Addr + Regs.XR));
1953 static void OPC_6502_DE (void)
1954 /* Opcode $DE: DEC abs,x */
1959 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
1960 Val = MemReadByte (Addr) - 1;
1961 MemWriteByte (Addr, Val);
1969 static void OPC_6502_E0 (void)
1970 /* Opcode $E0: CPX #imm */
1973 CMP (Regs.XR, MemReadByte (Regs.PC+1));
1979 static void OPC_6502_E1 (void)
1980 /* Opcode $E1: SBC (zp,x) */
1982 unsigned char ZPAddr;
1985 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
1986 Addr = MemReadZPWord (ZPAddr);
1987 SBC (MemReadByte (Addr));
1993 static void OPC_6502_E4 (void)
1994 /* Opcode $E4: CPX zp */
1996 unsigned char ZPAddr;
1998 ZPAddr = MemReadByte (Regs.PC+1);
1999 CMP (Regs.XR, MemReadByte (ZPAddr));
2005 static void OPC_6502_E5 (void)
2006 /* Opcode $E5: SBC zp */
2008 unsigned char ZPAddr;
2010 ZPAddr = MemReadByte (Regs.PC+1);
2011 SBC (MemReadByte (ZPAddr));
2017 static void OPC_6502_E6 (void)
2018 /* Opcode $E6: INC zp */
2020 unsigned char ZPAddr;
2023 ZPAddr = MemReadByte (Regs.PC+1);
2024 Val = MemReadByte (ZPAddr) + 1;
2025 MemWriteByte (ZPAddr, Val);
2033 static void OPC_6502_E8 (void)
2034 /* Opcode $E8: INX */
2037 Regs.XR = (Regs.XR + 1) & 0xFF;
2045 static void OPC_6502_E9 (void)
2046 /* Opcode $E9: SBC #imm */
2049 SBC (MemReadByte (Regs.PC+1));
2055 static void OPC_6502_EA (void)
2056 /* Opcode $EA: NOP */
2058 /* This one is easy... */
2065 static void OPC_6502_EC (void)
2066 /* Opcode $EC: CPX abs */
2070 Addr = MemReadWord (Regs.PC+1);
2071 CMP (Regs.XR, MemReadByte (Addr));
2077 static void OPC_6502_ED (void)
2078 /* Opcode $ED: SBC abs */
2082 Addr = MemReadWord (Regs.PC+1);
2083 SBC (MemReadByte (Addr));
2089 static void OPC_6502_EE (void)
2090 /* Opcode $EE: INC abs */
2095 Addr = MemReadWord (Regs.PC+1);
2096 Val = MemReadByte (Addr) + 1;
2097 MemWriteByte (Addr, Val);
2105 static void OPC_6502_F0 (void)
2106 /* Opcode $F0: BEQ */
2113 static void OPC_6502_F1 (void)
2114 /* Opcode $F1: SBC (zp),y */
2116 unsigned char ZPAddr;
2119 ZPAddr = MemReadByte (Regs.PC+1);
2120 Addr = MemReadZPWord (ZPAddr);
2121 if (PAGE_CROSS (Addr, Regs.YR)) {
2124 SBC (MemReadByte (Addr + Regs.YR));
2130 static void OPC_6502_F5 (void)
2131 /* Opcode $F5: SBC zp,x */
2133 unsigned char ZPAddr;
2135 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
2136 SBC (MemReadByte (ZPAddr));
2142 static void OPC_6502_F6 (void)
2143 /* Opcode $F6: INC zp,x */
2145 unsigned char ZPAddr;
2148 ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR;
2149 Val = MemReadByte (ZPAddr) + 1;
2150 MemWriteByte (ZPAddr, Val);
2158 static void OPC_6502_F8 (void)
2159 /* Opcode $F8: SED */
2166 static void OPC_6502_F9 (void)
2167 /* Opcode $F9: SBC abs,y */
2171 Addr = MemReadWord (Regs.PC+1);
2172 if (PAGE_CROSS (Addr, Regs.YR)) {
2175 SBC (MemReadByte (Addr + Regs.YR));
2181 static void OPC_6502_FD (void)
2182 /* Opcode $FD: SBC abs,x */
2186 Addr = MemReadWord (Regs.PC+1);
2187 if (PAGE_CROSS (Addr, Regs.XR)) {
2190 SBC (MemReadByte (Addr + Regs.XR));
2196 static void OPC_6502_FE (void)
2197 /* Opcode $FE: INC abs,x */
2202 Addr = MemReadWord (Regs.PC+1) + Regs.XR;
2203 Val = MemReadByte (Addr) + 1;
2204 MemWriteByte (Addr, Val);
2212 /*****************************************************************************/
2213 /* Opcode handler tables */
2214 /*****************************************************************************/
2218 /* Opcode handler table for the 6502 */
2219 static const OPFunc OP6502Table[256] = {
2480 /* Opcode handler table for the 65C02 */
2481 static const OPFunc OP65C02Table[256] = {
2742 /* Tables with opcode handlers */
2743 static const OPFunc* Handlers[2] = {OP6502Table, OP65C02Table};
2747 /*****************************************************************************/
2749 /*****************************************************************************/
2753 void IRQRequest (void)
2754 /* Generate an IRQ */
2756 /* Remember the request */
2762 void NMIRequest (void)
2763 /* Generate an NMI */
2765 /* Remember the request */
2772 /* Generate a CPU RESET */
2778 Regs.PC = MemReadWord (0xFFFC);
2783 unsigned ExecuteInsn (void)
2784 /* Execute one CPU instruction */
2786 /* If we have an NMI request, handle it */
2787 if (HaveNMIRequest) {
2794 Regs.PC = MemReadWord (0xFFFA);
2797 } else if (HaveIRQRequest && GET_IF () == 0) {
2804 Regs.PC = MemReadWord (0xFFFE);
2809 /* Normal instruction - read the next opcode */
2810 unsigned char OPC = MemReadByte (Regs.PC);
2813 Handlers[CPU][OPC] ();
2817 TotalCycles += Cycles;
2819 /* Return the number of clock cycles needed by this insn */
2825 unsigned long GetCycles (void)
2826 /* Return the total number of cycles executed */
2828 /* Return the total number of cycles */