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