FabGL
ESP32 Display Controller and Graphics Library
MOS6502.cpp
1 /*
2  Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - www.fabgl.com
3  Copyright (c) 2019-2021 Fabrizio Di Vittorio.
4  All rights reserved.
5 
6  This file is part of FabGL Library.
7 
8  FabGL is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  FabGL is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with FabGL. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 
23 #include "MOS6502.h"
24 
25 
26 #pragma GCC optimize ("O2")
27 
28 
29 namespace fabgl {
30 
31 
32 // compose status word
33 #define COMPOSE_STATUS (0x20 | ((int)m_carry) | ((int)m_zero << 1) | ((int)m_intDisable << 2) | ((int)m_decimal << 3) | ((int)m_overflow << 6) | ((int) m_negative << 7))
34 
35 
36 // decompose status word
37 #define DECOMPOSE_STATUS(status) { \
38  int s = (status); \
39  m_carry = s & 0x01; \
40  m_zero = s & 0x02; \
41  m_intDisable = s & 0x04; \
42  m_decimal = s & 0x08; \
43  m_overflow = s & 0x40; \
44  m_negative = s & 0x80; \
45  setADCSBC(); \
46 }
47 
48 
49 #define BUSREAD(addr) (m_readByte(m_context, (addr)))
50 #define BUSWRITE(addr, value) (m_writeByte(m_context, (addr), (value)))
51 #define PAGE0READ(addr) (m_page0ReadByte(m_context, (addr)))
52 #define PAGE0WRITE(addr, value) (m_page0WriteByte(m_context, (addr), (value)))
53 #define PAGE1READ(addr) (m_page1ReadByte(m_context, (addr)))
54 #define PAGE1WRITE(addr, value) (m_page1WriteByte(m_context, (addr), (value)))
55 
56 
57 #define STACKPUSHBYTE(v) PAGE1WRITE(m_SP--, (v))
58 
59 #define STACKPUSHWORD(v) { PAGE1WRITE(m_SP--, (v) >> 8); PAGE1WRITE(m_SP--, (v) & 0xff); }
60 
61 #define STACKPOPBYTE() PAGE1READ(++m_SP)
62 
63 #define STACKPOPWORD() (m_SP += 2, (PAGE1READ(m_SP - 1) | (PAGE1READ(m_SP) << 8)))
64 
65 
66 int MOS6502::reset()
67 {
68  m_A = m_X = m_Y = 0;
69  m_SP = 0xfd; // transistor level simulators reset SP to 0xfd
70  m_PC = (BUSREAD(0xfffd) << 8) + BUSREAD(0xfffc); // reset vector at 0xfffc
71  m_decimal = false;
72  setADCSBC();
73  return 6;
74 }
75 
76 
77 int MOS6502::IRQ()
78 {
79  if (!m_intDisable) {
80  STACKPUSHWORD(m_PC);
81  STACKPUSHBYTE(COMPOSE_STATUS);
82  m_PC = (BUSREAD(0xffff) << 8) + BUSREAD(0xfffe); // IRQ vector at 0xfffe
83  m_intDisable = true;
84  return 7;
85  }
86  return 0;
87 }
88 
89 
90 int MOS6502::NMI()
91 {
92  STACKPUSHWORD(m_PC);
93  STACKPUSHBYTE(COMPOSE_STATUS);
94  m_PC = (BUSREAD(0xfffb) << 8) + BUSREAD(0xfffa); // NMI vector at 0xfffa
95  m_intDisable = true;
96  return 7;
97 }
98 
99 
100 void MOS6502::setADCSBC()
101 {
102  if (m_decimal) {
103  m_OP_ADC = &MOS6502::OP_BCDADC;
104  m_OP_SBC = &MOS6502::OP_BCDSBC;
105  } else {
106  m_OP_ADC = &MOS6502::OP_BINADC;
107  m_OP_SBC = &MOS6502::OP_BINSBC;
108  }
109 }
110 
111 
112 void MOS6502::OP_BINADC(uint8_t m)
113 {
114  uint32_t t = m + m_A + (int)m_carry;
115  m_zero = !(t & 0xff);
116  m_negative = t & 0x80;
117  m_overflow = !((m_A ^ m) & 0x80) && ((m_A ^ t) & 0x80);
118  m_carry = t & 0x100;
119  m_A = t & 0xff;
120 }
121 
122 
123 void MOS6502::OP_BINSBC(uint8_t m)
124 {
125  uint32_t t = m_A - m - (int)(!m_carry);
126  m_zero = !(t & 0xff);
127  m_negative = t & 0x80;
128  m_overflow = ((m_A ^ t) & 0x80) && ((m_A ^ m) & 0x80);
129  m_carry = !(t & 0x100);
130  m_A = t & 0xff;
131 }
132 
133 
134 void MOS6502::OP_BCDADC(uint8_t m)
135 {
136  uint32_t t = m + m_A + (int)m_carry;
137  m_zero = !(t & 0xff);
138  if (((m_A & 0x0f) + (m & 0x0f) + (int)m_carry) > 9)
139  t += 6;
140  m_negative = t & 0x80;
141  m_overflow = !((m_A ^ m) & 0x80) && ((m_A ^ t) & 0x80);
142  if (t > 0x99)
143  t += 96;
144  m_carry = t > 0x99;
145  m_A = t & 0xff;
146 }
147 
148 
149 void MOS6502::OP_BCDSBC(uint8_t m)
150 {
151  uint32_t t = m_A - m - (int)(!m_carry);
152  m_zero = !(t & 0xff);
153  m_negative = t & 0x80;
154  m_overflow = ((m_A ^ t) & 0x80) && ((m_A ^ m) & 0x80);
155  if (((m_A & 0x0f) - (int)(!m_carry)) < (m & 0x0f))
156  t -= 6;
157  if (t > 0x99)
158  t -= 0x60;
159  m_carry = t < 0x100;
160  m_A = t & 0xff;
161 }
162 
163 
164 #define OP_AND { \
165  m_A = m & m_A; \
166  m_zero = !m_A; \
167  m_negative = m_A & 0x80; \
168 }
169 
170 
171 #define OP_ASL { \
172  m_carry = m & 0x80; \
173  m = (m << 1) & 0xff; \
174  m_zero = !m; \
175  m_negative = m & 0x80; \
176 }
177 
178 
179 #define OP_BIT { \
180  m_zero = !(m & m_A); \
181  m_overflow = m & 0x40; \
182  m_negative = m & 0x80; \
183 }
184 
185 
186 #define OP_CMP { \
187  uint32_t t = m_A - m; \
188  m_zero = !(t & 0xff); \
189  m_carry = !(t & 0x100); \
190  m_negative = t & 0x80; \
191 }
192 
193 
194 #define OP_CPX { \
195  uint32_t t = m_X - m; \
196  m_zero = !(t & 0xff); \
197  m_carry = !(t & 0x100); \
198  m_negative = t & 0x80; \
199 }
200 
201 
202 #define OP_CPY { \
203  uint32_t t = m_Y - m; \
204  m_zero = !(t & 0xff); \
205  m_carry = !(t & 0x100); \
206  m_negative = t & 0x80; \
207 }
208 
209 
210 #define OP_DEC { \
211  m = (m - 1) & 0xff; \
212  m_zero = !m; \
213  m_negative = m & 0x80; \
214 }
215 
216 
217 #define OP_EOR { \
218  m_A ^= m; \
219  m_zero = !m_A; \
220  m_negative = m_A & 0x80; \
221 }
222 
223 
224 #define OP_INC { \
225  m = (m + 1) & 0xff; \
226  m_negative = m & 0x80; \
227  m_zero = !m; \
228 }
229 
230 
231 #define OP_LDA { \
232  m_zero = !m; \
233  m_negative = m & 0x80; \
234  m_A = m; \
235 }
236 
237 
238 #define OP_LDX { \
239  m_zero = !m; \
240  m_negative = m & 0x80; \
241  m_X = m; \
242 }
243 
244 
245 #define OP_LDY { \
246  m_zero = !m; \
247  m_negative = m & 0x80; \
248  m_Y = m; \
249 }
250 
251 
252 #define OP_LSR { \
253  m_negative = false; \
254  m_carry = m & 0x01; \
255  m >>= 1; \
256  m_zero = !m; \
257 }
258 
259 
260 #define OP_ORA { \
261  m_A |= m; \
262  m_negative = m_A & 0x80; \
263  m_zero = !m_A; \
264 }
265 
266 
267 #define OP_ROL { \
268  m = (m << 1) | (int)m_carry; \
269  m_carry = m & 0x100; \
270  m &= 0xff; \
271  m_negative = m & 0x80; \
272  m_zero = !m; \
273 }
274 
275 
276 #define OP_ROR { \
277  m |= (int)m_carry << 8; \
278  m_carry = m & 0x01; \
279  m = (m >> 1) & 0xff; \
280  m_negative = m & 0x80; \
281  m_zero = !m; \
282 }
283 
284 
285 #define PAGECROSS() (al >> 8)
286 
287 
288 // immediate: op #dd
289 #define ADR_IMM { \
290  m = BUSREAD(m_PC++); \
291 }
292 
293 
294 // zero page absolute: op aa
295 #define ADR_ZABS_GETADDR { \
296  a = BUSREAD(m_PC++); \
297 }
298 #define ADR_ZABS { \
299  ADR_ZABS_GETADDR; \
300  m = PAGE0READ(a); \
301 }
302 
303 
304 // zero page absolute + X: op aa, X
305 #define ADR_ZABSX_GETADDR { \
306  a = (BUSREAD(m_PC++) + m_X) & 0xff; \
307 }
308 #define ADR_ZABSX { \
309  ADR_ZABSX_GETADDR; \
310  m = PAGE0READ(a); \
311 }
312 
313 
314 // zero page absolute + Y: op aa, Y
315 #define ADR_ZABSY_GETADDR { \
316  a = (BUSREAD(m_PC++) + m_Y) & 0xff; \
317 }
318 #define ADR_ZABSY { \
319  ADR_ZABSY_GETADDR; \
320  m = PAGE0READ(a); \
321 }
322 
323 
324 // absolute: op aaaa
325 #define ADR_ABS_GETADDR { \
326  a = BUSREAD(m_PC) | (BUSREAD(m_PC + 1) << 8); \
327  m_PC += 2; \
328 }
329 #define ADR_ABS { \
330  ADR_ABS_GETADDR; \
331  m = BUSREAD(a); \
332 }
333 
334 
335 // absolute + X: op aaaa, X
336 #define ADR_ABSX_GETADDR { \
337  al = BUSREAD(m_PC++) + m_X; \
338  a = al + (BUSREAD(m_PC++) << 8); \
339 }
340 #define ADR_ABSX { \
341  ADR_ABSX_GETADDR; \
342  m = BUSREAD(a); \
343 }
344 
345 
346 // absolute + Y: op aaaa, Y
347 #define ADR_ABSY_GETADDR { \
348  al = BUSREAD(m_PC++) + m_Y; \
349  a = al + (BUSREAD(m_PC++) << 8); \
350 }
351 #define ADR_ABSY { \
352  ADR_ABSY_GETADDR; \
353  m = BUSREAD(a); \
354 }
355 
356 
357 // indexed indirect: op (aa, X)
358 #define ADR_IIND_GETADDR { \
359  int l = (BUSREAD(m_PC++) + m_X) & 0xff; \
360  int h = (l + 1) & 0xff; \
361  a = PAGE0READ(l) | (PAGE0READ(h) << 8); \
362 }
363 #define ADR_IIND { \
364  ADR_IIND_GETADDR; \
365  m = BUSREAD(a); \
366 }
367 
368 
369 // indirect index: op (aa), Y
370 #define ADR_INDI_GETADDR { \
371  int l = BUSREAD(m_PC++); \
372  int h = (l + 1) & 0xff; \
373  al = PAGE0READ(l) + m_Y; \
374  a = al + (PAGE0READ(h) << 8); \
375 }
376 #define ADR_INDI { \
377  ADR_INDI_GETADDR; \
378  m = BUSREAD(a); \
379 }
380 
381 
382 // relative: op aa
383 #define ADR_REL { \
384  m = (int8_t)BUSREAD(m_PC++); \
385  a = m_PC + m; \
386  al = (m_PC & 0xff) + m; \
387 }
388 
389 
390 // indirect: op (aaaa)
391 #define ADR_IND { \
392  int l = BUSREAD(m_PC++); \
393  int h = BUSREAD(m_PC++); \
394  a = l | (h << 8); \
395  l = BUSREAD(a); \
396  h = BUSREAD((a & 0xff00) | ((a + 1) & 0xff)); \
397  a = l | (h << 8); \
398 }
399 
400 
401 int MOS6502::step()
402 {
403  int m; // operand value
404  int al; // address low + index
405  int a; // complete address
406 
407  switch (BUSREAD(m_PC++)) {
408 
410 
411  // ADC #dd
412  case 0x69:
413  ADR_IMM;
414  (this->*m_OP_ADC)(m);
415  return 2;
416 
417  // ADC aa
418  case 0x65:
419  ADR_ZABS;
420  (this->*m_OP_ADC)(m);
421  return 3;
422 
423  // ADC aa, X
424  case 0x75:
425  ADR_ZABSX;
426  (this->*m_OP_ADC)(m);
427  return 4;
428 
429  // ADC aaaa
430  case 0x6d:
431  ADR_ABS;
432  (this->*m_OP_ADC)(m);
433  return 4;
434 
435  // ADC aaaa, X
436  case 0x7d:
437  ADR_ABSX;
438  (this->*m_OP_ADC)(m);
439  return 4 + PAGECROSS();
440 
441  // ADC aaaa, Y
442  case 0x79:
443  ADR_ABSY;
444  (this->*m_OP_ADC)(m);
445  return 4 + PAGECROSS();
446 
447  // ADC (aa, X)
448  case 0x61:
449  ADR_IIND;
450  (this->*m_OP_ADC)(m);
451  return 6;
452 
453  // ADC (aa), Y
454  case 0x71:
455  ADR_INDI;
456  (this->*m_OP_ADC)(m);
457  return 5 + PAGECROSS();
458 
460 
461  // AND #dd
462  case 0x29:
463  ADR_IMM;
464  OP_AND;
465  return 2;
466 
467  // AND aa
468  case 0x25:
469  ADR_ZABS;
470  OP_AND;
471  return 3;
472 
473  // AND aa, X
474  case 0x35:
475  ADR_ZABSX;
476  OP_AND;
477  return 4;
478 
479  // AND aaaa
480  case 0x2d:
481  ADR_ABS;
482  OP_AND;
483  return 4;
484 
485  // AND aaaa, X
486  case 0x3d:
487  ADR_ABSX;
488  OP_AND;
489  return 4 + PAGECROSS();
490 
491  // AND aaaa, Y
492  case 0x39:
493  ADR_ABSY;
494  OP_AND;
495  return 4 + PAGECROSS();
496 
497  // AND (aa, X)
498  case 0x21:
499  ADR_IIND;
500  OP_AND;
501  return 6;
502 
503  // AND (aa), Y
504  case 0x31:
505  ADR_INDI;
506  OP_AND;
507  return 5 + PAGECROSS();
508 
510 
511  // ASL A
512  case 0x0a:
513  m = m_A;
514  OP_ASL;
515  m_A = m;
516  return 2;
517 
518  // ASL aa
519  case 0x06:
520  ADR_ZABS;
521  OP_ASL;
522  PAGE0WRITE(a, m);
523  return 5;
524 
525  // ASL aa, X
526  case 0x16:
527  ADR_ZABSX;
528  OP_ASL;
529  PAGE0WRITE(a, m);
530  return 6;
531 
532  // ASL aaaa
533  case 0x0e:
534  ADR_ABS;
535  OP_ASL;
536  BUSWRITE(a, m);
537  return 6;
538 
539  // ASL aaaa, X
540  case 0x1e:
541  ADR_ABSX;
542  OP_ASL;
543  BUSWRITE(a, m);
544  return 7;
545 
547 
548  // BCC aa
549  case 0x90:
550  if (m_carry) {
551  ++m_PC;
552  return 2;
553  } else {
554  ADR_REL;
555  m_PC = a;
556  return 3 + PAGECROSS();
557  }
558 
560 
561  // BCS aa
562  case 0xb0:
563  if (m_carry) {
564  ADR_REL;
565  m_PC = a;
566  return 3 + PAGECROSS();
567  } else {
568  ++m_PC;
569  return 2;
570  }
571 
573 
574  // BEQ aa
575  case 0xf0:
576  if (m_zero) {
577  ADR_REL;
578  m_PC = a;
579  return 3 + PAGECROSS();
580  } else {
581  ++m_PC;
582  return 2;
583  }
584 
586 
587  // BIT aa
588  case 0x24:
589  ADR_ZABS;
590  OP_BIT;
591  return 3;
592 
593  // BIT aaaa
594  case 0x2c:
595  ADR_ABS;
596  OP_BIT;
597  return 4;
598 
600 
601  // BMI aa
602  case 0x30:
603  if (m_negative) {
604  ADR_REL;
605  m_PC = a;
606  return 3 + PAGECROSS();
607  } else {
608  ++m_PC;
609  return 2;
610  }
611 
613 
614  // BNE aa
615  case 0xd0:
616  if (m_zero) {
617  ++m_PC;
618  return 2;
619  } else {
620  ADR_REL;
621  m_PC = a;
622  return 3 + PAGECROSS();
623  }
624 
626 
627  // BPL aa
628  case 0x10:
629  if (m_negative) {
630  ++m_PC;
631  return 2;
632  } else {
633  ADR_REL;
634  m_PC = a;
635  return 3 + PAGECROSS();
636  }
637 
639 
640  // BRK
641  case 0x00:
642  ++m_PC;
643  STACKPUSHWORD(m_PC);
644  STACKPUSHBYTE(COMPOSE_STATUS | 0x10); // set BREAK bit
645  m_intDisable = true;
646  m_PC = (BUSREAD(0xffff) << 8) + BUSREAD(0xfffe); // BRK (IRQ) vector at 0xfffe
647  return 7;
648 
650 
651  // BVC aa
652  case 0x50:
653  if (m_overflow) {
654  ++m_PC;
655  return 2;
656  } else {
657  ADR_REL;
658  m_PC = a;
659  return 3 + PAGECROSS();
660  }
661 
663 
664  // BVS aa
665  case 0x70:
666  if (m_overflow) {
667  ADR_REL;
668  m_PC = a;
669  return 3 + PAGECROSS();
670  } else {
671  ++m_PC;
672  return 2;
673  }
674 
676 
677  case 0x18:
678  m_carry = false;
679  return 2;
680 
682 
683  case 0xd8:
684  m_decimal = false;
685  setADCSBC();
686  return 2;
687 
689 
690  case 0x58:
691  m_intDisable = false;
692  return 2;
693 
695 
696  case 0xb8:
697  m_overflow = false;
698  return 2;
699 
701 
702  // CMP #dd
703  case 0xc9:
704  ADR_IMM;
705  OP_CMP;
706  return 2;
707 
708  // CMP aa
709  case 0xc5:
710  ADR_ZABS;
711  OP_CMP;
712  return 3;
713 
714  // CMP aa, X
715  case 0xd5:
716  ADR_ZABSX;
717  OP_CMP;
718  return 4;
719 
720  // CMP aaaa
721  case 0xcd:
722  ADR_ABS;
723  OP_CMP;
724  return 4;
725 
726  // CMP aaaa, X
727  case 0xdd:
728  ADR_ABSX;
729  OP_CMP;
730  return 4 + PAGECROSS();
731 
732  // CMP aaaa, Y
733  case 0xd9:
734  ADR_ABSY;
735  OP_CMP;
736  return 4 + PAGECROSS();
737 
738  // CMP (aa, X)
739  case 0xc1:
740  ADR_IIND;
741  OP_CMP;
742  return 6;
743 
744  // CMP (aa), Y
745  case 0xd1:
746  ADR_INDI;
747  OP_CMP;
748  return 5 + PAGECROSS();
749 
751 
752  // CPX #dd
753  case 0xe0:
754  ADR_IMM;
755  OP_CPX;
756  return 2;
757 
758  // CPX aa
759  case 0xe4:
760  ADR_ZABS;
761  OP_CPX;
762  return 3;
763 
764  // CPX aaaa
765  case 0xec:
766  ADR_ABS;
767  OP_CPX;
768  return 4;
769 
771 
772  // CPY #dd
773  case 0xc0:
774  ADR_IMM;
775  OP_CPY;
776  return 2;
777 
778  // CPY aa
779  case 0xc4:
780  ADR_ZABS;
781  OP_CPY;
782  return 3;
783 
784  // CPY aaaa
785  case 0xcc:
786  ADR_ABS;
787  OP_CPY;
788  return 4;
789 
791 
792  // DEC aa
793  case 0xc6:
794  ADR_ZABS;
795  OP_DEC;
796  PAGE0WRITE(a, m);
797  return 5;
798 
799  // DEC aa, X
800  case 0xd6:
801  ADR_ZABSX;
802  OP_DEC;
803  PAGE0WRITE(a, m);
804  return 6;
805 
806  // DEC aaaa
807  case 0xce:
808  ADR_ABS;
809  OP_DEC;
810  BUSWRITE(a, m);
811  return 6;
812 
813  // DEC aaaa, X
814  case 0xde:
815  ADR_ABSX;
816  OP_DEC;
817  BUSWRITE(a, m);
818  return 7;
819 
821 
822  case 0xca:
823  m_X = (m_X - 1) & 0xff;
824  m_negative = m_X & 0x80;
825  m_zero = !m_X;
826  return 2;
827 
829 
830  case 0x88:
831  m_Y = (m_Y - 1) & 0xff;
832  m_negative = m_Y & 0x80;
833  m_zero = !m_Y;
834  return 2;
835 
837 
838  // EOR #dd
839  case 0x49:
840  ADR_IMM;
841  OP_EOR;
842  return 2;
843 
844  // EOR aa
845  case 0x45:
846  ADR_ZABS;
847  OP_EOR;
848  return 3;
849 
850  // EOR aa, X
851  case 0x55:
852  ADR_ZABSX;
853  OP_EOR;
854  return 4;
855 
856  // EOR aaaa
857  case 0x4d:
858  ADR_ABS;
859  OP_EOR;
860  return 4;
861 
862  // EOR aaaa, X
863  case 0x5d:
864  ADR_ABSX;
865  OP_EOR;
866  return 4 + PAGECROSS();
867 
868  // EOR aaaa, Y
869  case 0x59:
870  ADR_ABSY;
871  OP_EOR;
872  return 4 + PAGECROSS();
873 
874  // EOR (aa, X)
875  case 0x41:
876  ADR_IIND;
877  OP_EOR;
878  return 6;
879 
880  // EOR (aa), Y
881  case 0x51:
882  ADR_INDI;
883  OP_EOR;
884  return 5 + PAGECROSS();
885 
887 
888  // INC aa
889  case 0xe6:
890  ADR_ZABS;
891  OP_INC;
892  PAGE0WRITE(a, m);
893  return 5;
894 
895  // INC aa, X
896  case 0xf6:
897  ADR_ZABSX;
898  OP_INC;
899  PAGE0WRITE(a, m);
900  return 6;
901 
902  // INC aaaa
903  case 0xee:
904  ADR_ABS;
905  OP_INC;
906  BUSWRITE(a, m);
907  return 6;
908 
909  // INC aaaa, X
910  case 0xfe:
911  ADR_ABSX;
912  OP_INC;
913  BUSWRITE(a, m);
914  return 7;
915 
917 
918  case 0xe8:
919  m_X = (m_X + 1) & 0xff;
920  m_negative = m_X & 0x80;
921  m_zero = !m_X;
922  return 2;
923 
925 
926  case 0xc8:
927  m_Y = (m_Y + 1) & 0xff;
928  m_negative = m_Y & 0x80;
929  m_zero = !m_Y;
930  return 2;
931 
933 
934  // JMP aaaa
935  case 0x4c:
936  ADR_ABS;
937  m_PC = a;
938  return 3;
939 
940  // JMP (aaaa)
941  case 0x6c:
942  ADR_IND;
943  m_PC = a;
944  return 5;
945 
947 
948  // JSR aaaa
949  case 0x20:
950  a = (m_PC + 1) & 0xffff;
951  STACKPUSHWORD(a);
952  ADR_ABS;
953  m_PC = a;
954  return 6;
955 
957 
958  // LDA #dd
959  case 0xa9:
960  ADR_IMM;
961  OP_LDA;
962  return 2;
963 
964  // LDA aa
965  case 0xa5:
966  ADR_ZABS;
967  OP_LDA;
968  return 3;
969 
970  // LDA aa, X
971  case 0xb5:
972  ADR_ZABSX;
973  OP_LDA;
974  return 4;
975 
976  // LDA aaaa
977  case 0xad:
978  ADR_ABS;
979  OP_LDA;
980  return 4;
981 
982  // LDA aaaa, X
983  case 0xbd:
984  ADR_ABSX;
985  OP_LDA;
986  return 4 + PAGECROSS();
987 
988  // LDA aaaa, Y
989  case 0xb9:
990  ADR_ABSY;
991  OP_LDA;
992  return 4 + PAGECROSS();
993 
994  // LDA (aa, X)
995  case 0xa1:
996  ADR_IIND;
997  OP_LDA;
998  return 6;
999 
1000  // LDA (aa), Y
1001  case 0xb1:
1002  ADR_INDI;
1003  OP_LDA;
1004  return 5 + PAGECROSS();
1005 
1007 
1008  // LDX #dd
1009  case 0xa2:
1010  ADR_IMM;
1011  OP_LDX;
1012  return 2;
1013 
1014  // LDX aa
1015  case 0xa6:
1016  ADR_ZABS;
1017  OP_LDX;
1018  return 3;
1019 
1020  // LDX aa, Y
1021  case 0xb6:
1022  ADR_ZABSY;
1023  OP_LDX;
1024  return 4;
1025 
1026  // LDX aaaa
1027  case 0xae:
1028  ADR_ABS;
1029  OP_LDX;
1030  return 4;
1031 
1032  // LDX aaaa, Y
1033  case 0xbe:
1034  ADR_ABSY;
1035  OP_LDX;
1036  return 4 + PAGECROSS();
1037 
1039 
1040  // LDY #dd
1041  case 0xa0:
1042  ADR_IMM;
1043  OP_LDY;
1044  return 2;
1045 
1046  // LDY aa
1047  case 0xa4:
1048  ADR_ZABS;
1049  OP_LDY;
1050  return 3;
1051 
1052  // LDY aa, X
1053  case 0xb4:
1054  ADR_ZABSX;
1055  OP_LDY;
1056  return 4;
1057 
1058  // LDY aaaa
1059  case 0xac:
1060  ADR_ABS;
1061  OP_LDY;
1062  return 4;
1063 
1064  // LDY aaaa, X
1065  case 0xbc:
1066  ADR_ABSX;
1067  OP_LDY;
1068  return 4 + PAGECROSS();
1069 
1071 
1072  // LSR A
1073  case 0x4a:
1074  m = m_A;
1075  OP_LSR;
1076  m_A = m;
1077  return 2;
1078 
1079  // LSR aa
1080  case 0x46:
1081  ADR_ZABS;
1082  OP_LSR;
1083  PAGE0WRITE(a, m);
1084  return 5;
1085 
1086  // LSR aa, X
1087  case 0x56:
1088  ADR_ZABSX;
1089  OP_LSR;
1090  PAGE0WRITE(a, m);
1091  return 6;
1092 
1093  // LSR aaaa
1094  case 0x4e:
1095  ADR_ABS;
1096  OP_LSR;
1097  BUSWRITE(a, m);
1098  return 6;
1099 
1100  // LSR aaaa, X
1101  case 0x5e:
1102  ADR_ABSX;
1103  OP_LSR;
1104  BUSWRITE(a, m);
1105  return 7;
1106 
1108 
1109  case 0xea:
1110  return 2;
1111 
1113 
1114  // ORA #dd
1115  case 0x09:
1116  ADR_IMM;
1117  OP_ORA;
1118  return 2;
1119 
1120  // ORA aa
1121  case 0x05:
1122  ADR_ZABS;
1123  OP_ORA;
1124  return 3;
1125 
1126  // ORA aa, X
1127  case 0x15:
1128  ADR_ZABSX;
1129  OP_ORA;
1130  return 4;
1131 
1132  // ORA aaaa
1133  case 0x0d:
1134  ADR_ABS;
1135  OP_ORA;
1136  return 4;
1137 
1138  // ORA aaaa, X
1139  case 0x1d:
1140  ADR_ABSX;
1141  OP_ORA;
1142  return 4 + PAGECROSS();
1143 
1144  // ORA aaaa, Y
1145  case 0x19:
1146  ADR_ABSY;
1147  OP_ORA;
1148  return 4 + PAGECROSS();
1149 
1150  // ORA (aa, X)
1151  case 0x01:
1152  ADR_IIND;
1153  OP_ORA;
1154  return 6;
1155 
1156  // ORA (aa), Y
1157  case 0x11:
1158  ADR_INDI;
1159  OP_ORA;
1160  return 5 + PAGECROSS();
1161 
1163 
1164  case 0x48:
1165  STACKPUSHBYTE(m_A);
1166  return 3;
1167 
1169 
1170  case 0x08:
1171  STACKPUSHBYTE(COMPOSE_STATUS | 0x10); // set BREAK bit
1172  return 3;
1173 
1175 
1176  case 0x68:
1177  m_A = STACKPOPBYTE();
1178  m_zero = !m_A;
1179  m_negative = m_A & 0x80;
1180  return 4;
1181 
1183 
1184  case 0x28:
1185  DECOMPOSE_STATUS(STACKPOPBYTE());
1186  return 4;
1187 
1189 
1190  // ROL A
1191  case 0x2a:
1192  m = m_A;
1193  OP_ROL;
1194  m_A = m;
1195  return 2;
1196 
1197  // ROL aa
1198  case 0x26:
1199  ADR_ZABS;
1200  OP_ROL;
1201  PAGE0WRITE(a, m);
1202  return 5;
1203 
1204  // ROL aa, X
1205  case 0x36:
1206  ADR_ZABSX;
1207  OP_ROL;
1208  PAGE0WRITE(a, m);
1209  return 6;
1210 
1211  // ROL aaaa
1212  case 0x2e:
1213  ADR_ABS;
1214  OP_ROL;
1215  BUSWRITE(a, m);
1216  return 6;
1217 
1218  // ROL aaaa, X
1219  case 0x3e:
1220  ADR_ABSX;
1221  OP_ROL;
1222  BUSWRITE(a, m);
1223  return 7;
1224 
1226 
1227  // ROR A
1228  case 0x6a:
1229  m = m_A;
1230  OP_ROR;
1231  m_A = m;
1232  return 2;
1233 
1234  // ROR aa
1235  case 0x66:
1236  ADR_ZABS;
1237  OP_ROR;
1238  PAGE0WRITE(a, m);
1239  return 5;
1240 
1241  // ROR aa, X
1242  case 0x76:
1243  ADR_ZABSX;
1244  OP_ROR;
1245  PAGE0WRITE(a, m);
1246  return 6;
1247 
1248  // ROR aaaa
1249  case 0x6e:
1250  ADR_ABS;
1251  OP_ROR;
1252  BUSWRITE(a, m);
1253  return 6;
1254 
1255  // ROR aaaa, X
1256  case 0x7e:
1257  ADR_ABSX;
1258  OP_ROR;
1259  BUSWRITE(a, m);
1260  return 7;
1261 
1263 
1264  case 0x40:
1265  {
1266  DECOMPOSE_STATUS(STACKPOPBYTE());
1267  m_PC = STACKPOPWORD();
1268  return 6;
1269  }
1270 
1272 
1273  case 0x60:
1274  {
1275  m_PC = STACKPOPWORD() + 1;
1276  return 6;
1277  }
1278 
1280 
1281  // SBC #dd
1282  case 0xe9:
1283  ADR_IMM;
1284  (this->*m_OP_SBC)(m);
1285  return 2;
1286 
1287  // SBC aa
1288  case 0xe5:
1289  ADR_ZABS;
1290  (this->*m_OP_SBC)(m);
1291  return 3;
1292 
1293  // SBC aa, X
1294  case 0xf5:
1295  ADR_ZABSX;
1296  (this->*m_OP_SBC)(m);
1297  return 4;
1298 
1299  // SBC aaaa
1300  case 0xed:
1301  ADR_ABS;
1302  (this->*m_OP_SBC)(m);
1303  return 4;
1304 
1305  // SBC aaaa, X
1306  case 0xfd:
1307  ADR_ABSX;
1308  (this->*m_OP_SBC)(m);
1309  return 4 + PAGECROSS();
1310 
1311  // SBC aaaa, Y
1312  case 0xf9:
1313  ADR_ABSY;
1314  (this->*m_OP_SBC)(m);
1315  return 4 + PAGECROSS();
1316 
1317  // SBC (aa, X)
1318  case 0xe1:
1319  ADR_IIND;
1320  (this->*m_OP_SBC)(m);
1321  return 6;
1322 
1323  // SBC (aa), Y
1324  case 0xf1:
1325  ADR_INDI;
1326  (this->*m_OP_SBC)(m);
1327  return 5 + PAGECROSS();
1328 
1330 
1331  case 0x38:
1332  m_carry = true;
1333  return 2;
1334 
1336 
1337  case 0xf8:
1338  m_decimal = true;
1339  setADCSBC();
1340  return 2;
1341 
1343 
1344  case 0x78:
1345  m_intDisable = true;
1346  return 2;
1347 
1349 
1350  // STA aa
1351  case 0x85:
1352  ADR_ZABS_GETADDR;
1353  PAGE0WRITE(a, m_A);
1354  return 3;
1355 
1356  // STA aa, X
1357  case 0x95:
1358  ADR_ZABSX_GETADDR;
1359  PAGE0WRITE(a, m_A);
1360  return 4;
1361 
1362  // STA aaaa
1363  case 0x8d:
1364  ADR_ABS_GETADDR;
1365  BUSWRITE(a, m_A);
1366  return 4;
1367 
1368  // STA aaaa, X
1369  case 0x9d:
1370  ADR_ABSX_GETADDR;
1371  BUSWRITE(a, m_A);
1372  return 5;
1373 
1374  // STA aaaa, Y
1375  case 0x99:
1376  ADR_ABSY_GETADDR;
1377  BUSWRITE(a, m_A);
1378  return 5;
1379 
1380  // STA (aa, X)
1381  case 0x81:
1382  ADR_IIND_GETADDR;
1383  BUSWRITE(a, m_A);
1384  return 6;
1385 
1386  // STA (aa), Y
1387  case 0x91:
1388  ADR_INDI_GETADDR;
1389  BUSWRITE(a, m_A);
1390  return 6;
1391 
1393 
1394  // STX aa
1395  case 0x86:
1396  ADR_ZABS_GETADDR;
1397  PAGE0WRITE(a, m_X);
1398  return 3;
1399 
1400  // STX aa, Y
1401  case 0x96:
1402  ADR_ZABSY_GETADDR;
1403  PAGE0WRITE(a, m_X);
1404  return 4;
1405 
1406  // STX aaaa
1407  case 0x8e:
1408  ADR_ABS_GETADDR;
1409  BUSWRITE(a, m_X);
1410  return 4;
1411 
1413 
1414  // STY aa
1415  case 0x84:
1416  ADR_ZABS_GETADDR;
1417  PAGE0WRITE(a, m_Y);
1418  return 3;
1419 
1420  // STY aa, X
1421  case 0x94:
1422  ADR_ZABSX_GETADDR;
1423  PAGE0WRITE(a, m_Y);
1424  return 4;
1425 
1426  // STY aaaa
1427  case 0x8c:
1428  ADR_ABS_GETADDR;
1429  BUSWRITE(a, m_Y);
1430  return 4;
1431 
1433 
1434  case 0xaa:
1435  m_X = m_A;
1436  m_zero = !m_X;
1437  m_negative = m_X & 0x80;
1438  return 2;
1439 
1441 
1442  case 0xa8:
1443  m_Y = m_A;
1444  m_zero = !m_Y;
1445  m_negative = m_Y & 0x80;
1446  return 2;
1447 
1449 
1450  case 0xba:
1451  m_X = m_SP;
1452  m_zero = !m_X;
1453  m_negative = m_X & 0x80;
1454  return 2;
1455 
1457 
1458  case 0x8a:
1459  m_A = m_X;
1460  m_zero = !m_A;
1461  m_negative = m_A & 0x80;
1462  return 2;
1463 
1465 
1466  case 0x9a:
1467  m_SP = m_X;
1468  return 2;
1469 
1471 
1472  case 0x98:
1473  m_A = m_Y;
1474  m_zero = !m_A;
1475  m_negative = m_A & 0x80;
1476  return 2;
1477 
1479 
1480  case 0x1a:
1481  case 0x3a:
1482  case 0x5a:
1483  case 0x7a:
1484  case 0xda:
1485  case 0xfa:
1486  return 2;
1487 
1489 
1490  // DOP aa
1491  case 0x04:
1492  case 0x44:
1493  case 0x64:
1494  ADR_ZABS;
1495  return 3;
1496 
1497  // DOP aa, X
1498  case 0x14:
1499  case 0x34:
1500  case 0x54:
1501  case 0x74:
1502  case 0xd4:
1503  case 0xf4:
1504  ADR_ZABSX;
1505  return 4;
1506 
1507  // DOP #dd
1508  case 0x80:
1509  case 0x82:
1510  case 0x89:
1511  case 0xc2:
1512  case 0xe2:
1513  ADR_IMM;
1514  return 2;
1515 
1517 
1518  // ISC aa
1519  case 0xe7:
1520  ADR_ZABS;
1521  OP_INC;
1522  (this->*m_OP_SBC)(m);
1523  return 5;
1524 
1525  // ISC aa, X
1526  case 0xf7:
1527  ADR_ZABSX;
1528  OP_INC;
1529  (this->*m_OP_SBC)(m);
1530  return 6;
1531 
1532  // ISC aaaa
1533  case 0xef:
1534  ADR_ABS;
1535  OP_INC;
1536  (this->*m_OP_SBC)(m);
1537  return 6;
1538 
1539  // ISC aaaa, X
1540  case 0xff:
1541  ADR_ABSX;
1542  OP_INC;
1543  (this->*m_OP_SBC)(m);
1544  return 7;
1545 
1546  // ISC aaaa, Y
1547  case 0xfb:
1548  ADR_ABSY;
1549  OP_INC;
1550  (this->*m_OP_SBC)(m);
1551  return 7;
1552 
1553  // ISC (aa, X)
1554  case 0xe3:
1555  ADR_IIND;
1556  OP_INC;
1557  (this->*m_OP_SBC)(m);
1558  return 8;
1559 
1560  // ISC (aa), Y
1561  case 0xf3:
1562  ADR_INDI;
1563  OP_INC;
1564  (this->*m_OP_SBC)(m);
1565  return 8;
1566 
1567  default:
1568  // unsupported opcode
1569  //Serial.printf("6502 illegal 0x%02x\n", BUSREAD(m_PC - 1));
1570  return 0;
1571 
1572  }
1573 }
1574 
1575 
1576 }; // namespace fabgl
This file contains fabgl::MOS6502 definition.
Definition: canvas.cpp:32