2 // Virtual 65C02 Emulator v1.0
5 // (c) 2005 Underground Software
7 // JLH = James Hammons <jlhamm@acm.org>
10 // --- ---------- -----------------------------------------------------------
11 // JLH 01/04/2006 Added changelog ;-)
12 // JLH 01/18/2009 Fixed EA_ABS_* macros
15 //OK, the wraparound bug exists in both the Apple and Atari versions of Ultima
16 //II. However, the Atari version *does* occassionally pick strength while the
17 //Apple versions do not--which would seem to indicate a bug either in the RNG
18 //algorithm, the 65C02 core, or the Apple hardware. Need to investigate all
22 //#define __DEBUGMON__
33 #define CLR_Z (regs.cc &= ~FLAG_Z)
34 #define CLR_ZN (regs.cc &= ~(FLAG_Z | FLAG_N))
35 #define CLR_ZNC (regs.cc &= ~(FLAG_Z | FLAG_N | FLAG_C))
36 #define CLR_V (regs.cc &= ~FLAG_V)
37 #define CLR_N (regs.cc &= ~FLAG_N)
38 #define SET_Z(r) (regs.cc = ((r) == 0 ? regs.cc | FLAG_Z : regs.cc & ~FLAG_Z))
39 #define SET_N(r) (regs.cc = ((r) & 0x80 ? regs.cc | FLAG_N : regs.cc & ~FLAG_N))
41 //Not sure that this code is computing the carry correctly... Investigate! [Seems to be]
42 #define SET_C_ADD(a,b) (regs.cc = ((uint8_t)(b) > (uint8_t)(~(a)) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
43 //#define SET_C_SUB(a,b) (regs.cc = ((uint8_t)(b) >= (uint8_t)(a) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
44 #define SET_C_CMP(a,b) (regs.cc = ((uint8_t)(b) >= (uint8_t)(a) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
45 #define SET_ZN(r) SET_N(r); SET_Z(r)
46 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
47 //#define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
48 #define SET_ZNC_CMP(a,b,r) SET_N(r); SET_Z(r); SET_C_CMP(a,b)
50 //Small problem with the EA_ macros: ABS macros don't increment the PC!!! !!! FIX !!!
51 //NB: It's properly handled by everything that uses it, so it works, even if it's klunky
52 //Small problem with fixing it is that you can't do it in a single instruction, i.e.,
53 //you have to read the value THEN you have to increment the PC. Unless there's another
56 #define EA_IMM regs.pc++
57 #define EA_ZP regs.RdMem(regs.pc++)
58 #define EA_ZP_X (regs.RdMem(regs.pc++) + regs.x) & 0xFF
59 #define EA_ZP_Y (regs.RdMem(regs.pc++) + regs.y) & 0xFF
60 #define EA_ABS FetchMemW(regs.pc)
61 #define EA_ABS_X FetchMemW(regs.pc) + regs.x
62 #define EA_ABS_Y FetchMemW(regs.pc) + regs.y
63 #define EA_IND_ZP_X RdMemW((regs.RdMem(regs.pc++) + regs.x) & 0xFF)
64 #define EA_IND_ZP_Y RdMemW(regs.RdMem(regs.pc++)) + regs.y
65 #define EA_IND_ZP RdMemW(regs.RdMem(regs.pc++))
67 #define READ_IMM regs.RdMem(EA_IMM)
68 #define READ_ZP regs.RdMem(EA_ZP)
69 #define READ_ZP_X regs.RdMem(EA_ZP_X)
70 #define READ_ZP_Y regs.RdMem(EA_ZP_Y)
71 #define READ_ABS regs.RdMem(EA_ABS)
72 #define READ_ABS_X regs.RdMem(EA_ABS_X)
73 #define READ_ABS_Y regs.RdMem(EA_ABS_Y)
74 #define READ_IND_ZP_X regs.RdMem(EA_IND_ZP_X)
75 #define READ_IND_ZP_Y regs.RdMem(EA_IND_ZP_Y)
76 #define READ_IND_ZP regs.RdMem(EA_IND_ZP)
78 #define READ_IMM_WB(v) uint16_t addr = EA_IMM; v = regs.RdMem(addr)
79 #define READ_ZP_WB(v) uint16_t addr = EA_ZP; v = regs.RdMem(addr)
80 #define READ_ZP_X_WB(v) uint16_t addr = EA_ZP_X; v = regs.RdMem(addr)
81 #define READ_ABS_WB(v) uint16_t addr = EA_ABS; v = regs.RdMem(addr)
82 #define READ_ABS_X_WB(v) uint16_t addr = EA_ABS_X; v = regs.RdMem(addr)
83 #define READ_ABS_Y_WB(v) uint16_t addr = EA_ABS_Y; v = regs.RdMem(addr)
84 #define READ_IND_ZP_X_WB(v) uint16_t addr = EA_IND_ZP_X; v = regs.RdMem(addr)
85 #define READ_IND_ZP_Y_WB(v) uint16_t addr = EA_IND_ZP_Y; v = regs.RdMem(addr)
86 #define READ_IND_ZP_WB(v) uint16_t addr = EA_IND_ZP; v = regs.RdMem(addr)
88 #define WRITE_BACK(d) regs.WrMem(addr, (d))
90 // Private global variables
92 static V65C02REGS regs;
94 //This is probably incorrect, at least WRT to the $x7 and $xF opcodes... !!! FIX !!!
95 //Also this doesn't take into account the extra cycle it takes when an indirect fetch
96 //(ABS, ABS X/Y, ZP) crosses a page boundary, or extra cycle for BCD add/subtract...
97 #warning "Cycle counts are not accurate--!!! FIX !!!"
98 static uint8_t CPUCycles[256] = {
100 7, 6, 1, 1, 5, 3, 5, 1, 3, 2, 2, 1, 6, 4, 6, 1,
101 2, 5, 5, 1, 5, 4, 6, 1, 2, 4, 2, 1, 6, 4, 6, 1,
102 6, 6, 1, 1, 3, 3, 5, 1, 4, 2, 2, 1, 4, 4, 6, 1,
103 2, 5, 5, 1, 4, 4, 6, 1, 2, 4, 2, 1, 4, 4, 6, 1,
104 6, 6, 1, 1, 1, 3, 5, 1, 3, 2, 2, 1, 3, 4, 6, 1,
105 2, 5, 5, 1, 1, 4, 6, 1, 2, 4, 3, 1, 1, 4, 6, 1,
106 6, 6, 1, 1, 3, 3, 5, 1, 4, 2, 2, 1, 6, 4, 6, 1,
107 2, 5, 5, 1, 4, 4, 6, 1, 2, 4, 4, 1, 6, 4, 6, 1,
108 2, 6, 1, 1, 3, 3, 3, 1, 2, 2, 2, 1, 4, 4, 4, 1,
109 2, 6, 5, 1, 4, 4, 4, 1, 2, 5, 2, 1, 4, 5, 5, 1,
110 2, 6, 2, 1, 3, 3, 3, 1, 2, 2, 2, 1, 4, 4, 4, 1,
111 2, 5, 5, 1, 4, 4, 4, 1, 2, 4, 2, 1, 4, 4, 4, 1,
112 2, 6, 1, 1, 3, 3, 5, 1, 2, 2, 2, 1, 4, 4, 6, 1,
113 2, 5, 5, 1, 1, 4, 6, 1, 2, 4, 3, 1, 1, 4, 6, 1,
114 2, 6, 1, 1, 3, 3, 5, 1, 2, 2, 2, 1, 4, 4, 6, 1,
115 2, 5, 5, 1, 1, 4, 6, 1, 2, 4, 4, 1, 1, 4, 6, 1 };
117 7, 6, 2, 2, 5, 3, 5, 2, 3, 2, 2, 2, 6, 4, 6, 2,
118 2, 5, 5, 2, 5, 4, 6, 2, 2, 4, 2, 2, 6, 4, 6, 2,
119 6, 6, 2, 2, 3, 3, 5, 2, 4, 2, 2, 2, 4, 2, 6, 2,
120 2, 5, 5, 2, 4, 4, 6, 2, 2, 4, 2, 2, 4, 4, 6, 2,
121 6, 6, 2, 2, 3, 3, 5, 2, 3, 2, 2, 2, 3, 4, 6, 2,
122 2, 5, 5, 2, 4, 4, 6, 2, 2, 4, 3, 2, 8, 4, 6, 2,
123 6, 6, 2, 2, 3, 3, 5, 2, 4, 2, 2, 2, 6, 4, 6, 2,
124 2, 5, 5, 2, 4, 4, 6, 2, 2, 4, 4, 2, 6, 4, 6, 2,
125 2, 6, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 4, 4, 4, 2,
126 2, 6, 5, 2, 4, 4, 4, 2, 2, 5, 2, 2, 4, 5, 5, 2,
127 2, 6, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 4, 4, 4, 2,
128 2, 5, 5, 2, 4, 4, 4, 2, 2, 4, 2, 2, 4, 4, 4, 2,
129 2, 6, 2, 2, 3, 3, 5, 2, 2, 2, 2, 2, 4, 4, 5, 2,
130 2, 5, 5, 2, 4, 4, 6, 2, 2, 4, 3, 2, 4, 4, 6, 2,
131 2, 6, 2, 2, 3, 3, 5, 2, 2, 2, 2, 2, 4, 4, 6, 2,
132 2, 5, 5, 2, 4, 4, 6, 2, 2, 4, 4, 2, 4, 4, 6, 2 };
136 static uint8_t _6502Cycles[256] = {
137 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6,
138 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 6, 7,
139 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 2, 6, 6,
140 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 6, 7,
141 6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6,
142 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 6, 7,
143 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 6, 4, 6, 6,
144 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 6, 7,
145 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
146 2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
147 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
148 2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4,
149 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 5, 6,
150 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 6, 7,
151 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
152 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 6, 7 };
154 static uint8_t _65C02Cycles[256] = {
155 7, 6, 2, 2, 5, 3, 5, 2, 3, 2, 2, 2, 6, 4, 6, 2,
156 2, 5, 5, 2, 5, 4, 6, 2, 2, 4, 2, 2, 6, 4, 6, 2,
157 6, 6, 2, 2, 3, 3, 5, 2, 4, 2, 2, 2, 4, 2, 6, 2,
158 2, 5, 5, 2, 4, 4, 6, 2, 2, 4, 2, 2, 4, 4, 6, 2,
159 6, 6, 2, 2, 3, 3, 5, 2, 3, 2, 2, 2, 3, 4, 6, 2,
160 2, 5, 5, 2, 4, 4, 6, 2, 2, 4, 3, 2, 8, 4, 6, 2,
161 6, 6, 2, 2, 3, 3, 5, 2, 4, 2, 2, 2, 6, 4, 6, 2,
162 2, 5, 5, 2, 4, 4, 6, 2, 2, 4, 4, 2, 6, 4, 6, 2,
163 2, 6, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 4, 4, 4, 2,
164 2, 6, 5, 2, 4, 4, 4, 2, 2, 5, 2, 2, 4, 5, 5, 2,
165 2, 6, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 4, 4, 4, 2,
166 2, 5, 5, 2, 4, 4, 4, 2, 2, 4, 2, 2, 4, 4, 4, 2,
167 2, 6, 2, 2, 3, 3, 5, 2, 2, 2, 2, 2, 4, 4, 5, 2,
168 2, 5, 5, 2, 4, 4, 6, 2, 2, 4, 3, 2, 4, 4, 6, 2,
169 2, 6, 2, 2, 3, 3, 5, 2, 2, 2, 2, 2, 4, 4, 6, 2,
170 2, 5, 5, 2, 4, 4, 6, 2, 2, 4, 4, 2, 4, 4, 6, 2 };
175 // +1 if branch taken
176 // +1 if page boundary crossed
177 #define BRANCH_TAKEN { \
180 if ((base ^ regs.pc) & 0xFF00) \
189 if ((oldc ^ regs.pc) & 0xFF00)
196 6502 cycles (includes illegal opcodes):
198 case 0x00: BRK CYC(7) break;
199 case 0x01: INDX ORA CYC(6) break;
200 case 0x02: INV HLT CYC(2) break;
201 case 0x03: INV INDX ASO CYC(8) break;
202 case 0x04: INV ZPG NOP CYC(3) break;
203 case 0x05: ZPG ORA CYC(3) break;
204 case 0x06: ZPG ASL_NMOS CYC(5) break;
205 case 0x07: INV ZPG ASO CYC(5) break;
206 case 0x08: PHP CYC(3) break;
207 case 0x09: IMM ORA CYC(2) break;
208 case 0x0A: ASLA CYC(2) break;
209 case 0x0B: INV IMM ANC CYC(2) break;
210 case 0x0C: INV ABSX NOP CYC(4) break;
211 case 0x0D: ABS ORA CYC(4) break;
212 case 0x0E: ABS ASL_NMOS CYC(6) break;
213 case 0x0F: INV ABS ASO CYC(6) break;
214 case 0x10: REL BPL CYC(2) break;
215 case 0x11: INDY ORA CYC(5) break;
216 case 0x12: INV HLT CYC(2) break;
217 case 0x13: INV INDY ASO CYC(8) break;
218 case 0x14: INV ZPGX NOP CYC(4) break;
219 case 0x15: ZPGX ORA CYC(4) break;
220 case 0x16: ZPGX ASL_NMOS CYC(6) break;
221 case 0x17: INV ZPGX ASO CYC(6) break;
222 case 0x18: CLC CYC(2) break;
223 case 0x19: ABSY ORA CYC(4) break;
224 case 0x1A: INV NOP CYC(2) break;
225 case 0x1B: INV ABSY ASO CYC(7) break;
226 case 0x1C: INV ABSX NOP CYC(4) break;
227 case 0x1D: ABSX ORA CYC(4) break;
228 case 0x1E: ABSX ASL_NMOS CYC(6) break;
229 case 0x1F: INV ABSX ASO CYC(7) break;
230 case 0x20: ABS JSR CYC(6) break;
231 case 0x21: INDX AND CYC(6) break;
232 case 0x22: INV HLT CYC(2) break;
233 case 0x23: INV INDX RLA CYC(8) break;
234 case 0x24: ZPG BIT CYC(3) break;
235 case 0x25: ZPG AND CYC(3) break;
236 case 0x26: ZPG ROL_NMOS CYC(5) break;
237 case 0x27: INV ZPG RLA CYC(5) break;
238 case 0x28: PLP CYC(4) break;
239 case 0x29: IMM AND CYC(2) break;
240 case 0x2A: ROLA CYC(2) break;
241 case 0x2B: INV IMM ANC CYC(2) break;
242 case 0x2C: ABS BIT CYC(4) break;
243 case 0x2D: ABS AND CYC(2) break;
244 case 0x2E: ABS ROL_NMOS CYC(6) break;
245 case 0x2F: INV ABS RLA CYC(6) break;
246 case 0x30: REL BMI CYC(2) break;
247 case 0x31: INDY AND CYC(5) break;
248 case 0x32: INV HLT CYC(2) break;
249 case 0x33: INV INDY RLA CYC(8) break;
250 case 0x34: INV ZPGX NOP CYC(4) break;
251 case 0x35: ZPGX AND CYC(4) break;
252 case 0x36: ZPGX ROL_NMOS CYC(6) break;
253 case 0x37: INV ZPGX RLA CYC(6) break;
254 case 0x38: SEC CYC(2) break;
255 case 0x39: ABSY AND CYC(4) break;
256 case 0x3A: INV NOP CYC(2) break;
257 case 0x3B: INV ABSY RLA CYC(7) break;
258 case 0x3C: INV ABSX NOP CYC(4) break;
259 case 0x3D: ABSX AND CYC(4) break;
260 case 0x3E: ABSX ROL_NMOS CYC(6) break;
261 case 0x3F: INV ABSX RLA CYC(7) break;
262 case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break;
263 case 0x41: INDX EOR CYC(6) break;
264 case 0x42: INV HLT CYC(2) break;
265 case 0x43: INV INDX LSE CYC(8) break;
266 case 0x44: INV ZPG NOP CYC(3) break;
267 case 0x45: ZPG EOR CYC(3) break;
268 case 0x46: ZPG LSR_NMOS CYC(5) break;
269 case 0x47: INV ZPG LSE CYC(5) break;
270 case 0x48: PHA CYC(3) break;
271 case 0x49: IMM EOR CYC(2) break;
272 case 0x4A: LSRA CYC(2) break;
273 case 0x4B: INV IMM ALR CYC(2) break;
274 case 0x4C: ABS JMP CYC(3) break;
275 case 0x4D: ABS EOR CYC(4) break;
276 case 0x4E: ABS LSR_NMOS CYC(6) break;
277 case 0x4F: INV ABS LSE CYC(6) break;
278 case 0x50: REL BVC CYC(2) break;
279 case 0x51: INDY EOR CYC(5) break;
280 case 0x52: INV HLT CYC(2) break;
281 case 0x53: INV INDY LSE CYC(8) break;
282 case 0x54: INV ZPGX NOP CYC(4) break;
283 case 0x55: ZPGX EOR CYC(4) break;
284 case 0x56: ZPGX LSR_NMOS CYC(6) break;
285 case 0x57: INV ZPGX LSE CYC(6) break;
286 case 0x58: CLI CYC(2) break;
287 case 0x59: ABSY EOR CYC(4) break;
288 case 0x5A: INV NOP CYC(2) break;
289 case 0x5B: INV ABSY LSE CYC(7) break;
290 case 0x5C: INV ABSX NOP CYC(4) break;
291 case 0x5D: ABSX EOR CYC(4) break;
292 case 0x5E: ABSX LSR_NMOS CYC(6) break;
293 case 0x5F: INV ABSX LSE CYC(7) break;
294 case 0x60: RTS CYC(6) break;
295 case 0x61: INDX ADC_NMOS CYC(6) break;
296 case 0x62: INV HLT CYC(2) break;
297 case 0x63: INV INDX RRA CYC(8) break;
298 case 0x64: INV ZPG NOP CYC(3) break;
299 case 0x65: ZPG ADC_NMOS CYC(3) break;
300 case 0x66: ZPG ROR_NMOS CYC(5) break;
301 case 0x67: INV ZPG RRA CYC(5) break;
302 case 0x68: PLA CYC(4) break;
303 case 0x69: IMM ADC_NMOS CYC(2) break;
304 case 0x6A: RORA CYC(2) break;
305 case 0x6B: INV IMM ARR CYC(2) break;
306 case 0x6C: IABSNMOS JMP CYC(6) break;
307 case 0x6D: ABS ADC_NMOS CYC(4) break;
308 case 0x6E: ABS ROR_NMOS CYC(6) break;
309 case 0x6F: INV ABS RRA CYC(6) break;
310 case 0x70: REL BVS CYC(2) break;
311 case 0x71: INDY ADC_NMOS CYC(5) break;
312 case 0x72: INV HLT CYC(2) break;
313 case 0x73: INV INDY RRA CYC(8) break;
314 case 0x74: INV ZPGX NOP CYC(4) break;
315 case 0x75: ZPGX ADC_NMOS CYC(4) break;
316 case 0x76: ZPGX ROR_NMOS CYC(6) break;
317 case 0x77: INV ZPGX RRA CYC(6) break;
318 case 0x78: SEI CYC(2) break;
319 case 0x79: ABSY ADC_NMOS CYC(4) break;
320 case 0x7A: INV NOP CYC(2) break;
321 case 0x7B: INV ABSY RRA CYC(7) break;
322 case 0x7C: INV ABSX NOP CYC(4) break;
323 case 0x7D: ABSX ADC_NMOS CYC(4) break;
324 case 0x7E: ABSX ROR_NMOS CYC(6) break;
325 case 0x7F: INV ABSX RRA CYC(7) break;
326 case 0x80: INV IMM NOP CYC(2) break;
327 case 0x81: INDX STA CYC(6) break;
328 case 0x82: INV IMM NOP CYC(2) break;
329 case 0x83: INV INDX AXS CYC(6) break;
330 case 0x84: ZPG STY CYC(3) break;
331 case 0x85: ZPG STA CYC(3) break;
332 case 0x86: ZPG STX CYC(3) break;
333 case 0x87: INV ZPG AXS CYC(3) break;
334 case 0x88: DEY CYC(2) break;
335 case 0x89: INV IMM NOP CYC(2) break;
336 case 0x8A: TXA CYC(2) break;
337 case 0x8B: INV IMM XAA CYC(2) break;
338 case 0x8C: ABS STY CYC(4) break;
339 case 0x8D: ABS STA CYC(4) break;
340 case 0x8E: ABS STX CYC(4) break;
341 case 0x8F: INV ABS AXS CYC(4) break;
342 case 0x90: REL BCC CYC(2) break;
343 case 0x91: INDY STA CYC(6) break;
344 case 0x92: INV HLT CYC(2) break;
345 case 0x93: INV INDY AXA CYC(6) break;
346 case 0x94: ZPGX STY CYC(4) break;
347 case 0x95: ZPGX STA CYC(4) break;
348 case 0x96: ZPGY STX CYC(4) break;
349 case 0x97: INV ZPGY AXS CYC(4) break;
350 case 0x98: TYA CYC(2) break;
351 case 0x99: ABSY STA CYC(5) break;
352 case 0x9A: TXS CYC(2) break;
353 case 0x9B: INV ABSY TAS CYC(5) break;
354 case 0x9C: INV ABSX SAY CYC(5) break;
355 case 0x9D: ABSX STA CYC(5) break;
356 case 0x9E: INV ABSY XAS CYC(5) break;
357 case 0x9F: INV ABSY AXA CYC(5) break;
358 case 0xA0: IMM LDY CYC(2) break;
359 case 0xA1: INDX LDA CYC(6) break;
360 case 0xA2: IMM LDX CYC(2) break;
361 case 0xA3: INV INDX LAX CYC(6) break;
362 case 0xA4: ZPG LDY CYC(3) break;
363 case 0xA5: ZPG LDA CYC(3) break;
364 case 0xA6: ZPG LDX CYC(3) break;
365 case 0xA7: INV ZPG LAX CYC(3) break;
366 case 0xA8: TAY CYC(2) break;
367 case 0xA9: IMM LDA CYC(2) break;
368 case 0xAA: TAX CYC(2) break;
369 case 0xAB: INV IMM OAL CYC(2) break;
370 case 0xAC: ABS LDY CYC(4) break;
371 case 0xAD: ABS LDA CYC(4) break;
372 case 0xAE: ABS LDX CYC(4) break;
373 case 0xAF: INV ABS LAX CYC(4) break;
374 case 0xB0: REL BCS CYC(2) break;
375 case 0xB1: INDY LDA CYC(5) break;
376 case 0xB2: INV HLT CYC(2) break;
377 case 0xB3: INV INDY LAX CYC(5) break;
378 case 0xB4: ZPGX LDY CYC(4) break;
379 case 0xB5: ZPGX LDA CYC(4) break;
380 case 0xB6: ZPGY LDX CYC(4) break;
381 case 0xB7: INV ZPGY LAX CYC(4) break;
382 case 0xB8: CLV CYC(2) break;
383 case 0xB9: ABSY LDA CYC(4) break;
384 case 0xBA: TSX CYC(2) break;
385 case 0xBB: INV ABSY LAS CYC(4) break;
386 case 0xBC: ABSX LDY CYC(4) break;
387 case 0xBD: ABSX LDA CYC(4) break;
388 case 0xBE: ABSY LDX CYC(4) break;
389 case 0xBF: INV ABSY LAX CYC(4) break;
390 case 0xC0: IMM CPY CYC(2) break;
391 case 0xC1: INDX CMP CYC(6) break;
392 case 0xC2: INV IMM NOP CYC(2) break;
393 case 0xC3: INV INDX DCM CYC(8) break;
394 case 0xC4: ZPG CPY CYC(3) break;
395 case 0xC5: ZPG CMP CYC(3) break;
396 case 0xC6: ZPG DEC_NMOS CYC(5) break;
397 case 0xC7: INV ZPG DCM CYC(5) break;
398 case 0xC8: INY CYC(2) break;
399 case 0xC9: IMM CMP CYC(2) break;
400 case 0xCA: DEX CYC(2) break;
401 case 0xCB: INV IMM SAX CYC(2) break;
402 case 0xCC: ABS CPY CYC(4) break;
403 case 0xCD: ABS CMP CYC(4) break;
404 case 0xCE: ABS DEC_NMOS CYC(5) break;
405 case 0xCF: INV ABS DCM CYC(6) break;
406 case 0xD0: REL BNE CYC(2) break;
407 case 0xD1: INDY CMP CYC(5) break;
408 case 0xD2: INV HLT CYC(2) break;
409 case 0xD3: INV INDY DCM CYC(8) break;
410 case 0xD4: INV ZPGX NOP CYC(4) break;
411 case 0xD5: ZPGX CMP CYC(4) break;
412 case 0xD6: ZPGX DEC_NMOS CYC(6) break;
413 case 0xD7: INV ZPGX DCM CYC(6) break;
414 case 0xD8: CLD CYC(2) break;
415 case 0xD9: ABSY CMP CYC(4) break;
416 case 0xDA: INV NOP CYC(2) break;
417 case 0xDB: INV ABSY DCM CYC(7) break;
418 case 0xDC: INV ABSX NOP CYC(4) break;
419 case 0xDD: ABSX CMP CYC(4) break;
420 case 0xDE: ABSX DEC_NMOS CYC(6) break;
421 case 0xDF: INV ABSX DCM CYC(7) break;
422 case 0xE0: IMM CPX CYC(2) break;
423 case 0xE1: INDX SBC_NMOS CYC(6) break;
424 case 0xE2: INV IMM NOP CYC(2) break;
425 case 0xE3: INV INDX INS CYC(8) break;
426 case 0xE4: ZPG CPX CYC(3) break;
427 case 0xE5: ZPG SBC_NMOS CYC(3) break;
428 case 0xE6: ZPG INC_NMOS CYC(5) break;
429 case 0xE7: INV ZPG INS CYC(5) break;
430 case 0xE8: INX CYC(2) break;
431 case 0xE9: IMM SBC_NMOS CYC(2) break;
432 case 0xEA: NOP CYC(2) break;
433 case 0xEB: INV IMM SBC_NMOS CYC(2) break;
434 case 0xEC: ABS CPX CYC(4) break;
435 case 0xED: ABS SBC_NMOS CYC(4) break;
436 case 0xEE: ABS INC_NMOS CYC(6) break;
437 case 0xEF: INV ABS INS CYC(6) break;
438 case 0xF0: REL BEQ CYC(2) break;
439 case 0xF1: INDY SBC_NMOS CYC(5) break;
440 case 0xF2: INV HLT CYC(2) break;
441 case 0xF3: INV INDY INS CYC(8) break;
442 case 0xF4: INV ZPGX NOP CYC(4) break;
443 case 0xF5: ZPGX SBC_NMOS CYC(4) break;
444 case 0xF6: ZPGX INC_NMOS CYC(6) break;
445 case 0xF7: INV ZPGX INS CYC(6) break;
446 case 0xF8: SED CYC(2) break;
447 case 0xF9: ABSY SBC_NMOS CYC(4) break;
448 case 0xFA: INV NOP CYC(2) break;
449 case 0xFB: INV ABSY INS CYC(7) break;
450 case 0xFC: INV ABSX NOP CYC(4) break;
451 case 0xFD: ABSX SBC_NMOS CYC(4) break;
452 case 0xFE: ABSX INC_NMOS CYC(6) break;
453 case 0xFF: INV ABSX INS CYC(7) break;
456 65C02 opcodes: (all illegal are NOP, but have cycle counts)
458 case 0x00: BRK CYC(7) break;
459 case 0x01: INDX ORA CYC(6) break;
460 case 0x02: INV IMM NOP CYC(2) break;
461 case 0x03: INV NOP CYC(2) break;
462 case 0x04: ZPG TSB CYC(5) break;
463 case 0x05: ZPG ORA CYC(3) break;
464 case 0x06: ZPG ASL_CMOS CYC(5) break;
465 case 0x07: INV NOP CYC(2) break;
466 case 0x08: PHP CYC(3) break;
467 case 0x09: IMM ORA CYC(2) break;
468 case 0x0A: ASLA CYC(2) break;
469 case 0x0B: INV NOP CYC(2) break;
470 case 0x0C: ABS TSB CYC(6) break;
471 case 0x0D: ABS ORA CYC(4) break;
472 case 0x0E: ABS ASL_CMOS CYC(6) break;
473 case 0x0F: INV NOP CYC(2) break;
474 case 0x10: REL BPL CYC(2) break;
475 case 0x11: INDY ORA CYC(5) break;
476 case 0x12: IZPG ORA CYC(5) break;
477 case 0x13: INV NOP CYC(2) break;
478 case 0x14: ZPG TRB CYC(5) break;
479 case 0x15: ZPGX ORA CYC(4) break;
480 case 0x16: ZPGX ASL_CMOS CYC(6) break;
481 case 0x17: INV NOP CYC(2) break;
482 case 0x18: CLC CYC(2) break;
483 case 0x19: ABSY ORA CYC(4) break;
484 case 0x1A: INA CYC(2) break;
485 case 0x1B: INV NOP CYC(2) break;
486 case 0x1C: ABS TRB CYC(6) break;
487 case 0x1D: ABSX ORA CYC(4) break;
488 case 0x1E: ABSX ASL_CMOS CYC(6) break;
489 case 0x1F: INV NOP CYC(2) break;
490 case 0x20: ABS JSR CYC(6) break;
491 case 0x21: INDX AND CYC(6) break;
492 case 0x22: INV IMM NOP CYC(2) break;
493 case 0x23: INV NOP CYC(2) break;
494 case 0x24: ZPG BIT CYC(3) break;
495 case 0x25: ZPG AND CYC(3) break;
496 case 0x26: ZPG ROL_CMOS CYC(5) break;
497 case 0x27: INV NOP CYC(2) break;
498 case 0x28: PLP CYC(4) break;
499 case 0x29: IMM AND CYC(2) break;
500 case 0x2A: ROLA CYC(2) break;
501 case 0x2B: INV NOP CYC(2) break;
502 case 0x2C: ABS BIT CYC(4) break;
503 case 0x2D: ABS AND CYC(2) break;
504 case 0x2E: ABS ROL_CMOS CYC(6) break;
505 case 0x2F: INV NOP CYC(2) break;
506 case 0x30: REL BMI CYC(2) break;
507 case 0x31: INDY AND CYC(5) break;
508 case 0x32: IZPG AND CYC(5) break;
509 case 0x33: INV NOP CYC(2) break;
510 case 0x34: ZPGX BIT CYC(4) break;
511 case 0x35: ZPGX AND CYC(4) break;
512 case 0x36: ZPGX ROL_CMOS CYC(6) break;
513 case 0x37: INV NOP CYC(2) break;
514 case 0x38: SEC CYC(2) break;
515 case 0x39: ABSY AND CYC(4) break;
516 case 0x3A: DEA CYC(2) break;
517 case 0x3B: INV NOP CYC(2) break;
518 case 0x3C: ABSX BIT CYC(4) break;
519 case 0x3D: ABSX AND CYC(4) break;
520 case 0x3E: ABSX ROL_CMOS CYC(6) break;
521 case 0x3F: INV NOP CYC(2) break;
522 case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break;
523 case 0x41: INDX EOR CYC(6) break;
524 case 0x42: INV IMM NOP CYC(2) break;
525 case 0x43: INV NOP CYC(2) break;
526 case 0x44: INV ZPG NOP CYC(3) break;
527 case 0x45: ZPG EOR CYC(3) break;
528 case 0x46: ZPG LSR_CMOS CYC(5) break;
529 case 0x47: INV NOP CYC(2) break;
530 case 0x48: PHA CYC(3) break;
531 case 0x49: IMM EOR CYC(2) break;
532 case 0x4A: LSRA CYC(2) break;
533 case 0x4B: INV NOP CYC(2) break;
534 case 0x4C: ABS JMP CYC(3) break;
535 case 0x4D: ABS EOR CYC(4) break;
536 case 0x4E: ABS LSR_CMOS CYC(6) break;
537 case 0x4F: INV NOP CYC(2) break;
538 case 0x50: REL BVC CYC(2) break;
539 case 0x51: INDY EOR CYC(5) break;
540 case 0x52: IZPG EOR CYC(5) break;
541 case 0x53: INV NOP CYC(2) break;
542 case 0x54: INV ZPGX NOP CYC(4) break;
543 case 0x55: ZPGX EOR CYC(4) break;
544 case 0x56: ZPGX LSR_CMOS CYC(6) break;
545 case 0x57: INV NOP CYC(2) break;
546 case 0x58: CLI CYC(2) break;
547 case 0x59: ABSY EOR CYC(4) break;
548 case 0x5A: PHY CYC(3) break;
549 case 0x5B: INV NOP CYC(2) break;
550 case 0x5C: INV ABSX NOP CYC(8) break;
551 case 0x5D: ABSX EOR CYC(4) break;
552 case 0x5E: ABSX LSR_CMOS CYC(6) break;
553 case 0x5F: INV NOP CYC(2) break;
554 case 0x60: RTS CYC(6) break;
555 case 0x61: INDX ADC_CMOS CYC(6) break;
556 case 0x62: INV IMM NOP CYC(2) break;
557 case 0x63: INV NOP CYC(2) break;
558 case 0x64: ZPG STZ CYC(3) break;
559 case 0x65: ZPG ADC_CMOS CYC(3) break;
560 case 0x66: ZPG ROR_CMOS CYC(5) break;
561 case 0x67: INV NOP CYC(2) break;
562 case 0x68: PLA CYC(4) break;
563 case 0x69: IMM ADC_CMOS CYC(2) break;
564 case 0x6A: RORA CYC(2) break;
565 case 0x6B: INV NOP CYC(2) break;
566 case 0x6C: IABSCMOS JMP CYC(6) break;
567 case 0x6D: ABS ADC_CMOS CYC(4) break;
568 case 0x6E: ABS ROR_CMOS CYC(6) break;
569 case 0x6F: INV NOP CYC(2) break;
570 case 0x70: REL BVS CYC(2) break;
571 case 0x71: INDY ADC_CMOS CYC(5) break;
572 case 0x72: IZPG ADC_CMOS CYC(5) break;
573 case 0x73: INV NOP CYC(2) break;
574 case 0x74: ZPGX STZ CYC(4) break;
575 case 0x75: ZPGX ADC_CMOS CYC(4) break;
576 case 0x76: ZPGX ROR_CMOS CYC(6) break;
577 case 0x77: INV NOP CYC(2) break;
578 case 0x78: SEI CYC(2) break;
579 case 0x79: ABSY ADC_CMOS CYC(4) break;
580 case 0x7A: PLY CYC(4) break;
581 case 0x7B: INV NOP CYC(2) break;
582 case 0x7C: IABSX JMP CYC(6) break;
583 case 0x7D: ABSX ADC_CMOS CYC(4) break;
584 case 0x7E: ABSX ROR_CMOS CYC(6) break;
585 case 0x7F: INV NOP CYC(2) break;
586 case 0x80: REL BRA CYC(2) break;
587 case 0x81: INDX STA CYC(6) break;
588 case 0x82: INV IMM NOP CYC(2) break;
589 case 0x83: INV NOP CYC(2) break;
590 case 0x84: ZPG STY CYC(3) break;
591 case 0x85: ZPG STA CYC(3) break;
592 case 0x86: ZPG STX CYC(3) break;
593 case 0x87: INV NOP CYC(2) break;
594 case 0x88: DEY CYC(2) break;
595 case 0x89: IMM BITI CYC(2) break;
596 case 0x8A: TXA CYC(2) break;
597 case 0x8B: INV NOP CYC(2) break;
598 case 0x8C: ABS STY CYC(4) break;
599 case 0x8D: ABS STA CYC(4) break;
600 case 0x8E: ABS STX CYC(4) break;
601 case 0x8F: INV NOP CYC(2) break;
602 case 0x90: REL BCC CYC(2) break;
603 case 0x91: INDY STA CYC(6) break;
604 case 0x92: IZPG STA CYC(5) break;
605 case 0x93: INV NOP CYC(2) break;
606 case 0x94: ZPGX STY CYC(4) break;
607 case 0x95: ZPGX STA CYC(4) break;
608 case 0x96: ZPGY STX CYC(4) break;
609 case 0x97: INV NOP CYC(2) break;
610 case 0x98: TYA CYC(2) break;
611 case 0x99: ABSY STA CYC(5) break;
612 case 0x9A: TXS CYC(2) break;
613 case 0x9B: INV NOP CYC(2) break;
614 case 0x9C: ABS STZ CYC(4) break;
615 case 0x9D: ABSX STA CYC(5) break;
616 case 0x9E: ABSX STZ CYC(5) break;
617 case 0x9F: INV NOP CYC(2) break;
618 case 0xA0: IMM LDY CYC(2) break;
619 case 0xA1: INDX LDA CYC(6) break;
620 case 0xA2: IMM LDX CYC(2) break;
621 case 0xA3: INV NOP CYC(2) break;
622 case 0xA4: ZPG LDY CYC(3) break;
623 case 0xA5: ZPG LDA CYC(3) break;
624 case 0xA6: ZPG LDX CYC(3) break;
625 case 0xA7: INV NOP CYC(2) break;
626 case 0xA8: TAY CYC(2) break;
627 case 0xA9: IMM LDA CYC(2) break;
628 case 0xAA: TAX CYC(2) break;
629 case 0xAB: INV NOP CYC(2) break;
630 case 0xAC: ABS LDY CYC(4) break;
631 case 0xAD: ABS LDA CYC(4) break;
632 case 0xAE: ABS LDX CYC(4) break;
633 case 0xAF: INV NOP CYC(2) break;
634 case 0xB0: REL BCS CYC(2) break;
635 case 0xB1: INDY LDA CYC(5) break;
636 case 0xB2: IZPG LDA CYC(5) break;
637 case 0xB3: INV NOP CYC(2) break;
638 case 0xB4: ZPGX LDY CYC(4) break;
639 case 0xB5: ZPGX LDA CYC(4) break;
640 case 0xB6: ZPGY LDX CYC(4) break;
641 case 0xB7: INV NOP CYC(2) break;
642 case 0xB8: CLV CYC(2) break;
643 case 0xB9: ABSY LDA CYC(4) break;
644 case 0xBA: TSX CYC(2) break;
645 case 0xBB: INV NOP CYC(2) break;
646 case 0xBC: ABSX LDY CYC(4) break;
647 case 0xBD: ABSX LDA CYC(4) break;
648 case 0xBE: ABSY LDX CYC(4) break;
649 case 0xBF: INV NOP CYC(2) break;
650 case 0xC0: IMM CPY CYC(2) break;
651 case 0xC1: INDX CMP CYC(6) break;
652 case 0xC2: INV IMM NOP CYC(2) break;
653 case 0xC3: INV NOP CYC(2) break;
654 case 0xC4: ZPG CPY CYC(3) break;
655 case 0xC5: ZPG CMP CYC(3) break;
656 case 0xC6: ZPG DEC_CMOS CYC(5) break;
657 case 0xC7: INV NOP CYC(2) break;
658 case 0xC8: INY CYC(2) break;
659 case 0xC9: IMM CMP CYC(2) break;
660 case 0xCA: DEX CYC(2) break;
661 case 0xCB: INV NOP CYC(2) break;
662 case 0xCC: ABS CPY CYC(4) break;
663 case 0xCD: ABS CMP CYC(4) break;
664 case 0xCE: ABS DEC_CMOS CYC(5) break;
665 case 0xCF: INV NOP CYC(2) break;
666 case 0xD0: REL BNE CYC(2) break;
667 case 0xD1: INDY CMP CYC(5) break;
668 case 0xD2: IZPG CMP CYC(5) break;
669 case 0xD3: INV NOP CYC(2) break;
670 case 0xD4: INV ZPGX NOP CYC(4) break;
671 case 0xD5: ZPGX CMP CYC(4) break;
672 case 0xD6: ZPGX DEC_CMOS CYC(6) break;
673 case 0xD7: INV NOP CYC(2) break;
674 case 0xD8: CLD CYC(2) break;
675 case 0xD9: ABSY CMP CYC(4) break;
676 case 0xDA: PHX CYC(3) break;
677 case 0xDB: INV NOP CYC(2) break;
678 case 0xDC: INV ABSX NOP CYC(4) break;
679 case 0xDD: ABSX CMP CYC(4) break;
680 case 0xDE: ABSX DEC_CMOS CYC(6) break;
681 case 0xDF: INV NOP CYC(2) break;
682 case 0xE0: IMM CPX CYC(2) break;
683 case 0xE1: INDX SBC_CMOS CYC(6) break;
684 case 0xE2: INV IMM NOP CYC(2) break;
685 case 0xE3: INV NOP CYC(2) break;
686 case 0xE4: ZPG CPX CYC(3) break;
687 case 0xE5: ZPG SBC_CMOS CYC(3) break;
688 case 0xE6: ZPG INC_CMOS CYC(5) break;
689 case 0xE7: INV NOP CYC(2) break;
690 case 0xE8: INX CYC(2) break;
691 case 0xE9: IMM SBC_CMOS CYC(2) break;
692 case 0xEA: NOP CYC(2) break;
693 case 0xEB: INV NOP CYC(2) break;
694 case 0xEC: ABS CPX CYC(4) break;
695 case 0xED: ABS SBC_CMOS CYC(4) break;
696 case 0xEE: ABS INC_CMOS CYC(6) break;
697 case 0xEF: INV NOP CYC(2) break;
698 case 0xF0: REL BEQ CYC(2) break;
699 case 0xF1: INDY SBC_CMOS CYC(5) break;
700 case 0xF2: IZPG SBC_CMOS CYC(5) break;
701 case 0xF3: INV NOP CYC(2) break;
702 case 0xF4: INV ZPGX NOP CYC(4) break;
703 case 0xF5: ZPGX SBC_CMOS CYC(4) break;
704 case 0xF6: ZPGX INC_CMOS CYC(6) break;
705 case 0xF7: INV NOP CYC(2) break;
706 case 0xF8: SED CYC(2) break;
707 case 0xF9: ABSY SBC_CMOS CYC(4) break;
708 case 0xFA: PLX CYC(4) break;
709 case 0xFB: INV NOP CYC(2) break;
710 case 0xFC: INV ABSX NOP CYC(4) break;
711 case 0xFD: ABSX SBC_CMOS CYC(4) break;
712 case 0xFE: ABSX INC_CMOS CYC(6) break;
713 case 0xFF: INV NOP CYC(2) break;
716 // Private function prototypes
718 static uint16_t RdMemW(uint16_t);
719 static uint16_t FetchMemW(uint16_t addr);
722 // Read a uint16_t out of 65C02 memory (big endian format)
724 static inline uint16_t RdMemW(uint16_t address)
726 return (uint16_t)(regs.RdMem(address + 1) << 8) | regs.RdMem(address + 0);
730 // Read a uint16_t out of 65C02 memory (big endian format) and increment PC
732 static inline uint16_t FetchMemW(uint16_t address)
735 return (uint16_t)(regs.RdMem(address + 1) << 8) | regs.RdMem(address + 0);
740 // 65C02 OPCODE IMPLEMENTATION
742 // NOTE: Lots of macros are used here to save a LOT of typing. Also
743 // helps speed the debugging process. :-) Because of this, combining
744 // certain lines may look like a good idea but would end in disaster.
745 // You have been warned! ;-)
749 Mnemonic Addressing mode Form Opcode Size Timing
751 ADC Immediate ADC #Oper 69 2 2
752 Zero Page ADC Zpg 65 2 3
753 Zero Page,X ADC Zpg,X 75 2 4
754 Absolute ADC Abs 6D 3 4
755 Absolute,X ADC Abs,X 7D 3 4
756 Absolute,Y ADC Abs,Y 79 3 4
757 (Zero Page,X) ADC (Zpg,X) 61 2 6
758 (Zero Page),Y ADC (Zpg),Y 71 2 5
759 (Zero Page) ADC (Zpg) 72 2 5
764 //This is non-optimal, but it works--optimize later. :-)
765 #define OP_ADC_HANDLER(m) \
766 uint16_t sum = (uint16_t)regs.a + (m) + (uint16_t)(regs.cc & FLAG_C); \
768 if (regs.cc & FLAG_D) \
770 if ((sum & 0x0F) > 0x09) \
773 if ((sum & 0xF0) > 0x90) \
777 regs.cc = (regs.cc & ~FLAG_C) | (sum >> 8); \
778 regs.cc = (~(regs.a ^ (m)) & (regs.a ^ sum) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V); \
779 regs.a = sum & 0xFF; \
782 //OLD V detection: regs.cc = ((regs.a ^ (m) ^ sum ^ (regs.cc << 7)) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V);
784 static void Op69(void) // ADC #
786 uint16_t m = READ_IMM;
790 static void Op65(void) // ADC ZP
792 uint16_t m = READ_ZP;
796 static void Op75(void) // ADC ZP, X
798 uint16_t m = READ_ZP_X;
802 static void Op6D(void) // ADC ABS
804 uint16_t m = READ_ABS;
808 static void Op7D(void) // ADC ABS, X
810 uint16_t m = READ_ABS_X;
814 static void Op79(void) // ADC ABS, Y
816 uint16_t m = READ_ABS_Y;
820 static void Op61(void) // ADC (ZP, X)
822 uint16_t m = READ_IND_ZP_X;
826 static void Op71(void) // ADC (ZP), Y
828 uint16_t m = READ_IND_ZP_Y;
832 static void Op72(void) // ADC (ZP)
834 uint16_t m = READ_IND_ZP;
839 AND Immediate AND #Oper 29 2 2
840 Zero Page AND Zpg 25 2 3
841 Zero Page,X AND Zpg,X 35 2 4
842 Absolute AND Abs 2D 3 4
843 Absolute,X AND Abs,X 3D 3 4
844 Absolute,Y AND Abs,Y 39 3 4
845 (Zero Page,X) AND (Zpg,X) 21 2 6
846 (Zero Page),Y AND (Zpg),Y 31 2 5
847 (Zero Page) AND (Zpg) 32 2 5
852 #define OP_AND_HANDLER(m) \
856 static void Op29(void) // AND #
858 uint8_t m = READ_IMM;
862 static void Op25(void) // AND ZP
868 static void Op35(void) // AND ZP, X
870 uint8_t m = READ_ZP_X;
874 static void Op2D(void) // AND ABS
876 uint8_t m = READ_ABS;
880 static void Op3D(void) // AND ABS, X
882 uint8_t m = READ_ABS_X;
886 static void Op39(void) // AND ABS, Y
888 uint8_t m = READ_ABS_Y;
892 static void Op21(void) // AND (ZP, X)
894 uint8_t m = READ_IND_ZP_X;
898 static void Op31(void) // AND (ZP), Y
900 uint8_t m = READ_IND_ZP_Y;
904 static void Op32(void) // AND (ZP)
906 uint8_t m = READ_IND_ZP;
911 ASL Accumulator ASL A 0A 1 2
912 Zero Page ASL Zpg 06 2 5
913 Zero Page,X ASL Zpg,X 16 2 6
914 Absolute ASL Abs 0E 3 6
915 Absolute,X ASL Abs,X 1E 3 7
918 /*static void Op78(void) // LSL ABS
920 uint8_t tmp; uint16_t addr;
922 tmp = regs.RdMem(addr);
923 (tmp&0x80 ? regs.cc |= 0x01 : regs.cc &= 0xFE); // Shift hi bit into Carry
925 regs.WrMem(addr, tmp);
926 (tmp == 0 ? regs.cc |= 0x04 : regs.cc &= 0xFB); // Adjust Zero flag
927 (tmp&0x80 ? regs.cc |= 0x08 : regs.cc &= 0xF7); // Adjust Negative flag
932 #define OP_ASL_HANDLER(m) \
933 regs.cc = ((m) & 0x80 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
937 static void Op0A(void) // ASL A
939 OP_ASL_HANDLER(regs.a);
942 static void Op06(void) // ASL ZP
950 static void Op16(void) // ASL ZP, X
958 static void Op0E(void) // ASL ABS
966 static void Op1E(void) // ASL ABS, X
975 BBR0 Relative BBR0 Oper 0F 2 2
976 BBR1 Relative BBR1 Oper 1F 2 2
977 BBR2 Relative BBR2 Oper 2F 2 2
978 BBR3 Relative BBR3 Oper 3F 2 2
979 BBR4 Relative BBR4 Oper 4F 2 2
980 BBR5 Relative BBR5 Oper 5F 2 2
981 BBR6 Relative BBR6 Oper 6F 2 2
982 BBR7 Relative BBR7 Oper 7F 2 2
983 BBS0 Relative BBS0 Oper 8F 2 2
984 BBS1 Relative BBS1 Oper 9F 2 2
985 BBS2 Relative BBS2 Oper AF 2 2
986 BBS3 Relative BBS3 Oper BF 2 2
987 BBS4 Relative BBS4 Oper CF 2 2
988 BBS5 Relative BBS5 Oper DF 2 2
989 BBS6 Relative BBS6 Oper EF 2 2
990 BBS7 Relative BBS7 Oper FF 2 2
995 static void Op0F(void) // BBR0
997 int16_t m = (int16_t)(int8_t)READ_IMM;
999 if (!(regs.a & 0x01))
1003 static void Op1F(void) // BBR1
1005 int16_t m = (int16_t)(int8_t)READ_IMM;
1007 if (!(regs.a & 0x02))
1011 static void Op2F(void) // BBR2
1013 int16_t m = (int16_t)(int8_t)READ_IMM;
1015 if (!(regs.a & 0x04))
1019 static void Op3F(void) // BBR3
1021 int16_t m = (int16_t)(int8_t)READ_IMM;
1023 if (!(regs.a & 0x08))
1027 static void Op4F(void) // BBR4
1029 int16_t m = (int16_t)(int8_t)READ_IMM;
1031 if (!(regs.a & 0x10))
1035 static void Op5F(void) // BBR5
1037 int16_t m = (int16_t)(int8_t)READ_IMM;
1039 if (!(regs.a & 0x20))
1043 static void Op6F(void) // BBR6
1045 int16_t m = (int16_t)(int8_t)READ_IMM;
1047 if (!(regs.a & 0x40))
1051 static void Op7F(void) // BBR7
1053 int16_t m = (int16_t)(int8_t)READ_IMM;
1055 if (!(regs.a & 0x80))
1059 static void Op8F(void) // BBS0
1061 int16_t m = (int16_t)(int8_t)READ_IMM;
1067 static void Op9F(void) // BBS1
1069 int16_t m = (int16_t)(int8_t)READ_IMM;
1075 static void OpAF(void) // BBS2
1077 int16_t m = (int16_t)(int8_t)READ_IMM;
1083 static void OpBF(void) // BBS3
1085 int16_t m = (int16_t)(int8_t)READ_IMM;
1091 static void OpCF(void) // BBS4
1093 int16_t m = (int16_t)(int8_t)READ_IMM;
1099 static void OpDF(void) // BBS5
1101 int16_t m = (int16_t)(int8_t)READ_IMM;
1107 static void OpEF(void) // BBS6
1109 int16_t m = (int16_t)(int8_t)READ_IMM;
1115 static void OpFF(void) // BBS7
1117 int16_t m = (int16_t)(int8_t)READ_IMM;
1124 BCC Relative BCC Oper 90 2 2
1125 BCS Relative BCS Oper B0 2 2
1126 BEQ Relative BEQ Oper F0 2 2
1129 // Branch taken adds a cycle, crossing page adds one more
1131 #define HANDLE_BRANCH_TAKEN(m) \
1133 uint16_t oldpc = regs.pc; \
1137 if ((oldpc ^ regs.pc) & 0xFF00) \
1143 static void Op90(void) // BCC
1145 int16_t m = (int16_t)(int8_t)READ_IMM;
1147 if (!(regs.cc & FLAG_C))
1148 HANDLE_BRANCH_TAKEN(m)
1151 static void OpB0(void) // BCS
1153 int16_t m = (int16_t)(int8_t)READ_IMM;
1155 if (regs.cc & FLAG_C)
1156 HANDLE_BRANCH_TAKEN(m)
1159 static void OpF0(void) // BEQ
1161 int16_t m = (int16_t)(int8_t)READ_IMM;
1163 if (regs.cc & FLAG_Z)
1164 HANDLE_BRANCH_TAKEN(m)
1168 BIT Immediate BIT #Oper 89 2 2
1169 Zero Page BIT Zpg 24 2 3
1170 Zero Page,X BIT Zpg,X 34 2 4
1171 Absolute BIT Abs 2C 3 4
1172 Absolute,X BIT Abs,X 3C 3 4
1177 /* 1. The BIT instruction copies bit 6 to the V flag, and bit 7 to the N flag (except in immediate
1178 addressing mode where V & N are untouched.) The accumulator and the operand are ANDed and the
1179 Z flag is set appropriately. */
1181 #define OP_BIT_HANDLER(m) \
1182 int8_t result = regs.a & (m); \
1183 regs.cc &= ~(FLAG_N | FLAG_V); \
1184 regs.cc |= ((m) & 0xC0); \
1187 static void Op89(void) // BIT #
1189 int8_t m = READ_IMM;
1190 int8_t result = regs.a & m;
1194 static void Op24(void) // BIT ZP
1200 static void Op34(void) // BIT ZP, X
1202 uint8_t m = READ_ZP_X;
1206 static void Op2C(void) // BIT ABS
1208 uint8_t m = READ_ABS;
1212 static void Op3C(void) // BIT ABS, X
1214 uint8_t m = READ_ABS_X;
1219 BMI Relative BMI Oper 30 2 2
1220 BNE Relative BNE Oper D0 2 2
1221 BPL Relative BPL Oper 10 2 2
1222 BRA Relative BRA Oper 80 2 3
1225 // More branch opcodes
1227 static void Op30(void) // BMI
1229 int16_t m = (int16_t)(int8_t)READ_IMM;
1231 if (regs.cc & FLAG_N)
1232 HANDLE_BRANCH_TAKEN(m)
1236 static void OpD0(void) // BNE
1238 int16_t m = (int16_t)(int8_t)READ_IMM;
1240 if (!(regs.cc & FLAG_Z))
1241 HANDLE_BRANCH_TAKEN(m)
1245 static void Op10(void) // BPL
1247 int16_t m = (int16_t)(int8_t)READ_IMM;
1249 if (!(regs.cc & FLAG_N))
1250 HANDLE_BRANCH_TAKEN(m)
1254 static void Op80(void) // BRA
1256 int16_t m = (int16_t)(int8_t)READ_IMM;
1257 HANDLE_BRANCH_TAKEN(m)
1262 BRK Implied BRK 00 1 7
1265 static void Op00(void) // BRK
1269 WriteLog("\n*** BRK ***\n\n");
1270 WriteLog(" [PC=%04X, SP=%04X, CC=%s%s.%s%s%s%s%s, A=%02X, X=%02X, Y=%02X]\n",
1271 regs.pc, 0x0100 + regs.sp,
1272 (regs.cc & FLAG_N ? "N" : "-"), (regs.cc & FLAG_V ? "V" : "-"),
1273 (regs.cc & FLAG_B ? "B" : "-"), (regs.cc & FLAG_D ? "D" : "-"),
1274 (regs.cc & FLAG_I ? "I" : "-"), (regs.cc & FLAG_Z ? "Z" : "-"),
1275 (regs.cc & FLAG_C ? "C" : "-"), regs.a, regs.x, regs.y);
1277 regs.cc |= FLAG_B; // Set B
1278 regs.pc++; // RTI comes back to the instruction one byte after the BRK
1279 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8); // Save PC and CC
1280 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
1281 regs.WrMem(0x0100 + regs.sp--, regs.cc);
1282 regs.cc |= FLAG_I; // Set I
1283 regs.cc &= ~FLAG_D; // & clear D
1284 regs.pc = RdMemW(0xFFFE); // Grab the IRQ vector & go...
1288 BVC Relative BVC Oper 50 2 2
1289 BVS Relative BVS Oper 70 2 2
1292 // Even more branch opcodes
1294 static void Op50(void) // BVC
1296 int16_t m = (int16_t)(int8_t)READ_IMM;
1298 if (!(regs.cc & FLAG_V))
1299 HANDLE_BRANCH_TAKEN(m)
1303 static void Op70(void) // BVS
1305 int16_t m = (int16_t)(int8_t)READ_IMM;
1307 if (regs.cc & FLAG_V)
1308 HANDLE_BRANCH_TAKEN(m)
1313 CLC Implied CLC 18 1 2
1316 static void Op18(void) // CLC
1322 CLD Implied CLD D8 1 2
1325 static void OpD8(void) // CLD
1331 CLI Implied CLI 58 1 2
1334 static void Op58(void) // CLI
1340 CLV Implied CLV B8 1 2
1343 static void OpB8(void) // CLV
1349 CMP Immediate CMP #Oper C9 2 2
1350 Zero Page CMP Zpg C5 2 3
1351 Zero Page,X CMP Zpg D5 2 4
1352 Absolute CMP Abs CD 3 4
1353 Absolute,X CMP Abs,X DD 3 4
1354 Absolute,Y CMP Abs,Y D9 3 4
1355 (Zero Page,X) CMP (Zpg,X) C1 2 6
1356 (Zero Page),Y CMP (Zpg),Y D1 2 5
1357 (Zero Page) CMP (Zpg) D2 2 5
1363 Here's the latest: The CMP is NOT generating the Z flag when A=$C0!
1365 FABA: A0 07 LDY #$07 [PC=FABC, SP=01FF, CC=---B-IZ-, A=00, X=00, Y=07]
1366 FABC: C6 01 DEC $01 [PC=FABE, SP=01FF, CC=N--B-I--, A=00, X=00, Y=07]
1367 FABE: A5 01 LDA $01 [PC=FAC0, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
1368 FAC0: C9 C0 CMP #$C0 [PC=FAC2, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
1369 FAC2: F0 D7 BEQ $FA9B [PC=FAC4, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
1370 FAC4: 8D F8 07 STA $07F8 [PC=FAC7, SP=01FF, CC=N--B-I--, A=C0, X=00, Y=07]
1371 FAC7: B1 00 LDA ($00),Y
1372 *** Read at I/O address C007
1373 [PC=FAC9, SP=01FF, CC=---B-IZ-, A=00, X=00, Y=07]
1374 FAC9: D9 01 FB CMP $FB01,Y [PC=FACC, SP=01FF, CC=---B-I--, A=00, X=00, Y=07]
1375 FACC: D0 EC BNE $FABA [PC=FABA, SP=01FF, CC=---B-I--, A=00, X=00, Y=07]
1377 Should be fixed now... (was adding instead of subtracting!)
1379 Small problem here... First two should set the carry while the last one should clear it. !!! FIX !!! [DONE]
1381 FDF0: C9 A0 CMP #$A0 [PC=FDF2, SP=01F1, CC=---B-IZ-, A=A0, X=02, Y=03]
1382 FD7E: C9 E0 CMP #$E0 [PC=FD80, SP=01F4, CC=N--B-I--, A=A0, X=02, Y=03]
1383 FD38: C9 9B CMP #$9B [PC=FD3A, SP=01F2, CC=---B-I-C, A=A0, X=02, Y=03]
1385 Compare sets flags as if a subtraction had been carried out. If the value in the accumulator is equal or greater than the compared value, the Carry will be set. The equal (Z) and sign (S) flags will be set based on equality or lack thereof and the sign (i.e. A>=$80) of the accumulator.
1388 #define OP_CMP_HANDLER(m) \
1389 uint8_t result = regs.a - (m); \
1390 SET_ZNC_CMP(m, regs.a, result)
1392 static void OpC9(void) // CMP #
1394 uint8_t m = READ_IMM;
1398 static void OpC5(void) // CMP ZP
1400 uint8_t m = READ_ZP;
1404 static void OpD5(void) // CMP ZP, X
1406 uint8_t m = READ_ZP_X;
1410 static void OpCD(void) // CMP ABS
1412 uint8_t m = READ_ABS;
1416 static void OpDD(void) // CMP ABS, X
1418 uint8_t m = READ_ABS_X;
1422 static void OpD9(void) // CMP ABS, Y
1424 uint8_t m = READ_ABS_Y;
1428 static void OpC1(void) // CMP (ZP, X)
1430 uint8_t m = READ_IND_ZP_X;
1434 static void OpD1(void) // CMP (ZP), Y
1436 uint8_t m = READ_IND_ZP_Y;
1440 static void OpD2(void) // CMP (ZP)
1442 uint8_t m = READ_IND_ZP;
1447 CPX Immediate CPX #Oper E0 2 2
1448 Zero Page CPX Zpg E4 2 3
1449 Absolute CPX Abs EC 3 4
1454 #define OP_CPX_HANDLER(m) \
1455 uint8_t result = regs.x - (m); \
1456 SET_ZNC_CMP(m, regs.x, result)
1458 static void OpE0(void) // CPX #
1460 uint8_t m = READ_IMM;
1464 static void OpE4(void) // CPX ZP
1466 uint8_t m = READ_ZP;
1470 static void OpEC(void) // CPX ABS
1472 uint8_t m = READ_ABS;
1477 CPY Immediate CPY #Oper C0 2 2
1478 Zero Page CPY Zpg C4 2 3
1479 Absolute CPY Abs CC 3 4
1484 #define OP_CPY_HANDLER(m) \
1485 uint8_t result = regs.y - (m); \
1486 SET_ZNC_CMP(m, regs.y, result)
1488 static void OpC0(void) // CPY #
1490 uint8_t m = READ_IMM;
1494 static void OpC4(void) // CPY ZP
1496 uint8_t m = READ_ZP;
1500 static void OpCC(void) // CPY ABS
1502 uint8_t m = READ_ABS;
1507 DEA Accumulator DEA 3A 1 2
1510 static void Op3A(void) // DEA
1517 DEC Zero Page DEC Zpg C6 2 5
1518 Zero Page,X DEC Zpg,X D6 2 6
1519 Absolute DEC Abs CE 3 6
1520 Absolute,X DEC Abs,X DE 3 7
1525 #define OP_DEC_HANDLER(m) \
1529 static void OpC6(void) // DEC ZP
1537 static void OpD6(void) // DEC ZP, X
1545 static void OpCE(void) // DEC ABS
1553 static void OpDE(void) // DEC ABS, X
1562 Here's one problem: DEX is setting the N flag!
1564 D3EE: A2 09 LDX #$09 [PC=D3F0, SP=01F7, CC=---B-I-C, A=01, X=09, Y=08]
1565 D3F0: 98 TYA [PC=D3F1, SP=01F7, CC=N--B-I-C, A=08, X=09, Y=08]
1566 D3F1: 48 PHA [PC=D3F2, SP=01F6, CC=N--B-I-C, A=08, X=09, Y=08]
1567 D3F2: B5 93 LDA $93,X [PC=D3F4, SP=01F6, CC=---B-IZC, A=00, X=09, Y=08]
1568 D3F4: CA DEX [PC=D3F5, SP=01F6, CC=N--B-I-C, A=00, X=08, Y=08]
1569 D3F5: 10 FA BPL $D3F1 [PC=D3F7, SP=01F6, CC=N--B-I-C, A=00, X=08, Y=08]
1570 D3F7: 20 84 E4 JSR $E484 [PC=E484, SP=01F4, CC=N--B-I-C, A=00, X=08, Y=08]
1572 should be fixed now...
1576 DEX Implied DEX CA 1 2
1579 static void OpCA(void) // DEX
1586 DEY Implied DEY 88 1 2
1589 static void Op88(void) // DEY
1596 EOR Immediate EOR #Oper 49 2 2
1597 Zero Page EOR Zpg 45 2 3
1598 Zero Page,X EOR Zpg,X 55 2 4
1599 Absolute EOR Abs 4D 3 4
1600 Absolute,X EOR Abs,X 5D 3 4
1601 Absolute,Y EOR Abs,Y 59 3 4
1602 (Zero Page,X) EOR (Zpg,X) 41 2 6
1603 (Zero Page),Y EOR (Zpg),Y 51 2 5
1604 (Zero Page) EOR (Zpg) 52 2 5
1609 #define OP_EOR_HANDLER(m) \
1613 static void Op49(void) // EOR #
1615 uint8_t m = READ_IMM;
1619 static void Op45(void) // EOR ZP
1621 uint8_t m = READ_ZP;
1625 static void Op55(void) // EOR ZP, X
1627 uint8_t m = READ_ZP_X;
1631 static void Op4D(void) // EOR ABS
1633 uint8_t m = READ_ABS;
1637 static void Op5D(void) // EOR ABS, X
1639 uint8_t m = READ_ABS_X;
1643 static void Op59(void) // EOR ABS, Y
1645 uint8_t m = READ_ABS_Y;
1649 static void Op41(void) // EOR (ZP, X)
1651 uint8_t m = READ_IND_ZP_X;
1655 static void Op51(void) // EOR (ZP), Y
1657 uint8_t m = READ_IND_ZP_Y;
1661 static void Op52(void) // EOR (ZP)
1663 uint8_t m = READ_IND_ZP;
1668 INA Accumulator INA 1A 1 2
1671 static void Op1A(void) // INA
1678 INC Zero Page INC Zpg E6 2 5
1679 Zero Page,X INC Zpg,X F6 2 6
1680 Absolute INC Abs EE 3 6
1681 Absolute,X INC Abs,X FE 3 7
1686 #define OP_INC_HANDLER(m) \
1690 static void OpE6(void) // INC ZP
1698 static void OpF6(void) // INC ZP, X
1706 static void OpEE(void) // INC ABS
1714 static void OpFE(void) // INC ABS, X
1723 INX Implied INX E8 1 2
1726 static void OpE8(void) // INX
1733 INY Implied INY C8 1 2
1736 static void OpC8(void) // INY
1743 JMP Absolute JMP Abs 4C 3 3
1744 (Absolute) JMP (Abs) 6C 3 5
1745 (Absolute,X) JMP (Abs,X) 7C 3 6
1750 static void Op4C(void) // JMP ABS
1752 regs.pc = RdMemW(regs.pc);
1755 static void Op6C(void) // JMP (ABS)
1757 // uint16_t addr = RdMemW(regs.pc);
1759 //WriteLog("\n[JMP ABS]: addr fetched = %04X, bytes at %04X = %02X %02X (RdMemw=%04X)\n",
1760 // addr, addr, regs.RdMem(addr), regs.RdMem(addr+1), RdMemW(addr));
1762 // addr = RdMemW(addr);
1763 regs.pc = RdMemW(RdMemW(regs.pc));
1766 static void Op7C(void) // JMP (ABS, X)
1768 regs.pc = RdMemW(RdMemW(regs.pc) + regs.x);
1772 JSR Absolute JSR Abs 20 3 6
1775 //This is not jumping to the correct address... !!! FIX !!! [DONE]
1776 static void Op20(void) // JSR
1778 uint16_t addr = RdMemW(regs.pc);
1779 regs.pc++; // Since it pushes return address - 1...
1780 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8);
1781 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
1786 LDA Immediate LDA #Oper A9 2 2
1787 Zero Page LDA Zpg A5 2 3
1788 Zero Page,X LDA Zpg,X B5 2 4
1789 Absolute LDA Abs AD 3 4
1790 Absolute,X LDA Abs,X BD 3 4
1791 Absolute,Y LDA Abs,Y B9 3 4
1792 (Zero Page,X) LDA (Zpg,X) A1 2 6
1793 (Zero Page),Y LDA (Zpg),Y B1 2 5
1794 (Zero Page) LDA (Zpg) B2 2 5
1799 #define OP_LDA_HANDLER(m) \
1803 static void OpA9(void) // LDA #
1805 uint8_t m = READ_IMM;
1809 static void OpA5(void) // LDA ZP
1811 uint8_t m = READ_ZP;
1815 static void OpB5(void) // LDA ZP, X
1817 uint8_t m = READ_ZP_X;
1821 static void OpAD(void) // LDA ABS
1823 uint8_t m = READ_ABS;
1827 static void OpBD(void) // LDA ABS, X
1829 uint8_t m = READ_ABS_X;
1833 static void OpB9(void) // LDA ABS, Y
1835 uint8_t m = READ_ABS_Y;
1839 static void OpA1(void) // LDA (ZP, X)
1841 uint8_t m = READ_IND_ZP_X;
1845 static void OpB1(void) // LDA (ZP), Y
1847 uint8_t m = READ_IND_ZP_Y;
1851 static void OpB2(void) // LDA (ZP)
1853 uint8_t m = READ_IND_ZP;
1858 LDX Immediate LDX #Oper A2 2 2
1859 Zero Page LDX Zpg A6 2 3
1860 Zero Page,Y LDX Zpg,Y B6 2 4
1861 Absolute LDX Abs AE 3 4
1862 Absolute,Y LDX Abs,Y BE 3 4
1867 #define OP_LDX_HANDLER(m) \
1871 static void OpA2(void) // LDX #
1873 uint8_t m = READ_IMM;
1877 static void OpA6(void) // LDX ZP
1879 uint8_t m = READ_ZP;
1883 static void OpB6(void) // LDX ZP, Y
1885 uint8_t m = READ_ZP_Y;
1889 static void OpAE(void) // LDX ABS
1891 uint8_t m = READ_ABS;
1895 static void OpBE(void) // LDX ABS, Y
1897 uint8_t m = READ_ABS_Y;
1902 LDY Immediate LDY #Oper A0 2 2
1903 Zero Page LDY Zpg A4 2 3
1904 Zero Page,Y LDY Zpg,X B4 2 4
1905 Absolute LDY Abs AC 3 4
1906 Absolute,Y LDY Abs,X BC 3 4
1911 #define OP_LDY_HANDLER(m) \
1915 static void OpA0(void) // LDY #
1917 uint8_t m = READ_IMM;
1921 static void OpA4(void) // LDY ZP
1923 uint8_t m = READ_ZP;
1927 static void OpB4(void) // LDY ZP, X
1929 uint8_t m = READ_ZP_X;
1933 static void OpAC(void) // LDY ABS
1935 uint8_t m = READ_ABS;
1939 static void OpBC(void) // LDY ABS, X
1941 uint8_t m = READ_ABS_X;
1946 LSR Accumulator LSR A 4A 1 2
1947 Zero Page LSR Zpg 46 2 5
1948 Zero Page,X LSR Zpg,X 56 2 6
1949 Absolute LSR Abs 4E 3 6
1950 Absolute,X LSR Abs,X 5E 3 7
1955 #define OP_LSR_HANDLER(m) \
1956 regs.cc = ((m) & 0x01 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
1960 static void Op4A(void) // LSR A
1962 OP_LSR_HANDLER(regs.a);
1965 static void Op46(void) // LSR ZP
1973 static void Op56(void) // LSR ZP, X
1981 static void Op4E(void) // LSR ABS
1989 static void Op5E(void) // LSR ABS, X
1998 NOP Implied NOP EA 1 2
2001 static void OpEA(void) // NOP
2006 ORA Immediate ORA #Oper 09 2 2
2007 Zero Page ORA Zpg 05 2 3
2008 Zero Page,X ORA Zpg,X 15 2 4
2009 Absolute ORA Abs 0D 3 4
2010 Absolute,X ORA Abs,X 1D 3 4
2011 Absolute,Y ORA Abs,Y 19 3 4
2012 (Zero Page,X) ORA (Zpg,X) 01 2 6
2013 (Zero Page),Y ORA (Zpg),Y 11 2 5
2014 (Zero Page) ORA (Zpg) 12 2 5
2019 #define OP_ORA_HANDLER(m) \
2023 static void Op09(void) // ORA #
2025 uint8_t m = READ_IMM;
2029 static void Op05(void) // ORA ZP
2031 uint8_t m = READ_ZP;
2035 static void Op15(void) // ORA ZP, X
2037 uint8_t m = READ_ZP_X;
2041 static void Op0D(void) // ORA ABS
2043 uint8_t m = READ_ABS;
2047 static void Op1D(void) // ORA ABS, X
2049 uint8_t m = READ_ABS_X;
2053 static void Op19(void) // ORA ABS, Y
2055 uint8_t m = READ_ABS_Y;
2059 static void Op01(void) // ORA (ZP, X)
2061 uint8_t m = READ_IND_ZP_X;
2065 static void Op11(void) // ORA (ZP), Y
2067 uint8_t m = READ_IND_ZP_Y;
2071 static void Op12(void) // ORA (ZP)
2073 uint8_t m = READ_IND_ZP;
2078 PHA Implied PHA 48 1 3
2081 static void Op48(void) // PHA
2083 regs.WrMem(0x0100 + regs.sp--, regs.a);
2086 static void Op08(void) // PHP
2088 regs.cc |= FLAG_UNK; // Make sure that the unused bit is always set
2089 regs.WrMem(0x0100 + regs.sp--, regs.cc);
2093 PHX Implied PHX DA 1 3
2096 static void OpDA(void) // PHX
2098 regs.WrMem(0x0100 + regs.sp--, regs.x);
2102 PHY Implied PHY 5A 1 3
2105 static void Op5A(void) // PHY
2107 regs.WrMem(0x0100 + regs.sp--, regs.y);
2111 PLA Implied PLA 68 1 4
2114 static void Op68(void) // PLA
2116 regs.a = regs.RdMem(0x0100 + ++regs.sp);
2120 static void Op28(void) // PLP
2122 regs.cc = regs.RdMem(0x0100 + ++regs.sp);
2126 PLX Implied PLX FA 1 4
2129 static void OpFA(void) // PLX
2131 regs.x = regs.RdMem(0x0100 + ++regs.sp);
2136 PLY Implied PLY 7A 1 4
2139 static void Op7A(void) // PLY
2141 regs.y = regs.RdMem(0x0100 + ++regs.sp);
2146 The bit set and clear instructions have the form xyyy0111, where x is 0 to clear a bit or 1 to set it, and yyy is which bit at the memory location to set or clear.
2147 RMB0 RMB1 RMB2 RMB3 RMB4 RMB5 RMB6 RMB7
2148 zp 07 17 27 37 47 57 67 77
2149 SMB0 SMB1 SMB2 SMB3 SMB4 SMB5 SMB6 SMB7
2150 zp 87 97 A7 B7 C7 D7 E7 F7
2155 static void Op07(void) // RMB0 ZP
2163 static void Op17(void) // RMB1 ZP
2171 static void Op27(void) // RMB2 ZP
2179 static void Op37(void) // RMB3 ZP
2187 static void Op47(void) // RMB4 ZP
2195 static void Op57(void) // RMB5 ZP
2203 static void Op67(void) // RMB6 ZP
2211 static void Op77(void) // RMB7 ZP
2220 ROL Accumulator ROL A 2A 1 2
2221 Zero Page ROL Zpg 26 2 5
2222 Zero Page,X ROL Zpg,X 36 2 6
2223 Absolute ROL Abs 2E 3 6
2224 Absolute,X ROL Abs,X 3E 3 7
2229 #define OP_ROL_HANDLER(m) \
2230 uint8_t tmp = regs.cc & 0x01; \
2231 regs.cc = ((m) & 0x80 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
2232 (m) = ((m) << 1) | tmp; \
2235 static void Op2A(void) // ROL A
2237 OP_ROL_HANDLER(regs.a);
2240 static void Op26(void) // ROL ZP
2248 static void Op36(void) // ROL ZP, X
2256 static void Op2E(void) // ROL ABS
2264 static void Op3E(void) // ROL ABS, X
2273 ROR Accumulator ROR A 6A 1 2
2274 Zero Page ROR Zpg 66 2 5
2275 Zero Page,X ROR Zpg,X 76 2 6
2276 Absolute ROR Abs 6E 3 6
2277 Absolute,X ROR Abs,X 7E 3 7
2282 #define OP_ROR_HANDLER(m) \
2283 uint8_t tmp = (regs.cc & 0x01) << 7; \
2284 regs.cc = ((m) & 0x01 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C); \
2285 (m) = ((m) >> 1) | tmp; \
2288 static void Op6A(void) // ROR A
2290 OP_ROR_HANDLER(regs.a);
2293 static void Op66(void) // ROR ZP
2301 static void Op76(void) // ROR ZP, X
2309 static void Op6E(void) // ROR ABS
2317 static void Op7E(void) // ROR ABS, X
2326 RTI Implied RTI 40 1 6
2329 static void Op40(void) // RTI
2331 regs.cc = regs.RdMem(0x0100 + ++regs.sp);
2332 //clear I (seems to be the case, either that or clear it in the IRQ setup...)
2333 //I can't find *any* verification that this is the case.
2334 // regs.cc &= ~FLAG_I;
2335 regs.pc = regs.RdMem(0x0100 + ++regs.sp);
2336 regs.pc |= (uint16_t)(regs.RdMem(0x0100 + ++regs.sp)) << 8;
2340 RTS Implied RTS 60 1 6
2343 static void Op60(void) // RTS
2345 regs.pc = regs.RdMem(0x0100 + ++regs.sp);
2346 regs.pc |= (uint16_t)(regs.RdMem(0x0100 + ++regs.sp)) << 8;
2347 regs.pc++; // Since it pushes return address - 1...
2348 //printf("*** RTS: PC = $%04X, SP= $1%02X\n", regs.pc, regs.sp);
2353 SBC Immediate SBC #Oper E9 2 2
2354 Zero Page SBC Zpg E5 2 3
2355 Zero Page,X SBC Zpg,X F5 2 4
2356 Absolute SBC Abs ED 3 4
2357 Absolute,X SBC Abs,X FD 3 4
2358 Absolute,Y SBC Abs,Y F9 3 4
2359 (Zero Page,X) SBC (Zpg,X) E1 2 6
2360 (Zero Page),Y SBC (Zpg),Y F1 2 5
2361 (Zero Page) SBC (Zpg) F2 2 5
2366 //This is non-optimal, but it works--optimize later. :-)
2367 //This is correct except for the BCD handling... !!! FIX !!! [Possibly DONE]
2368 #define OP_SBC_HANDLER(m) \
2369 uint16_t sum = (uint16_t)regs.a - (m) - (uint16_t)((regs.cc & FLAG_C) ^ 0x01); \
2371 if (regs.cc & FLAG_D) \
2373 if ((sum & 0x0F) > 0x09) \
2376 if ((sum & 0xF0) > 0x90) \
2380 regs.cc = (regs.cc & ~FLAG_C) | (((sum >> 8) ^ 0x01) & FLAG_C); \
2381 regs.cc = ((regs.a ^ (m)) & (regs.a ^ sum) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V); \
2382 regs.a = sum & 0xFF; \
2386 D5AF: 38 SEC [PC=D5B0, SP=01F6, CC=---B-I-C, A=4C, X=00, Y=06]
2388 *** HERE'S where it sets the D flag on a subtract... Arg!
2390 D5B0: F1 9D SBC ($9D),Y [PC=D5B2, SP=01F6, CC=N--BDI--, A=FE, X=00, Y=06]
2395 //OLD V detection: regs.cc = ((regs.a ^ (m) ^ sum ^ (regs.cc << 7)) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V);
2397 static void OpE9(void) // SBC #
2399 uint16_t m = READ_IMM;
2403 static void OpE5(void) // SBC ZP
2405 uint16_t m = READ_ZP;
2409 static void OpF5(void) // SBC ZP, X
2411 uint16_t m = READ_ZP_X;
2415 static void OpED(void) // SBC ABS
2417 uint16_t m = READ_ABS;
2421 static void OpFD(void) // SBC ABS, X
2423 uint16_t m = READ_ABS_X;
2427 static void OpF9(void) // SBC ABS, Y
2429 uint16_t m = READ_ABS_Y;
2433 static void OpE1(void) // SBC (ZP, X)
2435 uint16_t m = READ_IND_ZP_X;
2439 static void OpF1(void) // SBC (ZP), Y
2441 uint16_t m = READ_IND_ZP_Y;
2445 static void OpF2(void) // SBC (ZP)
2447 uint16_t m = READ_IND_ZP;
2452 SEC Implied SEC 38 1 2
2455 static void Op38(void) // SEC
2461 SED Implied SED F8 1 2
2464 static void OpF8(void) // SED
2470 SEI Implied SEI 78 1 2
2473 static void Op78(void) // SEI
2479 The bit set and clear instructions have the form xyyy0111, where x is 0 to clear a bit or 1 to set it, and yyy is which bit at the memory location to set or clear.
2480 RMB0 RMB1 RMB2 RMB3 RMB4 RMB5 RMB6 RMB7
2481 zp 07 17 27 37 47 57 67 77
2482 SMB0 SMB1 SMB2 SMB3 SMB4 SMB5 SMB6 SMB7
2483 zp 87 97 A7 B7 C7 D7 E7 F7
2488 static void Op87(void) // SMB0 ZP
2496 static void Op97(void) // SMB1 ZP
2504 static void OpA7(void) // SMB2 ZP
2512 static void OpB7(void) // SMB3 ZP
2520 static void OpC7(void) // SMB4 ZP
2528 static void OpD7(void) // SMB5 ZP
2536 static void OpE7(void) // SMB6 ZP
2544 static void OpF7(void) // SMB7 ZP
2553 STA Zero Page STA Zpg 85 2 3
2554 Zero Page,X STA Zpg,X 95 2 4
2555 Absolute STA Abs 8D 3 4
2556 Absolute,X STA Abs,X 9D 3 5
2557 Absolute,Y STA Abs,Y 99 3 5
2558 (Zero Page,X) STA (Zpg,X) 81 2 6
2559 (Zero Page),Y STA (Zpg),Y 91 2 6
2560 (Zero Page) STA (Zpg) 92 2 5
2565 static void Op85(void)
2567 regs.WrMem(EA_ZP, regs.a);
2570 static void Op95(void)
2572 regs.WrMem(EA_ZP_X, regs.a);
2575 static void Op8D(void)
2577 regs.WrMem(EA_ABS, regs.a);
2580 static void Op9D(void)
2582 regs.WrMem(EA_ABS_X, regs.a);
2585 static void Op99(void)
2587 regs.WrMem(EA_ABS_Y, regs.a);
2590 static void Op81(void)
2592 regs.WrMem(EA_IND_ZP_X, regs.a);
2595 static void Op91(void)
2597 regs.WrMem(EA_IND_ZP_Y, regs.a);
2600 static void Op92(void)
2602 regs.WrMem(EA_IND_ZP, regs.a);
2606 STX Zero Page STX Zpg 86 2 3
2607 Zero Page,Y STX Zpg,Y 96 2 4
2608 Absolute STX Abs 8E 3 4
2613 static void Op86(void)
2615 regs.WrMem(EA_ZP, regs.x);
2618 static void Op96(void)
2621 //WAS: regs.WrMem(EA_ZP_X, regs.x);
2622 regs.WrMem(EA_ZP_Y, regs.x);
2625 static void Op8E(void)
2627 regs.WrMem(EA_ABS, regs.x);
2631 STY Zero Page STY Zpg 84 2 3
2632 Zero Page,X STY Zpg,X 94 2 4
2633 Absolute STY Abs 8C 3 4
2638 static void Op84(void)
2640 regs.WrMem(EA_ZP, regs.y);
2643 static void Op94(void)
2645 regs.WrMem(EA_ZP_X, regs.y);
2648 static void Op8C(void)
2650 regs.WrMem(EA_ABS, regs.y);
2654 STZ Zero Page STZ Zpg 64 2 3
2655 Zero Page,X STZ Zpg,X 74 2 4
2656 Absolute STZ Abs 9C 3 4
2657 Absolute,X STZ Abs,X 9E 3 5
2662 static void Op64(void)
2664 regs.WrMem(EA_ZP, 0x00);
2667 static void Op74(void)
2669 regs.WrMem(EA_ZP_X, 0x00);
2672 static void Op9C(void)
2674 regs.WrMem(EA_ABS, 0x00);
2677 static void Op9E(void)
2679 regs.WrMem(EA_ABS_X, 0x00);
2683 TAX Implied TAX AA 1 2
2686 static void OpAA(void) // TAX
2693 TAY Implied TAY A8 1 2
2696 static void OpA8(void) // TAY
2703 TRB Zero Page TRB Zpg 14 2 5
2704 Absolute TRB Abs 1C 3 6
2709 #define OP_TRB_HANDLER(m) \
2710 SET_Z(m & regs.a); \
2713 static void Op14(void) // TRB ZP
2721 static void Op1C(void) // TRB ABS
2730 TSB Zero Page TSB Zpg 04 2 5
2731 Absolute TSB Abs 0C 3 6
2736 #define OP_TSB_HANDLER(m) \
2737 SET_Z(m & regs.a); \
2740 static void Op04(void) // TSB ZP
2748 static void Op0C(void) // TSB ABS
2757 TSX Implied TSX BA 1 2
2760 static void OpBA(void) // TSX
2767 TXA Implied TXA 8A 1 2
2770 static void Op8A(void) // TXA
2777 TXS Implied TXS 9A 1 2
2780 static void Op9A(void) // TXS
2786 TYA Implied TYA 98 1 2
2788 static void Op98(void) // TYA
2794 static void Op__(void)
2796 regs.cpuFlags |= V65C02_STATE_ILLEGAL_INST;
2801 // Ok, the exec_op[] array is globally defined here basically to save
2802 // a LOT of unnecessary typing. Sure it's ugly, but hey, it works!
2804 void (* exec_op[256])() = {
2805 Op00, Op01, Op__, Op__, Op04, Op05, Op06, Op07, Op08, Op09, Op0A, Op__, Op0C, Op0D, Op0E, Op0F,
2806 Op10, Op11, Op12, Op__, Op14, Op15, Op16, Op17, Op18, Op19, Op1A, Op__, Op1C, Op1D, Op1E, Op1F,
2807 Op20, Op21, Op__, Op__, Op24, Op25, Op26, Op27, Op28, Op29, Op2A, Op__, Op2C, Op2D, Op2E, Op2F,
2808 Op30, Op31, Op32, Op__, Op34, Op35, Op36, Op37, Op38, Op39, Op3A, Op__, Op3C, Op3D, Op3E, Op3F,
2809 Op40, Op41, Op__, Op__, Op__, Op45, Op46, Op47, Op48, Op49, Op4A, Op__, Op4C, Op4D, Op4E, Op4F,
2810 Op50, Op51, Op52, Op__, Op__, Op55, Op56, Op57, Op58, Op59, Op5A, Op__, Op__, Op5D, Op5E, Op5F,
2811 Op60, Op61, Op__, Op__, Op64, Op65, Op66, Op67, Op68, Op69, Op6A, Op__, Op6C, Op6D, Op6E, Op6F,
2812 Op70, Op71, Op72, Op__, Op74, Op75, Op76, Op77, Op78, Op79, Op7A, Op__, Op7C, Op7D, Op7E, Op7F,
2813 Op80, Op81, Op__, Op__, Op84, Op85, Op86, Op87, Op88, Op89, Op8A, Op__, Op8C, Op8D, Op8E, Op8F,
2814 Op90, Op91, Op92, Op__, Op94, Op95, Op96, Op97, Op98, Op99, Op9A, Op__, Op9C, Op9D, Op9E, Op9F,
2815 OpA0, OpA1, OpA2, Op__, OpA4, OpA5, OpA6, OpA7, OpA8, OpA9, OpAA, Op__, OpAC, OpAD, OpAE, OpAF,
2816 OpB0, OpB1, OpB2, Op__, OpB4, OpB5, OpB6, OpB7, OpB8, OpB9, OpBA, Op__, OpBC, OpBD, OpBE, OpBF,
2817 OpC0, OpC1, Op__, Op__, OpC4, OpC5, OpC6, OpC7, OpC8, OpC9, OpCA, Op__, OpCC, OpCD, OpCE, OpCF,
2818 OpD0, OpD1, OpD2, Op__, Op__, OpD5, OpD6, OpD7, OpD8, OpD9, OpDA, Op__, Op__, OpDD, OpDE, OpDF,
2819 OpE0, OpE1, Op__, Op__, OpE4, OpE5, OpE6, OpE7, OpE8, OpE9, OpEA, Op__, OpEC, OpED, OpEE, OpEF,
2820 OpF0, OpF1, OpF2, Op__, Op__, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, Op__, Op__, OpFD, OpFE, OpFF
2825 // Internal "memcpy" (so we don't have to link with any external libraries!)
2827 static void myMemcpy(void * dst, void * src, uint32_t size)
2829 uint8_t * d = (uint8_t *)dst, * s = (uint8_t *)src;
2831 for(uint32_t i=0; i<size; i++)
2836 FCA8: 38 698 WAIT SEC
2837 FCA9: 48 699 WAIT2 PHA
2838 FCAA: E9 01 700 WAIT3 SBC #$01
2839 FCAC: D0 FC 701 BNE WAIT3 ;1.0204 USEC
2840 FCAE: 68 702 PLA ;(13+27/2*A+5/2*A*A)
2841 FCAF: E9 01 703 SBC #$01
2842 FCB1: D0 F6 704 BNE WAIT2
2845 FBD9: C9 87 592 BELL1 CMP #$87 ;BELL CHAR? (CNTRL-G)
2846 FBDB: D0 12 593 BNE RTS2B ; NO, RETURN
2847 FBDD: A9 40 594 LDA #$40 ;DELAY .01 SECONDS
2848 FBDF: 20 A8 FC 595 JSR WAIT
2849 FBE2: A0 C0 596 LDY #$C0
2850 FBE4: A9 0C 597 BELL2 LDA #$0C ;TOGGLE SPEAKER AT
2851 FBE6: 20 A8 FC 598 JSR WAIT ; 1 KHZ FOR .1 SEC.
2852 FBE9: AD 30 C0 599 LDA SPKR
2854 FBED: D0 F5 601 BNE BELL2
2855 FBEF: 60 602 RTS2B RTS
2857 //int instCount[256];
2859 bool dumpDis = false;
2860 //bool dumpDis = true;
2864 On //e, $FCAA is the delay routine. (seems to not have changed from ][+)
2868 //Note: could enforce regs.clock to zero on starting the CPU with an Init() function...
2870 //static uint32_t limit = 0;
2871 // Or, we could just say that initializing the CPU struct is the responsibility
2872 // of the caller. :-)
2874 #define DO_BACKTRACE
2876 #define BACKTRACE_SIZE 16384
2877 uint32_t btQueuePtr = 0;
2878 V65C02REGS btQueue[BACKTRACE_SIZE];
2879 uint8_t btQueueInst[BACKTRACE_SIZE][4];
2882 // Function to execute 65C02 for "cycles" cycles
2884 void Execute65C02(V65C02REGS * context, uint32_t cycles)
2886 myMemcpy(®s, context, sizeof(V65C02REGS));
2889 uint64_t endCycles = regs.clock + (uint64_t)cycles - regs.overflow;
2891 while (regs.clock < endCycles)
2894 static bool weGo = false;
2895 if (regs.pc == 0x80AE)
2900 else if (regs.pc == 0xFCA8 && weGo)
2903 WriteLog("\n*** DELAY (A=$%02X)\n\n", regs.a);
2905 else if (regs.pc == 0xFCB3 && weGo)
2911 /*if (regs.pc == 0x4007)
2915 if (regs.pc == 0x444B)
2917 WriteLog("\n*** End of wait...\n\n");
2920 if (regs.pc == 0x444E)
2922 WriteLog("\n*** Start of wait...\n\n");
2926 /*if (regs.pc >= 0xC600 && regs.pc <=0xC6FF)
2931 dumpDis = false;//*/
2932 /*if (regs.pc == 0xE039)
2938 /*if (regs.pc == 0x0801)
2940 WriteLog("\n*** DISK BOOT subroutine...\n\n");
2943 if (regs.pc == 0xE000)
2946 WriteLog("\n*** Dump of $E000 routine ***\n\n");
2948 for(uint32_t addr=0xE000; addr<0xF000;)
2950 addr += Decode65C02(addr);
2954 WriteLog("\n*** DISK part II subroutine...\n\n");
2957 if (regs.pc == 0xD000)
2959 WriteLog("\n*** CUSTOM DISK READ subroutine...\n\n");
2962 if (regs.pc == 0xD1BE)
2964 // WriteLog("\n*** DISK part II subroutine...\n\n");
2967 if (regs.pc == 0xD200)
2969 WriteLog("\n*** CUSTOM SCREEN subroutine...\n\n");
2972 if (regs.pc == 0xD269)
2974 // WriteLog("\n*** DISK part II subroutine...\n\n");
2978 //if (regs.pc == 0xE08E)
2979 /*if (regs.pc == 0xAD33)
2981 WriteLog("\n*** After loader ***\n\n");
2984 /*if (regs.pc == 0x0418)
2986 WriteLog("\n*** CUSTOM DISK READ subroutine...\n\n");
2994 //WAIT is commented out here because it's called by BELL1...
2995 if (regs.pc == 0xFCA8)
2997 WriteLog("\n*** WAIT subroutine...\n\n");
3000 if (regs.pc == 0xFBD9)
3002 WriteLog("\n*** BELL1 subroutine...\n\n");
3005 if (regs.pc == 0xFC58)
3007 WriteLog("\n*** HOME subroutine...\n\n");
3010 if (regs.pc == 0xFDED)
3012 WriteLog("\n*** COUT subroutine...\n\n");
3018 if (regs.pc == 0x2000)
3023 static char disbuf[80];
3026 Decode65C02(disbuf, regs.pc);
3027 WriteLog("%s", disbuf);
3030 uint8_t opcode = regs.RdMem(regs.pc++);
3032 //if (!(regs.cpuFlags & V65C02_STATE_ILLEGAL_INST))
3033 //instCount[opcode]++;
3035 // We need this because the opcode execute could add 1 or 2 cycles
3036 uint64_t clockSave = regs.clock;
3038 // Execute that opcode...
3040 regs.clock += CPUCycles[opcode];
3042 // Tell the timer function how many PHI2s have elapsed
3044 // regs.Timer(CPUCycles[opcode]);
3045 regs.Timer(regs.clock - clockSave);
3049 WriteLog(" [PC=%04X, SP=01%02X, CC=%s%s.%s%s%s%s%s, A=%02X, X=%02X, Y=%02X]\n",
3051 (regs.cc & FLAG_N ? "N" : "-"), (regs.cc & FLAG_V ? "V" : "-"),
3052 (regs.cc & FLAG_B ? "B" : "-"), (regs.cc & FLAG_D ? "D" : "-"),
3053 (regs.cc & FLAG_I ? "I" : "-"), (regs.cc & FLAG_Z ? "Z" : "-"),
3054 (regs.cc & FLAG_C ? "C" : "-"), regs.a, regs.x, regs.y);
3058 if (regs.pc == 0xFCB3) // WAIT exit point
3062 /*if (regs.pc == 0xFBEF) // BELL1 exit point
3066 /*if (regs.pc == 0xFC22) // HOME exit point
3070 if (regs.pc == 0xFDFF) // COUT exit point
3074 if (regs.pc == 0xFBD8)
3076 WriteLog("\n*** BASCALC set BASL/H = $%04X\n\n", RdMemW(0x0028));
3080 //These should be correct now...
3081 if (regs.cpuFlags & V65C02_ASSERT_LINE_RESET)
3083 // Not sure about this...
3085 regs.cc = FLAG_I; // Reset the CC register
3086 regs.pc = RdMemW(0xFFFC); // And load PC with the RESET vector
3088 context->cpuFlags = 0; // Clear CPU flags...
3091 WriteLog("\n*** RESET *** (PC = $%04X)\n\n", regs.pc);
3094 else if (regs.cpuFlags & V65C02_ASSERT_LINE_NMI)
3097 WriteLog("\n*** NMI ***\n\n");
3099 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8); // Save PC and CC
3100 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
3101 regs.WrMem(0x0100 + regs.sp--, regs.cc);
3102 regs.cc |= FLAG_I; // Set I
3103 regs.cc &= ~FLAG_D; // & clear D
3104 regs.pc = RdMemW(0xFFFA); // And do it!
3107 context->cpuFlags &= ~V65C02_ASSERT_LINE_NMI;// Reset the asserted line (NMI)...
3108 regs.cpuFlags &= ~V65C02_ASSERT_LINE_NMI; // Reset the asserted line (NMI)...
3110 else if (regs.cpuFlags & V65C02_ASSERT_LINE_IRQ)
3112 if (!(regs.cc & FLAG_I)) // Process an interrupt (I=0)?
3115 WriteLog("\n*** IRQ ***\n\n");
3116 WriteLog("Clock=$%X\n", regs.clock);
3119 regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8); // Save PC and CC
3120 regs.WrMem(0x0100 + regs.sp--, regs.pc & 0xFF);
3121 regs.WrMem(0x0100 + regs.sp--, regs.cc);
3122 regs.cc |= FLAG_I; // Set I
3123 regs.cc &= ~FLAG_D; // & clear D
3124 regs.pc = RdMemW(0xFFFE); // And do it!
3127 context->cpuFlags &= ~V65C02_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
3128 regs.cpuFlags &= ~V65C02_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
3133 // If we went longer than the passed in cycles, make a note of it so we can
3134 // subtract it out from a subsequent run. It's guaranteed to be positive,
3135 // because the condition that exits the main loop above is written such
3136 // that regs.clock has to be larger than endCycles to exit from it.
3137 regs.overflow = regs.clock - endCycles;
3139 myMemcpy(context, ®s, sizeof(V65C02REGS));
3144 // Get the clock of the currently executing CPU
3146 uint64_t GetCurrentV65C02Clock(void)
3153 // Assert 65C02 line in current context
3155 void AssertLine(uint16_t flags)
3157 regs.cpuFlags |= flags;