2 // Virtual 63701 Emulator v1.0
5 // (C) 2014 Underground Software
7 // JLH = James Hammons <jlhamm@acm.org>
10 // --- ---------- -----------------------------------------------------------
11 // JLH 06/15/2006 Added changelog ;-)
12 // JLH 06/15/2006 Scrubbed all BYTE, WORD & DWORD references from the code
13 // JLH 11/13/2006 Converted core to V65C02 macro style :-)
14 // JLH 11/13/2006 Converted flags to unpacked and separate flags
15 // JLH 07/21/2009 Converted clock from 32-bit to 64-bit value, added possible
16 // "don't branch" optimization
17 // JLH 09/21/2009 Fixed EA_ABS macros
18 // JLH 04/07/2014 Converted core to HD63701 type
19 // JLH 04/16/2014 Fixed a raft of bugs, added sane timer handling
22 // This is based on V6808, since it's in the same family apparently. The
23 // HD63701 has more opcodes, and apparently some built in timer facility as
26 // N.B.: There are some things missing from the emulation, such as the data
27 // ports, the Input Capture, RAM Control, sleep mode, processor modes,
28 // and probably some other stuff as well. What is here seems to work, and
29 // work well. It's a fair sight better than the one that's in MAME,
30 // that's for sure. :-D
32 // Some random thoughts: Could there be a performance gain by breaking
33 // out the flags in regs.cc into separate uint8_t variables (or bools)?
34 // You'd have to convert on entering and exiting the emulation loop, but I
35 // think the perfomance hit would be negligible compared to the gain in not
36 // having to mask and shift flags all the time. Investigate after the
37 // conversion to macro style opcodes is completed. :-)
38 // [DONE--remain to be seen if there is any performance increase]
41 #define TEST_DONT_BRANCH_OPTIMIZATION
44 //#include <stdio.h> // for printf()
49 #define WriteLog printf
54 #define CLR_Z (flagZ = 0)
55 #define CLR_ZN (flagZ = flagN = 0)
56 #define CLR_ZNC (flagZ = flagN = flagC = 0)
57 #define CLR_NVC (flagN = flagV = flagC = 0)
58 #define CLR_VC (flagV = flagC = 0)
59 #define CLR_V (flagV = 0)
60 #define CLR_N (flagN = 0)
61 #define SET_Z(r) (flagZ = ((r) == 0 ? 1 : 0))
62 #define SET_N(r) (flagN = ((r) & 0x80) >> 7)
63 #define SET_V(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x80) >> 7)
65 #define SET_C_CMP(a,b) (flagC = ((uint8_t)(b) < (uint8_t)(a) ? 1 : 0))
66 #define SET_ZN(r) SET_N(r); SET_Z(r)
67 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
68 #define SET_ZNVC_CMP(a,b,r) SET_N(r); SET_Z(r); SET_C_CMP(a,b); SET_V(a,b,r)
70 #define SET_N16(r) (flagN = ((r) & 0x8000) >> 15)
71 #define SET_V16(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x8000) >> 15)
72 #define SET_C_CMP16(a,b) (flagC = ((uint16_t)(b) < (uint16_t)(a) ? 1 : 0))
73 #define SET_ZNVC_CMP16(a,b,r) SET_N16(r); SET_Z(r); SET_C_CMP16(a,b); SET_V16(a,b,r)
75 #define EA_IMM regs.pc++
76 #define EA_ZP regs.RdMem(regs.pc++)
77 #define EA_ZP_X (regs.RdMem(regs.pc++) + regs.x)
78 #define EA_ABS FetchMemW(regs.pc)
80 #define READ_IMM regs.RdMem(EA_IMM)
81 #define READ_ZP regs.RdMem(EA_ZP)
82 #define READ_ZP_X regs.RdMem(EA_ZP_X)
83 #define READ_ABS regs.RdMem(EA_ABS)
85 #define READ_IMM16 FetchMemW(regs.pc);
86 #define READ_ZP16 RdMemW(EA_ZP)
87 #define READ_ZP_X16 RdMemW(EA_ZP_X)
88 #define READ_ABS16 RdMemW(EA_ABS)
90 #define READ_IMM_WB(v) uint16_t addr = EA_IMM; v = regs.RdMem(addr)
91 #define READ_ZP_WB(v) uint16_t addr = EA_ZP; v = regs.RdMem(addr)
92 #define READ_ZP_X_WB(v) uint16_t addr = EA_ZP_X; v = regs.RdMem(addr)
93 #define READ_ABS_WB(v) uint16_t addr = EA_ABS; v = regs.RdMem(addr)
95 #define WRITE_BACK(d) regs.WrMem(addr, (d))
97 #define PULL regs.RdMem(regs.s++)
98 #define PUSH(r) regs.WrMem(--regs.s, (r))
99 #define PULL16 RdMemW(regs.s); regs.s += 2
100 #define PUSH16(r) regs.WrMem(--regs.s, (r) & 0xFF); regs.WrMem(--regs.s, (r) >> 8)
102 #define PACK_FLAGS ((regs.cc & 0xC0) | (flagH << 5) | (flagI << 4) | (flagN << 3) | (flagZ << 2) | (flagV << 1) | flagC)
103 #define UNPACK_FLAGS flagH = (regs.cc & FLAG_H) >> 5; \
104 flagI = (regs.cc & FLAG_I) >> 4; \
105 flagN = (regs.cc & FLAG_N) >> 3; \
106 flagZ = (regs.cc & FLAG_Z) >> 2; \
107 flagV = (regs.cc & FLAG_V) >> 1; \
108 flagC = (regs.cc & FLAG_C)
110 // Private global variables
112 static V63701REGS regs;
113 static V63701REGS * regsPointer;
114 static uint8_t flagH, flagI, flagN, flagZ, flagV, flagC;
116 static uint8_t CPUCycles[256] = {
117 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
118 1, 1, 0, 0, 0, 0, 1, 1, 2, 2, 4, 1, 0, 0, 0, 0,
119 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
120 1, 1, 3, 3, 1, 1, 4, 4, 4, 5, 1, 10, 5, 7, 9, 12,
121 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1,
122 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1,
123 6, 7, 7, 6, 6, 7, 6, 6, 6, 6, 6, 5, 6, 4, 3, 5,
124 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 4, 3, 5,
125 2, 2, 2, 3, 2, 2, 2, 0, 2, 2, 2, 2, 3, 5, 3, 0,
126 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4,
127 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
128 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 5, 5,
129 2, 2, 2, 3, 2, 2, 2, 0, 2, 2, 2, 2, 3, 0, 3, 0,
130 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
131 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
132 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5
135 // Private function prototypes
137 static uint16_t RdMemW(uint16_t);
138 static uint16_t FetchMemW(uint16_t);
139 static inline void HandleInterrupt(uint16_t, uint16_t flag = 0);
143 // Read a word out of 63701 memory (little endian format)
145 static inline uint16_t RdMemW(uint16_t address)
147 return (uint16_t)(regs.RdMem(address) << 8) | regs.RdMem(address + 1);
152 // Fetch a word out of 63701 memory (little endian format). Increments PC
154 static inline uint16_t FetchMemW(uint16_t address)
157 return (uint16_t)(regs.RdMem(address) << 8) | regs.RdMem(address + 1);
162 // 63701 OPCODE IMPLEMENTATION
164 // NOTE: Lots of macros are used here to save a LOT of typing. Also
165 // helps speed the debugging process. :-) Because of this, combining
166 // certain lines may look like a good idea but would end in disaster.
167 // You have been warned! ;-)
171 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
172 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
173 Add |ADDA |8B 2 2|9B 3 2|AB 5 2|BB 4 3| |A=A+M |T TTTT|
174 |ADDB |CB 2 2|DB 3 2|EB 5 2|FB 4 3| |B=B+M |T TTTT|
175 Add Accumulators |ABA | | | | |1B 2 1|A=A+B |T TTTT|
180 #define OP_ADD_HANDLER(m, acc) \
181 uint16_t sum = (uint16_t)(acc) + (m); \
183 flagH = (sum >> 4) & 0x01; \
184 SET_V(m, acc, sum); \
185 (acc) = sum & 0xFF; \
188 #define OP_ADD_HANDLER16(m, acc) \
189 uint32_t sum = (uint32_t)(acc) + (m); \
191 SET_V16(m, acc, sum); \
192 (acc) = sum & 0xFFFF; \
196 static void Op8B(void) // ADDA #
198 uint16_t m = READ_IMM;
199 OP_ADD_HANDLER(m, regs.d.acc.a);
203 static void Op9B(void) // ADDA ZP
205 uint16_t m = READ_ZP;
206 OP_ADD_HANDLER(m, regs.d.acc.a);
210 static void OpAB(void) // ADDA ZP, X
212 uint16_t m = READ_ZP_X;
213 OP_ADD_HANDLER(m, regs.d.acc.a);
217 static void OpBB(void) // ADDA ABS
219 uint16_t m = READ_ABS;
220 OP_ADD_HANDLER(m, regs.d.acc.a);
224 static void OpCB(void) // ADDB #
226 uint16_t m = READ_IMM;
227 OP_ADD_HANDLER(m, regs.d.acc.b);
231 static void OpDB(void) // ADDB ZP
233 uint16_t m = READ_ZP;
234 OP_ADD_HANDLER(m, regs.d.acc.b);
238 static void OpEB(void) // ADDB ZP, X
240 uint16_t m = READ_ZP_X;
241 OP_ADD_HANDLER(m, regs.d.acc.b);
245 static void OpFB(void) // ADDB ABS
247 uint16_t m = READ_ABS;
248 OP_ADD_HANDLER(m, regs.d.acc.b);
252 static void Op1B(void) // ABA
254 OP_ADD_HANDLER(regs.d.acc.b, regs.d.acc.a);
258 static void Op3A(void) // ABX
260 // Seems this one does *not* affect any flags...
261 regs.x += (uint16_t)regs.d.acc.b;
265 static void OpC3(void) // ADDD #
267 uint16_t m = READ_IMM16;
268 OP_ADD_HANDLER16(m, regs.d.word);
272 static void OpD3(void) // ADDD ZP
274 uint16_t m = READ_ZP16;
275 OP_ADD_HANDLER16(m, regs.d.word);
279 static void OpE3(void) // ADDD ZP, X
281 uint16_t m = READ_ZP_X16;
282 OP_ADD_HANDLER16(m, regs.d.word);
286 static void OpF3(void) // ADDD ABS
288 uint16_t m = READ_ABS16;
289 OP_ADD_HANDLER16(m, regs.d.word);
294 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
295 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
296 Add with Carry |ADCA |89 2 2|99 3 2|A9 5 2|B9 4 3| |A=A+M+C |T TTTT|
297 |ADCB |C9 2 2|D9 3 2|E9 5 2|F9 4 3| |B=B+M+C |T TTTT|
302 #define OP_ADC_HANDLER(m, acc) \
303 uint16_t sum = (uint16_t)acc + (m) + (uint16_t)flagC; \
305 flagH = (sum >> 4) & 0x01; \
306 SET_V(m, acc, sum); \
310 static void Op89(void) // ADCA #
312 uint16_t m = READ_IMM;
313 OP_ADC_HANDLER(m, regs.d.acc.a);
317 static void Op99(void) // ADCA ZP
319 uint16_t m = READ_ZP;
320 OP_ADC_HANDLER(m, regs.d.acc.a);
324 static void OpA9(void) // ADCA ZP, X
326 uint16_t m = READ_ZP_X;
327 OP_ADC_HANDLER(m, regs.d.acc.a);
331 static void OpB9(void) // ADCA ABS
333 uint16_t m = READ_ABS;
334 OP_ADC_HANDLER(m, regs.d.acc.a);
338 static void OpC9(void) // ADCB #
340 uint16_t m = READ_IMM;
341 OP_ADC_HANDLER(m, regs.d.acc.b);
345 static void OpD9(void) // ADCB ZP
347 uint16_t m = READ_ZP;
348 OP_ADC_HANDLER(m, regs.d.acc.b);
352 static void OpE9(void) // ADCB ZP, X
354 uint16_t m = READ_ZP_X;
355 OP_ADC_HANDLER(m, regs.d.acc.b);
359 static void OpF9(void) // ADCB ABS
361 uint16_t m = READ_ABS;
362 OP_ADC_HANDLER(m, regs.d.acc.b);
367 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
368 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
369 And |ANDA |84 2 2|94 3 2|A4 5 2|B4 4 3| |A=A+M | TTR |
370 |ANDB |C4 2 2|D4 3 2|E4 5 2|F4 4 3| |B=B+M | TTR |
375 #define OP_AND_HANDLER(m, acc) \
380 static void Op84(void) // ANDA #
382 uint8_t m = READ_IMM;
383 OP_AND_HANDLER(m, regs.d.acc.a);
387 static void Op94(void) // ANDA ZP
390 OP_AND_HANDLER(m, regs.d.acc.a);
394 static void OpA4(void) // ANDA ZP, X
396 uint16_t m = READ_ZP_X;
397 OP_AND_HANDLER(m, regs.d.acc.a);
401 static void OpB4(void) // ANDA ABS
403 uint16_t m = READ_ABS;
404 OP_AND_HANDLER(m, regs.d.acc.a);
408 static void OpC4(void) // ANDB #
410 uint8_t m = READ_IMM;
411 OP_AND_HANDLER(m, regs.d.acc.b);
415 static void OpD4(void) // ANDB ZP
418 OP_AND_HANDLER(m, regs.d.acc.b);
422 static void OpE4(void) // ANDB ZP, X
424 uint16_t m = READ_ZP_X;
425 OP_AND_HANDLER(m, regs.d.acc.b);
429 static void OpF4(void) // ANDB ABS
431 uint16_t m = READ_ABS;
432 OP_AND_HANDLER(m, regs.d.acc.b);
436 static void Op61(void) // AIM ZP, X (AND immediate with index)
439 uint8_t immValue = READ_IMM;
441 OP_AND_HANDLER(immValue, m);
446 static void Op71(void) // AIM ZP (AND immediate with zero page)
449 uint8_t immValue = READ_IMM;
451 OP_AND_HANDLER(immValue, m);
457 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
458 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
459 Bit Test |BITA |85 2 2|95 3 2|A5 5 2|B5 4 3| |A+M | TTR |
460 |BITB |C5 2 2|D5 3 2|E5 5 2|F5 4 3| |B+M | TTR |
465 #define OP_BIT_HANDLER(m, acc) \
466 int8_t result = acc & (m); \
469 static void Op85(void) // BITA #
471 uint8_t m = READ_IMM;
472 OP_BIT_HANDLER(m, regs.d.acc.a);
476 static void Op95(void) // BITA ZP
479 OP_BIT_HANDLER(m, regs.d.acc.a);
483 static void OpA5(void) // BITA ZP, X
485 uint8_t m = READ_ZP_X;
486 OP_BIT_HANDLER(m, regs.d.acc.a);
490 static void OpB5(void) // BITA ABS
492 uint8_t m = READ_ABS;
493 OP_BIT_HANDLER(m, regs.d.acc.a);
497 static void OpC5(void) // BITB #
499 uint8_t m = READ_IMM;
500 OP_BIT_HANDLER(m, regs.d.acc.b);
504 static void OpD5(void) // BITB ZP
507 OP_BIT_HANDLER(m, regs.d.acc.b);
511 static void OpE5(void) // BITB ZP, X
513 uint8_t m = READ_ZP_X;
514 OP_BIT_HANDLER(m, regs.d.acc.b);
518 static void OpF5(void) // BITB ABS
520 uint8_t m = READ_ABS;
521 OP_BIT_HANDLER(m, regs.d.acc.b);
525 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
526 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
527 Clear |CLR | | |6F 7 2|7F 6 3| |M=00 | RSRR|
528 |CLRA | | | | |4F 2 1|A=00 | RSRR|
529 |CLRB | | | | |5F 2 1|B=00 | RSRR|
534 static void Op6F(void) // CLR ZP, X
536 regs.WrMem(EA_ZP_X, 0);
542 static void Op7F(void) // CLR ABS
544 regs.WrMem(EA_ABS, 0);
550 static void Op4F(void) // CLRA
558 static void Op5F(void) // CLRB
566 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
567 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
568 Compare |CMPA |81 2 2|91 3 2|A1 5 2|B1 4 3| |A-M | TTTT|
569 |CMPB |C1 2 2|D1 3 2|E1 5 2|F1 4 3| |B-M | TTTT|
570 Compare Accumulators |CBA | | | | |11 2 1|A-B | TTTT|
576 Compare sets flags as if a subtraction had been carried out. If the value in the accumulator is equal or greater than the compared value, the Carry will be set. The equal (Z) and sign (S) flags will be set based on equality or lack thereof and the sign (i.e. A>=$80) of the accumulator.
579 #define OP_CMP_HANDLER(m, acc) \
580 uint16_t result = acc - (m); \
581 SET_ZNVC_CMP(m, acc, result)
583 static void Op81(void) // CMPA #
585 uint8_t m = READ_IMM;
586 OP_CMP_HANDLER(m, regs.d.acc.a);
590 static void Op91(void) // CMPA ZP
593 OP_CMP_HANDLER(m, regs.d.acc.a);
597 static void OpA1(void) // CMPA ZP, X
599 uint8_t m = READ_ZP_X;
600 OP_CMP_HANDLER(m, regs.d.acc.a);
604 static void OpB1(void) // CMPA ABS
606 uint8_t m = READ_ABS;
607 OP_CMP_HANDLER(m, regs.d.acc.a);
611 static void OpC1(void) // CMPB #
613 uint8_t m = READ_IMM;
614 OP_CMP_HANDLER(m, regs.d.acc.b);
618 static void OpD1(void) // CMPB ZP
621 OP_CMP_HANDLER(m, regs.d.acc.b);
625 static void OpE1(void) // CMPB ZP, X
627 uint8_t m = READ_ZP_X;
628 OP_CMP_HANDLER(m, regs.d.acc.b);
632 static void OpF1(void) // CMPB ABS
634 uint8_t m = READ_ABS;
635 OP_CMP_HANDLER(m, regs.d.acc.b);
639 static void Op11(void) // CBA
641 OP_CMP_HANDLER(regs.d.acc.b, regs.d.acc.a);
645 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
646 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
647 Complement 1's |COM | | |63 7 2|73 6 3| |M=-M | TTRS|
648 |COMA | | | | |43 2 1|A=-A | TTRS|
649 |COMB | | | | |53 2 1|B=-B | TTRS|
654 #define OP_COM_HANDLER(m) \
660 static void Op63(void) // COM ZP, X
669 static void Op73(void) // COM ABS
678 static void Op43(void) // COMA
680 OP_COM_HANDLER(regs.d.acc.a);
684 static void Op53(void) // COMB
686 OP_COM_HANDLER(regs.d.acc.b);
690 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
691 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
692 Complement 2's |NEG | | |60 7 2|70 6 3| |M=00-M | TT12|
693 |NEGA | | | | |40 2 1|A=00-A | TT12|
694 |NEGB | | | | |50 2 1|B=00-B | TT12|
699 #define OP_NEG_HANDLER(m) \
702 flagV = (m == 0x80 ? 1 : 0); \
703 flagC = (m == 0x00 ? 1 : 0)
705 static void Op60(void) // NEG ZP, X
714 static void Op70(void) // NEG ABS
723 static void Op40(void) // NEGA
725 OP_NEG_HANDLER(regs.d.acc.a);
729 static void Op50(void) // NEGB
731 OP_NEG_HANDLER(regs.d.acc.b);
735 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
736 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
737 Decimal Adjust |DAA | | | | |19 2 1|* | TTT3|
740 static void Op19(void) // DAA
742 uint16_t result = (uint16_t)regs.d.acc.a;
744 if ((regs.d.acc.a & 0x0F) > 0x09 || flagH)
747 if ((regs.d.acc.a & 0xF0) > 0x90 || flagC || ((regs.d.acc.a & 0xF0) > 0x80 && (regs.d.acc.a & 0x0F) > 0x09))
750 regs.d.acc.a = (uint8_t)result;
752 CLR_V; // Not sure this is correct...
753 flagC |= (result & 0x100) >> 8; // Overwrite carry if it was 0, otherwise, ignore
757 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
758 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
759 Decrement |DEC | | |6A 7 2|7A 6 3| |M=M-1 | TT4 |
760 |DECA | | | | |4A 2 1|A=A-1 | TT4 |
761 |DECB | | | | |5A 2 1|B=B-1 | TT4 |
766 #define OP_DEC_HANDLER(m) \
769 flagV = (m == 0x7F ? 1 : 0)
771 static void Op6A(void) // DEC ZP, X
780 static void Op7A(void) // DEC ABS
789 static void Op4A(void) // DECA
791 OP_DEC_HANDLER(regs.d.acc.a);
795 static void Op5A(void) // DECB
797 OP_DEC_HANDLER(regs.d.acc.b);
801 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
802 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
803 Exclusive OR |EORA |88 2 2|98 3 2|A8 5 2|B8 4 3| |A=A(+)M | TTR |
804 |EORB |C8 2 2|D8 3 2|E8 5 2|F8 4 3| |B=B(+)M | TTR |
809 #define OP_EOR_HANDLER(m, acc) \
814 static void Op88(void) // EORA #
816 uint8_t m = READ_IMM;
817 OP_EOR_HANDLER(m, regs.d.acc.a);
821 static void Op98(void) // EORA ZP
824 OP_EOR_HANDLER(m, regs.d.acc.a);
828 static void OpA8(void) // EORA ZP, X
830 uint8_t m = READ_ZP_X;
831 OP_EOR_HANDLER(m, regs.d.acc.a);
835 static void OpB8(void) // EORA ABS
837 uint8_t m = READ_ABS;
838 OP_EOR_HANDLER(m, regs.d.acc.a);
842 static void OpC8(void) // EORB #
844 uint8_t m = READ_IMM;
845 OP_EOR_HANDLER(m, regs.d.acc.b);
849 static void OpD8(void) // EORB ZP
852 OP_EOR_HANDLER(m, regs.d.acc.b);
856 static void OpE8(void) // EORB ZP, X
858 uint8_t m = READ_ZP_X;
859 OP_EOR_HANDLER(m, regs.d.acc.b);
863 static void OpF8(void) // EORB ABS
865 uint8_t m = READ_ABS;
866 OP_EOR_HANDLER(m, regs.d.acc.b);
870 static void Op65(void) // EIM ZP, X (EOR immediate with index)
873 uint8_t immValue = READ_IMM;
875 OP_EOR_HANDLER(immValue, m);
880 static void Op75(void) // EIM ZP (EOR immediate with zero page)
883 uint8_t immValue = READ_IMM;
885 OP_EOR_HANDLER(immValue, m);
891 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
892 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
893 Increment |INC | | |6C 7 2|7C 6 3| |M=M+1 | TT5 |
894 |INCA | | | | |4C 2 1|A=A+1 | TT5 |
895 |INCB | | | | |5C 2 1|B=B+1 | TT5 |
900 #define OP_INC_HANDLER(m) \
903 flagV = (m == 0x80 ? 1 : 0)
905 static void Op6C(void) // INC ZP, X
914 static void Op7C(void) // INC ABS
923 static void Op4C(void) // INCA
925 OP_INC_HANDLER(regs.d.acc.a);
929 static void Op5C(void) // INCB
931 OP_INC_HANDLER(regs.d.acc.b);
935 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
936 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
937 Load Accumulator |LDAA |86 2 2|96 3 2|A6 5 2|B6 4 3| |A=M | TTR |
938 |LDAB |C6 2 2|D6 3 2|E6 5 2|F6 4 3| |B=M | TTR |
943 #define OP_LDA_HANDLER(m, acc) \
948 static void Op86(void) // LDAA #
950 uint8_t m = READ_IMM;
951 OP_LDA_HANDLER(m, regs.d.acc.a);
955 static void Op96(void) // LDAA ZP
958 OP_LDA_HANDLER(m, regs.d.acc.a);
962 static void OpA6(void) // LDAA ZP, X
964 uint8_t m = READ_ZP_X;
965 OP_LDA_HANDLER(m, regs.d.acc.a);
969 static void OpB6(void) // LDAA ABS
971 uint8_t m = READ_ABS;
972 OP_LDA_HANDLER(m, regs.d.acc.a);
976 static void OpC6(void) // LDAB #
978 uint8_t m = READ_IMM;
979 OP_LDA_HANDLER(m, regs.d.acc.b);
983 static void OpD6(void) // LDAB ZP
986 OP_LDA_HANDLER(m, regs.d.acc.b);
990 static void OpE6(void) // LDAB ZP, X
992 uint8_t m = READ_ZP_X;
993 OP_LDA_HANDLER(m, regs.d.acc.b);
997 static void OpF6(void) // LDAB ABS
999 uint8_t m = READ_ABS;
1000 OP_LDA_HANDLER(m, regs.d.acc.b);
1005 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1006 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1007 OR, Inclusive |ORAA |8A 2 2|9A 3 2|AA 5 2|BA 4 3| |A=A+M | TTR |
1008 |ORAB |CA 2 2|DA 3 2|EA 5 2|FA 4 3| |B=B+M | TTR |
1013 #define OP_ORA_HANDLER(m, acc) \
1018 static void Op8A(void) // ORAA #
1020 uint8_t m = READ_IMM;
1021 OP_ORA_HANDLER(m, regs.d.acc.a);
1025 static void Op9A(void) // ORAA ZP
1027 uint8_t m = READ_ZP;
1028 OP_ORA_HANDLER(m, regs.d.acc.a);
1032 static void OpAA(void) // ORAA ZP, X
1034 uint8_t m = READ_ZP_X;
1035 OP_ORA_HANDLER(m, regs.d.acc.a);
1039 static void OpBA(void) // ORAA ABS
1041 uint8_t m = READ_ABS;
1042 OP_ORA_HANDLER(m, regs.d.acc.a);
1046 static void OpCA(void) // ORAB #
1048 uint8_t m = READ_IMM;
1049 OP_ORA_HANDLER(m, regs.d.acc.b);
1053 static void OpDA(void) // ORAB ZP
1055 uint8_t m = READ_ZP;
1056 OP_ORA_HANDLER(m, regs.d.acc.b);
1060 static void OpEA(void) // ORAB ZP, X
1062 uint8_t m = READ_ZP_X;
1063 OP_ORA_HANDLER(m, regs.d.acc.b);
1067 static void OpFA(void) // ORAB ABS
1069 uint8_t m = READ_ABS;
1070 OP_ORA_HANDLER(m, regs.d.acc.b);
1074 static void Op62(void) // OIM ZP, X (ORA immediate with index)
1077 uint8_t immValue = READ_IMM;
1079 OP_ORA_HANDLER(immValue, m);
1084 static void Op72(void) // OIM ZP (ORA immediate with zero page)
1087 uint8_t immValue = READ_IMM;
1089 OP_ORA_HANDLER(immValue, m);
1095 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1096 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1097 Push Data |PSHA | | | | |36 4 1|Msp=A, *- | |
1098 |PSHB | | | | |37 4 1|Msp=B, *- | |
1099 Pull Data |PULA | | | | |32 4 1|A=Msp, *+ | |
1100 |PULB | | | | |33 4 1|B=Msp, *+ | |
1103 static void Op36(void) // PSHA
1109 static void Op37(void) // PSHB
1115 static void Op32(void) // PULA
1117 regs.d.acc.a = PULL;
1121 static void Op33(void) // PULB
1123 regs.d.acc.b = PULL;
1127 static void Op38(void) // PULX
1133 static void Op3C(void) // PSHX
1140 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1141 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1142 Rotate Left |ROL | | |69 7 2|79 6 3| |Memory *1| TT6T|
1143 |ROLA | | | | |49 2 1|Accum A *1| TT6T|
1144 |ROLB | | | | |59 2 1|Accum B *1| TT6T|
1149 #define OP_ROL_HANDLER(m) \
1150 uint8_t newCarry = (m & 0x80) >> 7; \
1151 m = (m << 1) | flagC; \
1154 flagV = flagN ^ flagC
1156 static void Op69(void) // ROL ZP, X
1165 static void Op79(void) // ROL ABS
1174 static void Op49(void) // ROLA
1176 OP_ROL_HANDLER(regs.d.acc.a);
1180 static void Op59(void) // ROLB
1182 OP_ROL_HANDLER(regs.d.acc.b);
1186 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1187 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1188 Rotate Right |ROR | | |66 7 2|76 6 3| |Memory *2| TT6T|
1189 |RORA | | | | |46 2 1|Accum A *2| TT6T|
1190 |RORB | | | | |56 2 1|Accum B *2| TT6T|
1195 #define OP_ROR_HANDLER(m) \
1196 uint8_t newCarry = m & 0x01; \
1197 m = (m >> 1) | (flagC << 7); \
1200 flagV = flagN ^ flagC
1202 static void Op66(void) // ROR ZP, X
1211 static void Op76(void) // ROR ABS
1220 static void Op46(void) // RORA
1222 OP_ROR_HANDLER(regs.d.acc.a);
1226 static void Op56(void) // RORB
1228 OP_ROR_HANDLER(regs.d.acc.b);
1232 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1233 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1234 Arithmetic Shift Left |ASL | | |68 7 2|78 6 3| |Memory *3| TT6T|
1235 |ASLA | | | | |48 2 1|Accum A *3| TT6T|
1236 |ASLB | | | | |58 2 1|Accum B *3| TT6T|
1241 #define OP_ASL_HANDLER(m) \
1242 uint8_t newCarry = (m & 0x80) >> 7; \
1246 flagV = flagN ^ flagC
1248 static void Op68(void) // ASL ZP, X
1257 static void Op78(void) // ASL ABS
1266 static void Op48(void) // ASLA
1268 OP_ASL_HANDLER(regs.d.acc.a);
1272 static void Op58(void) // ASLB
1274 OP_ASL_HANDLER(regs.d.acc.b);
1278 static void Op05(void) // ASLD
1280 uint8_t newCarry = (regs.d.word & 0x8000) >> 15;
1283 SET_N16(regs.d.word);
1285 flagV = flagN ^ flagC;
1290 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1291 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1292 Arithmetic Shift Right |ASR | | |67 7 2|77 6 3| |Memory *4| TT6T|
1293 |ASRA | | | | |47 2 1|Accum A *4| TT6T|
1294 |ASRB | | | | |57 2 1|Accum B *4| TT6T|
1299 #define OP_ASR_HANDLER(m) \
1300 uint8_t newCarry = m & 0x01; \
1301 m = (m >> 1) | (m & 0x80); \
1304 flagV = flagN ^ flagC
1306 static void Op67(void) // ASR ZP, X
1315 static void Op77(void) // ASR ABS
1324 static void Op47(void) // ASRA
1326 OP_ASR_HANDLER(regs.d.acc.a);
1330 static void Op57(void) // ASRB
1332 OP_ASR_HANDLER(regs.d.acc.b);
1337 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1338 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1339 Logic Shift Right |LSR | | |64 7 2|74 6 3| |Memory *5| TT6T|
1340 |LSRA | | | | |44 2 1|Accum A *5| TT6T|
1341 |LSRB | | | | |54 2 1|Accum B *5| TT6T|
1346 #define OP_LSR_HANDLER(m) \
1347 uint8_t newCarry = m & 0x01; \
1351 flagV = flagN ^ flagC
1353 static void Op64(void) // LSR ZP, X
1362 static void Op74(void) // LSR ABS
1371 static void Op44(void) // LSRA
1373 OP_LSR_HANDLER(regs.d.acc.a);
1377 static void Op54(void) // LSRB
1379 OP_LSR_HANDLER(regs.d.acc.b);
1383 static void Op04(void) // LSRD
1385 uint8_t newCarry = regs.d.word & 0x01;
1390 flagV = flagN ^ flagC;
1395 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1396 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1397 Store Accumulator |STAA | |97 4 2|A7 6 2|B7 5 3| |M=A | TTR |
1398 |STAB | |D7 4 2|E7 6 2|F7 5 3| |M=B | TTR |
1401 static void Op97(void) // STAA ZP
1403 regs.WrMem(EA_ZP, regs.d.acc.a);
1407 static void OpA7(void) // STAA ZP, X
1409 regs.WrMem(EA_ZP_X, regs.d.acc.a);
1413 static void OpB7(void) // STAA ABS
1415 regs.WrMem(EA_ABS, regs.d.acc.a);
1419 static void OpD7(void) // STAB ZP
1421 regs.WrMem(EA_ZP, regs.d.acc.b);
1425 static void OpE7(void) // STAB ZP, X
1427 regs.WrMem(EA_ZP_X, regs.d.acc.b);
1431 static void OpF7(void) // STAB ABS
1433 regs.WrMem(EA_ABS, regs.d.acc.b);
1437 // These are illegal instructions!
1439 static void Op87(void) // STA #
1441 // What does this even mean? Seems the M.A.M.E. guys think it's something
1443 uint16_t effectiveAddress = regs.pc;
1445 regs.WrMem(effectiveAddress, regs.d.acc.a);
1446 SET_ZN(regs.d.acc.a);
1448 // So, basically, what this does is change the immediate value in the
1449 // STA #. Seems like a completely useless thing to me.
1453 static void OpC7(void) // STB #
1455 uint16_t effectiveAddress = regs.pc;
1457 regs.WrMem(effectiveAddress, regs.d.acc.b);
1458 SET_ZN(regs.d.acc.b);
1465 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1466 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1467 Subtract |SUBA |80 2 2|90 3 2|A0 5 2|B0 4 3| |A=A-M | TTTT|
1468 |SUBB |C0 2 2|D0 3 2|E0 5 2|F0 4 3| |B=B-M | TTTT|
1469 Subtract Accumulators |SBA | | | | |10 2 1|A=A-B | TTTT|
1474 #define OP_SUB_HANDLER(m, acc) \
1475 uint16_t sum = (uint16_t)acc - (m); \
1476 flagC = sum >> 15; \
1477 SET_V(m, acc, sum); \
1478 acc = (uint8_t)sum; \
1481 #define OP_SUB_HANDLER16(m, acc) \
1482 uint32_t sum = (uint32_t)acc - (m); \
1483 flagC = sum >> 31; \
1484 SET_V16(m, acc, sum); \
1485 acc = (uint16_t)sum; \
1489 static void Op80(void) // SUBA #
1491 uint16_t m = READ_IMM;
1492 OP_SUB_HANDLER(m, regs.d.acc.a);
1496 static void Op90(void) // SUBA ZP
1498 uint16_t m = READ_ZP;
1499 OP_SUB_HANDLER(m, regs.d.acc.a);
1503 static void OpA0(void) // SUBA ZP, X
1505 uint16_t m = READ_ZP_X;
1506 OP_SUB_HANDLER(m, regs.d.acc.a);
1510 static void OpB0(void) // SUBA ABS
1512 uint16_t m = READ_ABS;
1513 OP_SUB_HANDLER(m, regs.d.acc.a);
1517 static void OpC0(void) // SUBB #
1519 uint16_t m = READ_IMM;
1520 OP_SUB_HANDLER(m, regs.d.acc.b);
1524 static void OpD0(void) // SUBB ZP
1526 uint16_t m = READ_ZP;
1527 OP_SUB_HANDLER(m, regs.d.acc.b);
1531 static void OpE0(void) // SUBB ZP, X
1533 uint16_t m = READ_ZP_X;
1534 OP_SUB_HANDLER(m, regs.d.acc.b);
1538 static void OpF0(void) // SUBB ABS
1540 uint16_t m = READ_ABS;
1541 OP_SUB_HANDLER(m, regs.d.acc.b);
1545 static void Op10(void) // SBA
1547 OP_SUB_HANDLER(regs.d.acc.b, regs.d.acc.a);
1551 static void Op83(void) // SUBD #
1553 uint16_t m = READ_IMM16;
1554 OP_SUB_HANDLER16(m, regs.d.word);
1558 static void Op93(void) // SUBD ZP
1560 uint16_t m = READ_ZP16;
1561 OP_SUB_HANDLER16(m, regs.d.word);
1565 static void OpA3(void) // SUBD ZP, X
1567 uint16_t m = READ_ZP_X16;
1568 OP_SUB_HANDLER16(m, regs.d.word);
1572 static void OpB3(void) // SUBD ABS
1574 uint16_t m = READ_ABS16;
1575 OP_SUB_HANDLER16(m, regs.d.word);
1580 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1581 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1582 Subtract with Carry |SBCA |82 2 2|92 3 2|A2 5 2|B2 4 3| |A=A-M-C | TTTT|
1583 |SBCB |C2 2 2|D2 3 2|E2 5 2|F2 4 3| |B=B-M-C | TTTT|
1588 #define OP_SBC_HANDLER(m, acc) \
1589 uint16_t sum = (uint16_t)acc - (m) - (uint16_t)flagC; \
1590 flagC = sum >> 15; \
1591 SET_V(m, acc, sum); \
1592 acc = (uint8_t)sum; \
1595 static void Op82(void) // SBCA #
1597 uint16_t m = READ_IMM;
1598 OP_SBC_HANDLER(m, regs.d.acc.a);
1602 static void Op92(void) // SBCA ZP
1604 uint16_t m = READ_ZP;
1605 OP_SBC_HANDLER(m, regs.d.acc.a);
1609 static void OpA2(void) // SBCA ZP, X
1611 uint16_t m = READ_ZP_X;
1612 OP_SBC_HANDLER(m, regs.d.acc.a);
1616 static void OpB2(void) // SBCA ABS
1618 uint16_t m = READ_ABS;
1619 OP_SBC_HANDLER(m, regs.d.acc.a);
1623 static void OpC2(void) // SBCB #
1625 uint16_t m = READ_IMM;
1626 OP_SBC_HANDLER(m, regs.d.acc.b);
1630 static void OpD2(void) // SBCB ZP
1632 uint16_t m = READ_ZP;
1633 OP_SBC_HANDLER(m, regs.d.acc.b);
1637 static void OpE2(void) // SBCB ZP, X
1639 uint16_t m = READ_ZP_X;
1640 OP_SBC_HANDLER(m, regs.d.acc.b);
1644 static void OpF2(void) // SBCB ABS
1646 uint16_t m = READ_ABS;
1647 OP_SBC_HANDLER(m, regs.d.acc.b);
1651 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1652 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1653 Transfer Accumulators |TAB | | | | |16 2 1|B=A | TTR |
1654 |TBA | | | | |17 2 1|A=B | TTR |
1657 static void Op16(void) // TAB
1659 regs.d.acc.b = regs.d.acc.a;
1660 SET_ZN(regs.d.acc.b);
1665 static void Op17(void) // TBA
1667 regs.d.acc.a = regs.d.acc.b;
1668 SET_ZN(regs.d.acc.a);
1673 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1674 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1675 Test, Zero/Minus |TST | | |6D 7 2|7D 6 3| |M-00 | TTRR|
1676 |TSTA | | | | |4D 2 1|A-00 | TTRR|
1677 |TSTB | | | | |5D 2 1|B-00 | TTRR|
1682 #define OP_TST_HANDLER(m) \
1683 uint8_t result = m; \
1687 #define OP_TST_IMM_HANDLER(m, acc) \
1688 uint8_t result = m & acc; \
1692 static void Op6D(void) // TST ZP, X
1700 OP_TST_HANDLER(READ_ZP_X);
1705 static void Op7D(void) // TST ABS
1713 OP_TST_HANDLER(READ_ABS);
1718 static void Op4D(void) // TSTA
1720 OP_TST_HANDLER(regs.d.acc.a);
1724 static void Op5D(void) // TSTB
1726 OP_TST_HANDLER(regs.d.acc.b);
1730 static void Op6B(void) // TIM ZP, X (TST immediate with index)
1733 uint8_t immValue = READ_IMM;
1735 OP_TST_IMM_HANDLER(immValue, READ_ZP_X);
1740 static void Op7B(void) // TIM ZP (TST immediate with zero page)
1743 uint8_t immValue = READ_IMM;
1745 OP_TST_IMM_HANDLER(immValue, READ_ZP);
1751 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1752 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1753 Compare Index Register |CPX |8C 3 3|9C 4 2|AC 6 2|BC 5 3| |Formula 1 | 7T8 |
1759 Compare sets flags as if a subtraction had been carried out. If the value in the X register is equal or greater than the compared value, the Carry will be set. The equal (Z) and sign (S) flags will be set based on equality or lack thereof and the sign (i.e. X>=$8000) of the X register.
1762 #define OP_CPX_HANDLER(m) \
1763 uint32_t result = regs.x - (m); \
1764 SET_ZNVC_CMP16(m, regs.x, result)
1766 static void Op8C(void) // CPX #
1768 uint16_t m = READ_IMM16;
1773 static void Op9C(void) // CPX ZP
1775 uint16_t m = READ_ZP16;
1780 static void OpAC(void) // CPX ZP, X
1782 uint16_t m = READ_ZP_X16;
1787 static void OpBC(void) // CPX ABS
1789 uint16_t m = READ_ABS16;
1794 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1795 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1796 Decrement Index Register|DEX | | | | |09 4 1|X=X-1 | T |
1797 Dec Stack Pointer |DES | | | | |34 4 1|SP=SP-1 | |
1798 Inc Index Regster |INX | | | | |08 4 1|X=X+1 | T |
1799 Inc Stack Pointer |INS | | | | |31 4 1|SP=SP+1 | |
1802 static void Op09(void) // DEX
1809 static void Op34(void) // DES
1815 static void Op08(void) // INX
1822 static void Op31(void) // INS
1828 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1829 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1830 Load Index Register |LDX |CE 3 3|DE 4 2|EE 6 2|FE 5 3| |Formula 2 | 9TR |
1831 Load Stack Pointer |LDS |8E 3 3|9E 4 2|AE 6 2|BE 5 3| |Formula 3 | 9TR |
1834 // LD* opcode handler
1836 #define OP_LD_HANDLER(acc) \
1841 static void OpCE(void) // LDX #
1843 regs.x = READ_IMM16;
1844 OP_LD_HANDLER(regs.x);
1848 static void OpDE(void) // LDX ZP
1851 OP_LD_HANDLER(regs.x);
1855 static void OpEE(void) // LDX ZP, X
1857 regs.x = READ_ZP_X16;
1858 OP_LD_HANDLER(regs.x);
1862 static void OpFE(void) // LDX ABS
1864 regs.x = READ_ABS16;
1865 OP_LD_HANDLER(regs.x);
1869 static void Op8E(void) // LDS #
1871 regs.s = READ_IMM16;
1872 OP_LD_HANDLER(regs.s);
1876 static void Op9E(void) // LDS ZP
1879 OP_LD_HANDLER(regs.s);
1883 static void OpAE(void) // LDS ZP, X
1885 regs.s = READ_ZP_X16;
1886 OP_LD_HANDLER(regs.s);
1890 static void OpBE(void) // LDS ABS
1892 regs.s = READ_ABS16;
1893 OP_LD_HANDLER(regs.s);
1897 static void OpCC(void) // LDD #
1899 regs.d.word = READ_IMM16;
1900 OP_LD_HANDLER(regs.d.word);
1904 static void OpDC(void) // LDD ZP
1906 regs.d.word = READ_ZP16;
1907 OP_LD_HANDLER(regs.d.word);
1911 static void OpEC(void) // LDD ZP, X
1913 regs.d.word = READ_ZP_X16;
1914 OP_LD_HANDLER(regs.d.word);
1918 static void OpFC(void) // LDD ABS
1920 regs.d.word = READ_ABS16;
1921 OP_LD_HANDLER(regs.d.word);
1926 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1927 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1928 Store Index Register |STX | |DF 5 2|EF 7 2|FF 6 3| |Formula 4 | 9TR |
1929 Store Stack Pointer |STS | |9F 5 2|AF 7 2|BF 6 3| |Formula 5 | 9TR |
1932 // ST* opcode handler
1934 #define OP_ST_HANDLER(m, acc) \
1935 regs.WrMem(m + 0, acc >> 8); \
1936 regs.WrMem(m + 1, acc & 0xFF); \
1941 static void OpDF(void) // STX ZP
1944 OP_ST_HANDLER(m, regs.x);
1948 static void OpEF(void) // STX ZP, X
1950 uint16_t m = EA_ZP_X;
1951 OP_ST_HANDLER(m, regs.x);
1955 static void OpFF(void) // STX ABS
1957 uint16_t m = EA_ABS;
1958 OP_ST_HANDLER(m, regs.x);
1962 static void Op9F(void) // STS ZP
1965 OP_ST_HANDLER(m, regs.s);
1969 static void OpAF(void) // STS ZP, X
1971 uint16_t m = EA_ZP_X;
1972 OP_ST_HANDLER(m, regs.s);
1976 static void OpBF(void) // STS ABS
1978 uint16_t m = EA_ABS;
1979 OP_ST_HANDLER(m, regs.s);
1983 // These are illegal instructions!
1985 // Store immediate--nonsensical opcodes :-P
1986 static void Op8F(void) // STS #
1988 uint16_t effectiveAddress = regs.pc;
1990 OP_ST_HANDLER(effectiveAddress, regs.s);
1994 static void OpCF(void) // STX #
1996 uint16_t effectiveAddress = regs.pc;
1998 OP_ST_HANDLER(effectiveAddress, regs.x);
2002 static void OpCD(void) // STD #
2004 uint16_t effectiveAddress = regs.pc;
2006 OP_ST_HANDLER(effectiveAddress, regs.d.word);
2011 static void OpDD(void) // STD ZP
2014 OP_ST_HANDLER(m, regs.d.word);
2018 static void OpED(void) // STD ZP, X
2020 uint16_t m = EA_ZP_X;
2021 OP_ST_HANDLER(m, regs.d.word);
2025 static void OpFD(void) // STD ABS
2027 uint16_t m = EA_ABS;
2028 OP_ST_HANDLER(m, regs.d.word);
2033 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
2034 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
2035 Index Reg > Stack Pnter |TXS | | | | |35 4 1|SP=X-1 | |
2036 Stack Ptr > Index Regtr |TSX | | | | |30 4 1|X=SP+1 | |
2039 static void Op35(void) // TXS
2041 regs.s = regs.x - 1;
2045 static void Op30(void) // TSX
2047 regs.x = regs.s + 1;
2051 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
2052 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
2053 Always |BRA | |20 4 2| | | |none | |
2054 Carry is Clear |BCC | |24 4 2| | | |C=0 | |
2055 Carry is Set |BCS | |25 4 2| | | |C=1 | |
2056 Equals Zero |BEQ | |27 4 2| | | |Z=1 | |
2057 Greater or Equal to Zero|BGE | |2C 4 2| | | |N(+)V=0 | |
2058 Greater than Zero |BGT | |2E 4 2| | | |Z+N(+)V=0 | |
2059 Higher |BHI | |22 4 2| | | |C+Z=0 | |
2060 Less or Equal than Zero |BLE | |2F 4 2| | | |Z+N(+)V=1 | |
2061 Lower or Same |BLS | |23 4 2| | | |C+Z=1 | |
2062 Less Than Zero |BLT | |2D 4 2| | | |N(+)V=1 | |
2063 Minus |BMI | |2B 4 2| | | |N=1 | |
2064 Not Zero |BNE | |26 4 2| | | |Z=0 | |
2065 Overflow Clear |BVC | |28 4 2| | | |V=0 | |
2066 Overflow Set |BVS | |29 4 2| | | |V=1 | |
2067 Plus |BPL | |2A 4 2| | | |N=0 | |
2070 static void Op20(void) // BRA
2072 int16_t m = (int16_t)(int8_t)READ_IMM;
2077 static void Op21(void) // BRN
2079 int16_t m = (int16_t)(int8_t)READ_IMM;
2084 static void Op24(void) // BCC
2086 // NOTE: We can optimize this by following the maxim: "Don't branch!" by
2087 // converting the boolean result into a multiplication. The only way to
2088 // know if this is a win is to do some profiling both with and without
2089 // the optimization.
2090 int16_t m = (int16_t)(int8_t)READ_IMM;
2092 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2093 //Note sure if the ! operator will do what we want, so we use ^ 1
2094 regs.pc += m * (flagC ^ 0x01);
2102 static void Op25(void) // BCS
2104 int16_t m = (int16_t)(int8_t)READ_IMM;
2106 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2107 regs.pc += m * (flagC);
2115 static void Op27(void) // BEQ
2117 int16_t m = (int16_t)(int8_t)READ_IMM;
2119 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2120 regs.pc += m * (flagZ);
2128 static void Op2C(void) // BGE
2130 int16_t m = (int16_t)(int8_t)READ_IMM;
2132 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2133 regs.pc += m * ((flagN ^ flagV) ^ 0x01);
2135 if (!(flagN ^ flagV))
2141 static void Op2E(void) // BGT
2143 int16_t m = (int16_t)(int8_t)READ_IMM;
2145 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2146 regs.pc += m * ((flagZ | (flagN ^ flagV)) ^ 0x01);
2148 if (!(flagZ | (flagN ^ flagV)))
2154 static void Op22(void) // BHI
2156 int16_t m = (int16_t)(int8_t)READ_IMM;
2158 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2159 regs.pc += m * ((flagZ | flagC) ^ 0x01);
2161 if (!(flagZ | flagC))
2167 static void Op2F(void) // BLE
2169 int16_t m = (int16_t)(int8_t)READ_IMM;
2171 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2172 regs.pc += m * (flagZ | (flagN ^ flagV));
2174 if (flagZ | (flagN ^ flagV))
2180 static void Op23(void) // BLS
2182 int16_t m = (int16_t)(int8_t)READ_IMM;
2184 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2185 regs.pc += m * (flagZ | flagC);
2193 static void Op2D(void) // BLT
2195 int16_t m = (int16_t)(int8_t)READ_IMM;
2197 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2198 regs.pc += m * (flagN ^ flagV);
2206 static void Op2B(void) // BMI
2208 int16_t m = (int16_t)(int8_t)READ_IMM;
2210 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2211 regs.pc += m * (flagN);
2219 static void Op26(void) // BNE
2221 int16_t m = (int16_t)(int8_t)READ_IMM;
2223 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2224 regs.pc += m * (flagZ ^ 0x01);
2232 static void Op28(void) // BVC
2234 int16_t m = (int16_t)(int8_t)READ_IMM;
2236 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2237 regs.pc += m * (flagV ^ 0x01);
2245 static void Op29(void) // BVS
2247 int16_t m = (int16_t)(int8_t)READ_IMM;
2249 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2250 regs.pc += m * (flagV);
2258 static void Op2A(void) // BPL
2260 int16_t m = (int16_t)(int8_t)READ_IMM;
2262 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2263 regs.pc += m * (flagN ^ 0x01);
2271 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
2272 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
2273 Branch to Subroutine |BSR | |8D 8 2| | | | | |
2274 Jump |JMP | | |6E 4 2|7E 3 3| | | |
2275 Jump to Subroutine |JSR | | |AD 8 2|BD 9 3| | | |
2278 static void Op8D(void) // BSR
2280 int16_t m = (int16_t)(int8_t)READ_IMM;
2286 static void Op6E(void) // JMP ZP, X
2288 uint16_t m = EA_ZP_X;
2293 static void Op7E(void) // JMP ABS
2299 static void Op9D(void) // JSR ZP
2301 uint16_t m = (uint16_t)EA_ZP;
2307 static void OpAD(void) // JSR ZP, X
2309 uint16_t m = EA_ZP_X;
2315 static void OpBD(void) // JSR ABS
2317 uint16_t m = EA_ABS;
2324 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
2325 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
2326 No Operation |NOP | | | | |01 2 1| | |
2327 Return from Interrupt |RTI | | | | |3B A 1| |AAAAAA|
2328 Return from Subroutine |RTS | | | | |39 5 1| | |
2329 Software Interrupt |SWI | | | | |3F C 1| | S |
2330 Wait For Interrupt |WAI | | | | |3E 9 1| | B |
2333 static void Op01(void) // NOP
2338 static void Op3B(void) // RTI
2341 regs.d.acc.b = PULL;
2342 regs.d.acc.a = PULL;
2349 static void Op39(void) // RTS
2355 static void Op3F(void) // SWI
2357 // It seems that the SWI is non-maskable, unlike the IRQ...
2359 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2360 PUSH16(regs.pc); // Save all regs...
2365 regs.pc = RdMemW(0xFFFA); // And do it!
2366 flagI = 1; // Also, set IRQ inhibit
2368 HandleInterrupt(0xFFFA);
2372 static void Op3E(void) // WAI
2375 WriteLog("*** WAI STATE ASSERTED ***\n");
2377 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2378 PUSH16(regs.pc); // Save all regs...
2383 regs.cpuFlags |= V63701_STATE_WAI; // And signal that we're in WAI mode
2389 static void Op3D(void) // MUL
2391 regs.d.word = (uint16_t)regs.d.acc.a * (uint16_t)regs.d.acc.b;
2392 flagC = regs.d.acc.b >> 7; // bug? No, this is how it really does it
2396 // Exchange X and D opcode
2398 static void Op18(void) // XGDX
2400 // This doesn't affect flags apparently
2401 uint16_t temp = regs.x;
2402 regs.x = regs.d.word;
2407 // Sleep opcode (similar to WAI)
2409 static void Op1A(void) // SLP
2411 // Apparently doesn't stack the state, so no need for RTI
2412 // It would seem that this opcode is intended for use in interrupt
2413 // routines, as it prevents stacking the state when one happens.
2414 // (Actually, this is used to put the MCU into a low power "sleep" mode,
2415 // where it stays until an interrupt or RESET occurs.)
2416 regs.cpuFlags |= V63701_STATE_WAI;
2420 // Undocumented opcode ($12 & $13)
2422 static void OpUN(void) // Undocumented
2424 regs.x += regs.RdMem(regs.s + 1);
2429 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
2430 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
2431 Clear Carry |CLC | | | | |0C 2 1|C=0 | R|
2432 Clear Interrupt |CLI | | | | |0E 2 1|I=0 | R |
2433 Clear Overflow |CLV | | | | |0A 2 1|V=0 | R |
2434 Set Carry |SEC | | | | |0D 2 1|C=1 | S|
2435 Set Interrupt |SEI | | | | |0F 2 1|I=1 | S |
2436 Set Overflow |SEV | | | | |0B 2 1|V=1 | S |
2437 CCR=Accumulator A |TAP | | | | |06 2 1|CCR=A |CCCCCC|
2438 Accumlator A=CCR |TPA | | | | |07 2 1|A=CCR | |
2441 static void Op0C(void) // CLC
2447 static void Op0E(void) // CLI
2453 static void Op0A(void) // CLV
2459 static void Op0D(void) // SEC
2465 static void Op0F(void) // SEI
2471 static void Op0B(void) // SEV
2477 static void Op06(void) // TAP
2479 regs.cc = regs.d.acc.a;
2484 static void Op07(void) // TPA
2486 regs.d.acc.a = PACK_FLAGS;
2491 OP Operation Code, in Hexadecimal
2492 ~ Number of MPU cycles required
2493 # Number of program bytes required
2497 Msp Contents of Memory pointed to be Stack Pointer
2498 + Boolean Inclusive OR
2499 (+) Boolean Exclusive OR (XOR)
2500 * Converts Binary Addition of BCD Characters into BCD Format
2504 Condition Code Register Legend
2508 T Tests and sets if True, cleared otherise
2509 1 Test: Result=10000000?
2510 2 Test: Result=00000000?
2511 3 Test: Decimal value of most significant BCD character greater than nine?
2512 (Not cleared if previously set)
2513 4 Test: Operand=10000000 prior to execution?
2514 5 Test: Operand=01111111 prior to execution?
2515 6 Test: Set equal to result or N(+)C after shift has occurred.
2516 7 Test: Sign bit of most significant byte or result=1?
2517 8 Test: 2's compliment overflow from subtraction of least
2519 9 Test: Result less than zero? (Bit 15=1)
2520 A Load Condition Code Register from Stack.
2521 B Set when interrupt occurs. If previously set, a NMI is
2522 required to exit the wait state.
2523 C Set according to the contents of Accumulator A.
2525 *x SHIFT AND ROTATION DIAGRAMS
2526 *1 +-----------------+ C to LSB
2529 *2 +-----------------+
2532 *3 C <- 76543210 <- 0(Data)
2535 *4 �>76543210 -> C
2537 *5 (Data)0 -> 76543210 -> C
2547 static void Op__(void)
2549 // TRAP is non-maskable, unlike the IRQ... Also, highest priority after
2551 HandleInterrupt(0xFFEE);
2552 // regs.cpuFlags |= V63701_STATE_ILLEGAL_INST;
2557 // Ok, the exec_op[] array is globally defined here basically to save
2558 // a LOT of unnecessary typing. Sure it's ugly, but hey, it works!
2560 static void (* exec_op[256])() = {
2561 Op__, Op01, Op__, Op__, Op04, Op05, Op06, Op07, Op08, Op09, Op0A, Op0B, Op0C, Op0D, Op0E, Op0F,
2562 Op10, Op11, OpUN, OpUN, Op__, Op__, Op16, Op17, Op18, Op19, Op1A, Op1B, Op__, Op__, Op__, Op__,
2563 Op20, Op21, Op22, Op23, Op24, Op25, Op26, Op27, Op28, Op29, Op2A, Op2B, Op2C, Op2D, Op2E, Op2F,
2564 Op30, Op31, Op32, Op33, Op34, Op35, Op36, Op37, Op38, Op39, Op3A, Op3B, Op3C, Op3D, Op3E, Op3F,
2565 Op40, Op__, Op__, Op43, Op44, Op__, Op46, Op47, Op48, Op49, Op4A, Op__, Op4C, Op4D, Op__, Op4F,
2566 Op50, Op__, Op__, Op53, Op54, Op__, Op56, Op57, Op58, Op59, Op5A, Op__, Op5C, Op5D, Op__, Op5F,
2567 Op60, Op61, Op62, Op63, Op64, Op65, Op66, Op67, Op68, Op69, Op6A, Op6B, Op6C, Op6D, Op6E, Op6F,
2568 Op70, Op71, Op72, Op73, Op74, Op75, Op76, Op77, Op78, Op79, Op7A, Op7B, Op7C, Op7D, Op7E, Op7F,
2569 Op80, Op81, Op82, Op83, Op84, Op85, Op86, Op__, Op88, Op89, Op8A, Op8B, Op8C, Op8D, Op8E, Op__,
2570 Op90, Op91, Op92, Op93, Op94, Op95, Op96, Op97, Op98, Op99, Op9A, Op9B, Op9C, Op9D, Op9E, Op9F,
2571 OpA0, OpA1, OpA2, OpA3, OpA4, OpA5, OpA6, OpA7, OpA8, OpA9, OpAA, OpAB, OpAC, OpAD, OpAE, OpAF,
2572 OpB0, OpB1, OpB2, OpB3, OpB4, OpB5, OpB6, OpB7, OpB8, OpB9, OpBA, OpBB, OpBC, OpBD, OpBE, OpBF,
2573 OpC0, OpC1, OpC2, OpC3, OpC4, OpC5, OpC6, Op__, OpC8, OpC9, OpCA, OpCB, OpCC, Op__, OpCE, Op__,
2574 OpD0, OpD1, OpD2, OpD3, OpD4, OpD5, OpD6, OpD7, OpD8, OpD9, OpDA, OpDB, OpDC, OpDD, OpDE, OpDF,
2575 OpE0, OpE1, OpE2, OpE3, OpE4, OpE5, OpE6, OpE7, OpE8, OpE9, OpEA, OpEB, OpEC, OpED, OpEE, OpEF,
2576 OpF0, OpF1, OpF2, OpF3, OpF4, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, OpFB, OpFC, OpFD, OpFE, OpFF
2581 // Internal "memcpy" (so we don't have to link with any external libraries!)
2583 static void myMemcpy(void * dst, void * src, uint32_t size)
2585 uint8_t * d = (uint8_t *)dst, * s = (uint8_t *)src;
2587 for(uint32_t i=0; i<size; i++)
2593 //int instCount[256];
2594 //static bool logGo = false;
2595 static bool logGo = true;
2597 extern uint8_t memory[];
2600 // Function to execute 63701 for "cycles" cycles
2602 void Execute63701(V63701REGS * context, uint32_t cycles)
2604 //#warning "V63701_STATE_WAI is not properly handled yet! !!! FIX !!!"
2605 //#warning "Need to convert from destructive clock to non-destructive. !!! FIX !!!"
2606 regsPointer = context;
2607 myMemcpy(®s, context, sizeof(V63701REGS));
2608 // Explode flags register into individual uint8_ts
2613 while (regs.clock < cycles)
2616 uint64_t endCycles = regs.clock + (uint64_t)cycles - regs.clockOverrun;
2618 while (regs.clock < endCycles)
2624 Decode63701(memory, regs.pc, instBuf);
2625 WriteLog("%s\n", instBuf);
2628 if (regs.cpuFlags & V63701_STATE_WAI)
2630 // Only bail out if no interrupts/resets are pending
2631 if (!(regs.cpuFlags & (V63701_ASSERT_LINE_IRQ | V63701_ASSERT_LINE_NMI | V63701_ASSERT_LINE_RESET | V63701_ASSERT_TIMER_OVERFLOW | V63701_ASSERT_OUTPUT_COMPARE | V63701_ASSERT_INPUT_CAPTURE)))
2632 // Burn any remaining cycles...
2633 regs.clock = endCycles;
2637 uint8_t opcode = regs.RdMem(regs.pc++);
2638 exec_op[opcode](); // Execute that opcode...
2639 regs.clock += CPUCycles[opcode];
2640 uint16_t oldCounter = regs.counter.word;
2641 regs.counter.word += CPUCycles[opcode];
2643 // We fake the free running counter above, by adding cycle counts
2644 // to it; this means we can never be sure that the counter will
2645 // be equal to the output compare register. So we have to check
2646 // for two cases: 1st, look for the previous counter value and see
2647 // if we went past it, and 2nd, do the same but check to see if we
2648 // overflowed in the meantime.
2649 if (((oldCounter < regs.outputCompare.word)
2650 && (regs.counter.word >= regs.outputCompare.word))
2651 || ((oldCounter > regs.counter.word)
2652 && (regs.counter.word >= regs.outputCompare.word)))
2654 // Set the output compare flag bit
2655 regs.tcsr.bit.ocf = 1;
2657 if (regs.tcsr.bit.eoci)
2659 regs.cpuFlags |= V63701_ASSERT_OUTPUT_COMPARE;
2660 regsPointer->cpuFlags |= V63701_ASSERT_OUTPUT_COMPARE;
2664 // Check for counter overflow
2665 if (regs.counter.word < oldCounter)
2667 // Set the timer overflow flag bit
2668 regs.tcsr.bit.tof = 1;
2670 if (regs.tcsr.bit.etoi)
2672 regs.cpuFlags |= V63701_ASSERT_TIMER_OVERFLOW;
2673 regsPointer->cpuFlags |= V63701_ASSERT_TIMER_OVERFLOW;
2678 // WriteLog(" [PC=%04X, S=%04X, X=%04X, A=%02X, B=%02X, CC=%s%s%s%s%s%s%s%s]\n", regs.pc, regs.s, regs.x, regs.d.acc.a, regs.d.acc.b, (regs.cc & FLAG_E ? "E" : " "), (regs.cc & FLAG_F ? "F" : " "), (regs.cc & FLAG_H ? "H" : " "), (regs.cc & FLAG_I ? "I" : " "), (regs.cc & FLAG_N ? "N" : " "), (regs.cc & FLAG_Z ? "Z" : " "), (regs.cc & FLAG_V ? "V" : " "), (regs.cc & FLAG_C ? "C" : " "));
2679 WriteLog(" [PC=%04X S=%04X X=%04X A=%02X B=%02X CC=%s%s%s%s%s%s TCSR=%s%s%s%s%s%s%s%s CT=%04X OC=%04X]\n", regs.pc, regs.s, regs.x, regs.d.acc.a, regs.d.acc.b, (flagH ? "H" : "."), (flagI ? "I" : "."), (flagN ? "N" : "."), (flagZ ? "Z" : "."), (flagV ? "V" : "."), (flagC ? "C" : "."), (regs.tcsr.bit.icf ? "I" :"."), (regs.tcsr.bit.ocf ? "O" :"."), (regs.tcsr.bit.tof ? "T" :"."), (regs.tcsr.bit.eici ? "i" :"."), (regs.tcsr.bit.eoci ? "o" :"."), (regs.tcsr.bit.etoi ? "t" :"."), (regs.tcsr.bit.iedg ? "E" :"."), (regs.tcsr.bit.olvl ? "O" :"."), regs.counter.word, regs.outputCompare.word);
2683 if (regs.cpuFlags & V63701_ASSERT_LINE_RESET)
2686 WriteLog("*** RESET LINE ASSERTED ***\n");
2689 regs.tcsrWasRead = false;
2690 regs.counter.word = 0;
2691 regs.outputCompare.word = 0xFFFF;
2693 regs.pc = RdMemW(0xFFFE); // And load PC with the RESET vector
2694 context->cpuFlags = 0; // Clear all lingering flags...
2697 else if (regs.cpuFlags & V63701_ASSERT_LINE_NMI)
2700 WriteLog("*** NMI LINE ASSERTED ***\n");
2702 HandleInterrupt(0xFFFC, V63701_ASSERT_LINE_NMI);
2704 else if (regs.cpuFlags & V63701_ASSERT_LINE_IRQ)
2707 WriteLog("*** IRQ LINE ASSERTED ***\n");
2709 // if (!(regs.cc & FLAG_I)) // Process an interrupt (I=0)?
2710 if (!flagI) // Process an interrupt (I=0)?
2713 WriteLog(" IRQ TAKEN!\n");
2716 HandleInterrupt(0xFFF8, V63701_ASSERT_LINE_IRQ);
2719 else if (regs.cpuFlags & V63701_ASSERT_INPUT_CAPTURE)
2722 WriteLog("*** INPUT CAPTURE ASSERTED ***\n");
2724 // Process interrupt if no I inhibit set, & enable in TCSR is set
2725 if (!flagI && regs.tcsr.bit.eici)
2728 WriteLog(" IC TAKEN!\n");
2731 HandleInterrupt(0xFFF6, V63701_ASSERT_INPUT_CAPTURE);
2734 else if (regs.cpuFlags & V63701_ASSERT_OUTPUT_COMPARE)
2737 WriteLog("*** OUTPUT COMPARE ASSERTED ***\n");
2739 // Process interrupt if no I inhibit set, & enable in TCSR is set
2740 if (!flagI && regs.tcsr.bit.eoci)
2743 WriteLog(" OC TAKEN!\n");
2746 HandleInterrupt(0xFFF4, V63701_ASSERT_OUTPUT_COMPARE);
2749 else if (regs.cpuFlags & V63701_ASSERT_TIMER_OVERFLOW)
2752 WriteLog("*** TIMER OVER ASSERTED ***\n");
2754 // Process interrupt if no I inhibit set, & enable in TCSR is set
2755 if (!flagI && regs.tcsr.bit.etoi)
2758 WriteLog(" TO TAKEN!\n");
2761 HandleInterrupt(0xFFF2, V63701_ASSERT_TIMER_OVERFLOW);
2766 // If we went longer than the passed in cycles, make a note of it so we can
2767 // subtract it out from a subsequent run. It's guaranteed to be positive,
2768 // because the condition that exits the main loop above is written such
2769 // that regs.clock has to be larger than endCycles to exit from it.
2770 regs.clockOverrun = regs.clock - endCycles;
2772 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2773 myMemcpy(context, ®s, sizeof(V63701REGS));
2778 // Get the clock of the currently executing CPU
2780 uint64_t GetCurrentV63701Clock(void)
2786 static inline void HandleInterrupt(uint16_t vector, uint16_t flag/*= 0*/)
2788 if (regs.cpuFlags & V63701_STATE_WAI)
2792 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2793 PUSH16(regs.pc); // Save all regs...
2801 regs.pc = RdMemW(vector); // And do it!
2804 // Clear the passed in flag + WAI state
2805 regs.cpuFlags &= ~(flag | V63701_STATE_WAI);
2806 regsPointer->cpuFlags &= ~(flag | V63701_STATE_WAI);
2810 uint8_t InternalRegisterRead(uint16_t address)
2812 switch (address & 0x1F)
2817 return /*(regs.port1read & ~regs.ddr1) |*/ (regs.port1 & regs.ddr1);
2818 // Timer Control and Status Register
2820 regs.tcsrWasRead = true;
2821 return regs.tcsr.byte;
2822 // Counter high byte
2824 if (regs.tcsrWasRead)
2826 regs.tcsr.bit.tof = 0;
2827 regs.tcsrWasRead = false;
2830 regs.cReadLatch = regs.counter.byte.lo;
2831 return regs.counter.byte.hi;
2834 return regs.cReadLatch;
2835 // Output compare high byte
2837 return regs.outputCompare.byte.hi;
2838 // Output compare low byte
2840 return regs.outputCompare.byte.lo;
2841 // RAM Control register (only bits 6 & 7 are valid)
2843 return (regs.ramCtrl & 0xC0) | 0x3F;
2846 printf("V63701: Unhandled register read @ $%02X...\n", address);
2856 void InternalRegisterWrite(uint16_t address, uint8_t data)
2858 switch (address & 0x1F)
2873 // Timer Control and Status Register
2875 // Top 3 bits are RO, so protect them
2876 regs.tcsr.byte = (data & 0x1F) | (regs.tcsr.byte & 0xE0);
2878 // Counter (High Byte)
2880 regs.cWriteLatch = data;
2881 regs.counter.word = 0xFFF8;
2883 // Counter (Low Byte)
2885 regs.counter.word = (regs.cWriteLatch << 8) | data;
2887 // Output Compare Register (High Byte)
2889 regs.outputCompare.byte.hi = data;
2891 if (regs.tcsrWasRead)
2893 regs.tcsr.bit.ocf = 0;
2894 regs.tcsrWasRead = false;
2898 // Output Compare Register (Low Byte)
2900 regs.outputCompare.byte.lo = data;
2902 if (regs.tcsrWasRead)
2904 regs.tcsr.bit.ocf = 0;
2905 regs.tcsrWasRead = false;
2909 // RAM Control register
2911 regs.ramCtrl = data;
2915 WriteLog("V63701: Unhandled register write @ $%02X...\n", address);