1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* 6502.c */ |
4 | /* */ |
5 | /* CPU core for the 6502 */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2003-2012, Ullrich von Bassewitz */ |
10 | /* Roemerstrasse 52 */ |
11 | /* D-70794 Filderstadt */ |
12 | /* EMail: uz@cc65.org */ |
13 | /* */ |
14 | /* Mar-2017, Christian Krueger, added support for 65SC02 */ |
15 | /* */ |
16 | /* This software is provided 'as-is', without any expressed or implied */ |
17 | /* warranty. In no event will the authors be held liable for any damages */ |
18 | /* arising from the use of this software. */ |
19 | /* */ |
20 | /* Permission is granted to anyone to use this software for any purpose, */ |
21 | /* including commercial applications, and to alter it and redistribute it */ |
22 | /* freely, subject to the following restrictions: */ |
23 | /* */ |
24 | /* 1. The origin of this software must not be misrepresented; you must not */ |
25 | /* claim that you wrote the original software. If you use this software */ |
26 | /* in a product, an acknowledgment in the product documentation would be */ |
27 | /* appreciated but is not required. */ |
28 | /* 2. Altered source versions must be plainly marked as such, and must not */ |
29 | /* be misrepresented as being the original software. */ |
30 | /* 3. This notice may not be removed or altered from any source */ |
31 | /* distribution. */ |
32 | /* */ |
33 | /*****************************************************************************/ |
34 | |
35 | /* Known bugs and limitations of the 65C02 simulation: |
36 | * support currently only on the level of 65SC02: |
37 | BBRx, BBSx, RMBx, SMBx, WAI, and STP are unsupported |
38 | * BCD flag handling equals 6502 (unchecked if bug is simulated or wrong for |
39 | 6502) |
40 | */ |
41 | |
42 | #include "memory.h" |
43 | #include "error.h" |
44 | #include "6502.h" |
45 | #include "paravirt.h" |
46 | |
47 | |
48 | |
49 | /*****************************************************************************/ |
50 | /* Data */ |
51 | /*****************************************************************************/ |
52 | |
53 | |
54 | |
55 | /* Current CPU */ |
56 | CPUType CPU; |
57 | |
58 | /* Type of an opcode handler function */ |
59 | typedef void (*OPFunc) (void); |
60 | |
61 | /* The CPU registers */ |
62 | static CPURegs Regs; |
63 | |
64 | /* Cycles for the current insn */ |
65 | static unsigned Cycles; |
66 | |
67 | /* Total number of CPU cycles exec'd */ |
68 | static unsigned long TotalCycles; |
69 | |
70 | /* NMI request active */ |
71 | static unsigned HaveNMIRequest; |
72 | |
73 | /* IRQ request active */ |
74 | static unsigned HaveIRQRequest; |
75 | |
76 | /* flag to print cycles at program termination */ |
77 | int PrintCycles; |
78 | |
79 | |
80 | /*****************************************************************************/ |
81 | /* Helper functions and macros */ |
82 | /*****************************************************************************/ |
83 | |
84 | |
85 | |
86 | /* Return the flags as boolean values (0/1) */ |
87 | #define GET_CF() ((Regs.SR & CF) != 0) |
88 | #define GET_ZF() ((Regs.SR & ZF) != 0) |
89 | #define GET_IF() ((Regs.SR & IF) != 0) |
90 | #define GET_DF() ((Regs.SR & DF) != 0) |
91 | #define GET_OF() ((Regs.SR & OF) != 0) |
92 | #define GET_SF() ((Regs.SR & SF) != 0) |
93 | |
94 | /* Set the flags. The parameter is a boolean flag that says if the flag should be |
95 | ** set or reset. |
96 | */ |
97 | #define SET_CF(f) do { if (f) { Regs.SR |= CF; } else { Regs.SR &= ~CF; } } while (0) |
98 | #define SET_ZF(f) do { if (f) { Regs.SR |= ZF; } else { Regs.SR &= ~ZF; } } while (0) |
99 | #define SET_IF(f) do { if (f) { Regs.SR |= IF; } else { Regs.SR &= ~IF; } } while (0) |
100 | #define SET_DF(f) do { if (f) { Regs.SR |= DF; } else { Regs.SR &= ~DF; } } while (0) |
101 | #define SET_OF(f) do { if (f) { Regs.SR |= OF; } else { Regs.SR &= ~OF; } } while (0) |
102 | #define SET_SF(f) do { if (f) { Regs.SR |= SF; } else { Regs.SR &= ~SF; } } while (0) |
103 | |
104 | /* Special test and set macros. The meaning of the parameter depends on the |
105 | ** actual flag that should be set or reset. |
106 | */ |
107 | #define TEST_ZF(v) SET_ZF (((v) & 0xFF) == 0) |
108 | #define TEST_SF(v) SET_SF (((v) & 0x80) != 0) |
109 | #define TEST_CF(v) SET_CF (((v) & 0xFF00) != 0) |
110 | |
111 | /* Program counter halves */ |
112 | #define PCL (Regs.PC & 0xFF) |
113 | #define PCH ((Regs.PC >> 8) & 0xFF) |
114 | |
115 | /* Stack operations */ |
116 | #define PUSH(Val) MemWriteByte (0x0100 | (Regs.SP-- & 0xFF), Val) |
117 | #define POP() MemReadByte (0x0100 | (++Regs.SP & 0xFF)) |
118 | |
119 | /* Test for page cross */ |
120 | #define PAGE_CROSS(addr,offs) ((((addr) & 0xFF) + offs) >= 0x100) |
121 | |
122 | /* #imm */ |
123 | #define AC_OP_IMM(op) \ |
124 | Cycles = 2; \ |
125 | Regs.AC = Regs.AC op MemReadByte (Regs.PC+1); \ |
126 | TEST_ZF (Regs.AC); \ |
127 | TEST_SF (Regs.AC); \ |
128 | Regs.PC += 2 |
129 | |
130 | /* zp */ |
131 | #define AC_OP_ZP(op) \ |
132 | Cycles = 3; \ |
133 | Regs.AC = Regs.AC op MemReadByte (MemReadByte (Regs.PC+1)); \ |
134 | TEST_ZF (Regs.AC); \ |
135 | TEST_SF (Regs.AC); \ |
136 | Regs.PC += 2 |
137 | |
138 | /* zp,x */ |
139 | #define AC_OP_ZPX(op) \ |
140 | unsigned char ZPAddr; \ |
141 | Cycles = 4; \ |
142 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; \ |
143 | Regs.AC = Regs.AC op MemReadByte (ZPAddr); \ |
144 | TEST_ZF (Regs.AC); \ |
145 | TEST_SF (Regs.AC); \ |
146 | Regs.PC += 2 |
147 | |
148 | /* zp,y */ |
149 | #define AC_OP_ZPY(op) \ |
150 | unsigned char ZPAddr; \ |
151 | Cycles = 4; \ |
152 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR; \ |
153 | Regs.AC = Regs.AC op MemReadByte (ZPAddr); \ |
154 | TEST_ZF (Regs.AC); \ |
155 | TEST_SF (Regs.AC); \ |
156 | Regs.PC += 2 |
157 | |
158 | /* abs */ |
159 | #define AC_OP_ABS(op) \ |
160 | unsigned Addr; \ |
161 | Cycles = 4; \ |
162 | Addr = MemReadWord (Regs.PC+1); \ |
163 | Regs.AC = Regs.AC op MemReadByte (Addr); \ |
164 | TEST_ZF (Regs.AC); \ |
165 | TEST_SF (Regs.AC); \ |
166 | Regs.PC += 3 |
167 | |
168 | /* abs,x */ |
169 | #define AC_OP_ABSX(op) \ |
170 | unsigned Addr; \ |
171 | Cycles = 4; \ |
172 | Addr = MemReadWord (Regs.PC+1); \ |
173 | if (PAGE_CROSS (Addr, Regs.XR)) { \ |
174 | ++Cycles; \ |
175 | } \ |
176 | Regs.AC = Regs.AC op MemReadByte (Addr + Regs.XR); \ |
177 | TEST_ZF (Regs.AC); \ |
178 | TEST_SF (Regs.AC); \ |
179 | Regs.PC += 3 |
180 | |
181 | /* abs,y */ |
182 | #define AC_OP_ABSY(op) \ |
183 | unsigned Addr; \ |
184 | Cycles = 4; \ |
185 | Addr = MemReadWord (Regs.PC+1); \ |
186 | if (PAGE_CROSS (Addr, Regs.YR)) { \ |
187 | ++Cycles; \ |
188 | } \ |
189 | Regs.AC = Regs.AC op MemReadByte (Addr + Regs.YR); \ |
190 | TEST_ZF (Regs.AC); \ |
191 | TEST_SF (Regs.AC); \ |
192 | Regs.PC += 3 |
193 | |
194 | /* (zp,x) */ |
195 | #define AC_OP_ZPXIND(op) \ |
196 | unsigned char ZPAddr; \ |
197 | unsigned Addr; \ |
198 | Cycles = 6; \ |
199 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; \ |
200 | Addr = MemReadZPWord (ZPAddr); \ |
201 | Regs.AC = Regs.AC op MemReadByte (Addr); \ |
202 | TEST_ZF (Regs.AC); \ |
203 | TEST_SF (Regs.AC); \ |
204 | Regs.PC += 2 |
205 | |
206 | /* (zp),y */ |
207 | #define AC_OP_ZPINDY(op) \ |
208 | unsigned char ZPAddr; \ |
209 | unsigned Addr; \ |
210 | Cycles = 5; \ |
211 | ZPAddr = MemReadByte (Regs.PC+1); \ |
212 | Addr = MemReadZPWord (ZPAddr); \ |
213 | if (PAGE_CROSS (Addr, Regs.YR)) { \ |
214 | ++Cycles; \ |
215 | } \ |
216 | Addr += Regs.YR; \ |
217 | Regs.AC = Regs.AC op MemReadByte (Addr); \ |
218 | TEST_ZF (Regs.AC); \ |
219 | TEST_SF (Regs.AC); \ |
220 | Regs.PC += 2 |
221 | |
222 | /* (zp) */ |
223 | #define AC_OP_ZPIND(op) \ |
224 | unsigned char ZPAddr; \ |
225 | unsigned Addr; \ |
226 | Cycles = 5; \ |
227 | ZPAddr = MemReadByte (Regs.PC+1); \ |
228 | Addr = MemReadZPWord (ZPAddr); \ |
229 | Regs.AC = Regs.AC op MemReadByte (Addr); \ |
230 | TEST_ZF (Regs.AC); \ |
231 | TEST_SF (Regs.AC); \ |
232 | Regs.PC += 2 |
233 | |
234 | /* ADC */ |
235 | #define ADC(v) \ |
236 | do { \ |
237 | unsigned old = Regs.AC; \ |
238 | unsigned rhs = (v & 0xFF); \ |
239 | if (GET_DF ()) { \ |
240 | unsigned lo; \ |
241 | int res; \ |
242 | lo = (old & 0x0F) + (rhs & 0x0F) + GET_CF (); \ |
243 | if (lo >= 0x0A) { \ |
244 | lo = ((lo + 0x06) & 0x0F) + 0x10; \ |
245 | } \ |
246 | Regs.AC = (old & 0xF0) + (rhs & 0xF0) + lo; \ |
247 | res = (signed char)(old & 0xF0) + \ |
248 | (signed char)(rhs & 0xF0) + \ |
249 | (signed char)lo; \ |
250 | TEST_ZF (old + rhs + GET_CF ()); \ |
251 | TEST_SF (Regs.AC); \ |
252 | if (Regs.AC >= 0xA0) { \ |
253 | Regs.AC += 0x60; \ |
254 | } \ |
255 | TEST_CF (Regs.AC); \ |
256 | SET_OF ((res < -128) || (res > 127)); \ |
257 | if (CPU != CPU_6502) { \ |
258 | ++Cycles; \ |
259 | } \ |
260 | } else { \ |
261 | Regs.AC += rhs + GET_CF (); \ |
262 | TEST_ZF (Regs.AC); \ |
263 | TEST_SF (Regs.AC); \ |
264 | TEST_CF (Regs.AC); \ |
265 | SET_OF (!((old ^ rhs) & 0x80) && \ |
266 | ((old ^ Regs.AC) & 0x80)); \ |
267 | Regs.AC &= 0xFF; \ |
268 | } \ |
269 | } while (0) |
270 | |
271 | /* branches */ |
272 | #define BRANCH(cond) \ |
273 | Cycles = 2; \ |
274 | if (cond) { \ |
275 | signed char Offs; \ |
276 | unsigned char OldPCH; \ |
277 | ++Cycles; \ |
278 | Offs = (signed char) MemReadByte (Regs.PC+1); \ |
279 | OldPCH = PCH; \ |
280 | Regs.PC += 2 + (int) Offs; \ |
281 | if (PCH != OldPCH) { \ |
282 | ++Cycles; \ |
283 | } \ |
284 | } else { \ |
285 | Regs.PC += 2; \ |
286 | } |
287 | |
288 | /* compares */ |
289 | #define CMP(v1, v2) \ |
290 | do { \ |
291 | unsigned Result = v1 - v2; \ |
292 | TEST_ZF (Result & 0xFF); \ |
293 | TEST_SF (Result); \ |
294 | SET_CF (Result <= 0xFF); \ |
295 | } while (0) |
296 | |
297 | |
298 | /* ROL */ |
299 | #define ROL(Val) \ |
300 | Val <<= 1; \ |
301 | if (GET_CF ()) { \ |
302 | Val |= 0x01; \ |
303 | } \ |
304 | TEST_ZF (Val); \ |
305 | TEST_SF (Val); \ |
306 | TEST_CF (Val) |
307 | |
308 | /* ROR */ |
309 | #define ROR(Val) \ |
310 | if (GET_CF ()) { \ |
311 | Val |= 0x100; \ |
312 | } \ |
313 | SET_CF (Val & 0x01); \ |
314 | Val >>= 1; \ |
315 | TEST_ZF (Val); \ |
316 | TEST_SF (Val) |
317 | |
318 | /* SBC */ |
319 | #define SBC(v) \ |
320 | do { \ |
321 | unsigned old = Regs.AC; \ |
322 | unsigned rhs = (v & 0xFF); \ |
323 | if (GET_DF ()) { \ |
324 | unsigned lo; \ |
325 | int res; \ |
326 | lo = (old & 0x0F) - (rhs & 0x0F) + GET_CF () - 1; \ |
327 | if (lo & 0x80) { \ |
328 | lo = ((lo - 0x06) & 0x0F) - 0x10; \ |
329 | } \ |
330 | Regs.AC = (old & 0xF0) - (rhs & 0xF0) + lo; \ |
331 | if (Regs.AC & 0x80) { \ |
332 | Regs.AC -= 0x60; \ |
333 | } \ |
334 | res = Regs.AC - rhs + (!GET_CF ()); \ |
335 | TEST_ZF (res); \ |
336 | TEST_SF (res); \ |
337 | SET_CF (res <= 0xFF); \ |
338 | SET_OF (((old^rhs) & (old^res) & 0x80)); \ |
339 | if (CPU != CPU_6502) { \ |
340 | ++Cycles; \ |
341 | } \ |
342 | } else { \ |
343 | Regs.AC -= rhs + (!GET_CF ()); \ |
344 | TEST_ZF (Regs.AC); \ |
345 | TEST_SF (Regs.AC); \ |
346 | SET_CF (Regs.AC <= 0xFF); \ |
347 | SET_OF (((old^rhs) & (old^Regs.AC) & 0x80)); \ |
348 | Regs.AC &= 0xFF; \ |
349 | } \ |
350 | } while (0) |
351 | |
352 | |
353 | |
354 | /*****************************************************************************/ |
355 | /* Opcode handling functions */ |
356 | /*****************************************************************************/ |
357 | |
358 | |
359 | |
360 | static void OPC_Illegal (void) |
361 | { |
362 | Error ("Illegal opcode $%02X at address $%04X" , |
363 | MemReadByte (Regs.PC), Regs.PC); |
364 | } |
365 | |
366 | |
367 | |
368 | static void OPC_6502_00 (void) |
369 | /* Opcode $00: BRK */ |
370 | { |
371 | Cycles = 7; |
372 | Regs.PC += 2; |
373 | PUSH (PCH); |
374 | PUSH (PCL); |
375 | PUSH (Regs.SR); |
376 | SET_IF (1); |
377 | if (CPU != CPU_6502) |
378 | { |
379 | SET_DF (0); |
380 | } |
381 | Regs.PC = MemReadWord (0xFFFE); |
382 | } |
383 | |
384 | |
385 | |
386 | static void OPC_6502_01 (void) |
387 | /* Opcode $01: ORA (ind,x) */ |
388 | { |
389 | AC_OP_ZPXIND (|); |
390 | } |
391 | |
392 | |
393 | |
394 | static void OPC_65SC02_04 (void) |
395 | /* Opcode $04: TSB zp */ |
396 | { |
397 | unsigned char ZPAddr; |
398 | unsigned char Val; |
399 | Cycles = 5; |
400 | ZPAddr = MemReadByte (Regs.PC+1); |
401 | Val = MemReadByte (ZPAddr); |
402 | SET_ZF ((Val & Regs.AC) == 0); |
403 | MemWriteByte (ZPAddr, (unsigned char)(Val | Regs.AC)); |
404 | Regs.PC += 2; |
405 | } |
406 | |
407 | |
408 | |
409 | static void OPC_6502_05 (void) |
410 | /* Opcode $05: ORA zp */ |
411 | { |
412 | AC_OP_ZP (|); |
413 | } |
414 | |
415 | |
416 | |
417 | static void OPC_6502_06 (void) |
418 | /* Opcode $06: ASL zp */ |
419 | { |
420 | unsigned char ZPAddr; |
421 | unsigned Val; |
422 | Cycles = 5; |
423 | ZPAddr = MemReadByte (Regs.PC+1); |
424 | Val = MemReadByte (ZPAddr) << 1; |
425 | MemWriteByte (ZPAddr, (unsigned char) Val); |
426 | TEST_ZF (Val & 0xFF); |
427 | TEST_SF (Val); |
428 | SET_CF (Val & 0x100); |
429 | Regs.PC += 2; |
430 | } |
431 | |
432 | |
433 | |
434 | static void OPC_6502_08 (void) |
435 | /* Opcode $08: PHP */ |
436 | { |
437 | Cycles = 3; |
438 | PUSH (Regs.SR); |
439 | Regs.PC += 1; |
440 | } |
441 | |
442 | |
443 | |
444 | static void OPC_6502_09 (void) |
445 | /* Opcode $09: ORA #imm */ |
446 | { |
447 | AC_OP_IMM (|); |
448 | } |
449 | |
450 | |
451 | |
452 | static void OPC_6502_0A (void) |
453 | /* Opcode $0A: ASL a */ |
454 | { |
455 | Cycles = 2; |
456 | Regs.AC <<= 1; |
457 | TEST_ZF (Regs.AC & 0xFF); |
458 | TEST_SF (Regs.AC); |
459 | SET_CF (Regs.AC & 0x100); |
460 | Regs.AC &= 0xFF; |
461 | Regs.PC += 1; |
462 | } |
463 | |
464 | |
465 | |
466 | static void OPC_65SC02_0C (void) |
467 | /* Opcode $0C: TSB abs */ |
468 | { |
469 | unsigned Addr; |
470 | unsigned char Val; |
471 | Cycles = 6; |
472 | Addr = MemReadWord (Regs.PC+1); |
473 | Val = MemReadByte (Addr); |
474 | SET_ZF ((Val & Regs.AC) == 0); |
475 | MemWriteByte (Addr, (unsigned char) (Val | Regs.AC)); |
476 | Regs.PC += 3; |
477 | } |
478 | |
479 | |
480 | |
481 | static void OPC_6502_0D (void) |
482 | /* Opcode $0D: ORA abs */ |
483 | { |
484 | AC_OP_ABS (|); |
485 | } |
486 | |
487 | |
488 | |
489 | static void OPC_6502_0E (void) |
490 | /* Opcode $0E: ALS abs */ |
491 | { |
492 | unsigned Addr; |
493 | unsigned Val; |
494 | Cycles = 6; |
495 | Addr = MemReadWord (Regs.PC+1); |
496 | Val = MemReadByte (Addr) << 1; |
497 | MemWriteByte (Addr, (unsigned char) Val); |
498 | TEST_ZF (Val & 0xFF); |
499 | TEST_SF (Val); |
500 | SET_CF (Val & 0x100); |
501 | Regs.PC += 3; |
502 | } |
503 | |
504 | |
505 | |
506 | static void OPC_6502_10 (void) |
507 | /* Opcode $10: BPL */ |
508 | { |
509 | BRANCH (!GET_SF ()); |
510 | } |
511 | |
512 | |
513 | |
514 | static void OPC_6502_11 (void) |
515 | /* Opcode $11: ORA (zp),y */ |
516 | { |
517 | AC_OP_ZPINDY (|); |
518 | } |
519 | |
520 | |
521 | |
522 | static void OPC_65SC02_12 (void) |
523 | /* Opcode $12: ORA (zp) */ |
524 | { |
525 | AC_OP_ZPIND (|); |
526 | } |
527 | |
528 | |
529 | |
530 | static void OPC_65SC02_14 (void) |
531 | /* Opcode $14: TRB zp */ |
532 | { |
533 | unsigned char ZPAddr; |
534 | unsigned char Val; |
535 | Cycles = 5; |
536 | ZPAddr = MemReadByte (Regs.PC+1); |
537 | Val = MemReadByte (ZPAddr); |
538 | SET_ZF ((Val & Regs.AC) == 0); |
539 | MemWriteByte (ZPAddr, (unsigned char)(Val & ~Regs.AC)); |
540 | Regs.PC += 2; |
541 | } |
542 | |
543 | |
544 | |
545 | static void OPC_6502_15 (void) |
546 | /* Opcode $15: ORA zp,x */ |
547 | { |
548 | AC_OP_ZPX (|); |
549 | } |
550 | |
551 | |
552 | |
553 | static void OPC_6502_16 (void) |
554 | /* Opcode $16: ASL zp,x */ |
555 | { |
556 | unsigned char ZPAddr; |
557 | unsigned Val; |
558 | Cycles = 6; |
559 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
560 | Val = MemReadByte (ZPAddr) << 1; |
561 | MemWriteByte (ZPAddr, (unsigned char) Val); |
562 | TEST_ZF (Val & 0xFF); |
563 | TEST_SF (Val); |
564 | SET_CF (Val & 0x100); |
565 | Regs.PC += 2; |
566 | } |
567 | |
568 | |
569 | |
570 | static void OPC_6502_18 (void) |
571 | /* Opcode $18: CLC */ |
572 | { |
573 | Cycles = 2; |
574 | SET_CF (0); |
575 | Regs.PC += 1; |
576 | } |
577 | |
578 | |
579 | |
580 | static void OPC_6502_19 (void) |
581 | /* Opcode $19: ORA abs,y */ |
582 | { |
583 | AC_OP_ABSY (|); |
584 | } |
585 | |
586 | |
587 | |
588 | static void OPC_65SC02_1A (void) |
589 | /* Opcode $1A: INC a */ |
590 | { |
591 | Cycles = 2; |
592 | Regs.AC = (Regs.AC + 1) & 0xFF; |
593 | TEST_ZF (Regs.AC); |
594 | TEST_SF (Regs.AC); |
595 | Regs.PC += 1; |
596 | } |
597 | |
598 | |
599 | |
600 | static void OPC_65SC02_1C (void) |
601 | /* Opcode $1C: TRB abs */ |
602 | { |
603 | unsigned Addr; |
604 | unsigned char Val; |
605 | Cycles = 6; |
606 | Addr = MemReadWord (Regs.PC+1); |
607 | Val = MemReadByte (Addr); |
608 | SET_ZF ((Val & Regs.AC) == 0); |
609 | MemWriteByte (Addr, (unsigned char) (Val & ~Regs.AC)); |
610 | Regs.PC += 3; |
611 | } |
612 | |
613 | |
614 | |
615 | static void OPC_6502_1D (void) |
616 | /* Opcode $1D: ORA abs,x */ |
617 | { |
618 | AC_OP_ABSX (|); |
619 | } |
620 | |
621 | |
622 | |
623 | static void OPC_6502_1E (void) |
624 | /* Opcode $1E: ASL abs,x */ |
625 | { |
626 | unsigned Addr; |
627 | unsigned Val; |
628 | Cycles = 7; |
629 | Addr = MemReadWord (Regs.PC+1) + Regs.XR; |
630 | if (CPU != CPU_6502 && !PAGE_CROSS (Addr, Regs.XR)) |
631 | --Cycles; |
632 | Val = MemReadByte (Addr) << 1; |
633 | MemWriteByte (Addr, (unsigned char) Val); |
634 | TEST_ZF (Val & 0xFF); |
635 | TEST_SF (Val); |
636 | SET_CF (Val & 0x100); |
637 | Regs.PC += 3; |
638 | } |
639 | |
640 | |
641 | |
642 | static void OPC_6502_20 (void) |
643 | /* Opcode $20: JSR */ |
644 | { |
645 | unsigned Addr; |
646 | Cycles = 6; |
647 | Addr = MemReadWord (Regs.PC+1); |
648 | Regs.PC += 2; |
649 | PUSH (PCH); |
650 | PUSH (PCL); |
651 | Regs.PC = Addr; |
652 | |
653 | ParaVirtHooks (&Regs); |
654 | } |
655 | |
656 | |
657 | |
658 | static void OPC_6502_21 (void) |
659 | /* Opcode $21: AND (zp,x) */ |
660 | { |
661 | AC_OP_ZPXIND (&); |
662 | } |
663 | |
664 | |
665 | |
666 | static void OPC_6502_24 (void) |
667 | /* Opcode $24: BIT zp */ |
668 | { |
669 | unsigned char ZPAddr; |
670 | unsigned char Val; |
671 | Cycles = 3; |
672 | ZPAddr = MemReadByte (Regs.PC+1); |
673 | Val = MemReadByte (ZPAddr); |
674 | SET_SF (Val & 0x80); |
675 | SET_OF (Val & 0x40); |
676 | SET_ZF ((Val & Regs.AC) == 0); |
677 | Regs.PC += 2; |
678 | } |
679 | |
680 | |
681 | |
682 | static void OPC_6502_25 (void) |
683 | /* Opcode $25: AND zp */ |
684 | { |
685 | AC_OP_ZP (&); |
686 | } |
687 | |
688 | |
689 | |
690 | static void OPC_6502_26 (void) |
691 | /* Opcode $26: ROL zp */ |
692 | { |
693 | unsigned char ZPAddr; |
694 | unsigned Val; |
695 | Cycles = 5; |
696 | ZPAddr = MemReadByte (Regs.PC+1); |
697 | Val = MemReadByte (ZPAddr); |
698 | ROL (Val); |
699 | MemWriteByte (ZPAddr, Val); |
700 | Regs.PC += 2; |
701 | } |
702 | |
703 | |
704 | |
705 | static void OPC_6502_28 (void) |
706 | /* Opcode $28: PLP */ |
707 | { |
708 | Cycles = 4; |
709 | |
710 | /* Bits 5 and 4 aren't used, and always are 1! */ |
711 | Regs.SR = (POP () | 0x30); |
712 | Regs.PC += 1; |
713 | } |
714 | |
715 | |
716 | |
717 | static void OPC_6502_29 (void) |
718 | /* Opcode $29: AND #imm */ |
719 | { |
720 | AC_OP_IMM (&); |
721 | } |
722 | |
723 | |
724 | |
725 | static void OPC_6502_2A (void) |
726 | /* Opcode $2A: ROL a */ |
727 | { |
728 | Cycles = 2; |
729 | ROL (Regs.AC); |
730 | Regs.AC &= 0xFF; |
731 | Regs.PC += 1; |
732 | } |
733 | |
734 | |
735 | |
736 | static void OPC_6502_2C (void) |
737 | /* Opcode $2C: BIT abs */ |
738 | { |
739 | unsigned Addr; |
740 | unsigned char Val; |
741 | Cycles = 4; |
742 | Addr = MemReadWord (Regs.PC+1); |
743 | Val = MemReadByte (Addr); |
744 | SET_SF (Val & 0x80); |
745 | SET_OF (Val & 0x40); |
746 | SET_ZF ((Val & Regs.AC) == 0); |
747 | Regs.PC += 3; |
748 | } |
749 | |
750 | |
751 | |
752 | static void OPC_6502_2D (void) |
753 | /* Opcode $2D: AND abs */ |
754 | { |
755 | AC_OP_ABS (&); |
756 | } |
757 | |
758 | |
759 | |
760 | static void OPC_6502_2E (void) |
761 | /* Opcode $2E: ROL abs */ |
762 | { |
763 | unsigned Addr; |
764 | unsigned Val; |
765 | Cycles = 6; |
766 | Addr = MemReadWord (Regs.PC+1); |
767 | Val = MemReadByte (Addr); |
768 | ROL (Val); |
769 | MemWriteByte (Addr, Val); |
770 | Regs.PC += 3; |
771 | } |
772 | |
773 | |
774 | |
775 | static void OPC_6502_30 (void) |
776 | /* Opcode $30: BMI */ |
777 | { |
778 | BRANCH (GET_SF ()); |
779 | } |
780 | |
781 | |
782 | |
783 | static void OPC_6502_31 (void) |
784 | /* Opcode $31: AND (zp),y */ |
785 | { |
786 | AC_OP_ZPINDY (&); |
787 | } |
788 | |
789 | |
790 | |
791 | static void OPC_65SC02_32 (void) |
792 | /* Opcode $32: AND (zp) */ |
793 | { |
794 | AC_OP_ZPIND (&); |
795 | } |
796 | |
797 | |
798 | |
799 | static void OPC_65SC02_34 (void) |
800 | /* Opcode $34: BIT zp,x */ |
801 | { |
802 | unsigned char ZPAddr; |
803 | unsigned char Val; |
804 | Cycles = 4; |
805 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
806 | Val = MemReadByte (ZPAddr); |
807 | SET_SF (Val & 0x80); |
808 | SET_OF (Val & 0x40); |
809 | SET_ZF ((Val & Regs.AC) == 0); |
810 | Regs.PC += 2; |
811 | } |
812 | |
813 | |
814 | |
815 | static void OPC_6502_35 (void) |
816 | /* Opcode $35: AND zp,x */ |
817 | { |
818 | AC_OP_ZPX (&); |
819 | } |
820 | |
821 | |
822 | |
823 | static void OPC_6502_36 (void) |
824 | /* Opcode $36: ROL zp,x */ |
825 | { |
826 | unsigned char ZPAddr; |
827 | unsigned Val; |
828 | Cycles = 6; |
829 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
830 | Val = MemReadByte (ZPAddr); |
831 | ROL (Val); |
832 | MemWriteByte (ZPAddr, Val); |
833 | Regs.PC += 2; |
834 | } |
835 | |
836 | |
837 | |
838 | static void OPC_6502_38 (void) |
839 | /* Opcode $38: SEC */ |
840 | { |
841 | Cycles = 2; |
842 | SET_CF (1); |
843 | Regs.PC += 1; |
844 | } |
845 | |
846 | |
847 | |
848 | static void OPC_6502_39 (void) |
849 | /* Opcode $39: AND abs,y */ |
850 | { |
851 | AC_OP_ABSY (&); |
852 | } |
853 | |
854 | |
855 | |
856 | static void OPC_65SC02_3A (void) |
857 | /* Opcode $3A: DEC a */ |
858 | { |
859 | Cycles = 2; |
860 | Regs.AC = (Regs.AC - 1) & 0xFF; |
861 | TEST_ZF (Regs.AC); |
862 | TEST_SF (Regs.AC); |
863 | Regs.PC += 1; |
864 | } |
865 | |
866 | |
867 | |
868 | static void OPC_65SC02_3C (void) |
869 | /* Opcode $3C: BIT abs,x */ |
870 | { |
871 | unsigned Addr; |
872 | unsigned char Val; |
873 | Cycles = 4; |
874 | Addr = MemReadWord (Regs.PC+1); |
875 | if (PAGE_CROSS (Addr, Regs.XR)) |
876 | ++Cycles; |
877 | Val = MemReadByte (Addr + Regs.XR); |
878 | SET_SF (Val & 0x80); |
879 | SET_OF (Val & 0x40); |
880 | SET_ZF ((Val & Regs.AC) == 0); |
881 | Regs.PC += 3; |
882 | } |
883 | |
884 | |
885 | |
886 | static void OPC_6502_3D (void) |
887 | /* Opcode $3D: AND abs,x */ |
888 | { |
889 | AC_OP_ABSX (&); |
890 | } |
891 | |
892 | |
893 | |
894 | static void OPC_6502_3E (void) |
895 | /* Opcode $3E: ROL abs,x */ |
896 | { |
897 | unsigned Addr; |
898 | unsigned Val; |
899 | Cycles = 7; |
900 | Addr = MemReadWord (Regs.PC+1) + Regs.XR; |
901 | if (CPU != CPU_6502 && !PAGE_CROSS (Addr, Regs.XR)) |
902 | --Cycles; |
903 | Val = MemReadByte (Addr); |
904 | ROL (Val); |
905 | MemWriteByte (Addr, Val); |
906 | Regs.PC += 2; |
907 | } |
908 | |
909 | |
910 | |
911 | static void OPC_6502_40 (void) |
912 | /* Opcode $40: RTI */ |
913 | { |
914 | Cycles = 6; |
915 | |
916 | /* Bits 5 and 4 aren't used, and always are 1! */ |
917 | Regs.SR = POP () | 0x30; |
918 | Regs.PC = POP (); /* PCL */ |
919 | Regs.PC |= (POP () << 8); /* PCH */ |
920 | } |
921 | |
922 | |
923 | |
924 | static void OPC_6502_41 (void) |
925 | /* Opcode $41: EOR (zp,x) */ |
926 | { |
927 | AC_OP_ZPXIND (^); |
928 | } |
929 | |
930 | |
931 | |
932 | static void OPC_65C02_44 (void) |
933 | /* Opcode $44: 'zp' 3 cycle NOP */ |
934 | { |
935 | Cycles = 3; |
936 | Regs.PC += 2; |
937 | } |
938 | |
939 | |
940 | |
941 | static void OPC_6502_45 (void) |
942 | /* Opcode $45: EOR zp */ |
943 | { |
944 | AC_OP_ZP (^); |
945 | } |
946 | |
947 | |
948 | |
949 | static void OPC_6502_46 (void) |
950 | /* Opcode $46: LSR zp */ |
951 | { |
952 | unsigned char ZPAddr; |
953 | unsigned char Val; |
954 | Cycles = 5; |
955 | ZPAddr = MemReadByte (Regs.PC+1); |
956 | Val = MemReadByte (ZPAddr); |
957 | SET_CF (Val & 0x01); |
958 | Val >>= 1; |
959 | MemWriteByte (ZPAddr, Val); |
960 | TEST_ZF (Val); |
961 | TEST_SF (Val); |
962 | Regs.PC += 2; |
963 | } |
964 | |
965 | |
966 | |
967 | static void OPC_6502_48 (void) |
968 | /* Opcode $48: PHA */ |
969 | { |
970 | Cycles = 3; |
971 | PUSH (Regs.AC); |
972 | Regs.PC += 1; |
973 | } |
974 | |
975 | |
976 | |
977 | static void OPC_6502_49 (void) |
978 | /* Opcode $49: EOR #imm */ |
979 | { |
980 | AC_OP_IMM (^); |
981 | } |
982 | |
983 | |
984 | |
985 | static void OPC_6502_4A (void) |
986 | /* Opcode $4A: LSR a */ |
987 | { |
988 | Cycles = 2; |
989 | SET_CF (Regs.AC & 0x01); |
990 | Regs.AC >>= 1; |
991 | TEST_ZF (Regs.AC); |
992 | TEST_SF (Regs.AC); |
993 | Regs.PC += 1; |
994 | } |
995 | |
996 | |
997 | |
998 | static void OPC_6502_4C (void) |
999 | /* Opcode $4C: JMP abs */ |
1000 | { |
1001 | Cycles = 3; |
1002 | Regs.PC = MemReadWord (Regs.PC+1); |
1003 | |
1004 | ParaVirtHooks (&Regs); |
1005 | } |
1006 | |
1007 | |
1008 | |
1009 | static void OPC_6502_4D (void) |
1010 | /* Opcode $4D: EOR abs */ |
1011 | { |
1012 | AC_OP_ABS (^); |
1013 | } |
1014 | |
1015 | |
1016 | |
1017 | static void OPC_6502_4E (void) |
1018 | /* Opcode $4E: LSR abs */ |
1019 | { |
1020 | unsigned Addr; |
1021 | unsigned char Val; |
1022 | Cycles = 6; |
1023 | Addr = MemReadWord (Regs.PC+1); |
1024 | Val = MemReadByte (Addr); |
1025 | SET_CF (Val & 0x01); |
1026 | Val >>= 1; |
1027 | MemWriteByte (Addr, Val); |
1028 | TEST_ZF (Val); |
1029 | TEST_SF (Val); |
1030 | Regs.PC += 3; |
1031 | } |
1032 | |
1033 | |
1034 | |
1035 | static void OPC_6502_50 (void) |
1036 | /* Opcode $50: BVC */ |
1037 | { |
1038 | BRANCH (!GET_OF ()); |
1039 | } |
1040 | |
1041 | |
1042 | |
1043 | static void OPC_6502_51 (void) |
1044 | /* Opcode $51: EOR (zp),y */ |
1045 | { |
1046 | AC_OP_ZPINDY (^); |
1047 | } |
1048 | |
1049 | |
1050 | |
1051 | static void OPC_65SC02_52 (void) |
1052 | /* Opcode $52: EOR (zp) */ |
1053 | { |
1054 | AC_OP_ZPIND (^); |
1055 | } |
1056 | |
1057 | |
1058 | |
1059 | static void OPC_6502_55 (void) |
1060 | /* Opcode $55: EOR zp,x */ |
1061 | { |
1062 | AC_OP_ZPX (^); |
1063 | } |
1064 | |
1065 | |
1066 | |
1067 | static void OPC_6502_56 (void) |
1068 | /* Opcode $56: LSR zp,x */ |
1069 | { |
1070 | unsigned char ZPAddr; |
1071 | unsigned char Val; |
1072 | Cycles = 6; |
1073 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
1074 | Val = MemReadByte (ZPAddr); |
1075 | SET_CF (Val & 0x01); |
1076 | Val >>= 1; |
1077 | MemWriteByte (ZPAddr, Val); |
1078 | TEST_ZF (Val); |
1079 | TEST_SF (Val); |
1080 | Regs.PC += 2; |
1081 | } |
1082 | |
1083 | |
1084 | |
1085 | static void OPC_6502_58 (void) |
1086 | /* Opcode $58: CLI */ |
1087 | { |
1088 | Cycles = 2; |
1089 | SET_IF (0); |
1090 | Regs.PC += 1; |
1091 | } |
1092 | |
1093 | |
1094 | |
1095 | static void OPC_6502_59 (void) |
1096 | /* Opcode $59: EOR abs,y */ |
1097 | { |
1098 | AC_OP_ABSY (^); |
1099 | } |
1100 | |
1101 | |
1102 | |
1103 | static void OPC_65SC02_5A (void) |
1104 | /* Opcode $5A: PHY */ |
1105 | { |
1106 | Cycles = 3; |
1107 | PUSH (Regs.YR); |
1108 | Regs.PC += 1; |
1109 | } |
1110 | |
1111 | |
1112 | |
1113 | static void OPC_65C02_5C (void) |
1114 | /* Opcode $5C: 'Absolute' 8 cycle NOP */ |
1115 | { |
1116 | Cycles = 8; |
1117 | Regs.PC += 3; |
1118 | } |
1119 | |
1120 | |
1121 | |
1122 | static void OPC_6502_5D (void) |
1123 | /* Opcode $5D: EOR abs,x */ |
1124 | { |
1125 | AC_OP_ABSX (^); |
1126 | } |
1127 | |
1128 | |
1129 | |
1130 | static void OPC_6502_5E (void) |
1131 | /* Opcode $5E: LSR abs,x */ |
1132 | { |
1133 | unsigned Addr; |
1134 | unsigned char Val; |
1135 | Cycles = 7; |
1136 | Addr = MemReadWord (Regs.PC+1) + Regs.XR; |
1137 | if (CPU != CPU_6502 && !PAGE_CROSS (Addr, Regs.XR)) |
1138 | --Cycles; |
1139 | Val = MemReadByte (Addr); |
1140 | SET_CF (Val & 0x01); |
1141 | Val >>= 1; |
1142 | MemWriteByte (Addr, Val); |
1143 | TEST_ZF (Val); |
1144 | TEST_SF (Val); |
1145 | Regs.PC += 3; |
1146 | } |
1147 | |
1148 | |
1149 | |
1150 | static void OPC_6502_60 (void) |
1151 | /* Opcode $60: RTS */ |
1152 | { |
1153 | Cycles = 6; |
1154 | Regs.PC = POP (); /* PCL */ |
1155 | Regs.PC |= (POP () << 8); /* PCH */ |
1156 | Regs.PC += 1; |
1157 | } |
1158 | |
1159 | |
1160 | |
1161 | static void OPC_6502_61 (void) |
1162 | /* Opcode $61: ADC (zp,x) */ |
1163 | { |
1164 | unsigned char ZPAddr; |
1165 | unsigned Addr; |
1166 | Cycles = 6; |
1167 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
1168 | Addr = MemReadZPWord (ZPAddr); |
1169 | ADC (MemReadByte (Addr)); |
1170 | Regs.PC += 2; |
1171 | } |
1172 | |
1173 | |
1174 | |
1175 | static void OPC_65SC02_64 (void) |
1176 | /* Opcode $64: STZ zp */ |
1177 | { |
1178 | unsigned char ZPAddr; |
1179 | Cycles = 3; |
1180 | ZPAddr = MemReadByte (Regs.PC+1); |
1181 | MemWriteByte (ZPAddr, 0); |
1182 | Regs.PC += 2; |
1183 | } |
1184 | |
1185 | |
1186 | |
1187 | static void OPC_6502_65 (void) |
1188 | /* Opcode $65: ADC zp */ |
1189 | { |
1190 | unsigned char ZPAddr; |
1191 | Cycles = 3; |
1192 | ZPAddr = MemReadByte (Regs.PC+1); |
1193 | ADC (MemReadByte (ZPAddr)); |
1194 | Regs.PC += 2; |
1195 | } |
1196 | |
1197 | |
1198 | |
1199 | static void OPC_6502_66 (void) |
1200 | /* Opcode $66: ROR zp */ |
1201 | { |
1202 | unsigned char ZPAddr; |
1203 | unsigned Val; |
1204 | Cycles = 5; |
1205 | ZPAddr = MemReadByte (Regs.PC+1); |
1206 | Val = MemReadByte (ZPAddr); |
1207 | ROR (Val); |
1208 | MemWriteByte (ZPAddr, Val); |
1209 | Regs.PC += 2; |
1210 | } |
1211 | |
1212 | |
1213 | |
1214 | static void OPC_6502_68 (void) |
1215 | /* Opcode $68: PLA */ |
1216 | { |
1217 | Cycles = 4; |
1218 | Regs.AC = POP (); |
1219 | TEST_ZF (Regs.AC); |
1220 | TEST_SF (Regs.AC); |
1221 | Regs.PC += 1; |
1222 | } |
1223 | |
1224 | |
1225 | |
1226 | static void OPC_6502_69 (void) |
1227 | /* Opcode $69: ADC #imm */ |
1228 | { |
1229 | Cycles = 2; |
1230 | ADC (MemReadByte (Regs.PC+1)); |
1231 | Regs.PC += 2; |
1232 | } |
1233 | |
1234 | |
1235 | |
1236 | static void OPC_6502_6A (void) |
1237 | /* Opcode $6A: ROR a */ |
1238 | { |
1239 | Cycles = 2; |
1240 | ROR (Regs.AC); |
1241 | Regs.PC += 1; |
1242 | } |
1243 | |
1244 | |
1245 | |
1246 | static void OPC_6502_6C (void) |
1247 | /* Opcode $6C: JMP (ind) */ |
1248 | { |
1249 | unsigned PC, Lo, Hi; |
1250 | PC = Regs.PC; |
1251 | Lo = MemReadWord (PC+1); |
1252 | |
1253 | if (CPU == CPU_6502) |
1254 | { |
1255 | /* Emulate the 6502 bug */ |
1256 | Cycles = 5; |
1257 | Regs.PC = MemReadByte (Lo); |
1258 | Hi = (Lo & 0xFF00) | ((Lo + 1) & 0xFF); |
1259 | Regs.PC |= (MemReadByte (Hi) << 8); |
1260 | |
1261 | /* Output a warning if the bug is triggered */ |
1262 | if (Hi != Lo + 1) |
1263 | { |
1264 | Warning ("6502 indirect jump bug triggered at $%04X, ind addr = $%04X" , |
1265 | PC, Lo); |
1266 | } |
1267 | } |
1268 | else |
1269 | { |
1270 | Cycles = 6; |
1271 | Regs.PC = MemReadWord(Lo); |
1272 | } |
1273 | |
1274 | ParaVirtHooks (&Regs); |
1275 | } |
1276 | |
1277 | |
1278 | |
1279 | static void OPC_65C02_6C (void) |
1280 | /* Opcode $6C: JMP (ind) */ |
1281 | { |
1282 | /* 6502 bug fixed here */ |
1283 | Cycles = 5; |
1284 | Regs.PC = MemReadWord (MemReadWord (Regs.PC+1)); |
1285 | |
1286 | ParaVirtHooks (&Regs); |
1287 | } |
1288 | |
1289 | |
1290 | |
1291 | static void OPC_6502_6D (void) |
1292 | /* Opcode $6D: ADC abs */ |
1293 | { |
1294 | unsigned Addr; |
1295 | Cycles = 4; |
1296 | Addr = MemReadWord (Regs.PC+1); |
1297 | ADC (MemReadByte (Addr)); |
1298 | Regs.PC += 3; |
1299 | } |
1300 | |
1301 | |
1302 | |
1303 | static void OPC_6502_6E (void) |
1304 | /* Opcode $6E: ROR abs */ |
1305 | { |
1306 | unsigned Addr; |
1307 | unsigned Val; |
1308 | Cycles = 6; |
1309 | Addr = MemReadWord (Regs.PC+1); |
1310 | Val = MemReadByte (Addr); |
1311 | ROR (Val); |
1312 | MemWriteByte (Addr, Val); |
1313 | Regs.PC += 3; |
1314 | } |
1315 | |
1316 | |
1317 | |
1318 | static void OPC_6502_70 (void) |
1319 | /* Opcode $70: BVS */ |
1320 | { |
1321 | BRANCH (GET_OF ()); |
1322 | } |
1323 | |
1324 | |
1325 | |
1326 | static void OPC_6502_71 (void) |
1327 | /* Opcode $71: ADC (zp),y */ |
1328 | { |
1329 | unsigned char ZPAddr; |
1330 | unsigned Addr; |
1331 | Cycles = 5; |
1332 | ZPAddr = MemReadByte (Regs.PC+1); |
1333 | Addr = MemReadZPWord (ZPAddr); |
1334 | if (PAGE_CROSS (Addr, Regs.YR)) { |
1335 | ++Cycles; |
1336 | } |
1337 | ADC (MemReadByte (Addr + Regs.YR)); |
1338 | Regs.PC += 2; |
1339 | } |
1340 | |
1341 | |
1342 | |
1343 | static void OPC_65SC02_72 (void) |
1344 | /* Opcode $72: ADC (zp) */ |
1345 | { |
1346 | unsigned char ZPAddr; |
1347 | unsigned Addr; |
1348 | Cycles = 5; |
1349 | ZPAddr = MemReadByte (Regs.PC+1); |
1350 | Addr = MemReadZPWord (ZPAddr); |
1351 | ADC (MemReadByte (Addr)); |
1352 | Regs.PC += 2; |
1353 | } |
1354 | |
1355 | |
1356 | |
1357 | static void OPC_65SC02_74 (void) |
1358 | /* Opcode $74: STZ zp,x */ |
1359 | { |
1360 | unsigned char ZPAddr; |
1361 | Cycles = 4; |
1362 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
1363 | MemWriteByte (ZPAddr, 0); |
1364 | Regs.PC += 2; |
1365 | } |
1366 | |
1367 | |
1368 | |
1369 | static void OPC_6502_75 (void) |
1370 | /* Opcode $75: ADC zp,x */ |
1371 | { |
1372 | unsigned char ZPAddr; |
1373 | Cycles = 4; |
1374 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
1375 | ADC (MemReadByte (ZPAddr)); |
1376 | Regs.PC += 2; |
1377 | } |
1378 | |
1379 | |
1380 | |
1381 | static void OPC_6502_76 (void) |
1382 | /* Opcode $76: ROR zp,x */ |
1383 | { |
1384 | unsigned char ZPAddr; |
1385 | unsigned Val; |
1386 | Cycles = 6; |
1387 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
1388 | Val = MemReadByte (ZPAddr); |
1389 | ROR (Val); |
1390 | MemWriteByte (ZPAddr, Val); |
1391 | Regs.PC += 2; |
1392 | } |
1393 | |
1394 | |
1395 | |
1396 | static void OPC_6502_78 (void) |
1397 | /* Opcode $78: SEI */ |
1398 | { |
1399 | Cycles = 2; |
1400 | SET_IF (1); |
1401 | Regs.PC += 1; |
1402 | } |
1403 | |
1404 | |
1405 | |
1406 | static void OPC_6502_79 (void) |
1407 | /* Opcode $79: ADC abs,y */ |
1408 | { |
1409 | unsigned Addr; |
1410 | Cycles = 4; |
1411 | Addr = MemReadWord (Regs.PC+1); |
1412 | if (PAGE_CROSS (Addr, Regs.YR)) { |
1413 | ++Cycles; |
1414 | } |
1415 | ADC (MemReadByte (Addr + Regs.YR)); |
1416 | Regs.PC += 3; |
1417 | } |
1418 | |
1419 | |
1420 | |
1421 | static void OPC_65SC02_7A (void) |
1422 | /* Opcode $7A: PLY */ |
1423 | { |
1424 | Cycles = 4; |
1425 | Regs.YR = POP (); |
1426 | TEST_ZF (Regs.YR); |
1427 | TEST_SF (Regs.YR); |
1428 | Regs.PC += 1; |
1429 | } |
1430 | |
1431 | |
1432 | |
1433 | static void OPC_65SC02_7C (void) |
1434 | /* Opcode $7C: JMP (ind,X) */ |
1435 | { |
1436 | unsigned PC, Adr; |
1437 | Cycles = 6; |
1438 | PC = Regs.PC; |
1439 | Adr = MemReadWord (PC+1); |
1440 | Regs.PC = MemReadWord(Adr+Regs.XR); |
1441 | |
1442 | ParaVirtHooks (&Regs); |
1443 | } |
1444 | |
1445 | |
1446 | |
1447 | static void OPC_6502_7D (void) |
1448 | /* Opcode $7D: ADC abs,x */ |
1449 | { |
1450 | unsigned Addr; |
1451 | Cycles = 4; |
1452 | Addr = MemReadWord (Regs.PC+1); |
1453 | if (PAGE_CROSS (Addr, Regs.XR)) { |
1454 | ++Cycles; |
1455 | } |
1456 | ADC (MemReadByte (Addr + Regs.XR)); |
1457 | Regs.PC += 3; |
1458 | } |
1459 | |
1460 | |
1461 | |
1462 | static void OPC_6502_7E (void) |
1463 | /* Opcode $7E: ROR abs,x */ |
1464 | { |
1465 | unsigned Addr; |
1466 | unsigned Val; |
1467 | Cycles = 7; |
1468 | Addr = MemReadWord (Regs.PC+1) + Regs.XR; |
1469 | if (CPU != CPU_6502 && !PAGE_CROSS (Addr, Regs.XR)) |
1470 | --Cycles; |
1471 | Val = MemReadByte (Addr); |
1472 | ROR (Val); |
1473 | MemWriteByte (Addr, Val); |
1474 | Regs.PC += 3; |
1475 | } |
1476 | |
1477 | |
1478 | |
1479 | static void OPC_65SC02_80 (void) |
1480 | /* Opcode $80: BRA */ |
1481 | { |
1482 | BRANCH (1); |
1483 | } |
1484 | |
1485 | |
1486 | |
1487 | static void OPC_6502_81 (void) |
1488 | /* Opcode $81: STA (zp,x) */ |
1489 | { |
1490 | unsigned char ZPAddr; |
1491 | unsigned Addr; |
1492 | Cycles = 6; |
1493 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
1494 | Addr = MemReadZPWord (ZPAddr); |
1495 | MemWriteByte (Addr, Regs.AC); |
1496 | Regs.PC += 2; |
1497 | } |
1498 | |
1499 | |
1500 | |
1501 | static void OPC_6502_84 (void) |
1502 | /* Opcode $84: STY zp */ |
1503 | { |
1504 | unsigned char ZPAddr; |
1505 | Cycles = 3; |
1506 | ZPAddr = MemReadByte (Regs.PC+1); |
1507 | MemWriteByte (ZPAddr, Regs.YR); |
1508 | Regs.PC += 2; |
1509 | } |
1510 | |
1511 | |
1512 | |
1513 | static void OPC_6502_85 (void) |
1514 | /* Opcode $85: STA zp */ |
1515 | { |
1516 | unsigned char ZPAddr; |
1517 | Cycles = 3; |
1518 | ZPAddr = MemReadByte (Regs.PC+1); |
1519 | MemWriteByte (ZPAddr, Regs.AC); |
1520 | Regs.PC += 2; |
1521 | } |
1522 | |
1523 | |
1524 | |
1525 | static void OPC_6502_86 (void) |
1526 | /* Opcode $86: STX zp */ |
1527 | { |
1528 | unsigned char ZPAddr; |
1529 | Cycles = 3; |
1530 | ZPAddr = MemReadByte (Regs.PC+1); |
1531 | MemWriteByte (ZPAddr, Regs.XR); |
1532 | Regs.PC += 2; |
1533 | } |
1534 | |
1535 | |
1536 | |
1537 | static void OPC_6502_88 (void) |
1538 | /* Opcode $88: DEY */ |
1539 | { |
1540 | Cycles = 2; |
1541 | Regs.YR = (Regs.YR - 1) & 0xFF; |
1542 | TEST_ZF (Regs.YR); |
1543 | TEST_SF (Regs.YR); |
1544 | Regs.PC += 1; |
1545 | } |
1546 | |
1547 | |
1548 | |
1549 | static void OPC_65SC02_89 (void) |
1550 | /* Opcode $89: BIT #imm */ |
1551 | { |
1552 | unsigned char Val; |
1553 | Cycles = 2; |
1554 | Val = MemReadByte (Regs.PC+1); |
1555 | SET_SF (Val & 0x80); |
1556 | SET_OF (Val & 0x40); |
1557 | SET_ZF ((Val & Regs.AC) == 0); |
1558 | Regs.PC += 2; |
1559 | } |
1560 | |
1561 | |
1562 | |
1563 | static void OPC_6502_8A (void) |
1564 | /* Opcode $8A: TXA */ |
1565 | { |
1566 | Cycles = 2; |
1567 | Regs.AC = Regs.XR; |
1568 | TEST_ZF (Regs.AC); |
1569 | TEST_SF (Regs.AC); |
1570 | Regs.PC += 1; |
1571 | } |
1572 | |
1573 | |
1574 | |
1575 | static void OPC_6502_8C (void) |
1576 | /* Opcode $8C: STY abs */ |
1577 | { |
1578 | unsigned Addr; |
1579 | Cycles = 4; |
1580 | Addr = MemReadWord (Regs.PC+1); |
1581 | MemWriteByte (Addr, Regs.YR); |
1582 | Regs.PC += 3; |
1583 | } |
1584 | |
1585 | |
1586 | |
1587 | static void OPC_6502_8D (void) |
1588 | /* Opcode $8D: STA abs */ |
1589 | { |
1590 | unsigned Addr; |
1591 | Cycles = 4; |
1592 | Addr = MemReadWord (Regs.PC+1); |
1593 | MemWriteByte (Addr, Regs.AC); |
1594 | Regs.PC += 3; |
1595 | } |
1596 | |
1597 | |
1598 | |
1599 | static void OPC_6502_8E (void) |
1600 | /* Opcode $8E: STX abs */ |
1601 | { |
1602 | unsigned Addr; |
1603 | Cycles = 4; |
1604 | Addr = MemReadWord (Regs.PC+1); |
1605 | MemWriteByte (Addr, Regs.XR); |
1606 | Regs.PC += 3; |
1607 | } |
1608 | |
1609 | |
1610 | |
1611 | static void OPC_6502_90 (void) |
1612 | /* Opcode $90: BCC */ |
1613 | { |
1614 | BRANCH (!GET_CF ()); |
1615 | } |
1616 | |
1617 | |
1618 | |
1619 | static void OPC_6502_91 (void) |
1620 | /* Opcode $91: sta (zp),y */ |
1621 | { |
1622 | unsigned char ZPAddr; |
1623 | unsigned Addr; |
1624 | Cycles = 6; |
1625 | ZPAddr = MemReadByte (Regs.PC+1); |
1626 | Addr = MemReadZPWord (ZPAddr) + Regs.YR; |
1627 | MemWriteByte (Addr, Regs.AC); |
1628 | Regs.PC += 2; |
1629 | } |
1630 | |
1631 | |
1632 | |
1633 | static void OPC_65SC02_92 (void) |
1634 | /* Opcode $92: sta (zp) */ |
1635 | { |
1636 | unsigned char ZPAddr; |
1637 | unsigned Addr; |
1638 | Cycles = 5; |
1639 | ZPAddr = MemReadByte (Regs.PC+1); |
1640 | Addr = MemReadZPWord (ZPAddr); |
1641 | MemWriteByte (Addr, Regs.AC); |
1642 | Regs.PC += 2; |
1643 | } |
1644 | |
1645 | |
1646 | |
1647 | static void OPC_6502_94 (void) |
1648 | /* Opcode $94: STY zp,x */ |
1649 | { |
1650 | unsigned char ZPAddr; |
1651 | Cycles = 4; |
1652 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
1653 | MemWriteByte (ZPAddr, Regs.YR); |
1654 | Regs.PC += 2; |
1655 | } |
1656 | |
1657 | |
1658 | |
1659 | static void OPC_6502_95 (void) |
1660 | /* Opcode $95: STA zp,x */ |
1661 | { |
1662 | unsigned char ZPAddr; |
1663 | Cycles = 4; |
1664 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
1665 | MemWriteByte (ZPAddr, Regs.AC); |
1666 | Regs.PC += 2; |
1667 | } |
1668 | |
1669 | |
1670 | |
1671 | static void OPC_6502_96 (void) |
1672 | /* Opcode $96: stx zp,y */ |
1673 | { |
1674 | unsigned char ZPAddr; |
1675 | Cycles = 4; |
1676 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR; |
1677 | MemWriteByte (ZPAddr, Regs.XR); |
1678 | Regs.PC += 2; |
1679 | } |
1680 | |
1681 | |
1682 | |
1683 | static void OPC_6502_98 (void) |
1684 | /* Opcode $98: TYA */ |
1685 | { |
1686 | Cycles = 2; |
1687 | Regs.AC = Regs.YR; |
1688 | TEST_ZF (Regs.AC); |
1689 | TEST_SF (Regs.AC); |
1690 | Regs.PC += 1; |
1691 | } |
1692 | |
1693 | |
1694 | |
1695 | static void OPC_6502_99 (void) |
1696 | /* Opcode $99: STA abs,y */ |
1697 | { |
1698 | unsigned Addr; |
1699 | Cycles = 5; |
1700 | Addr = MemReadWord (Regs.PC+1) + Regs.YR; |
1701 | MemWriteByte (Addr, Regs.AC); |
1702 | Regs.PC += 3; |
1703 | } |
1704 | |
1705 | |
1706 | |
1707 | static void OPC_6502_9A (void) |
1708 | /* Opcode $9A: TXS */ |
1709 | { |
1710 | Cycles = 2; |
1711 | Regs.SP = Regs.XR; |
1712 | Regs.PC += 1; |
1713 | } |
1714 | |
1715 | |
1716 | |
1717 | static void OPC_65SC02_9C (void) |
1718 | /* Opcode $9C: STZ abs */ |
1719 | { |
1720 | unsigned Addr; |
1721 | Cycles = 4; |
1722 | Addr = MemReadWord (Regs.PC+1); |
1723 | MemWriteByte (Addr, 0); |
1724 | Regs.PC += 3; |
1725 | } |
1726 | |
1727 | |
1728 | |
1729 | static void OPC_6502_9D (void) |
1730 | /* Opcode $9D: STA abs,x */ |
1731 | { |
1732 | unsigned Addr; |
1733 | Cycles = 5; |
1734 | Addr = MemReadWord (Regs.PC+1) + Regs.XR; |
1735 | MemWriteByte (Addr, Regs.AC); |
1736 | Regs.PC += 3; |
1737 | } |
1738 | |
1739 | |
1740 | |
1741 | static void OPC_65SC02_9E (void) |
1742 | /* Opcode $9E: STZ abs,x */ |
1743 | { |
1744 | unsigned Addr; |
1745 | Cycles = 5; |
1746 | Addr = MemReadWord (Regs.PC+1) + Regs.XR; |
1747 | MemWriteByte (Addr, 0); |
1748 | Regs.PC += 3; |
1749 | } |
1750 | |
1751 | |
1752 | |
1753 | static void OPC_6502_A0 (void) |
1754 | /* Opcode $A0: LDY #imm */ |
1755 | { |
1756 | Cycles = 2; |
1757 | Regs.YR = MemReadByte (Regs.PC+1); |
1758 | TEST_ZF (Regs.YR); |
1759 | TEST_SF (Regs.YR); |
1760 | Regs.PC += 2; |
1761 | } |
1762 | |
1763 | |
1764 | |
1765 | static void OPC_6502_A1 (void) |
1766 | /* Opcode $A1: LDA (zp,x) */ |
1767 | { |
1768 | unsigned char ZPAddr; |
1769 | unsigned Addr; |
1770 | Cycles = 6; |
1771 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
1772 | Addr = MemReadZPWord (ZPAddr); |
1773 | Regs.AC = MemReadByte (Addr); |
1774 | TEST_ZF (Regs.AC); |
1775 | TEST_SF (Regs.AC); |
1776 | Regs.PC += 2; |
1777 | } |
1778 | |
1779 | |
1780 | |
1781 | static void OPC_6502_A2 (void) |
1782 | /* Opcode $A2: LDX #imm */ |
1783 | { |
1784 | Cycles = 2; |
1785 | Regs.XR = MemReadByte (Regs.PC+1); |
1786 | TEST_ZF (Regs.XR); |
1787 | TEST_SF (Regs.XR); |
1788 | Regs.PC += 2; |
1789 | } |
1790 | |
1791 | |
1792 | |
1793 | static void OPC_6502_A4 (void) |
1794 | /* Opcode $A4: LDY zp */ |
1795 | { |
1796 | unsigned char ZPAddr; |
1797 | Cycles = 3; |
1798 | ZPAddr = MemReadByte (Regs.PC+1); |
1799 | Regs.YR = MemReadByte (ZPAddr); |
1800 | TEST_ZF (Regs.YR); |
1801 | TEST_SF (Regs.YR); |
1802 | Regs.PC += 2; |
1803 | } |
1804 | |
1805 | |
1806 | |
1807 | static void OPC_6502_A5 (void) |
1808 | /* Opcode $A5: LDA zp */ |
1809 | { |
1810 | unsigned char ZPAddr; |
1811 | Cycles = 3; |
1812 | ZPAddr = MemReadByte (Regs.PC+1); |
1813 | Regs.AC = MemReadByte (ZPAddr); |
1814 | TEST_ZF (Regs.AC); |
1815 | TEST_SF (Regs.AC); |
1816 | Regs.PC += 2; |
1817 | } |
1818 | |
1819 | |
1820 | |
1821 | static void OPC_6502_A6 (void) |
1822 | /* Opcode $A6: LDX zp */ |
1823 | { |
1824 | unsigned char ZPAddr; |
1825 | Cycles = 3; |
1826 | ZPAddr = MemReadByte (Regs.PC+1); |
1827 | Regs.XR = MemReadByte (ZPAddr); |
1828 | TEST_ZF (Regs.XR); |
1829 | TEST_SF (Regs.XR); |
1830 | Regs.PC += 2; |
1831 | } |
1832 | |
1833 | |
1834 | |
1835 | static void OPC_6502_A8 (void) |
1836 | /* Opcode $A8: TAY */ |
1837 | { |
1838 | Cycles = 2; |
1839 | Regs.YR = Regs.AC; |
1840 | TEST_ZF (Regs.YR); |
1841 | TEST_SF (Regs.YR); |
1842 | Regs.PC += 1; |
1843 | } |
1844 | |
1845 | |
1846 | |
1847 | static void OPC_6502_A9 (void) |
1848 | /* Opcode $A9: LDA #imm */ |
1849 | { |
1850 | Cycles = 2; |
1851 | Regs.AC = MemReadByte (Regs.PC+1); |
1852 | TEST_ZF (Regs.AC); |
1853 | TEST_SF (Regs.AC); |
1854 | Regs.PC += 2; |
1855 | } |
1856 | |
1857 | |
1858 | |
1859 | static void OPC_6502_AA (void) |
1860 | /* Opcode $AA: TAX */ |
1861 | { |
1862 | Cycles = 2; |
1863 | Regs.XR = Regs.AC; |
1864 | TEST_ZF (Regs.XR); |
1865 | TEST_SF (Regs.XR); |
1866 | Regs.PC += 1; |
1867 | } |
1868 | |
1869 | |
1870 | |
1871 | static void OPC_6502_AC (void) |
1872 | /* Opcode $Regs.AC: LDY abs */ |
1873 | { |
1874 | unsigned Addr; |
1875 | Cycles = 4; |
1876 | Addr = MemReadWord (Regs.PC+1); |
1877 | Regs.YR = MemReadByte (Addr); |
1878 | TEST_ZF (Regs.YR); |
1879 | TEST_SF (Regs.YR); |
1880 | Regs.PC += 3; |
1881 | } |
1882 | |
1883 | |
1884 | |
1885 | static void OPC_6502_AD (void) |
1886 | /* Opcode $AD: LDA abs */ |
1887 | { |
1888 | unsigned Addr; |
1889 | Cycles = 4; |
1890 | Addr = MemReadWord (Regs.PC+1); |
1891 | Regs.AC = MemReadByte (Addr); |
1892 | TEST_ZF (Regs.AC); |
1893 | TEST_SF (Regs.AC); |
1894 | Regs.PC += 3; |
1895 | } |
1896 | |
1897 | |
1898 | |
1899 | static void OPC_6502_AE (void) |
1900 | /* Opcode $AE: LDX abs */ |
1901 | { |
1902 | unsigned Addr; |
1903 | Cycles = 4; |
1904 | Addr = MemReadWord (Regs.PC+1); |
1905 | Regs.XR = MemReadByte (Addr); |
1906 | TEST_ZF (Regs.XR); |
1907 | TEST_SF (Regs.XR); |
1908 | Regs.PC += 3; |
1909 | } |
1910 | |
1911 | |
1912 | |
1913 | static void OPC_6502_B0 (void) |
1914 | /* Opcode $B0: BCS */ |
1915 | { |
1916 | BRANCH (GET_CF ()); |
1917 | } |
1918 | |
1919 | |
1920 | |
1921 | static void OPC_6502_B1 (void) |
1922 | /* Opcode $B1: LDA (zp),y */ |
1923 | { |
1924 | unsigned char ZPAddr; |
1925 | unsigned Addr; |
1926 | Cycles = 5; |
1927 | ZPAddr = MemReadByte (Regs.PC+1); |
1928 | Addr = MemReadZPWord (ZPAddr); |
1929 | if (PAGE_CROSS (Addr, Regs.YR)) { |
1930 | ++Cycles; |
1931 | } |
1932 | Regs.AC = MemReadByte (Addr + Regs.YR); |
1933 | TEST_ZF (Regs.AC); |
1934 | TEST_SF (Regs.AC); |
1935 | Regs.PC += 2; |
1936 | } |
1937 | |
1938 | |
1939 | |
1940 | static void OPC_65SC02_B2 (void) |
1941 | /* Opcode $B2: LDA (zp) */ |
1942 | { |
1943 | unsigned char ZPAddr; |
1944 | unsigned Addr; |
1945 | Cycles = 5; |
1946 | ZPAddr = MemReadByte (Regs.PC+1); |
1947 | Addr = MemReadZPWord (ZPAddr); |
1948 | Regs.AC = MemReadByte (Addr); |
1949 | TEST_ZF (Regs.AC); |
1950 | TEST_SF (Regs.AC); |
1951 | Regs.PC += 2; |
1952 | } |
1953 | |
1954 | |
1955 | |
1956 | static void OPC_6502_B4 (void) |
1957 | /* Opcode $B4: LDY zp,x */ |
1958 | { |
1959 | unsigned char ZPAddr; |
1960 | Cycles = 4; |
1961 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
1962 | Regs.YR = MemReadByte (ZPAddr); |
1963 | TEST_ZF (Regs.YR); |
1964 | TEST_SF (Regs.YR); |
1965 | Regs.PC += 2; |
1966 | } |
1967 | |
1968 | |
1969 | |
1970 | static void OPC_6502_B5 (void) |
1971 | /* Opcode $B5: LDA zp,x */ |
1972 | { |
1973 | unsigned char ZPAddr; |
1974 | Cycles = 4; |
1975 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
1976 | Regs.AC = MemReadByte (ZPAddr); |
1977 | TEST_ZF (Regs.AC); |
1978 | TEST_SF (Regs.AC); |
1979 | Regs.PC += 2; |
1980 | } |
1981 | |
1982 | |
1983 | |
1984 | static void OPC_6502_B6 (void) |
1985 | /* Opcode $B6: LDX zp,y */ |
1986 | { |
1987 | unsigned char ZPAddr; |
1988 | Cycles = 4; |
1989 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.YR; |
1990 | Regs.XR = MemReadByte (ZPAddr); |
1991 | TEST_ZF (Regs.XR); |
1992 | TEST_SF (Regs.XR); |
1993 | Regs.PC += 2; |
1994 | } |
1995 | |
1996 | |
1997 | |
1998 | static void OPC_6502_B8 (void) |
1999 | /* Opcode $B8: CLV */ |
2000 | { |
2001 | Cycles = 2; |
2002 | SET_OF (0); |
2003 | Regs.PC += 1; |
2004 | } |
2005 | |
2006 | |
2007 | |
2008 | static void OPC_6502_B9 (void) |
2009 | /* Opcode $B9: LDA abs,y */ |
2010 | { |
2011 | unsigned Addr; |
2012 | Cycles = 4; |
2013 | Addr = MemReadWord (Regs.PC+1); |
2014 | if (PAGE_CROSS (Addr, Regs.YR)) { |
2015 | ++Cycles; |
2016 | } |
2017 | Regs.AC = MemReadByte (Addr + Regs.YR); |
2018 | TEST_ZF (Regs.AC); |
2019 | TEST_SF (Regs.AC); |
2020 | Regs.PC += 3; |
2021 | } |
2022 | |
2023 | |
2024 | |
2025 | static void OPC_6502_BA (void) |
2026 | /* Opcode $BA: TSX */ |
2027 | { |
2028 | Cycles = 2; |
2029 | Regs.XR = Regs.SP & 0xFF; |
2030 | TEST_ZF (Regs.XR); |
2031 | TEST_SF (Regs.XR); |
2032 | Regs.PC += 1; |
2033 | } |
2034 | |
2035 | |
2036 | |
2037 | static void OPC_6502_BC (void) |
2038 | /* Opcode $BC: LDY abs,x */ |
2039 | { |
2040 | unsigned Addr; |
2041 | Cycles = 4; |
2042 | Addr = MemReadWord (Regs.PC+1); |
2043 | if (PAGE_CROSS (Addr, Regs.XR)) { |
2044 | ++Cycles; |
2045 | } |
2046 | Regs.YR = MemReadByte (Addr + Regs.XR); |
2047 | TEST_ZF (Regs.YR); |
2048 | TEST_SF (Regs.YR); |
2049 | Regs.PC += 3; |
2050 | } |
2051 | |
2052 | |
2053 | |
2054 | static void OPC_6502_BD (void) |
2055 | /* Opcode $BD: LDA abs,x */ |
2056 | { |
2057 | unsigned Addr; |
2058 | Cycles = 4; |
2059 | Addr = MemReadWord (Regs.PC+1); |
2060 | if (PAGE_CROSS (Addr, Regs.XR)) { |
2061 | ++Cycles; |
2062 | } |
2063 | Regs.AC = MemReadByte (Addr + Regs.XR); |
2064 | TEST_ZF (Regs.AC); |
2065 | TEST_SF (Regs.AC); |
2066 | Regs.PC += 3; |
2067 | } |
2068 | |
2069 | |
2070 | |
2071 | static void OPC_6502_BE (void) |
2072 | /* Opcode $BE: LDX abs,y */ |
2073 | { |
2074 | unsigned Addr; |
2075 | Cycles = 4; |
2076 | Addr = MemReadWord (Regs.PC+1); |
2077 | if (PAGE_CROSS (Addr, Regs.YR)) { |
2078 | ++Cycles; |
2079 | } |
2080 | Regs.XR = MemReadByte (Addr + Regs.YR); |
2081 | TEST_ZF (Regs.XR); |
2082 | TEST_SF (Regs.XR); |
2083 | Regs.PC += 3; |
2084 | } |
2085 | |
2086 | |
2087 | |
2088 | static void OPC_6502_C0 (void) |
2089 | /* Opcode $C0: CPY #imm */ |
2090 | { |
2091 | Cycles = 2; |
2092 | CMP (Regs.YR, MemReadByte (Regs.PC+1)); |
2093 | Regs.PC += 2; |
2094 | } |
2095 | |
2096 | |
2097 | |
2098 | static void OPC_6502_C1 (void) |
2099 | /* Opcode $C1: CMP (zp,x) */ |
2100 | { |
2101 | unsigned char ZPAddr; |
2102 | unsigned Addr; |
2103 | Cycles = 6; |
2104 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
2105 | Addr = MemReadZPWord (ZPAddr); |
2106 | CMP (Regs.AC, MemReadByte (Addr)); |
2107 | Regs.PC += 2; |
2108 | } |
2109 | |
2110 | |
2111 | |
2112 | static void OPC_6502_C4 (void) |
2113 | /* Opcode $C4: CPY zp */ |
2114 | { |
2115 | unsigned char ZPAddr; |
2116 | Cycles = 3; |
2117 | ZPAddr = MemReadByte (Regs.PC+1); |
2118 | CMP (Regs.YR, MemReadByte (ZPAddr)); |
2119 | Regs.PC += 2; |
2120 | } |
2121 | |
2122 | |
2123 | |
2124 | static void OPC_6502_C5 (void) |
2125 | /* Opcode $C5: CMP zp */ |
2126 | { |
2127 | unsigned char ZPAddr; |
2128 | Cycles = 3; |
2129 | ZPAddr = MemReadByte (Regs.PC+1); |
2130 | CMP (Regs.AC, MemReadByte (ZPAddr)); |
2131 | Regs.PC += 2; |
2132 | } |
2133 | |
2134 | |
2135 | |
2136 | static void OPC_6502_C6 (void) |
2137 | /* Opcode $C6: DEC zp */ |
2138 | { |
2139 | unsigned char ZPAddr; |
2140 | unsigned char Val; |
2141 | Cycles = 5; |
2142 | ZPAddr = MemReadByte (Regs.PC+1); |
2143 | Val = MemReadByte (ZPAddr) - 1; |
2144 | MemWriteByte (ZPAddr, Val); |
2145 | TEST_ZF (Val); |
2146 | TEST_SF (Val); |
2147 | Regs.PC += 2; |
2148 | } |
2149 | |
2150 | |
2151 | |
2152 | static void OPC_6502_C8 (void) |
2153 | /* Opcode $C8: INY */ |
2154 | { |
2155 | Cycles = 2; |
2156 | Regs.YR = (Regs.YR + 1) & 0xFF; |
2157 | TEST_ZF (Regs.YR); |
2158 | TEST_SF (Regs.YR); |
2159 | Regs.PC += 1; |
2160 | } |
2161 | |
2162 | |
2163 | |
2164 | static void OPC_6502_C9 (void) |
2165 | /* Opcode $C9: CMP #imm */ |
2166 | { |
2167 | Cycles = 2; |
2168 | CMP (Regs.AC, MemReadByte (Regs.PC+1)); |
2169 | Regs.PC += 2; |
2170 | } |
2171 | |
2172 | |
2173 | |
2174 | static void OPC_6502_CA (void) |
2175 | /* Opcode $CA: DEX */ |
2176 | { |
2177 | Cycles = 2; |
2178 | Regs.XR = (Regs.XR - 1) & 0xFF; |
2179 | TEST_ZF (Regs.XR); |
2180 | TEST_SF (Regs.XR); |
2181 | Regs.PC += 1; |
2182 | } |
2183 | |
2184 | |
2185 | |
2186 | static void OPC_6502_CC (void) |
2187 | /* Opcode $CC: CPY abs */ |
2188 | { |
2189 | unsigned Addr; |
2190 | Cycles = 4; |
2191 | Addr = MemReadWord (Regs.PC+1); |
2192 | CMP (Regs.YR, MemReadByte (Addr)); |
2193 | Regs.PC += 3; |
2194 | } |
2195 | |
2196 | |
2197 | |
2198 | static void OPC_6502_CD (void) |
2199 | /* Opcode $CD: CMP abs */ |
2200 | { |
2201 | unsigned Addr; |
2202 | Cycles = 4; |
2203 | Addr = MemReadWord (Regs.PC+1); |
2204 | CMP (Regs.AC, MemReadByte (Addr)); |
2205 | Regs.PC += 3; |
2206 | } |
2207 | |
2208 | |
2209 | |
2210 | static void OPC_6502_CE (void) |
2211 | /* Opcode $CE: DEC abs */ |
2212 | { |
2213 | unsigned Addr; |
2214 | unsigned char Val; |
2215 | Cycles = 6; |
2216 | Addr = MemReadWord (Regs.PC+1); |
2217 | Val = MemReadByte (Addr) - 1; |
2218 | MemWriteByte (Addr, Val); |
2219 | TEST_ZF (Val); |
2220 | TEST_SF (Val); |
2221 | Regs.PC += 3; |
2222 | } |
2223 | |
2224 | |
2225 | |
2226 | static void OPC_6502_D0 (void) |
2227 | /* Opcode $D0: BNE */ |
2228 | { |
2229 | BRANCH (!GET_ZF ()); |
2230 | } |
2231 | |
2232 | |
2233 | |
2234 | static void OPC_6502_D1 (void) |
2235 | /* Opcode $D1: CMP (zp),y */ |
2236 | { |
2237 | unsigned ZPAddr; |
2238 | unsigned Addr; |
2239 | Cycles = 5; |
2240 | ZPAddr = MemReadByte (Regs.PC+1); |
2241 | Addr = MemReadWord (ZPAddr); |
2242 | if (PAGE_CROSS (Addr, Regs.YR)) { |
2243 | ++Cycles; |
2244 | } |
2245 | CMP (Regs.AC, MemReadByte (Addr + Regs.YR)); |
2246 | Regs.PC += 2; |
2247 | } |
2248 | |
2249 | |
2250 | |
2251 | static void OPC_65SC02_D2 (void) |
2252 | /* Opcode $D2: CMP (zp) */ |
2253 | { |
2254 | unsigned ZPAddr; |
2255 | unsigned Addr; |
2256 | Cycles = 5; |
2257 | ZPAddr = MemReadByte (Regs.PC+1); |
2258 | Addr = MemReadWord (ZPAddr); |
2259 | CMP (Regs.AC, MemReadByte (Addr)); |
2260 | Regs.PC += 2; |
2261 | } |
2262 | |
2263 | |
2264 | |
2265 | static void OPC_6502_D5 (void) |
2266 | /* Opcode $D5: CMP zp,x */ |
2267 | { |
2268 | unsigned char ZPAddr; |
2269 | Cycles = 4; |
2270 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
2271 | CMP (Regs.AC, MemReadByte (ZPAddr)); |
2272 | Regs.PC += 2; |
2273 | } |
2274 | |
2275 | |
2276 | |
2277 | static void OPC_6502_D6 (void) |
2278 | /* Opcode $D6: DEC zp,x */ |
2279 | { |
2280 | unsigned char ZPAddr; |
2281 | unsigned char Val; |
2282 | Cycles = 6; |
2283 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
2284 | Val = MemReadByte (ZPAddr) - 1; |
2285 | MemWriteByte (ZPAddr, Val); |
2286 | TEST_ZF (Val); |
2287 | TEST_SF (Val); |
2288 | Regs.PC += 2; |
2289 | } |
2290 | |
2291 | |
2292 | |
2293 | static void OPC_6502_D8 (void) |
2294 | /* Opcode $D8: CLD */ |
2295 | { |
2296 | Cycles = 2; |
2297 | SET_DF (0); |
2298 | Regs.PC += 1; |
2299 | } |
2300 | |
2301 | |
2302 | |
2303 | static void OPC_6502_D9 (void) |
2304 | /* Opcode $D9: CMP abs,y */ |
2305 | { |
2306 | unsigned Addr; |
2307 | Cycles = 4; |
2308 | Addr = MemReadWord (Regs.PC+1); |
2309 | if (PAGE_CROSS (Addr, Regs.YR)) { |
2310 | ++Cycles; |
2311 | } |
2312 | CMP (Regs.AC, MemReadByte (Addr + Regs.YR)); |
2313 | Regs.PC += 3; |
2314 | } |
2315 | |
2316 | |
2317 | |
2318 | static void OPC_65SC02_DA (void) |
2319 | /* Opcode $DA: PHX */ |
2320 | { |
2321 | Cycles = 3; |
2322 | PUSH (Regs.XR); |
2323 | Regs.PC += 1; |
2324 | } |
2325 | |
2326 | |
2327 | |
2328 | static void OPC_6502_DD (void) |
2329 | /* Opcode $DD: CMP abs,x */ |
2330 | { |
2331 | unsigned Addr; |
2332 | Cycles = 4; |
2333 | Addr = MemReadWord (Regs.PC+1); |
2334 | if (PAGE_CROSS (Addr, Regs.XR)) { |
2335 | ++Cycles; |
2336 | } |
2337 | CMP (Regs.AC, MemReadByte (Addr + Regs.XR)); |
2338 | Regs.PC += 3; |
2339 | } |
2340 | |
2341 | |
2342 | |
2343 | static void OPC_6502_DE (void) |
2344 | /* Opcode $DE: DEC abs,x */ |
2345 | { |
2346 | unsigned Addr; |
2347 | unsigned char Val; |
2348 | Cycles = 7; |
2349 | Addr = MemReadWord (Regs.PC+1) + Regs.XR; |
2350 | Val = MemReadByte (Addr) - 1; |
2351 | MemWriteByte (Addr, Val); |
2352 | TEST_ZF (Val); |
2353 | TEST_SF (Val); |
2354 | Regs.PC += 3; |
2355 | } |
2356 | |
2357 | |
2358 | |
2359 | static void OPC_6502_E0 (void) |
2360 | /* Opcode $E0: CPX #imm */ |
2361 | { |
2362 | Cycles = 2; |
2363 | CMP (Regs.XR, MemReadByte (Regs.PC+1)); |
2364 | Regs.PC += 2; |
2365 | } |
2366 | |
2367 | |
2368 | |
2369 | static void OPC_6502_E1 (void) |
2370 | /* Opcode $E1: SBC (zp,x) */ |
2371 | { |
2372 | unsigned char ZPAddr; |
2373 | unsigned Addr; |
2374 | Cycles = 6; |
2375 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
2376 | Addr = MemReadZPWord (ZPAddr); |
2377 | SBC (MemReadByte (Addr)); |
2378 | Regs.PC += 2; |
2379 | } |
2380 | |
2381 | |
2382 | |
2383 | static void OPC_6502_E4 (void) |
2384 | /* Opcode $E4: CPX zp */ |
2385 | { |
2386 | unsigned char ZPAddr; |
2387 | Cycles = 3; |
2388 | ZPAddr = MemReadByte (Regs.PC+1); |
2389 | CMP (Regs.XR, MemReadByte (ZPAddr)); |
2390 | Regs.PC += 2; |
2391 | } |
2392 | |
2393 | |
2394 | |
2395 | static void OPC_6502_E5 (void) |
2396 | /* Opcode $E5: SBC zp */ |
2397 | { |
2398 | unsigned char ZPAddr; |
2399 | Cycles = 3; |
2400 | ZPAddr = MemReadByte (Regs.PC+1); |
2401 | SBC (MemReadByte (ZPAddr)); |
2402 | Regs.PC += 2; |
2403 | } |
2404 | |
2405 | |
2406 | |
2407 | static void OPC_6502_E6 (void) |
2408 | /* Opcode $E6: INC zp */ |
2409 | { |
2410 | unsigned char ZPAddr; |
2411 | unsigned char Val; |
2412 | Cycles = 5; |
2413 | ZPAddr = MemReadByte (Regs.PC+1); |
2414 | Val = MemReadByte (ZPAddr) + 1; |
2415 | MemWriteByte (ZPAddr, Val); |
2416 | TEST_ZF (Val); |
2417 | TEST_SF (Val); |
2418 | Regs.PC += 2; |
2419 | } |
2420 | |
2421 | |
2422 | |
2423 | static void OPC_6502_E8 (void) |
2424 | /* Opcode $E8: INX */ |
2425 | { |
2426 | Cycles = 2; |
2427 | Regs.XR = (Regs.XR + 1) & 0xFF; |
2428 | TEST_ZF (Regs.XR); |
2429 | TEST_SF (Regs.XR); |
2430 | Regs.PC += 1; |
2431 | } |
2432 | |
2433 | |
2434 | |
2435 | static void OPC_6502_E9 (void) |
2436 | /* Opcode $E9: SBC #imm */ |
2437 | { |
2438 | Cycles = 2; |
2439 | SBC (MemReadByte (Regs.PC+1)); |
2440 | Regs.PC += 2; |
2441 | } |
2442 | |
2443 | |
2444 | |
2445 | static void OPC_6502_EA (void) |
2446 | /* Opcode $EA: NOP */ |
2447 | { |
2448 | /* This one is easy... */ |
2449 | Cycles = 2; |
2450 | Regs.PC += 1; |
2451 | } |
2452 | |
2453 | |
2454 | |
2455 | static void OPC_65C02_NOP11(void) |
2456 | /* Opcode 'Illegal' 1 cycle NOP */ |
2457 | { |
2458 | Cycles = 1; |
2459 | Regs.PC += 1; |
2460 | } |
2461 | |
2462 | |
2463 | |
2464 | static void OPC_65C02_NOP22 (void) |
2465 | /* Opcode 'Illegal' 2 byte 2 cycle NOP */ |
2466 | { |
2467 | Cycles = 2; |
2468 | Regs.PC += 2; |
2469 | } |
2470 | |
2471 | |
2472 | |
2473 | static void OPC_65C02_NOP24 (void) |
2474 | /* Opcode 'Illegal' 2 byte 4 cycle NOP */ |
2475 | { |
2476 | Cycles = 4; |
2477 | Regs.PC += 2; |
2478 | } |
2479 | |
2480 | |
2481 | |
2482 | static void OPC_65C02_NOP34 (void) |
2483 | /* Opcode 'Illegal' 3 byte 4 cycle NOP */ |
2484 | { |
2485 | Cycles = 4; |
2486 | Regs.PC += 3; |
2487 | } |
2488 | |
2489 | |
2490 | |
2491 | static void OPC_6502_EC (void) |
2492 | /* Opcode $EC: CPX abs */ |
2493 | { |
2494 | unsigned Addr; |
2495 | Cycles = 4; |
2496 | Addr = MemReadWord (Regs.PC+1); |
2497 | CMP (Regs.XR, MemReadByte (Addr)); |
2498 | Regs.PC += 3; |
2499 | } |
2500 | |
2501 | |
2502 | |
2503 | static void OPC_6502_ED (void) |
2504 | /* Opcode $ED: SBC abs */ |
2505 | { |
2506 | unsigned Addr; |
2507 | Cycles = 4; |
2508 | Addr = MemReadWord (Regs.PC+1); |
2509 | SBC (MemReadByte (Addr)); |
2510 | Regs.PC += 3; |
2511 | } |
2512 | |
2513 | |
2514 | |
2515 | static void OPC_6502_EE (void) |
2516 | /* Opcode $EE: INC abs */ |
2517 | { |
2518 | unsigned Addr; |
2519 | unsigned char Val; |
2520 | Cycles = 6; |
2521 | Addr = MemReadWord (Regs.PC+1); |
2522 | Val = MemReadByte (Addr) + 1; |
2523 | MemWriteByte (Addr, Val); |
2524 | TEST_ZF (Val); |
2525 | TEST_SF (Val); |
2526 | Regs.PC += 3; |
2527 | } |
2528 | |
2529 | |
2530 | |
2531 | static void OPC_6502_F0 (void) |
2532 | /* Opcode $F0: BEQ */ |
2533 | { |
2534 | BRANCH (GET_ZF ()); |
2535 | } |
2536 | |
2537 | |
2538 | |
2539 | static void OPC_6502_F1 (void) |
2540 | /* Opcode $F1: SBC (zp),y */ |
2541 | { |
2542 | unsigned char ZPAddr; |
2543 | unsigned Addr; |
2544 | Cycles = 5; |
2545 | ZPAddr = MemReadByte (Regs.PC+1); |
2546 | Addr = MemReadZPWord (ZPAddr); |
2547 | if (PAGE_CROSS (Addr, Regs.YR)) { |
2548 | ++Cycles; |
2549 | } |
2550 | SBC (MemReadByte (Addr + Regs.YR)); |
2551 | Regs.PC += 2; |
2552 | } |
2553 | |
2554 | |
2555 | |
2556 | static void OPC_65SC02_F2 (void) |
2557 | /* Opcode $F2: SBC (zp) */ |
2558 | { |
2559 | unsigned char ZPAddr; |
2560 | unsigned Addr; |
2561 | Cycles = 5; |
2562 | ZPAddr = MemReadByte (Regs.PC+1); |
2563 | Addr = MemReadZPWord (ZPAddr); |
2564 | SBC (MemReadByte (Addr)); |
2565 | Regs.PC += 2; |
2566 | } |
2567 | |
2568 | |
2569 | |
2570 | static void OPC_6502_F5 (void) |
2571 | /* Opcode $F5: SBC zp,x */ |
2572 | { |
2573 | unsigned char ZPAddr; |
2574 | Cycles = 4; |
2575 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
2576 | SBC (MemReadByte (ZPAddr)); |
2577 | Regs.PC += 2; |
2578 | } |
2579 | |
2580 | |
2581 | |
2582 | static void OPC_6502_F6 (void) |
2583 | /* Opcode $F6: INC zp,x */ |
2584 | { |
2585 | unsigned char ZPAddr; |
2586 | unsigned char Val; |
2587 | Cycles = 6; |
2588 | ZPAddr = MemReadByte (Regs.PC+1) + Regs.XR; |
2589 | Val = MemReadByte (ZPAddr) + 1; |
2590 | MemWriteByte (ZPAddr, Val); |
2591 | TEST_ZF (Val); |
2592 | TEST_SF (Val); |
2593 | Regs.PC += 2; |
2594 | } |
2595 | |
2596 | |
2597 | |
2598 | static void OPC_6502_F8 (void) |
2599 | /* Opcode $F8: SED */ |
2600 | { |
2601 | Cycles = 2; |
2602 | SET_DF (1); |
2603 | Regs.PC += 1; |
2604 | } |
2605 | |
2606 | |
2607 | |
2608 | static void OPC_6502_F9 (void) |
2609 | /* Opcode $F9: SBC abs,y */ |
2610 | { |
2611 | unsigned Addr; |
2612 | Cycles = 4; |
2613 | Addr = MemReadWord (Regs.PC+1); |
2614 | if (PAGE_CROSS (Addr, Regs.YR)) { |
2615 | ++Cycles; |
2616 | } |
2617 | SBC (MemReadByte (Addr + Regs.YR)); |
2618 | Regs.PC += 3; |
2619 | } |
2620 | |
2621 | |
2622 | |
2623 | static void OPC_65SC02_FA (void) |
2624 | /* Opcode $7A: PLX */ |
2625 | { |
2626 | Cycles = 4; |
2627 | Regs.XR = POP (); |
2628 | TEST_ZF (Regs.XR); |
2629 | TEST_SF (Regs.XR); |
2630 | Regs.PC += 1; |
2631 | } |
2632 | |
2633 | |
2634 | |
2635 | static void OPC_6502_FD (void) |
2636 | /* Opcode $FD: SBC abs,x */ |
2637 | { |
2638 | unsigned Addr; |
2639 | Cycles = 4; |
2640 | Addr = MemReadWord (Regs.PC+1); |
2641 | if (PAGE_CROSS (Addr, Regs.XR)) { |
2642 | ++Cycles; |
2643 | } |
2644 | SBC (MemReadByte (Addr + Regs.XR)); |
2645 | Regs.PC += 3; |
2646 | } |
2647 | |
2648 | |
2649 | |
2650 | static void OPC_6502_FE (void) |
2651 | /* Opcode $FE: INC abs,x */ |
2652 | { |
2653 | unsigned Addr; |
2654 | unsigned char Val; |
2655 | Cycles = 7; |
2656 | Addr = MemReadWord (Regs.PC+1) + Regs.XR; |
2657 | Val = MemReadByte (Addr) + 1; |
2658 | MemWriteByte (Addr, Val); |
2659 | TEST_ZF (Val); |
2660 | TEST_SF (Val); |
2661 | Regs.PC += 3; |
2662 | } |
2663 | |
2664 | |
2665 | |
2666 | /*****************************************************************************/ |
2667 | /* Opcode handler tables */ |
2668 | /*****************************************************************************/ |
2669 | |
2670 | |
2671 | |
2672 | /* Opcode handler table for the 6502 */ |
2673 | static const OPFunc OP6502Table[256] = { |
2674 | OPC_6502_00, |
2675 | OPC_6502_01, |
2676 | OPC_Illegal, |
2677 | OPC_Illegal, |
2678 | OPC_Illegal, |
2679 | OPC_6502_05, |
2680 | OPC_6502_06, |
2681 | OPC_Illegal, |
2682 | OPC_6502_08, |
2683 | OPC_6502_09, |
2684 | OPC_6502_0A, |
2685 | OPC_Illegal, |
2686 | OPC_Illegal, |
2687 | OPC_6502_0D, |
2688 | OPC_6502_0E, |
2689 | OPC_Illegal, |
2690 | OPC_6502_10, |
2691 | OPC_6502_11, |
2692 | OPC_Illegal, |
2693 | OPC_Illegal, |
2694 | OPC_Illegal, |
2695 | OPC_6502_15, |
2696 | OPC_6502_16, |
2697 | OPC_Illegal, |
2698 | OPC_6502_18, |
2699 | OPC_6502_19, |
2700 | OPC_Illegal, |
2701 | OPC_Illegal, |
2702 | OPC_Illegal, |
2703 | OPC_6502_1D, |
2704 | OPC_6502_1E, |
2705 | OPC_Illegal, |
2706 | OPC_6502_20, |
2707 | OPC_6502_21, |
2708 | OPC_Illegal, |
2709 | OPC_Illegal, |
2710 | OPC_6502_24, |
2711 | OPC_6502_25, |
2712 | OPC_6502_26, |
2713 | OPC_Illegal, |
2714 | OPC_6502_28, |
2715 | OPC_6502_29, |
2716 | OPC_6502_2A, |
2717 | OPC_Illegal, |
2718 | OPC_6502_2C, |
2719 | OPC_6502_2D, |
2720 | OPC_6502_2E, |
2721 | OPC_Illegal, |
2722 | OPC_6502_30, |
2723 | OPC_6502_31, |
2724 | OPC_Illegal, |
2725 | OPC_Illegal, |
2726 | OPC_Illegal, |
2727 | OPC_6502_35, |
2728 | OPC_6502_36, |
2729 | OPC_Illegal, |
2730 | OPC_6502_38, |
2731 | OPC_6502_39, |
2732 | OPC_Illegal, |
2733 | OPC_Illegal, |
2734 | OPC_Illegal, |
2735 | OPC_6502_3D, |
2736 | OPC_6502_3E, |
2737 | OPC_Illegal, |
2738 | OPC_6502_40, |
2739 | OPC_6502_41, |
2740 | OPC_Illegal, |
2741 | OPC_Illegal, |
2742 | OPC_Illegal, |
2743 | OPC_6502_45, |
2744 | OPC_6502_46, |
2745 | OPC_Illegal, |
2746 | OPC_6502_48, |
2747 | OPC_6502_49, |
2748 | OPC_6502_4A, |
2749 | OPC_Illegal, |
2750 | OPC_6502_4C, |
2751 | OPC_6502_4D, |
2752 | OPC_6502_4E, |
2753 | OPC_Illegal, |
2754 | OPC_6502_50, |
2755 | OPC_6502_51, |
2756 | OPC_Illegal, |
2757 | OPC_Illegal, |
2758 | OPC_Illegal, |
2759 | OPC_6502_55, |
2760 | OPC_6502_56, |
2761 | OPC_Illegal, |
2762 | OPC_6502_58, |
2763 | OPC_6502_59, |
2764 | OPC_Illegal, |
2765 | OPC_Illegal, |
2766 | OPC_Illegal, |
2767 | OPC_6502_5D, |
2768 | OPC_6502_5E, |
2769 | OPC_Illegal, |
2770 | OPC_6502_60, |
2771 | OPC_6502_61, |
2772 | OPC_Illegal, |
2773 | OPC_Illegal, |
2774 | OPC_Illegal, |
2775 | OPC_6502_65, |
2776 | OPC_6502_66, |
2777 | OPC_Illegal, |
2778 | OPC_6502_68, |
2779 | OPC_6502_69, |
2780 | OPC_6502_6A, |
2781 | OPC_Illegal, |
2782 | OPC_6502_6C, |
2783 | OPC_6502_6D, |
2784 | OPC_6502_6E, |
2785 | OPC_Illegal, |
2786 | OPC_6502_70, |
2787 | OPC_6502_71, |
2788 | OPC_Illegal, |
2789 | OPC_Illegal, |
2790 | OPC_Illegal, |
2791 | OPC_6502_75, |
2792 | OPC_6502_76, |
2793 | OPC_Illegal, |
2794 | OPC_6502_78, |
2795 | OPC_6502_79, |
2796 | OPC_Illegal, |
2797 | OPC_Illegal, |
2798 | OPC_Illegal, |
2799 | OPC_6502_7D, |
2800 | OPC_6502_7E, |
2801 | OPC_Illegal, |
2802 | OPC_Illegal, |
2803 | OPC_6502_81, |
2804 | OPC_Illegal, |
2805 | OPC_Illegal, |
2806 | OPC_6502_84, |
2807 | OPC_6502_85, |
2808 | OPC_6502_86, |
2809 | OPC_Illegal, |
2810 | OPC_6502_88, |
2811 | OPC_Illegal, |
2812 | OPC_6502_8A, |
2813 | OPC_Illegal, |
2814 | OPC_6502_8C, |
2815 | OPC_6502_8D, |
2816 | OPC_6502_8E, |
2817 | OPC_Illegal, |
2818 | OPC_6502_90, |
2819 | OPC_6502_91, |
2820 | OPC_Illegal, |
2821 | OPC_Illegal, |
2822 | OPC_6502_94, |
2823 | OPC_6502_95, |
2824 | OPC_6502_96, |
2825 | OPC_Illegal, |
2826 | OPC_6502_98, |
2827 | OPC_6502_99, |
2828 | OPC_6502_9A, |
2829 | OPC_Illegal, |
2830 | OPC_Illegal, |
2831 | OPC_6502_9D, |
2832 | OPC_Illegal, |
2833 | OPC_Illegal, |
2834 | OPC_6502_A0, |
2835 | OPC_6502_A1, |
2836 | OPC_6502_A2, |
2837 | OPC_Illegal, |
2838 | OPC_6502_A4, |
2839 | OPC_6502_A5, |
2840 | OPC_6502_A6, |
2841 | OPC_Illegal, |
2842 | OPC_6502_A8, |
2843 | OPC_6502_A9, |
2844 | OPC_6502_AA, |
2845 | OPC_Illegal, |
2846 | OPC_6502_AC, |
2847 | OPC_6502_AD, |
2848 | OPC_6502_AE, |
2849 | OPC_Illegal, |
2850 | OPC_6502_B0, |
2851 | OPC_6502_B1, |
2852 | OPC_Illegal, |
2853 | OPC_Illegal, |
2854 | OPC_6502_B4, |
2855 | OPC_6502_B5, |
2856 | OPC_6502_B6, |
2857 | OPC_Illegal, |
2858 | OPC_6502_B8, |
2859 | OPC_6502_B9, |
2860 | OPC_6502_BA, |
2861 | OPC_Illegal, |
2862 | OPC_6502_BC, |
2863 | OPC_6502_BD, |
2864 | OPC_6502_BE, |
2865 | OPC_Illegal, |
2866 | OPC_6502_C0, |
2867 | OPC_6502_C1, |
2868 | OPC_Illegal, |
2869 | OPC_Illegal, |
2870 | OPC_6502_C4, |
2871 | OPC_6502_C5, |
2872 | OPC_6502_C6, |
2873 | OPC_Illegal, |
2874 | OPC_6502_C8, |
2875 | OPC_6502_C9, |
2876 | OPC_6502_CA, |
2877 | OPC_Illegal, |
2878 | OPC_6502_CC, |
2879 | OPC_6502_CD, |
2880 | OPC_6502_CE, |
2881 | OPC_Illegal, |
2882 | OPC_6502_D0, |
2883 | OPC_6502_D1, |
2884 | OPC_Illegal, |
2885 | OPC_Illegal, |
2886 | OPC_Illegal, |
2887 | OPC_6502_D5, |
2888 | OPC_6502_D6, |
2889 | OPC_Illegal, |
2890 | OPC_6502_D8, |
2891 | OPC_6502_D9, |
2892 | OPC_Illegal, |
2893 | OPC_Illegal, |
2894 | OPC_Illegal, |
2895 | OPC_6502_DD, |
2896 | OPC_6502_DE, |
2897 | OPC_Illegal, |
2898 | OPC_6502_E0, |
2899 | OPC_6502_E1, |
2900 | OPC_Illegal, |
2901 | OPC_Illegal, |
2902 | OPC_6502_E4, |
2903 | OPC_6502_E5, |
2904 | OPC_6502_E6, |
2905 | OPC_Illegal, |
2906 | OPC_6502_E8, |
2907 | OPC_6502_E9, |
2908 | OPC_6502_EA, |
2909 | OPC_Illegal, |
2910 | OPC_6502_EC, |
2911 | OPC_6502_ED, |
2912 | OPC_6502_EE, |
2913 | OPC_Illegal, |
2914 | OPC_6502_F0, |
2915 | OPC_6502_F1, |
2916 | OPC_Illegal, |
2917 | OPC_Illegal, |
2918 | OPC_Illegal, |
2919 | OPC_6502_F5, |
2920 | OPC_6502_F6, |
2921 | OPC_Illegal, |
2922 | OPC_6502_F8, |
2923 | OPC_6502_F9, |
2924 | OPC_Illegal, |
2925 | OPC_Illegal, |
2926 | OPC_Illegal, |
2927 | OPC_6502_FD, |
2928 | OPC_6502_FE, |
2929 | OPC_Illegal, |
2930 | }; |
2931 | |
2932 | |
2933 | |
2934 | /* Opcode handler table for the 65C02 */ |
2935 | static const OPFunc OP65C02Table[256] = { |
2936 | OPC_6502_00, |
2937 | OPC_6502_01, |
2938 | OPC_65C02_NOP22, // $02 |
2939 | OPC_65C02_NOP11, // $03 |
2940 | OPC_65SC02_04, |
2941 | OPC_6502_05, |
2942 | OPC_6502_06, |
2943 | OPC_Illegal, // $07: RMB0 currently unsupported |
2944 | OPC_6502_08, |
2945 | OPC_6502_09, |
2946 | OPC_6502_0A, |
2947 | OPC_65C02_NOP11, // $0B |
2948 | OPC_65SC02_0C, |
2949 | OPC_6502_0D, |
2950 | OPC_6502_0E, |
2951 | OPC_Illegal, // $0F: BBR0 currently unsupported |
2952 | OPC_6502_10, |
2953 | OPC_6502_11, |
2954 | OPC_65SC02_12, |
2955 | OPC_65C02_NOP11, // $13 |
2956 | OPC_65SC02_14, |
2957 | OPC_6502_15, |
2958 | OPC_6502_16, |
2959 | OPC_Illegal, // $17: RMB1 currently unsupported |
2960 | OPC_6502_18, |
2961 | OPC_6502_19, |
2962 | OPC_65SC02_1A, |
2963 | OPC_65C02_NOP11, // $1B |
2964 | OPC_65SC02_1C, |
2965 | OPC_6502_1D, |
2966 | OPC_6502_1E, |
2967 | OPC_Illegal, // $1F: BBR1 currently unsupported |
2968 | OPC_6502_20, |
2969 | OPC_6502_21, |
2970 | OPC_65C02_NOP22, // $22 |
2971 | OPC_65C02_NOP11, // $23 |
2972 | OPC_6502_24, |
2973 | OPC_6502_25, |
2974 | OPC_6502_26, |
2975 | OPC_Illegal, // $27: RMB2 currently unsupported |
2976 | OPC_6502_28, |
2977 | OPC_6502_29, |
2978 | OPC_6502_2A, |
2979 | OPC_65C02_NOP11, // $2B |
2980 | OPC_6502_2C, |
2981 | OPC_6502_2D, |
2982 | OPC_6502_2E, |
2983 | OPC_Illegal, // $2F: BBR2 currently unsupported |
2984 | OPC_6502_30, |
2985 | OPC_6502_31, |
2986 | OPC_65SC02_32, |
2987 | OPC_65C02_NOP11, // $33 |
2988 | OPC_65SC02_34, |
2989 | OPC_6502_35, |
2990 | OPC_6502_36, |
2991 | OPC_Illegal, // $37: RMB3 currently unsupported |
2992 | OPC_6502_38, |
2993 | OPC_6502_39, |
2994 | OPC_65SC02_3A, |
2995 | OPC_65C02_NOP11, // $3B |
2996 | OPC_65SC02_3C, |
2997 | OPC_6502_3D, |
2998 | OPC_6502_3E, |
2999 | OPC_Illegal, // $3F: BBR3 currently unsupported |
3000 | OPC_6502_40, |
3001 | OPC_6502_41, |
3002 | OPC_65C02_NOP22, // $42 |
3003 | OPC_65C02_NOP11, // $43 |
3004 | OPC_65C02_44, // $44 |
3005 | OPC_6502_45, |
3006 | OPC_6502_46, |
3007 | OPC_Illegal, // $47: RMB4 currently unsupported |
3008 | OPC_6502_48, |
3009 | OPC_6502_49, |
3010 | OPC_6502_4A, |
3011 | OPC_65C02_NOP11, // $4B |
3012 | OPC_6502_4C, |
3013 | OPC_6502_4D, |
3014 | OPC_6502_4E, |
3015 | OPC_Illegal, // $4F: BBR4 currently unsupported |
3016 | OPC_6502_50, |
3017 | OPC_6502_51, |
3018 | OPC_65SC02_52, |
3019 | OPC_65C02_NOP11, // $53 |
3020 | OPC_65C02_NOP24, // $54 |
3021 | OPC_6502_55, |
3022 | OPC_6502_56, |
3023 | OPC_Illegal, // $57: RMB5 currently unsupported |
3024 | OPC_6502_58, |
3025 | OPC_6502_59, |
3026 | OPC_65SC02_5A, |
3027 | OPC_65C02_NOP11, // $5B |
3028 | OPC_65C02_5C, |
3029 | OPC_6502_5D, |
3030 | OPC_6502_5E, |
3031 | OPC_Illegal, // $5F: BBR5 currently unsupported |
3032 | OPC_6502_60, |
3033 | OPC_6502_61, |
3034 | OPC_65C02_NOP22, // $62 |
3035 | OPC_65C02_NOP11, // $63 |
3036 | OPC_65SC02_64, |
3037 | OPC_6502_65, |
3038 | OPC_6502_66, |
3039 | OPC_Illegal, // $67: RMB6 currently unsupported |
3040 | OPC_6502_68, |
3041 | OPC_6502_69, |
3042 | OPC_6502_6A, |
3043 | OPC_65C02_NOP11, // $6B |
3044 | OPC_65C02_6C, |
3045 | OPC_6502_6D, |
3046 | OPC_6502_6E, |
3047 | OPC_Illegal, // $6F: BBR6 currently unsupported |
3048 | OPC_6502_70, |
3049 | OPC_6502_71, |
3050 | OPC_65SC02_72, |
3051 | OPC_65C02_NOP11, // $73 |
3052 | OPC_65SC02_74, |
3053 | OPC_6502_75, |
3054 | OPC_6502_76, |
3055 | OPC_Illegal, // $77: RMB7 currently unsupported |
3056 | OPC_6502_78, |
3057 | OPC_6502_79, |
3058 | OPC_65SC02_7A, |
3059 | OPC_65C02_NOP11, // $7B |
3060 | OPC_65SC02_7C, |
3061 | OPC_6502_7D, |
3062 | OPC_6502_7E, |
3063 | OPC_Illegal, // $7F: BBR7 currently unsupported |
3064 | OPC_65SC02_80, |
3065 | OPC_6502_81, |
3066 | OPC_65C02_NOP22, // $82 |
3067 | OPC_65C02_NOP11, // $83 |
3068 | OPC_6502_84, |
3069 | OPC_6502_85, |
3070 | OPC_6502_86, |
3071 | OPC_Illegal, // $87: SMB0 currently unsupported |
3072 | OPC_6502_88, |
3073 | OPC_65SC02_89, |
3074 | OPC_6502_8A, |
3075 | OPC_65C02_NOP11, // $8B |
3076 | OPC_6502_8C, |
3077 | OPC_6502_8D, |
3078 | OPC_6502_8E, |
3079 | OPC_Illegal, // $8F: BBS0 currently unsupported |
3080 | OPC_6502_90, |
3081 | OPC_6502_91, |
3082 | OPC_65SC02_92, |
3083 | OPC_65C02_NOP11, // $93 |
3084 | OPC_6502_94, |
3085 | OPC_6502_95, |
3086 | OPC_6502_96, |
3087 | OPC_Illegal, // $97: SMB1 currently unsupported |
3088 | OPC_6502_98, |
3089 | OPC_6502_99, |
3090 | OPC_6502_9A, |
3091 | OPC_65C02_NOP11, // $9B |
3092 | OPC_65SC02_9C, |
3093 | OPC_6502_9D, |
3094 | OPC_65SC02_9E, |
3095 | OPC_Illegal, // $9F: BBS1 currently unsupported |
3096 | OPC_6502_A0, |
3097 | OPC_6502_A1, |
3098 | OPC_6502_A2, |
3099 | OPC_65C02_NOP11, // $A3 |
3100 | OPC_6502_A4, |
3101 | OPC_6502_A5, |
3102 | OPC_6502_A6, |
3103 | OPC_Illegal, // $A7: SMB2 currently unsupported |
3104 | OPC_6502_A8, |
3105 | OPC_6502_A9, |
3106 | OPC_6502_AA, |
3107 | OPC_65C02_NOP11, // $AB |
3108 | OPC_6502_AC, |
3109 | OPC_6502_AD, |
3110 | OPC_6502_AE, |
3111 | OPC_Illegal, // $AF: BBS2 currently unsupported |
3112 | OPC_6502_B0, |
3113 | OPC_6502_B1, |
3114 | OPC_65SC02_B2, |
3115 | OPC_65C02_NOP11, // $B3 |
3116 | OPC_6502_B4, |
3117 | OPC_6502_B5, |
3118 | OPC_6502_B6, |
3119 | OPC_Illegal, // $B7: SMB3 currently unsupported |
3120 | OPC_6502_B8, |
3121 | OPC_6502_B9, |
3122 | OPC_6502_BA, |
3123 | OPC_65C02_NOP11, // $BB |
3124 | OPC_6502_BC, |
3125 | OPC_6502_BD, |
3126 | OPC_6502_BE, |
3127 | OPC_Illegal, // $BF: BBS3 currently unsupported |
3128 | OPC_6502_C0, |
3129 | OPC_6502_C1, |
3130 | OPC_65C02_NOP22, // $C2 |
3131 | OPC_65C02_NOP11, // $C3 |
3132 | OPC_6502_C4, |
3133 | OPC_6502_C5, |
3134 | OPC_6502_C6, |
3135 | OPC_Illegal, // $C7: SMB4 currently unsupported |
3136 | OPC_6502_C8, |
3137 | OPC_6502_C9, |
3138 | OPC_6502_CA, |
3139 | OPC_Illegal, // $CB: WAI currently unsupported |
3140 | OPC_6502_CC, |
3141 | OPC_6502_CD, |
3142 | OPC_6502_CE, |
3143 | OPC_Illegal, // $CF: BBS4 currently unsupported |
3144 | OPC_6502_D0, |
3145 | OPC_6502_D1, |
3146 | OPC_65SC02_D2, |
3147 | OPC_65C02_NOP11, // $D3 |
3148 | OPC_65C02_NOP24, // $D4 |
3149 | OPC_6502_D5, |
3150 | OPC_6502_D6, |
3151 | OPC_Illegal, // $D7: SMB5 currently unsupported |
3152 | OPC_6502_D8, |
3153 | OPC_6502_D9, |
3154 | OPC_65SC02_DA, |
3155 | OPC_Illegal, // $DB: STP currently unsupported |
3156 | OPC_65C02_NOP34, // $DC |
3157 | OPC_6502_DD, |
3158 | OPC_6502_DE, |
3159 | OPC_Illegal, // $DF: BBS5 currently unsupported |
3160 | OPC_6502_E0, |
3161 | OPC_6502_E1, |
3162 | OPC_65C02_NOP22, // $E2 |
3163 | OPC_65C02_NOP11, // $E3 |
3164 | OPC_6502_E4, |
3165 | OPC_6502_E5, |
3166 | OPC_6502_E6, |
3167 | OPC_Illegal, // $E7: SMB6 currently unsupported |
3168 | OPC_6502_E8, |
3169 | OPC_6502_E9, |
3170 | OPC_6502_EA, |
3171 | OPC_65C02_NOP11, // $EB |
3172 | OPC_6502_EC, |
3173 | OPC_6502_ED, |
3174 | OPC_6502_EE, |
3175 | OPC_Illegal, // $EF: BBS6 currently unsupported |
3176 | OPC_6502_F0, |
3177 | OPC_6502_F1, |
3178 | OPC_65SC02_F2, |
3179 | OPC_65C02_NOP11, // $F3 |
3180 | OPC_65C02_NOP24, // $F4 |
3181 | OPC_6502_F5, |
3182 | OPC_6502_F6, |
3183 | OPC_Illegal, // $F7: SMB7 currently unsupported |
3184 | OPC_6502_F8, |
3185 | OPC_6502_F9, |
3186 | OPC_65SC02_FA, |
3187 | OPC_65C02_NOP11, // $FB |
3188 | OPC_65C02_NOP34, // $FC |
3189 | OPC_6502_FD, |
3190 | OPC_6502_FE, |
3191 | OPC_Illegal, // $FF: BBS7 currently unsupported |
3192 | }; |
3193 | |
3194 | |
3195 | |
3196 | /* Tables with opcode handlers */ |
3197 | static const OPFunc* Handlers[2] = {OP6502Table, OP65C02Table}; |
3198 | |
3199 | |
3200 | |
3201 | /*****************************************************************************/ |
3202 | /* Code */ |
3203 | /*****************************************************************************/ |
3204 | |
3205 | |
3206 | |
3207 | void IRQRequest (void) |
3208 | /* Generate an IRQ */ |
3209 | { |
3210 | /* Remember the request */ |
3211 | HaveIRQRequest = 1; |
3212 | } |
3213 | |
3214 | |
3215 | |
3216 | void NMIRequest (void) |
3217 | /* Generate an NMI */ |
3218 | { |
3219 | /* Remember the request */ |
3220 | HaveNMIRequest = 1; |
3221 | } |
3222 | |
3223 | |
3224 | |
3225 | void Reset (void) |
3226 | /* Generate a CPU RESET */ |
3227 | { |
3228 | /* Reset the CPU */ |
3229 | HaveIRQRequest = 0; |
3230 | HaveNMIRequest = 0; |
3231 | |
3232 | /* Bits 5 and 4 aren't used, and always are 1! */ |
3233 | Regs.SR = 0x30; |
3234 | Regs.PC = MemReadWord (0xFFFC); |
3235 | } |
3236 | |
3237 | |
3238 | |
3239 | unsigned ExecuteInsn (void) |
3240 | /* Execute one CPU instruction */ |
3241 | { |
3242 | /* If we have an NMI request, handle it */ |
3243 | if (HaveNMIRequest) { |
3244 | |
3245 | HaveNMIRequest = 0; |
3246 | PUSH (PCH); |
3247 | PUSH (PCL); |
3248 | PUSH (Regs.SR & ~BF); |
3249 | SET_IF (1); |
3250 | if (CPU != CPU_6502) |
3251 | { |
3252 | SET_DF (0); |
3253 | } |
3254 | Regs.PC = MemReadWord (0xFFFA); |
3255 | Cycles = 7; |
3256 | |
3257 | } else if (HaveIRQRequest && GET_IF () == 0) { |
3258 | |
3259 | HaveIRQRequest = 0; |
3260 | PUSH (PCH); |
3261 | PUSH (PCL); |
3262 | PUSH (Regs.SR & ~BF); |
3263 | SET_IF (1); |
3264 | if (CPU != CPU_6502) |
3265 | { |
3266 | SET_DF (0); |
3267 | } |
3268 | Regs.PC = MemReadWord (0xFFFE); |
3269 | Cycles = 7; |
3270 | |
3271 | } else { |
3272 | |
3273 | /* Normal instruction - read the next opcode */ |
3274 | unsigned char OPC = MemReadByte (Regs.PC); |
3275 | |
3276 | /* Execute it */ |
3277 | Handlers[CPU][OPC] (); |
3278 | } |
3279 | |
3280 | /* Count cycles */ |
3281 | TotalCycles += Cycles; |
3282 | |
3283 | /* Return the number of clock cycles needed by this insn */ |
3284 | return Cycles; |
3285 | } |
3286 | |
3287 | |
3288 | |
3289 | unsigned long GetCycles (void) |
3290 | /* Return the total number of cycles executed */ |
3291 | { |
3292 | /* Return the total number of cycles */ |
3293 | return TotalCycles; |
3294 | } |
3295 | |