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 /*****************************************************************************/
55 /*****************************************************************************/
57 /*****************************************************************************/
62 unsigned char AC; /* Accumulator */
63 unsigned char XR; /* X register */
64 unsigned char YR; /* Y register */
65 unsigned char SR; /* Status register */
66 unsigned char SP; /* Stackpointer */
67 unsigned PC; /* Program counter */
69 /* Count the total number of cylcles */
70 unsigned Cycles; /* Cycles per insn */
71 unsigned long TotalCycles; /* Total cycles */
73 /* Allow the stack page to be changed */
74 static unsigned StackPage = 0x100;
76 /* Status register bits */
77 #define CF 0x01 /* Carry flag */
78 #define ZF 0x02 /* Zero flag */
79 #define IF 0x04 /* Interrupt flag */
80 #define DF 0x08 /* Decimal flag */
81 #define BF 0x10 /* Break flag */
82 #define OF 0x40 /* Overflow flag */
83 #define SF 0x80 /* Sign flag */
89 static char BreakMsg[1024];
93 /*****************************************************************************/
94 /* Helper functions and macros */
95 /*****************************************************************************/
99 /* Return the flags as a boolean value (0/1) */
100 #define GET_CF() ((SR & CF) != 0)
101 #define GET_ZF() ((SR & ZF) != 0)
102 #define GET_IF() ((SR & IF) != 0)
103 #define GET_DF() ((SR & DF) != 0)
104 #define GET_BF() ((SR & BF) != 0)
105 #define GET_OF() ((SR & OF) != 0)
106 #define GET_SF() ((SR & SF) != 0)
108 /* Set the flags. The parameter is a boolean flag that says if the flag should be
111 #define SET_CF(f) do { if (f) { SR |= CF; } else { SR &= ~CF; } } while (0)
112 #define SET_ZF(f) do { if (f) { SR |= ZF; } else { SR &= ~ZF; } } while (0)
113 #define SET_IF(f) do { if (f) { SR |= IF; } else { SR &= ~IF; } } while (0)
114 #define SET_DF(f) do { if (f) { SR |= DF; } else { SR &= ~DF; } } while (0)
115 #define SET_BF(f) do { if (f) { SR |= BF; } else { SR &= ~BF; } } while (0)
116 #define SET_OF(f) do { if (f) { SR |= OF; } else { SR &= ~OF; } } while (0)
117 #define SET_SF(f) do { if (f) { SR |= SF; } else { SR &= ~SF; } } while (0)
119 /* Special test and set macros. The meaning of the parameter depends on the
120 * actual flag that should be set or reset.
122 #define TEST_ZF(v) SET_ZF (((v) & 0xFF) == 0)
123 #define TEST_SF(v) SET_SF (((v) & 0x80) != 0)
124 #define TEST_CF(v) SET_CF (((v) & 0xFF00) != 0)
126 /* Program counter halves */
127 #define PCL (PC & 0xFF)
128 #define PCH ((PC >> 8) & 0xFF)
130 /* Stack operations */
131 #define PUSH(Val) MemWriteByte (StackPage + SP--, Val)
132 #define POP() MemReadByte (StackPage + ++SP)
134 /* Test for page cross */
135 #define PAGE_CROSS(addr,offs) ((((addr) & 0xFF) + offs) >= 0x100)
138 #define AC_OP_IMM(op) \
140 AC = AC op MemReadByte (PC+1); \
146 #define AC_OP_ZP(op) \
148 AC = AC op MemReadByte (MemReadByte (PC+1));\
154 #define AC_OP_ZPX(op) \
155 unsigned char ZPAddr; \
157 ZPAddr = MemReadByte (PC+1) + XR; \
158 AC = AC op MemReadByte (ZPAddr); \
164 #define AC_OP_ZPY(op) \
165 unsigned char ZPAddr; \
167 ZPAddr = MemReadByte (PC+1) + YR; \
168 AC = AC op MemReadByte (ZPAddr); \
174 #define AC_OP_ABS(op) \
177 Addr = MemReadWord (PC+1); \
178 AC = AC op MemReadByte (Addr); \
184 #define AC_OP_ABSX(op) \
187 Addr = MemReadWord (PC+1); \
188 if (PAGE_CROSS (Addr, XR)) { \
191 AC = AC | MemReadByte (Addr + XR); \
197 #define AC_OP_ABSY(op) \
200 Addr = MemReadWord (PC+1); \
201 if (PAGE_CROSS (Addr, YR)) { \
204 AC = AC | MemReadByte (Addr + YR); \
210 #define AC_OP_ZPXIND(op) \
211 unsigned char ZPAddr; \
214 ZPAddr = MemReadByte (PC+1) + XR; \
215 Addr = MemReadZPWord (ZPAddr); \
216 AC = AC op MemReadByte (Addr); \
222 #define AC_OP_ZPINDY(op) \
223 unsigned char ZPAddr; \
226 ZPAddr = MemReadByte (PC+1); \
227 Addr = MemReadZPWord (ZPAddr) + YR; \
228 AC = AC op MemReadByte (Addr); \
236 Warning ("Decimal mode not available"); \
239 unsigned char rhs = v; \
240 Val = AC + rhs + GET_CF (); \
241 AC = (unsigned char) Val; \
245 SET_OF (!((AC ^ rhs) & 0x80) && \
246 ((AC ^ Val) & 0x80)); \
250 #define BRANCH(cond) \
254 unsigned char OldPCH; \
256 Offs = (signed char) MemReadByte (PC+1);\
258 PC += 2 + (int) Offs; \
259 if (PCH != OldPCH) { \
269 unsigned Result = v1 - v2; \
270 TEST_ZF (Result & 0xFF); \
272 SET_CF (Result <= 0xFF); \
291 SET_CF (Val & 0x01); \
299 Warning ("Decimal mode not available"); \
302 unsigned char rhs = v; \
303 Val = AC - rhs - (!GET_CF ()); \
304 AC = (unsigned char) Val; \
307 SET_CF (Val <= 0xFF); \
308 SET_OF (((AC^rhs) & (AC^Val) & 0x80)); \
313 /*****************************************************************************/
314 /* Helper functions */
315 /*****************************************************************************/
319 static void OPC_Illegal (void)
321 Warning ("Illegal opcode $%02X at address $%04X\n", MemReadByte (PC), PC);
326 /*****************************************************************************/
328 /*****************************************************************************/
332 static void OPC_6502_00 (void)
333 /* Opcode $00: BRK */
342 PC = MemReadWord (0xFFFE);
348 static void OPC_6502_01 (void)
349 /* Opcode $01: ORA (ind,x) */
356 static void OPC_6502_05 (void)
357 /* Opcode $05: ORA zp */
364 static void OPC_6502_06 (void)
365 /* Opcode $06: ASL zp */
367 unsigned char ZPAddr;
370 ZPAddr = MemReadByte (PC+1);
371 Val = MemReadByte (ZPAddr) << 1;
372 MemWriteByte (ZPAddr, (unsigned char) Val);
373 TEST_ZF (Val & 0xFF);
375 SET_CF (Val & 0x100);
381 static void OPC_6502_08 (void)
382 /* Opcode $08: PHP */
391 static void OPC_6502_09 (void)
392 /* Opcode $09: ORA #imm */
399 static void OPC_6502_0A (void)
400 /* Opcode $0A: ASL a */
405 AC = (unsigned char) Val;
406 TEST_ZF (Val & 0xFF);
408 SET_CF (Val & 0x100);
414 static void OPC_6502_0D (void)
415 /* Opcode $0D: ORA abs */
422 static void OPC_6502_0E (void)
423 /* Opcode $0E: ALS abs */
428 Addr = MemReadWord (PC+1);
429 Val = MemReadByte (Addr) << 1;
430 MemWriteByte (Addr, (unsigned char) Val);
431 TEST_ZF (Val & 0xFF);
433 SET_CF (Val & 0x100);
439 static void OPC_6502_10 (void)
440 /* Opcode $10: BPL */
447 static void OPC_6502_11 (void)
448 /* Opcode $11: ORA (zp),y */
455 static void OPC_6502_15 (void)
456 /* Opcode $15: ORA zp,x */
463 static void OPC_6502_16 (void)
464 /* Opcode $16: ASL zp,x */
466 unsigned char ZPAddr;
469 ZPAddr = MemReadByte (PC+1) + XR;
470 Val = MemReadByte (ZPAddr) << 1;
471 MemWriteByte (ZPAddr, (unsigned char) Val);
472 TEST_ZF (Val & 0xFF);
474 SET_CF (Val & 0x100);
480 static void OPC_6502_18 (void)
481 /* Opcode $18: CLC */
490 static void OPC_6502_19 (void)
491 /* Opcode $19: ORA abs,y */
498 static void OPC_6502_1D (void)
499 /* Opcode $1D: ORA abs,x */
506 static void OPC_6502_1E (void)
507 /* Opcode $1E: ASL abs,x */
512 Addr = MemReadWord (PC+1) + XR;
513 Val = MemReadByte (Addr) << 1;
514 MemWriteByte (Addr, (unsigned char) Val);
515 TEST_ZF (Val & 0xFF);
517 SET_CF (Val & 0x100);
523 static void OPC_6502_20 (void)
524 /* Opcode $20: JSR */
528 Addr = MemReadWord (PC+1);
537 static void OPC_6502_21 (void)
538 /* Opcode $21: AND (zp,x) */
545 static void OPC_6502_24 (void)
546 /* Opcode $24: BIT zp */
548 unsigned char ZPAddr;
551 ZPAddr = MemReadByte (PC+1);
552 Val = MemReadByte (ZPAddr);
555 SET_ZF ((Val & AC) == 0);
561 static void OPC_6502_25 (void)
562 /* Opcode $25: AND zp */
569 static void OPC_6502_26 (void)
570 /* Opcode $26: ROL zp */
572 unsigned char ZPAddr;
575 ZPAddr = MemReadByte (PC+1);
576 Val = MemReadByte (ZPAddr);
578 MemWriteByte (ZPAddr, Val);
584 static void OPC_6502_28 (void)
585 /* Opcode $28: PLP */
594 static void OPC_6502_29 (void)
595 /* Opcode $29: AND #imm */
602 static void OPC_6502_2A (void)
603 /* Opcode $2A: ROL a */
609 AC = (unsigned char) Val;
615 static void OPC_6502_2C (void)
616 /* Opcode $2C: BIT abs */
621 Addr = MemReadByte (PC+1);
622 Val = MemReadByte (Addr);
625 SET_ZF ((Val & AC) == 0);
631 static void OPC_6502_2D (void)
632 /* Opcode $2D: AND abs */
639 static void OPC_6502_2E (void)
640 /* Opcode $2E: ROL abs */
645 Addr = MemReadWord (PC+1);
646 Val = MemReadByte (Addr);
648 MemWriteByte (Addr, Val);
654 static void OPC_6502_30 (void)
655 /* Opcode $30: BMI */
662 static void OPC_6502_31 (void)
663 /* Opcode $31: AND (zp),y */
670 static void OPC_6502_35 (void)
671 /* Opcode $35: AND zp,x */
678 static void OPC_6502_36 (void)
679 /* Opcode $36: ROL zp,x */
681 unsigned char ZPAddr;
684 ZPAddr = MemReadByte (PC+1) + XR;
685 Val = MemReadByte (ZPAddr);
687 MemWriteByte (ZPAddr, Val);
693 static void OPC_6502_38 (void)
694 /* Opcode $38: SEC */
703 static void OPC_6502_39 (void)
704 /* Opcode $39: AND abs,y */
711 static void OPC_6502_3D (void)
712 /* Opcode $3D: AND abs,x */
719 static void OPC_6502_3E (void)
720 /* Opcode $3E: ROL abs,x */
725 Addr = MemReadWord (PC+1) + XR;
726 Val = MemReadByte (Addr);
728 MemWriteByte (Addr, Val);
734 static void OPC_6502_40 (void)
735 /* Opcode $40: RTI */
739 PC = POP (); /* PCL */
740 PC |= (POP () << 8); /* PCH */
745 static void OPC_6502_41 (void)
746 /* Opcode $41: EOR (zp,x) */
753 static void OPC_6502_45 (void)
754 /* Opcode $45: EOR zp */
761 static void OPC_6502_46 (void)
762 /* Opcode $46: LSR zp */
764 unsigned char ZPAddr;
767 ZPAddr = MemReadByte (PC+1);
768 Val = MemReadByte (ZPAddr);
771 MemWriteByte (ZPAddr, Val);
779 static void OPC_6502_48 (void)
780 /* Opcode $48: PHA */
789 static void OPC_6502_49 (void)
790 /* Opcode $49: EOR #imm */
797 static void OPC_6502_4A (void)
798 /* Opcode $4A: LSR a */
810 static void OPC_6502_4C (void)
811 /* Opcode $4C: JMP abs */
814 PC = MemReadWord (PC+1);
819 static void OPC_6502_4D (void)
820 /* Opcode $4D: EOR abs */
827 static void OPC_6502_4E (void)
828 /* Opcode $4E: LSR abs */
833 Addr = MemReadWord (PC+1);
834 Val = MemReadByte (Addr);
837 MemWriteByte (Addr, Val);
845 static void OPC_6502_50 (void)
846 /* Opcode $50: BVC */
853 static void OPC_6502_51 (void)
854 /* Opcode $51: EOR (zp),y */
861 static void OPC_6502_55 (void)
862 /* Opcode $55: EOR zp,x */
869 static void OPC_6502_56 (void)
870 /* Opcode $56: LSR zp,x */
872 unsigned char ZPAddr;
875 ZPAddr = MemReadByte (PC+1) + XR;
876 Val = MemReadByte (ZPAddr);
879 MemWriteByte (ZPAddr, Val);
887 static void OPC_6502_58 (void)
888 /* Opcode $58: CLI */
897 static void OPC_6502_59 (void)
898 /* Opcode $59: EOR abs,y */
905 static void OPC_6502_5D (void)
906 /* Opcode $5D: EOR abs,x */
913 static void OPC_6502_5E (void)
914 /* Opcode $5E: LSR abs,x */
919 Addr = MemReadWord (PC+1) + XR;
920 Val = MemReadByte (Addr);
923 MemWriteByte (Addr, Val);
931 static void OPC_6502_60 (void)
932 /* Opcode $60: RTS */
935 PC = POP (); /* PCL */
936 PC |= (POP () << 8); /* PCH */
942 static void OPC_6502_61 (void)
943 /* Opcode $61: ADC (zp,x) */
945 unsigned char ZPAddr;
948 ZPAddr = MemReadByte (PC+1) + XR;
949 Addr = MemReadZPWord (ZPAddr);
950 ADC (MemReadByte (Addr));
956 static void OPC_6502_65 (void)
957 /* Opcode $65: ADC zp */
959 unsigned char ZPAddr;
961 ZPAddr = MemReadByte (PC+1);
962 ADC (MemReadByte (ZPAddr));
968 static void OPC_6502_66 (void)
969 /* Opcode $66: ROR zp */
971 unsigned char ZPAddr;
974 ZPAddr = MemReadByte (PC+1);
975 Val = MemReadByte (ZPAddr);
977 MemWriteByte (ZPAddr, Val);
983 static void OPC_6502_68 (void)
984 /* Opcode $68: PLA */
995 static void OPC_6502_69 (void)
996 /* Opcode $69: ADC #imm */
999 ADC (MemReadByte (PC+1));
1005 static void OPC_6502_6A (void)
1006 /* Opcode $6A: ROR a */
1012 AC = (unsigned char) Val;
1018 static void OPC_6502_6C (void)
1019 /* Opcode $6C: JMP (ind) */
1023 Addr = MemReadWord (PC+1);
1024 if (CPU == CPU_6502) {
1025 /* Emulate the 6502 bug */
1026 PC = MemReadByte (Addr);
1027 Addr = (Addr & 0xFF00) | ((Addr + 1) & 0xFF);
1028 PC |= (MemReadByte (Addr) << 8);
1030 /* 65C02 and above have this bug fixed */
1031 PC = MemReadWord (Addr);
1037 static void OPC_6502_6D (void)
1038 /* Opcode $6D: ADC abs */
1042 Addr = MemReadWord (PC+1);
1043 ADC (MemReadByte (Addr));
1049 static void OPC_6502_6E (void)
1050 /* Opcode $6E: ROR abs */
1055 Addr = MemReadWord (PC+1);
1056 Val = MemReadByte (Addr);
1058 MemWriteByte (Addr, Val);
1064 static void OPC_6502_70 (void)
1065 /* Opcode $70: BVS */
1072 static void OPC_6502_71 (void)
1073 /* Opcode $71: ADC (zp),y */
1075 unsigned char ZPAddr;
1078 ZPAddr = MemReadByte (PC+1);
1079 Addr = MemReadZPWord (ZPAddr);
1080 if (PAGE_CROSS (Addr, YR)) {
1083 ADC (MemReadByte (Addr + YR));
1089 static void OPC_6502_75 (void)
1090 /* Opcode $75: ADC zp,x */
1092 unsigned char ZPAddr;
1094 ZPAddr = MemReadByte (PC+1) + XR;
1095 ADC (MemReadByte (ZPAddr));
1101 static void OPC_6502_76 (void)
1102 /* Opcode $76: ROR zp,x */
1104 unsigned char ZPAddr;
1107 ZPAddr = MemReadByte (PC+1) + XR;
1108 Val = MemReadByte (ZPAddr);
1110 MemWriteByte (ZPAddr, Val);
1116 static void OPC_6502_78 (void)
1117 /* Opcode $78: SEI */
1126 static void OPC_6502_79 (void)
1127 /* Opcode $79: ADC abs,y */
1131 Addr = MemReadWord (PC+1);
1132 if (PAGE_CROSS (Addr, YR)) {
1135 ADC (MemReadByte (Addr + YR));
1141 static void OPC_6502_7D (void)
1142 /* Opcode $7D: ADC abs,x */
1146 Addr = MemReadWord (PC+1);
1147 if (PAGE_CROSS (Addr, XR)) {
1150 ADC (MemReadByte (Addr + XR));
1156 static void OPC_6502_7E (void)
1157 /* Opcode $7E: ROR abs,x */
1162 Addr = MemReadByte (PC+1) + XR;
1163 Val = MemReadByte (Addr);
1165 MemWriteByte (Addr, Val);
1171 static void OPC_6502_81 (void)
1172 /* Opcode $81: STA (zp,x) */
1174 unsigned char ZPAddr;
1177 ZPAddr = MemReadByte (PC+1) + XR;
1178 Addr = MemReadZPWord (ZPAddr);
1179 MemWriteByte (Addr, AC);
1185 static void OPC_6502_84 (void)
1186 /* Opcode $84: STY zp */
1188 unsigned char ZPAddr;
1190 ZPAddr = MemReadByte (PC+1);
1191 MemWriteByte (ZPAddr, YR);
1197 static void OPC_6502_85 (void)
1198 /* Opcode $85: STA zp */
1200 unsigned char ZPAddr;
1202 ZPAddr = MemReadByte (PC+1);
1203 MemWriteByte (ZPAddr, AC);
1209 static void OPC_6502_86 (void)
1210 /* Opcode $86: STX zp */
1212 unsigned char ZPAddr;
1214 ZPAddr = MemReadByte (PC+1);
1215 MemWriteByte (ZPAddr, XR);
1221 static void OPC_6502_88 (void)
1222 /* Opcode $88: DEY */
1233 static void OPC_6502_8A (void)
1234 /* Opcode $8A: TXA */
1245 static void OPC_6502_8C (void)
1246 /* Opcode $8C: STY abs */
1250 Addr = MemReadWord (PC+1);
1251 MemWriteByte (Addr, YR);
1257 static void OPC_6502_8D (void)
1258 /* Opcode $8D: STA abs */
1262 Addr = MemReadWord (PC+1);
1263 MemWriteByte (Addr, AC);
1269 static void OPC_6502_8E (void)
1270 /* Opcode $8E: STX abs */
1274 Addr = MemReadWord (PC+1);
1275 MemWriteByte (Addr, XR);
1281 static void OPC_6502_90 (void)
1282 /* Opcode $90: BCC */
1284 BRANCH (!GET_CF ());
1289 static void OPC_6502_91 (void)
1290 /* Opcode $91: sta (zp),y */
1292 unsigned char ZPAddr;
1295 ZPAddr = MemReadByte (PC+1);
1296 Addr = MemReadZPWord (ZPAddr) + YR;
1297 MemWriteByte (Addr, AC);
1303 static void OPC_6502_94 (void)
1304 /* Opcode $94: STY zp,x */
1306 unsigned char ZPAddr;
1308 ZPAddr = MemReadByte (PC+1) + XR;
1309 MemWriteByte (ZPAddr, YR);
1315 static void OPC_6502_95 (void)
1316 /* Opcode $95: STA zp,x */
1318 unsigned char ZPAddr;
1320 ZPAddr = MemReadByte (PC+1) + XR;
1321 MemWriteByte (ZPAddr, AC);
1327 static void OPC_6502_96 (void)
1328 /* Opcode $96: stx zp,y */
1330 unsigned char ZPAddr;
1332 ZPAddr = MemReadByte (PC+1) + YR;
1333 MemWriteByte (ZPAddr, XR);
1339 static void OPC_6502_98 (void)
1340 /* Opcode $98: TYA */
1351 static void OPC_6502_99 (void)
1352 /* Opcode $99: STA abs,y */
1356 Addr = MemReadWord (PC+1) + YR;
1357 MemWriteByte (Addr, AC);
1363 static void OPC_6502_9A (void)
1364 /* Opcode $9A: TXS */
1373 static void OPC_6502_9D (void)
1374 /* Opcode $9D: STA abs,x */
1378 Addr = MemReadWord (PC+1) + XR;
1379 MemWriteByte (Addr, AC);
1385 static void OPC_6502_A0 (void)
1386 /* Opcode $A0: LDY #imm */
1389 YR = MemReadByte (PC+1);
1397 static void OPC_6502_A1 (void)
1398 /* Opcode $A1: LDA (zp,x) */
1400 unsigned char ZPAddr;
1403 ZPAddr = MemReadByte (PC+1) + XR;
1404 Addr = MemReadZPWord (ZPAddr);
1405 AC = MemReadByte (Addr);
1413 static void OPC_6502_A2 (void)
1414 /* Opcode $A2: LDX #imm */
1417 XR = MemReadByte (PC+1);
1425 static void OPC_6502_A4 (void)
1426 /* Opcode $A4: LDY zp */
1428 unsigned char ZPAddr;
1430 ZPAddr = MemReadByte (PC+1);
1431 YR = MemReadByte (ZPAddr);
1439 static void OPC_6502_A5 (void)
1440 /* Opcode $A5: LDA zp */
1442 unsigned char ZPAddr;
1444 ZPAddr = MemReadByte (PC+1);
1445 AC = MemReadByte (ZPAddr);
1453 static void OPC_6502_A6 (void)
1454 /* Opcode $A6: LDX zp */
1456 unsigned char ZPAddr;
1458 ZPAddr = MemReadByte (PC+1);
1459 XR = MemReadByte (ZPAddr);
1467 static void OPC_6502_A8 (void)
1468 /* Opcode $A8: TAY */
1479 static void OPC_6502_A9 (void)
1480 /* Opcode $A9: LDA #imm */
1483 AC = MemReadByte (PC+1);
1491 static void OPC_6502_AA (void)
1492 /* Opcode $AA: TAX */
1503 static void OPC_6502_AC (void)
1504 /* Opcode $AC: LDY abs */
1508 Addr = MemReadWord (PC+1);
1509 YR = MemReadByte (Addr);
1517 static void OPC_6502_AD (void)
1518 /* Opcode $AD: LDA abs */
1522 Addr = MemReadWord (PC+1);
1523 AC = MemReadByte (Addr);
1531 static void OPC_6502_AE (void)
1532 /* Opcode $AE: LDX abs */
1536 Addr = MemReadWord (PC+1);
1537 XR = MemReadByte (Addr);
1545 static void OPC_6502_B0 (void)
1546 /* Opcode $B0: BCS */
1553 static void OPC_6502_B1 (void)
1554 /* Opcode $B1: LDA (zp),y */
1556 unsigned char ZPAddr;
1559 ZPAddr = MemReadByte (PC+1);
1560 Addr = MemReadZPWord (ZPAddr);
1561 if (PAGE_CROSS (Addr, YR)) {
1564 AC = MemReadByte (Addr + YR);
1572 static void OPC_6502_B4 (void)
1573 /* Opcode $B4: LDY zp,x */
1575 unsigned char ZPAddr;
1577 ZPAddr = MemReadByte (PC+1) + XR;
1578 YR = MemReadByte (ZPAddr);
1586 static void OPC_6502_B5 (void)
1587 /* Opcode $B5: LDA zp,x */
1589 unsigned char ZPAddr;
1591 ZPAddr = MemReadByte (PC+1) + XR;
1592 AC = MemReadByte (ZPAddr);
1600 static void OPC_6502_B6 (void)
1601 /* Opcode $B6: LDX zp,y */
1603 unsigned char ZPAddr;
1605 ZPAddr = MemReadByte (PC+1) + YR;
1606 XR = MemReadByte (ZPAddr);
1614 static void OPC_6502_B8 (void)
1615 /* Opcode $B8: CLV */
1624 static void OPC_6502_B9 (void)
1625 /* Opcode $B9: LDA abs,y */
1629 Addr = MemReadWord (PC+1);
1630 if (PAGE_CROSS (Addr, YR)) {
1633 AC = MemReadByte (Addr + YR);
1641 static void OPC_6502_BA (void)
1642 /* Opcode $BA: TSX */
1653 static void OPC_6502_BC (void)
1654 /* Opcode $BC: LDY abs,x */
1658 Addr = MemReadWord (PC+1);
1659 if (PAGE_CROSS (Addr, XR)) {
1662 YR = MemReadByte (Addr + XR);
1670 static void OPC_6502_BD (void)
1671 /* Opcode $BD: LDA abs,x */
1675 Addr = MemReadWord (PC+1);
1676 if (PAGE_CROSS (Addr, XR)) {
1679 AC = MemReadByte (Addr + XR);
1687 static void OPC_6502_BE (void)
1688 /* Opcode $BE: LDX abs,y */
1692 Addr = MemReadWord (PC+1);
1693 if (PAGE_CROSS (Addr, YR)) {
1696 XR = MemReadByte (Addr + YR);
1704 static void OPC_6502_C0 (void)
1705 /* Opcode $C0: CPY #imm */
1708 CMP (YR, MemReadByte (PC+1));
1714 static void OPC_6502_C1 (void)
1715 /* Opcode $C1: CMP (zp,x) */
1717 unsigned char ZPAddr;
1720 ZPAddr = MemReadByte (PC+1) + XR;
1721 Addr = MemReadZPWord (ZPAddr);
1722 CMP (AC, MemReadByte (Addr));
1728 static void OPC_6502_C4 (void)
1729 /* Opcode $C4: CPY zp */
1731 unsigned char ZPAddr;
1733 ZPAddr = MemReadByte (PC+1);
1734 CMP (YR, MemReadByte (ZPAddr));
1740 static void OPC_6502_C5 (void)
1741 /* Opcode $C5: CMP zp */
1743 unsigned char ZPAddr;
1745 ZPAddr = MemReadByte (PC+1);
1746 CMP (AC, MemReadByte (ZPAddr));
1752 static void OPC_6502_C6 (void)
1753 /* Opcode $C6: DEC zp */
1755 unsigned char ZPAddr;
1758 ZPAddr = MemReadByte (PC+1);
1759 Val = MemReadByte (ZPAddr) - 1;
1760 MemWriteByte (ZPAddr, Val);
1768 static void OPC_6502_C8 (void)
1769 /* Opcode $C8: INY */
1780 static void OPC_6502_C9 (void)
1781 /* Opcode $C9: CMP #imm */
1784 CMP (AC, MemReadByte (PC+1));
1790 static void OPC_6502_CA (void)
1791 /* Opcode $CA: DEX */
1802 static void OPC_6502_CC (void)
1803 /* Opcode $CC: CPY abs */
1807 Addr = MemReadWord (PC+1);
1808 CMP (YR, MemReadByte (Addr));
1814 static void OPC_6502_CD (void)
1815 /* Opcode $CD: CMP abs */
1819 Addr = MemReadWord (PC+1);
1820 CMP (AC, MemReadByte (Addr));
1826 static void OPC_6502_CE (void)
1827 /* Opcode $CE: DEC abs */
1832 Addr = MemReadWord (PC+1);
1833 Val = MemReadByte (Addr) - 1;
1834 MemWriteByte (Addr, Val);
1842 static void OPC_6502_D0 (void)
1843 /* Opcode $D0: BNE */
1845 BRANCH (!GET_ZF ());
1850 static void OPC_6502_D1 (void)
1851 /* Opcode $D1: CMP (zp),y */
1856 ZPAddr = MemReadByte (PC+1);
1857 Addr = MemReadWord (ZPAddr);
1858 if (PAGE_CROSS (Addr, YR)) {
1861 CMP (AC, MemReadByte (Addr + YR));
1867 static void OPC_6502_D5 (void)
1868 /* Opcode $D5: CMP zp,x */
1870 unsigned char ZPAddr;
1872 ZPAddr = MemReadByte (PC+1) + XR;
1873 CMP (AC, MemReadByte (ZPAddr));
1879 static void OPC_6502_D6 (void)
1880 /* Opcode $D6: DEC zp,x */
1882 unsigned char ZPAddr;
1885 ZPAddr = MemReadByte (PC+1) + XR;
1886 Val = MemReadByte (ZPAddr) - 1;
1887 MemWriteByte (ZPAddr, Val);
1895 static void OPC_6502_D8 (void)
1896 /* Opcode $D8: CLD */
1905 static void OPC_6502_D9 (void)
1906 /* Opcode $D9: CMP abs,y */
1910 Addr = MemReadWord (PC+1);
1911 if (PAGE_CROSS (Addr, YR)) {
1914 CMP (AC, MemReadByte (Addr + YR));
1920 static void OPC_6502_DD (void)
1921 /* Opcode $DD: CMP abs,x */
1925 Addr = MemReadWord (PC+1);
1926 if (PAGE_CROSS (Addr, XR)) {
1929 CMP (AC, MemReadByte (Addr + XR));
1935 static void OPC_6502_DE (void)
1936 /* Opcode $DE: DEC abs,x */
1941 Addr = MemReadWord (PC+1) + XR;
1942 Val = MemReadByte (Addr) - 1;
1943 MemWriteByte (Addr, Val);
1951 static void OPC_6502_E0 (void)
1952 /* Opcode $E0: CPX #imm */
1955 CMP (XR, MemReadByte (PC+1));
1961 static void OPC_6502_E1 (void)
1962 /* Opcode $E1: SBC (zp,x) */
1964 unsigned char ZPAddr;
1967 ZPAddr = MemReadByte (PC+1) + XR;
1968 Addr = MemReadZPWord (ZPAddr);
1969 SBC (MemReadByte (Addr));
1975 static void OPC_6502_E4 (void)
1976 /* Opcode $E4: CPX zp */
1978 unsigned char ZPAddr;
1980 ZPAddr = MemReadByte (PC+1);
1981 CMP (XR, MemReadByte (ZPAddr));
1987 static void OPC_6502_E5 (void)
1988 /* Opcode $E5: SBC zp */
1990 unsigned char ZPAddr;
1992 ZPAddr = MemReadByte (PC+1);
1993 SBC (MemReadByte (ZPAddr));
1999 static void OPC_6502_E6 (void)
2000 /* Opcode $E6: INC zp */
2002 unsigned char ZPAddr;
2005 ZPAddr = MemReadByte (PC+1);
2006 Val = MemReadByte (ZPAddr) + 1;
2007 MemWriteByte (ZPAddr, Val);
2015 static void OPC_6502_E8 (void)
2016 /* Opcode $E8: INX */
2027 static void OPC_6502_E9 (void)
2028 /* Opcode $E9: SBC #imm */
2031 SBC (MemReadByte (PC+1));
2037 static void OPC_6502_EA (void)
2038 /* Opcode $EA: NOP */
2040 /* This one is easy... */
2047 static void OPC_6502_EC (void)
2048 /* Opcode $EC: CPX abs */
2052 Addr = MemReadWord (PC+1);
2053 CMP (XR, MemReadByte (Addr));
2059 static void OPC_6502_ED (void)
2060 /* Opcode $ED: SBC abs */
2064 Addr = MemReadWord (PC+1);
2065 SBC (MemReadByte (Addr));
2071 static void OPC_6502_EE (void)
2072 /* Opcode $EE: INC abs */
2077 Addr = MemReadWord (PC+1);
2078 Val = MemReadByte (Addr) + 1;
2079 MemWriteByte (Addr, Val);
2087 static void OPC_6502_F0 (void)
2088 /* Opcode $F0: BEQ */
2095 static void OPC_6502_F1 (void)
2096 /* Opcode $F1: SBC (zp),y */
2098 unsigned char ZPAddr;
2101 ZPAddr = MemReadByte (PC+1);
2102 Addr = MemReadZPWord (ZPAddr);
2103 if (PAGE_CROSS (Addr, YR)) {
2106 SBC (MemReadByte (Addr + YR));
2112 static void OPC_6502_F5 (void)
2113 /* Opcode $F5: SBC zp,x */
2115 unsigned char ZPAddr;
2117 ZPAddr = MemReadByte (PC+1) + XR;
2118 SBC (MemReadByte (ZPAddr));
2124 static void OPC_6502_F6 (void)
2125 /* Opcode $F6: INC zp,x */
2127 unsigned char ZPAddr;
2130 ZPAddr = MemReadByte (PC+1) + XR;
2131 Val = MemReadByte (ZPAddr) + 1;
2132 MemWriteByte (ZPAddr, Val);
2140 static void OPC_6502_F8 (void)
2141 /* Opcode $F8: SED */
2148 static void OPC_6502_F9 (void)
2149 /* Opcode $F9: SBC abs,y */
2153 Addr = MemReadWord (PC+1);
2154 if (PAGE_CROSS (Addr, YR)) {
2157 SBC (MemReadByte (Addr + YR));
2163 static void OPC_6502_FD (void)
2164 /* Opcode $FD: SBC abs,x */
2168 Addr = MemReadWord (PC+1);
2169 if (PAGE_CROSS (Addr, XR)) {
2172 SBC (MemReadByte (Addr + XR));
2178 static void OPC_6502_FE (void)
2179 /* Opcode $FE: INC abs,x */
2184 Addr = MemReadWord (PC+1) + XR;
2185 Val = MemReadByte (Addr) + 1;
2186 MemWriteByte (Addr, Val);
2194 /*****************************************************************************/
2196 /*****************************************************************************/
2200 /* Opcode handler table */
2201 typedef void (*OPCFunc) (void);
2202 static OPCFunc OPCTable[256] = {
2463 /*****************************************************************************/
2465 /*****************************************************************************/
2470 /* Initialize the CPU */
2472 PC = MemReadWord (0xFFFC);
2485 /* Generate an IRQ */
2492 /* Generate an NMI */
2498 void Break (const char* Format, ...)
2499 /* Stop running and display the given message */
2502 va_start (ap, Format);
2503 xvsprintf (BreakMsg, sizeof (BreakMsg), Format, ap);
2512 while (!CPUHalted) {
2514 /* Get the next opcode */
2515 unsigned char OPC = MemReadByte (PC);
2517 printf ("%9lu %06X %02X A=%02X X=%02X Y=%02X %c%c%c%c%c%c%c\n",
2518 TotalCycles, PC, OPC, AC, XR, YR,
2519 GET_SF()? 'S' : '-',
2520 GET_ZF()? 'Z' : '-',
2521 GET_CF()? 'C' : '-',
2522 GET_IF()? 'I' : '-',
2523 GET_BF()? 'B' : '-',
2524 GET_DF()? 'D' : '-',
2525 GET_OF()? 'V' : '-');
2531 TotalCycles += Cycles;
2534 printf ("%s\n", BreakMsg);