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
33 #define TEST_DONT_BRANCH_OPTIMIZATION
36 //#include <stdio.h> // for printf()
41 #include <stdio.h> // for printf()
42 #define WriteLog printf
47 #define CLR_Z (flagZ = 0)
48 #define CLR_ZN (flagZ = flagN = 0)
49 #define CLR_ZNC (flagZ = flagN = flagC = 0)
50 #define CLR_NVC (flagN = flagV = flagC = 0)
51 #define CLR_VC (flagV = flagC = 0)
52 #define CLR_V (flagV = 0)
53 #define CLR_N (flagN = 0)
54 #define SET_Z(r) (flagZ = ((r) == 0 ? 1 : 0))
55 #define SET_N(r) (flagN = ((r) & 0x80) >> 7)
56 #define SET_V(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x80) >> 7)
58 #define SET_C_CMP(a,b) (flagC = ((uint8_t)(b) < (uint8_t)(a) ? 1 : 0))
59 #define SET_ZN(r) SET_N(r); SET_Z(r)
60 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
61 #define SET_ZNVC_CMP(a,b,r) SET_N(r); SET_Z(r); SET_C_CMP(a,b); SET_V(a,b,r)
63 #define SET_N16(r) (flagN = ((r) & 0x8000) >> 15)
64 #define SET_V16(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x8000) >> 15)
65 #define SET_C_CMP16(a,b) (flagC = ((uint16_t)(b) < (uint16_t)(a) ? 1 : 0))
66 #define SET_ZNVC_CMP16(a,b,r) SET_N16(r); SET_Z(r); SET_C_CMP16(a,b); SET_V16(a,b,r)
68 #define EA_IMM regs.pc++
69 #define EA_ZP regs.RdMem(regs.pc++)
70 #define EA_ZP_X (regs.RdMem(regs.pc++) + regs.x)
71 #define EA_ABS FetchMemW(regs.pc)
73 #define READ_IMM regs.RdMem(EA_IMM)
74 #define READ_ZP regs.RdMem(EA_ZP)
75 #define READ_ZP_X regs.RdMem(EA_ZP_X)
76 #define READ_ABS regs.RdMem(EA_ABS)
78 #define READ_IMM16 FetchMemW(regs.pc);
79 #define READ_ZP16 RdMemW(EA_ZP)
80 #define READ_ZP_X16 RdMemW(EA_ZP_X)
81 #define READ_ABS16 RdMemW(EA_ABS)
83 #define READ_IMM_WB(v) uint16_t addr = EA_IMM; v = regs.RdMem(addr)
84 #define READ_ZP_WB(v) uint16_t addr = EA_ZP; v = regs.RdMem(addr)
85 #define READ_ZP_X_WB(v) uint16_t addr = EA_ZP_X; v = regs.RdMem(addr)
86 #define READ_ABS_WB(v) uint16_t addr = EA_ABS; v = regs.RdMem(addr)
88 #define WRITE_BACK(d) regs.WrMem(addr, (d))
90 // This is correct; PUSH writes the location *then* decrements the stack
91 // pointer, and PULL does the opposite. Verified from the data sheet.
92 #define PULL regs.RdMem(++regs.s)
93 #define PUSH(r) regs.WrMem(regs.s--, (r))
94 #define PULL16 RdMemW(++regs.s); ++regs.s;
95 #define PUSH16(r) regs.WrMem(regs.s--, (r) & 0xFF); regs.WrMem(regs.s--, (r) >> 8)
97 #define PACK_FLAGS ((regs.cc & 0xC0) | (flagH << 5) | (flagI << 4) | (flagN << 3) | (flagZ << 2) | (flagV << 1) | flagC)
98 #define UNPACK_FLAGS flagH = (regs.cc & FLAG_H) >> 5; \
99 flagI = (regs.cc & FLAG_I) >> 4; \
100 flagN = (regs.cc & FLAG_N) >> 3; \
101 flagZ = (regs.cc & FLAG_Z) >> 2; \
102 flagV = (regs.cc & FLAG_V) >> 1; \
103 flagC = (regs.cc & FLAG_C)
105 // Private global variables
107 static V63701REGS regs;
109 static V63701REGS * regsPointer;
110 //V63701REGS * regsPointer;
111 static uint8_t flagH, flagI, flagN, flagZ, flagV, flagC;
113 static uint8_t CPUCycles[256] = {
114 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
115 1, 1, 0, 0, 0, 0, 1, 1, 2, 2, 4, 1, 0, 0, 0, 0,
116 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
117 1, 1, 3, 3, 1, 1, 4, 4, 4, 5, 1, 10, 5, 7, 9, 12,
118 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1,
119 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1,
120 6, 7, 7, 6, 6, 7, 6, 6, 6, 6, 6, 5, 6, 4, 3, 5,
121 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 4, 3, 5,
122 2, 2, 2, 3, 2, 2, 2, 0, 2, 2, 2, 2, 3, 5, 3, 0,
123 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4,
124 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
125 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 5, 5,
126 2, 2, 2, 3, 2, 2, 2, 0, 2, 2, 2, 2, 3, 0, 3, 0,
127 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
128 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
129 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5
132 // Private function prototypes
134 static uint16_t RdMemW(uint16_t);
135 static uint16_t FetchMemW(uint16_t);
136 static inline void HandleInterrupt(uint16_t, uint16_t flag = 0);
139 // Read a word out of 63701 memory (little endian format)
141 static inline uint16_t RdMemW(uint16_t address)
143 return (uint16_t)(regs.RdMem(address) << 8) | regs.RdMem(address + 1);
147 // Fetch a word out of 63701 memory (little endian format). Increments PC
149 static inline uint16_t FetchMemW(uint16_t address)
152 return (uint16_t)(regs.RdMem(address) << 8) | regs.RdMem(address + 1);
156 // 63701 OPCODE IMPLEMENTATION
158 // NOTE: Lots of macros are used here to save a LOT of typing. Also
159 // helps speed the debugging process. :-) Because of this, combining
160 // certain lines may look like a good idea but would end in disaster.
161 // You have been warned! ;-)
165 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
166 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
167 Add |ADDA |8B 2 2|9B 3 2|AB 5 2|BB 4 3| |A=A+M |T TTTT|
168 |ADDB |CB 2 2|DB 3 2|EB 5 2|FB 4 3| |B=B+M |T TTTT|
169 Add Accumulators |ABA | | | | |1B 2 1|A=A+B |T TTTT|
174 #define OP_ADD_HANDLER(m, acc) \
175 uint16_t sum = (uint16_t)(acc) + (m); \
177 flagH = (sum >> 4) & 0x01; \
178 SET_V(m, acc, sum); \
179 (acc) = sum & 0xFF; \
182 #define OP_ADD_HANDLER16(m, acc) \
183 uint32_t sum = (uint32_t)(acc) + (m); \
185 SET_V16(m, acc, sum); \
186 (acc) = sum & 0xFFFF; \
190 static void Op8B(void) // ADDA #
192 uint16_t m = READ_IMM;
193 OP_ADD_HANDLER(m, regs.d.acc.a);
196 static void Op9B(void) // ADDA ZP
198 uint16_t m = READ_ZP;
199 OP_ADD_HANDLER(m, regs.d.acc.a);
202 static void OpAB(void) // ADDA ZP, X
204 uint16_t m = READ_ZP_X;
205 OP_ADD_HANDLER(m, regs.d.acc.a);
208 static void OpBB(void) // ADDA ABS
210 uint16_t m = READ_ABS;
211 OP_ADD_HANDLER(m, regs.d.acc.a);
214 static void OpCB(void) // ADDB #
216 uint16_t m = READ_IMM;
217 OP_ADD_HANDLER(m, regs.d.acc.b);
220 static void OpDB(void) // ADDB ZP
222 uint16_t m = READ_ZP;
223 OP_ADD_HANDLER(m, regs.d.acc.b);
226 static void OpEB(void) // ADDB ZP, X
228 uint16_t m = READ_ZP_X;
229 OP_ADD_HANDLER(m, regs.d.acc.b);
232 static void OpFB(void) // ADDB ABS
234 uint16_t m = READ_ABS;
235 OP_ADD_HANDLER(m, regs.d.acc.b);
238 static void Op1B(void) // ABA
240 OP_ADD_HANDLER(regs.d.acc.b, regs.d.acc.a);
243 static void Op3A(void) // ABX
245 // Seems this one does *not* affect any flags...
246 regs.x += (uint16_t)regs.d.acc.b;
249 static void OpC3(void) // ADDD #
251 uint16_t m = READ_IMM16;
252 OP_ADD_HANDLER16(m, regs.d.word);
255 static void OpD3(void) // ADDD ZP
257 uint16_t m = READ_ZP16;
258 OP_ADD_HANDLER16(m, regs.d.word);
261 static void OpE3(void) // ADDD ZP, X
263 uint16_t m = READ_ZP_X16;
264 OP_ADD_HANDLER16(m, regs.d.word);
267 static void OpF3(void) // ADDD ABS
269 uint16_t m = READ_ABS16;
270 OP_ADD_HANDLER16(m, regs.d.word);
274 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
275 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
276 Add with Carry |ADCA |89 2 2|99 3 2|A9 5 2|B9 4 3| |A=A+M+C |T TTTT|
277 |ADCB |C9 2 2|D9 3 2|E9 5 2|F9 4 3| |B=B+M+C |T TTTT|
282 #define OP_ADC_HANDLER(m, acc) \
283 uint16_t sum = (uint16_t)acc + (m) + (uint16_t)flagC; \
285 flagH = (sum >> 4) & 0x01; \
286 SET_V(m, acc, sum); \
290 static void Op89(void) // ADCA #
292 uint16_t m = READ_IMM;
293 OP_ADC_HANDLER(m, regs.d.acc.a);
296 static void Op99(void) // ADCA ZP
298 uint16_t m = READ_ZP;
299 OP_ADC_HANDLER(m, regs.d.acc.a);
302 static void OpA9(void) // ADCA ZP, X
304 uint16_t m = READ_ZP_X;
305 OP_ADC_HANDLER(m, regs.d.acc.a);
308 static void OpB9(void) // ADCA ABS
310 uint16_t m = READ_ABS;
311 OP_ADC_HANDLER(m, regs.d.acc.a);
314 static void OpC9(void) // ADCB #
316 uint16_t m = READ_IMM;
317 OP_ADC_HANDLER(m, regs.d.acc.b);
320 static void OpD9(void) // ADCB ZP
322 uint16_t m = READ_ZP;
323 OP_ADC_HANDLER(m, regs.d.acc.b);
326 static void OpE9(void) // ADCB ZP, X
328 uint16_t m = READ_ZP_X;
329 OP_ADC_HANDLER(m, regs.d.acc.b);
332 static void OpF9(void) // ADCB ABS
334 uint16_t m = READ_ABS;
335 OP_ADC_HANDLER(m, regs.d.acc.b);
339 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
340 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
341 And |ANDA |84 2 2|94 3 2|A4 5 2|B4 4 3| |A=A+M | TTR |
342 |ANDB |C4 2 2|D4 3 2|E4 5 2|F4 4 3| |B=B+M | TTR |
347 #define OP_AND_HANDLER(m, acc) \
352 static void Op84(void) // ANDA #
354 uint8_t m = READ_IMM;
355 OP_AND_HANDLER(m, regs.d.acc.a);
358 static void Op94(void) // ANDA ZP
361 OP_AND_HANDLER(m, regs.d.acc.a);
364 static void OpA4(void) // ANDA ZP, X
366 uint16_t m = READ_ZP_X;
367 OP_AND_HANDLER(m, regs.d.acc.a);
370 static void OpB4(void) // ANDA ABS
372 uint16_t m = READ_ABS;
373 OP_AND_HANDLER(m, regs.d.acc.a);
376 static void OpC4(void) // ANDB #
378 uint8_t m = READ_IMM;
379 OP_AND_HANDLER(m, regs.d.acc.b);
382 static void OpD4(void) // ANDB ZP
385 OP_AND_HANDLER(m, regs.d.acc.b);
388 static void OpE4(void) // ANDB ZP, X
390 uint16_t m = READ_ZP_X;
391 OP_AND_HANDLER(m, regs.d.acc.b);
394 static void OpF4(void) // ANDB ABS
396 uint16_t m = READ_ABS;
397 OP_AND_HANDLER(m, regs.d.acc.b);
400 static void Op61(void) // AIM ZP, X (AND immediate with index)
403 uint8_t immValue = READ_IMM;
405 OP_AND_HANDLER(immValue, m);
409 static void Op71(void) // AIM ZP (AND immediate with zero page)
412 uint8_t immValue = READ_IMM;
414 OP_AND_HANDLER(immValue, m);
419 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
420 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
421 Bit Test |BITA |85 2 2|95 3 2|A5 5 2|B5 4 3| |A+M | TTR |
422 |BITB |C5 2 2|D5 3 2|E5 5 2|F5 4 3| |B+M | TTR |
427 #define OP_BIT_HANDLER(m, acc) \
428 int8_t result = acc & (m); \
431 static void Op85(void) // BITA #
433 uint8_t m = READ_IMM;
434 OP_BIT_HANDLER(m, regs.d.acc.a);
437 static void Op95(void) // BITA ZP
440 OP_BIT_HANDLER(m, regs.d.acc.a);
443 static void OpA5(void) // BITA ZP, X
445 uint8_t m = READ_ZP_X;
446 OP_BIT_HANDLER(m, regs.d.acc.a);
449 static void OpB5(void) // BITA ABS
451 uint8_t m = READ_ABS;
452 OP_BIT_HANDLER(m, regs.d.acc.a);
455 static void OpC5(void) // BITB #
457 uint8_t m = READ_IMM;
458 OP_BIT_HANDLER(m, regs.d.acc.b);
461 static void OpD5(void) // BITB ZP
464 OP_BIT_HANDLER(m, regs.d.acc.b);
467 static void OpE5(void) // BITB ZP, X
469 uint8_t m = READ_ZP_X;
470 OP_BIT_HANDLER(m, regs.d.acc.b);
473 static void OpF5(void) // BITB ABS
475 uint8_t m = READ_ABS;
476 OP_BIT_HANDLER(m, regs.d.acc.b);
480 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
481 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
482 Clear |CLR | | |6F 7 2|7F 6 3| |M=00 | RSRR|
483 |CLRA | | | | |4F 2 1|A=00 | RSRR|
484 |CLRB | | | | |5F 2 1|B=00 | RSRR|
489 static void Op6F(void) // CLR ZP, X
491 regs.WrMem(EA_ZP_X, 0);
496 static void Op7F(void) // CLR ABS
498 regs.WrMem(EA_ABS, 0);
503 static void Op4F(void) // CLRA
510 static void Op5F(void) // CLRB
518 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
519 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
520 Compare |CMPA |81 2 2|91 3 2|A1 5 2|B1 4 3| |A-M | TTTT|
521 |CMPB |C1 2 2|D1 3 2|E1 5 2|F1 4 3| |B-M | TTTT|
522 Compare Accumulators |CBA | | | | |11 2 1|A-B | TTTT|
528 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.
531 #define OP_CMP_HANDLER(m, acc) \
532 uint16_t result = acc - (m); \
533 SET_ZNVC_CMP(m, acc, result)
535 static void Op81(void) // CMPA #
537 uint8_t m = READ_IMM;
538 OP_CMP_HANDLER(m, regs.d.acc.a);
541 static void Op91(void) // CMPA ZP
544 OP_CMP_HANDLER(m, regs.d.acc.a);
547 static void OpA1(void) // CMPA ZP, X
549 uint8_t m = READ_ZP_X;
550 OP_CMP_HANDLER(m, regs.d.acc.a);
553 static void OpB1(void) // CMPA ABS
555 uint8_t m = READ_ABS;
556 OP_CMP_HANDLER(m, regs.d.acc.a);
559 static void OpC1(void) // CMPB #
561 uint8_t m = READ_IMM;
562 OP_CMP_HANDLER(m, regs.d.acc.b);
565 static void OpD1(void) // CMPB ZP
568 OP_CMP_HANDLER(m, regs.d.acc.b);
571 static void OpE1(void) // CMPB ZP, X
573 uint8_t m = READ_ZP_X;
574 OP_CMP_HANDLER(m, regs.d.acc.b);
577 static void OpF1(void) // CMPB ABS
579 uint8_t m = READ_ABS;
580 OP_CMP_HANDLER(m, regs.d.acc.b);
583 static void Op11(void) // CBA
585 OP_CMP_HANDLER(regs.d.acc.b, regs.d.acc.a);
589 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
590 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
591 Complement 1's |COM | | |63 7 2|73 6 3| |M=-M | TTRS|
592 |COMA | | | | |43 2 1|A=-A | TTRS|
593 |COMB | | | | |53 2 1|B=-B | TTRS|
598 #define OP_COM_HANDLER(m) \
604 static void Op63(void) // COM ZP, X
612 static void Op73(void) // COM ABS
620 static void Op43(void) // COMA
622 OP_COM_HANDLER(regs.d.acc.a);
625 static void Op53(void) // COMB
627 OP_COM_HANDLER(regs.d.acc.b);
631 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
632 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
633 Complement 2's |NEG | | |60 7 2|70 6 3| |M=00-M | TT12|
634 |NEGA | | | | |40 2 1|A=00-A | TT12|
635 |NEGB | | | | |50 2 1|B=00-B | TT12|
640 #define OP_NEG_HANDLER(m) \
643 flagV = (m == 0x80 ? 1 : 0); \
644 flagC = (m == 0x00 ? 1 : 0)
646 static void Op60(void) // NEG ZP, X
654 static void Op70(void) // NEG ABS
662 static void Op40(void) // NEGA
664 OP_NEG_HANDLER(regs.d.acc.a);
667 static void Op50(void) // NEGB
669 OP_NEG_HANDLER(regs.d.acc.b);
673 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
674 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
675 Decimal Adjust |DAA | | | | |19 2 1|* | TTT3|
678 static void Op19(void) // DAA
680 uint16_t result = (uint16_t)regs.d.acc.a;
682 if ((regs.d.acc.a & 0x0F) > 0x09 || flagH)
685 if ((regs.d.acc.a & 0xF0) > 0x90 || flagC || ((regs.d.acc.a & 0xF0) > 0x80 && (regs.d.acc.a & 0x0F) > 0x09))
688 regs.d.acc.a = (uint8_t)result;
690 CLR_V; // Not sure this is correct...
691 flagC |= (result & 0x100) >> 8; // Overwrite carry if it was 0, otherwise, ignore
695 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
696 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
697 Decrement |DEC | | |6A 7 2|7A 6 3| |M=M-1 | TT4 |
698 |DECA | | | | |4A 2 1|A=A-1 | TT4 |
699 |DECB | | | | |5A 2 1|B=B-1 | TT4 |
704 #define OP_DEC_HANDLER(m) \
707 flagV = (m == 0x7F ? 1 : 0)
709 static void Op6A(void) // DEC ZP, X
717 static void Op7A(void) // DEC ABS
725 static void Op4A(void) // DECA
727 OP_DEC_HANDLER(regs.d.acc.a);
730 static void Op5A(void) // DECB
732 OP_DEC_HANDLER(regs.d.acc.b);
736 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
737 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
738 Exclusive OR |EORA |88 2 2|98 3 2|A8 5 2|B8 4 3| |A=A(+)M | TTR |
739 |EORB |C8 2 2|D8 3 2|E8 5 2|F8 4 3| |B=B(+)M | TTR |
744 #define OP_EOR_HANDLER(m, acc) \
749 static void Op88(void) // EORA #
751 uint8_t m = READ_IMM;
752 OP_EOR_HANDLER(m, regs.d.acc.a);
755 static void Op98(void) // EORA ZP
758 OP_EOR_HANDLER(m, regs.d.acc.a);
761 static void OpA8(void) // EORA ZP, X
763 uint8_t m = READ_ZP_X;
764 OP_EOR_HANDLER(m, regs.d.acc.a);
767 static void OpB8(void) // EORA ABS
769 uint8_t m = READ_ABS;
770 OP_EOR_HANDLER(m, regs.d.acc.a);
773 static void OpC8(void) // EORB #
775 uint8_t m = READ_IMM;
776 OP_EOR_HANDLER(m, regs.d.acc.b);
779 static void OpD8(void) // EORB ZP
782 OP_EOR_HANDLER(m, regs.d.acc.b);
785 static void OpE8(void) // EORB ZP, X
787 uint8_t m = READ_ZP_X;
788 OP_EOR_HANDLER(m, regs.d.acc.b);
791 static void OpF8(void) // EORB ABS
793 uint8_t m = READ_ABS;
794 OP_EOR_HANDLER(m, regs.d.acc.b);
797 static void Op65(void) // EIM ZP, X (EOR immediate with index)
800 uint8_t immValue = READ_IMM;
802 OP_EOR_HANDLER(immValue, m);
806 static void Op75(void) // EIM ZP (EOR immediate with zero page)
809 uint8_t immValue = READ_IMM;
811 OP_EOR_HANDLER(immValue, m);
816 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
817 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
818 Increment |INC | | |6C 7 2|7C 6 3| |M=M+1 | TT5 |
819 |INCA | | | | |4C 2 1|A=A+1 | TT5 |
820 |INCB | | | | |5C 2 1|B=B+1 | TT5 |
825 #define OP_INC_HANDLER(m) \
828 flagV = (m == 0x80 ? 1 : 0)
830 static void Op6C(void) // INC ZP, X
838 static void Op7C(void) // INC ABS
846 static void Op4C(void) // INCA
848 OP_INC_HANDLER(regs.d.acc.a);
851 static void Op5C(void) // INCB
853 OP_INC_HANDLER(regs.d.acc.b);
857 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
858 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
859 Load Accumulator |LDAA |86 2 2|96 3 2|A6 5 2|B6 4 3| |A=M | TTR |
860 |LDAB |C6 2 2|D6 3 2|E6 5 2|F6 4 3| |B=M | TTR |
865 #define OP_LDA_HANDLER(m, acc) \
870 static void Op86(void) // LDAA #
872 uint8_t m = READ_IMM;
873 OP_LDA_HANDLER(m, regs.d.acc.a);
876 static void Op96(void) // LDAA ZP
879 OP_LDA_HANDLER(m, regs.d.acc.a);
882 static void OpA6(void) // LDAA ZP, X
884 uint8_t m = READ_ZP_X;
885 OP_LDA_HANDLER(m, regs.d.acc.a);
888 static void OpB6(void) // LDAA ABS
890 uint8_t m = READ_ABS;
891 OP_LDA_HANDLER(m, regs.d.acc.a);
894 static void OpC6(void) // LDAB #
896 uint8_t m = READ_IMM;
897 OP_LDA_HANDLER(m, regs.d.acc.b);
900 static void OpD6(void) // LDAB ZP
903 OP_LDA_HANDLER(m, regs.d.acc.b);
906 static void OpE6(void) // LDAB ZP, X
908 uint8_t m = READ_ZP_X;
909 OP_LDA_HANDLER(m, regs.d.acc.b);
912 static void OpF6(void) // LDAB ABS
914 uint8_t m = READ_ABS;
915 OP_LDA_HANDLER(m, regs.d.acc.b);
919 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
920 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
921 OR, Inclusive |ORAA |8A 2 2|9A 3 2|AA 5 2|BA 4 3| |A=A+M | TTR |
922 |ORAB |CA 2 2|DA 3 2|EA 5 2|FA 4 3| |B=B+M | TTR |
927 #define OP_ORA_HANDLER(m, acc) \
932 static void Op8A(void) // ORAA #
934 uint8_t m = READ_IMM;
935 OP_ORA_HANDLER(m, regs.d.acc.a);
938 static void Op9A(void) // ORAA ZP
941 OP_ORA_HANDLER(m, regs.d.acc.a);
944 static void OpAA(void) // ORAA ZP, X
946 uint8_t m = READ_ZP_X;
947 OP_ORA_HANDLER(m, regs.d.acc.a);
950 static void OpBA(void) // ORAA ABS
952 uint8_t m = READ_ABS;
953 OP_ORA_HANDLER(m, regs.d.acc.a);
956 static void OpCA(void) // ORAB #
958 uint8_t m = READ_IMM;
959 OP_ORA_HANDLER(m, regs.d.acc.b);
962 static void OpDA(void) // ORAB ZP
965 OP_ORA_HANDLER(m, regs.d.acc.b);
968 static void OpEA(void) // ORAB ZP, X
970 uint8_t m = READ_ZP_X;
971 OP_ORA_HANDLER(m, regs.d.acc.b);
974 static void OpFA(void) // ORAB ABS
976 uint8_t m = READ_ABS;
977 OP_ORA_HANDLER(m, regs.d.acc.b);
980 static void Op62(void) // OIM ZP, X (ORA immediate with index)
983 uint8_t immValue = READ_IMM;
985 OP_ORA_HANDLER(immValue, m);
989 static void Op72(void) // OIM ZP (ORA immediate with zero page)
992 uint8_t immValue = READ_IMM;
994 OP_ORA_HANDLER(immValue, m);
999 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1000 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1001 Push Data |PSHA | | | | |36 4 1|Msp=A, *- | |
1002 |PSHB | | | | |37 4 1|Msp=B, *- | |
1003 Pull Data |PULA | | | | |32 4 1|A=Msp, *+ | |
1004 |PULB | | | | |33 4 1|B=Msp, *+ | |
1007 static void Op36(void) // PSHA
1012 static void Op37(void) // PSHB
1017 static void Op32(void) // PULA
1019 regs.d.acc.a = PULL;
1022 static void Op33(void) // PULB
1024 regs.d.acc.b = PULL;
1027 static void Op38(void) // PULX
1032 static void Op3C(void) // PSHX
1038 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1039 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1040 Rotate Left |ROL | | |69 7 2|79 6 3| |Memory *1| TT6T|
1041 |ROLA | | | | |49 2 1|Accum A *1| TT6T|
1042 |ROLB | | | | |59 2 1|Accum B *1| TT6T|
1047 #define OP_ROL_HANDLER(m) \
1048 uint8_t newCarry = (m & 0x80) >> 7; \
1049 m = (m << 1) | flagC; \
1052 flagV = flagN ^ flagC
1054 static void Op69(void) // ROL ZP, X
1062 static void Op79(void) // ROL ABS
1070 static void Op49(void) // ROLA
1072 OP_ROL_HANDLER(regs.d.acc.a);
1075 static void Op59(void) // ROLB
1077 OP_ROL_HANDLER(regs.d.acc.b);
1081 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1082 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1083 Rotate Right |ROR | | |66 7 2|76 6 3| |Memory *2| TT6T|
1084 |RORA | | | | |46 2 1|Accum A *2| TT6T|
1085 |RORB | | | | |56 2 1|Accum B *2| TT6T|
1090 #define OP_ROR_HANDLER(m) \
1091 uint8_t newCarry = m & 0x01; \
1092 m = (m >> 1) | (flagC << 7); \
1095 flagV = flagN ^ flagC
1097 static void Op66(void) // ROR ZP, X
1105 static void Op76(void) // ROR ABS
1113 static void Op46(void) // RORA
1115 OP_ROR_HANDLER(regs.d.acc.a);
1118 static void Op56(void) // RORB
1120 OP_ROR_HANDLER(regs.d.acc.b);
1124 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1125 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1126 Arithmetic Shift Left |ASL | | |68 7 2|78 6 3| |Memory *3| TT6T|
1127 |ASLA | | | | |48 2 1|Accum A *3| TT6T|
1128 |ASLB | | | | |58 2 1|Accum B *3| TT6T|
1133 #define OP_ASL_HANDLER(m) \
1134 uint8_t newCarry = (m & 0x80) >> 7; \
1138 flagV = flagN ^ flagC
1140 static void Op68(void) // ASL ZP, X
1148 static void Op78(void) // ASL ABS
1156 static void Op48(void) // ASLA
1158 OP_ASL_HANDLER(regs.d.acc.a);
1161 static void Op58(void) // ASLB
1163 OP_ASL_HANDLER(regs.d.acc.b);
1166 static void Op05(void) // ASLD
1168 uint8_t newCarry = (regs.d.word & 0x8000) >> 15;
1171 SET_N16(regs.d.word);
1173 flagV = flagN ^ flagC;
1177 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1178 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1179 Arithmetic Shift Right |ASR | | |67 7 2|77 6 3| |Memory *4| TT6T|
1180 |ASRA | | | | |47 2 1|Accum A *4| TT6T|
1181 |ASRB | | | | |57 2 1|Accum B *4| TT6T|
1186 #define OP_ASR_HANDLER(m) \
1187 uint8_t newCarry = m & 0x01; \
1188 m = (m >> 1) | (m & 0x80); \
1191 flagV = flagN ^ flagC
1193 static void Op67(void) // ASR ZP, X
1201 static void Op77(void) // ASR ABS
1209 static void Op47(void) // ASRA
1211 OP_ASR_HANDLER(regs.d.acc.a);
1214 static void Op57(void) // ASRB
1216 OP_ASR_HANDLER(regs.d.acc.b);
1220 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1221 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1222 Logic Shift Right |LSR | | |64 7 2|74 6 3| |Memory *5| TT6T|
1223 |LSRA | | | | |44 2 1|Accum A *5| TT6T|
1224 |LSRB | | | | |54 2 1|Accum B *5| TT6T|
1229 #define OP_LSR_HANDLER(m) \
1230 uint8_t newCarry = m & 0x01; \
1234 flagV = flagN ^ flagC
1236 static void Op64(void) // LSR ZP, X
1244 static void Op74(void) // LSR ABS
1252 static void Op44(void) // LSRA
1254 OP_LSR_HANDLER(regs.d.acc.a);
1257 static void Op54(void) // LSRB
1259 OP_LSR_HANDLER(regs.d.acc.b);
1262 static void Op04(void) // LSRD
1264 uint8_t newCarry = regs.d.word & 0x01;
1269 flagV = flagN ^ flagC;
1273 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1274 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1275 Store Accumulator |STAA | |97 4 2|A7 6 2|B7 5 3| |M=A | TTR |
1276 |STAB | |D7 4 2|E7 6 2|F7 5 3| |M=B | TTR |
1279 static void Op97(void) // STAA ZP
1281 regs.WrMem(EA_ZP, regs.d.acc.a);
1284 static void OpA7(void) // STAA ZP, X
1286 regs.WrMem(EA_ZP_X, regs.d.acc.a);
1289 static void OpB7(void) // STAA ABS
1291 regs.WrMem(EA_ABS, regs.d.acc.a);
1294 static void OpD7(void) // STAB ZP
1296 regs.WrMem(EA_ZP, regs.d.acc.b);
1299 static void OpE7(void) // STAB ZP, X
1301 regs.WrMem(EA_ZP_X, regs.d.acc.b);
1304 static void OpF7(void) // STAB ABS
1306 regs.WrMem(EA_ABS, regs.d.acc.b);
1309 // These are illegal instructions!
1311 static void Op87(void) // STA #
1313 // What does this even mean? Seems the M.A.M.E. guys think it's something
1315 uint16_t effectiveAddress = regs.pc;
1317 regs.WrMem(effectiveAddress, regs.d.acc.a);
1318 SET_ZN(regs.d.acc.a);
1320 // So, basically, what this does is change the immediate value in the
1321 // STA #. Seems like a completely useless thing to me.
1325 static void OpC7(void) // STB #
1327 uint16_t effectiveAddress = regs.pc;
1329 regs.WrMem(effectiveAddress, regs.d.acc.b);
1330 SET_ZN(regs.d.acc.b);
1336 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1337 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1338 Subtract |SUBA |80 2 2|90 3 2|A0 5 2|B0 4 3| |A=A-M | TTTT|
1339 |SUBB |C0 2 2|D0 3 2|E0 5 2|F0 4 3| |B=B-M | TTTT|
1340 Subtract Accumulators |SBA | | | | |10 2 1|A=A-B | TTTT|
1345 #define OP_SUB_HANDLER(m, acc) \
1346 uint16_t sum = (uint16_t)acc - (m); \
1347 flagC = sum >> 15; \
1348 SET_V(m, acc, sum); \
1349 acc = (uint8_t)sum; \
1352 #define OP_SUB_HANDLER16(m, acc) \
1353 uint32_t sum = (uint32_t)acc - (m); \
1354 flagC = sum >> 31; \
1355 SET_V16(m, acc, sum); \
1356 acc = (uint16_t)sum; \
1360 static void Op80(void) // SUBA #
1362 uint16_t m = READ_IMM;
1363 OP_SUB_HANDLER(m, regs.d.acc.a);
1366 static void Op90(void) // SUBA ZP
1368 uint16_t m = READ_ZP;
1369 OP_SUB_HANDLER(m, regs.d.acc.a);
1372 static void OpA0(void) // SUBA ZP, X
1374 uint16_t m = READ_ZP_X;
1375 OP_SUB_HANDLER(m, regs.d.acc.a);
1378 static void OpB0(void) // SUBA ABS
1380 uint16_t m = READ_ABS;
1381 OP_SUB_HANDLER(m, regs.d.acc.a);
1384 static void OpC0(void) // SUBB #
1386 uint16_t m = READ_IMM;
1387 OP_SUB_HANDLER(m, regs.d.acc.b);
1390 static void OpD0(void) // SUBB ZP
1392 uint16_t m = READ_ZP;
1393 OP_SUB_HANDLER(m, regs.d.acc.b);
1396 static void OpE0(void) // SUBB ZP, X
1398 uint16_t m = READ_ZP_X;
1399 OP_SUB_HANDLER(m, regs.d.acc.b);
1402 static void OpF0(void) // SUBB ABS
1404 uint16_t m = READ_ABS;
1405 OP_SUB_HANDLER(m, regs.d.acc.b);
1408 static void Op10(void) // SBA
1410 OP_SUB_HANDLER(regs.d.acc.b, regs.d.acc.a);
1413 static void Op83(void) // SUBD #
1415 uint16_t m = READ_IMM16;
1416 OP_SUB_HANDLER16(m, regs.d.word);
1419 static void Op93(void) // SUBD ZP
1421 uint16_t m = READ_ZP16;
1422 OP_SUB_HANDLER16(m, regs.d.word);
1425 static void OpA3(void) // SUBD ZP, X
1427 uint16_t m = READ_ZP_X16;
1428 OP_SUB_HANDLER16(m, regs.d.word);
1431 static void OpB3(void) // SUBD ABS
1433 uint16_t m = READ_ABS16;
1434 OP_SUB_HANDLER16(m, regs.d.word);
1438 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1439 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1440 Subtract with Carry |SBCA |82 2 2|92 3 2|A2 5 2|B2 4 3| |A=A-M-C | TTTT|
1441 |SBCB |C2 2 2|D2 3 2|E2 5 2|F2 4 3| |B=B-M-C | TTTT|
1446 #define OP_SBC_HANDLER(m, acc) \
1447 uint16_t sum = (uint16_t)acc - (m) - (uint16_t)flagC; \
1448 flagC = sum >> 15; \
1449 SET_V(m, acc, sum); \
1450 acc = (uint8_t)sum; \
1453 static void Op82(void) // SBCA #
1455 uint16_t m = READ_IMM;
1456 OP_SBC_HANDLER(m, regs.d.acc.a);
1459 static void Op92(void) // SBCA ZP
1461 uint16_t m = READ_ZP;
1462 OP_SBC_HANDLER(m, regs.d.acc.a);
1465 static void OpA2(void) // SBCA ZP, X
1467 uint16_t m = READ_ZP_X;
1468 OP_SBC_HANDLER(m, regs.d.acc.a);
1471 static void OpB2(void) // SBCA ABS
1473 uint16_t m = READ_ABS;
1474 OP_SBC_HANDLER(m, regs.d.acc.a);
1477 static void OpC2(void) // SBCB #
1479 uint16_t m = READ_IMM;
1480 OP_SBC_HANDLER(m, regs.d.acc.b);
1483 static void OpD2(void) // SBCB ZP
1485 uint16_t m = READ_ZP;
1486 OP_SBC_HANDLER(m, regs.d.acc.b);
1489 static void OpE2(void) // SBCB ZP, X
1491 uint16_t m = READ_ZP_X;
1492 OP_SBC_HANDLER(m, regs.d.acc.b);
1495 static void OpF2(void) // SBCB ABS
1497 uint16_t m = READ_ABS;
1498 OP_SBC_HANDLER(m, regs.d.acc.b);
1502 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1503 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1504 Transfer Accumulators |TAB | | | | |16 2 1|B=A | TTR |
1505 |TBA | | | | |17 2 1|A=B | TTR |
1508 static void Op16(void) // TAB
1510 regs.d.acc.b = regs.d.acc.a;
1511 SET_ZN(regs.d.acc.b);
1515 static void Op17(void) // TBA
1517 regs.d.acc.a = regs.d.acc.b;
1518 SET_ZN(regs.d.acc.a);
1523 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1524 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1525 Test, Zero/Minus |TST | | |6D 7 2|7D 6 3| |M-00 | TTRR|
1526 |TSTA | | | | |4D 2 1|A-00 | TTRR|
1527 |TSTB | | | | |5D 2 1|B-00 | TTRR|
1532 #define OP_TST_HANDLER(m) \
1533 uint8_t result = m; \
1537 #define OP_TST_IMM_HANDLER(m, acc) \
1538 uint8_t result = m & acc; \
1542 static void Op6D(void) // TST ZP, X
1550 OP_TST_HANDLER(READ_ZP_X);
1554 static void Op7D(void) // TST ABS
1562 OP_TST_HANDLER(READ_ABS);
1566 static void Op4D(void) // TSTA
1568 OP_TST_HANDLER(regs.d.acc.a);
1571 static void Op5D(void) // TSTB
1573 OP_TST_HANDLER(regs.d.acc.b);
1576 static void Op6B(void) // TIM ZP, X (TST immediate with index)
1579 uint8_t immValue = READ_IMM;
1581 OP_TST_IMM_HANDLER(immValue, READ_ZP_X);
1585 static void Op7B(void) // TIM ZP (TST immediate with zero page)
1588 uint8_t immValue = READ_IMM;
1590 OP_TST_IMM_HANDLER(immValue, READ_ZP);
1595 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1596 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1597 Compare Index Register |CPX |8C 3 3|9C 4 2|AC 6 2|BC 5 3| |Formula 1 | 7T8 |
1603 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.
1606 #define OP_CPX_HANDLER(m) \
1607 uint32_t result = regs.x - (m); \
1608 SET_ZNVC_CMP16(m, regs.x, result)
1610 static void Op8C(void) // CPX #
1612 uint16_t m = READ_IMM16;
1616 static void Op9C(void) // CPX ZP
1618 uint16_t m = READ_ZP16;
1622 static void OpAC(void) // CPX ZP, X
1624 uint16_t m = READ_ZP_X16;
1628 static void OpBC(void) // CPX ABS
1630 uint16_t m = READ_ABS16;
1635 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1636 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1637 Decrement Index Register|DEX | | | | |09 4 1|X=X-1 | T |
1638 Dec Stack Pointer |DES | | | | |34 4 1|SP=SP-1 | |
1639 Inc Index Regster |INX | | | | |08 4 1|X=X+1 | T |
1640 Inc Stack Pointer |INS | | | | |31 4 1|SP=SP+1 | |
1643 static void Op09(void) // DEX
1649 static void Op34(void) // DES
1654 static void Op08(void) // INX
1660 static void Op31(void) // INS
1666 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1667 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1668 Load Index Register |LDX |CE 3 3|DE 4 2|EE 6 2|FE 5 3| |Formula 2 | 9TR |
1669 Load Stack Pointer |LDS |8E 3 3|9E 4 2|AE 6 2|BE 5 3| |Formula 3 | 9TR |
1672 // LD* opcode handler
1674 #define OP_LD_HANDLER(acc) \
1679 static void OpCE(void) // LDX #
1681 regs.x = READ_IMM16;
1682 OP_LD_HANDLER(regs.x);
1685 static void OpDE(void) // LDX ZP
1688 OP_LD_HANDLER(regs.x);
1691 static void OpEE(void) // LDX ZP, X
1693 regs.x = READ_ZP_X16;
1694 OP_LD_HANDLER(regs.x);
1697 static void OpFE(void) // LDX ABS
1699 regs.x = READ_ABS16;
1700 OP_LD_HANDLER(regs.x);
1703 static void Op8E(void) // LDS #
1705 regs.s = READ_IMM16;
1706 OP_LD_HANDLER(regs.s);
1709 static void Op9E(void) // LDS ZP
1712 OP_LD_HANDLER(regs.s);
1715 static void OpAE(void) // LDS ZP, X
1717 regs.s = READ_ZP_X16;
1718 OP_LD_HANDLER(regs.s);
1721 static void OpBE(void) // LDS ABS
1723 regs.s = READ_ABS16;
1724 OP_LD_HANDLER(regs.s);
1727 static void OpCC(void) // LDD #
1729 regs.d.word = READ_IMM16;
1730 OP_LD_HANDLER(regs.d.word);
1733 static void OpDC(void) // LDD ZP
1735 regs.d.word = READ_ZP16;
1736 OP_LD_HANDLER(regs.d.word);
1739 static void OpEC(void) // LDD ZP, X
1741 regs.d.word = READ_ZP_X16;
1742 OP_LD_HANDLER(regs.d.word);
1745 static void OpFC(void) // LDD ABS
1747 regs.d.word = READ_ABS16;
1748 OP_LD_HANDLER(regs.d.word);
1752 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1753 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1754 Store Index Register |STX | |DF 5 2|EF 7 2|FF 6 3| |Formula 4 | 9TR |
1755 Store Stack Pointer |STS | |9F 5 2|AF 7 2|BF 6 3| |Formula 5 | 9TR |
1758 // ST* opcode handler
1760 #define OP_ST_HANDLER(m, acc) \
1761 regs.WrMem(m + 0, acc >> 8); \
1762 regs.WrMem(m + 1, acc & 0xFF); \
1767 static void OpDF(void) // STX ZP
1770 OP_ST_HANDLER(m, regs.x);
1773 static void OpEF(void) // STX ZP, X
1775 uint16_t m = EA_ZP_X;
1776 OP_ST_HANDLER(m, regs.x);
1779 static void OpFF(void) // STX ABS
1781 uint16_t m = EA_ABS;
1782 OP_ST_HANDLER(m, regs.x);
1785 static void Op9F(void) // STS ZP
1788 OP_ST_HANDLER(m, regs.s);
1791 static void OpAF(void) // STS ZP, X
1793 uint16_t m = EA_ZP_X;
1794 OP_ST_HANDLER(m, regs.s);
1797 static void OpBF(void) // STS ABS
1799 uint16_t m = EA_ABS;
1800 OP_ST_HANDLER(m, regs.s);
1803 // These are illegal instructions!
1805 // Store immediate--nonsensical opcodes :-P
1806 static void Op8F(void) // STS #
1808 uint16_t effectiveAddress = regs.pc;
1810 OP_ST_HANDLER(effectiveAddress, regs.s);
1813 static void OpCF(void) // STX #
1815 uint16_t effectiveAddress = regs.pc;
1817 OP_ST_HANDLER(effectiveAddress, regs.x);
1820 static void OpCD(void) // STD #
1822 uint16_t effectiveAddress = regs.pc;
1824 OP_ST_HANDLER(effectiveAddress, regs.d.word);
1828 static void OpDD(void) // STD ZP
1831 OP_ST_HANDLER(m, regs.d.word);
1834 static void OpED(void) // STD ZP, X
1836 uint16_t m = EA_ZP_X;
1837 OP_ST_HANDLER(m, regs.d.word);
1840 static void OpFD(void) // STD ABS
1842 uint16_t m = EA_ABS;
1843 OP_ST_HANDLER(m, regs.d.word);
1847 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1848 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1849 Index Reg > Stack Pnter |TXS | | | | |35 4 1|SP=X-1 | |
1850 Stack Ptr > Index Regtr |TSX | | | | |30 4 1|X=SP+1 | |
1853 static void Op35(void) // TXS
1855 regs.s = regs.x - 1;
1858 static void Op30(void) // TSX
1860 regs.x = regs.s + 1;
1864 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1865 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1866 Always |BRA | |20 4 2| | | |none | |
1867 Carry is Clear |BCC | |24 4 2| | | |C=0 | |
1868 Carry is Set |BCS | |25 4 2| | | |C=1 | |
1869 Equals Zero |BEQ | |27 4 2| | | |Z=1 | |
1870 Greater or Equal to Zero|BGE | |2C 4 2| | | |N(+)V=0 | |
1871 Greater than Zero |BGT | |2E 4 2| | | |Z+N(+)V=0 | |
1872 Higher |BHI | |22 4 2| | | |C+Z=0 | |
1873 Less or Equal than Zero |BLE | |2F 4 2| | | |Z+N(+)V=1 | |
1874 Lower or Same |BLS | |23 4 2| | | |C+Z=1 | |
1875 Less Than Zero |BLT | |2D 4 2| | | |N(+)V=1 | |
1876 Minus |BMI | |2B 4 2| | | |N=1 | |
1877 Not Zero |BNE | |26 4 2| | | |Z=0 | |
1878 Overflow Clear |BVC | |28 4 2| | | |V=0 | |
1879 Overflow Set |BVS | |29 4 2| | | |V=1 | |
1880 Plus |BPL | |2A 4 2| | | |N=0 | |
1883 static void Op20(void) // BRA
1885 int16_t m = (int16_t)(int8_t)READ_IMM;
1889 static void Op21(void) // BRN
1891 int16_t m = (int16_t)(int8_t)READ_IMM;
1895 static void Op24(void) // BCC
1897 // NOTE: We can optimize this by following the maxim: "Don't branch!" by
1898 // converting the boolean result into a multiplication. The only way to
1899 // know if this is a win is to do some profiling both with and without
1900 // the optimization.
1901 int16_t m = (int16_t)(int8_t)READ_IMM;
1903 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1904 //Note sure if the ! operator will do what we want, so we use ^ 1
1905 regs.pc += m * (flagC ^ 0x01);
1912 static void Op25(void) // BCS
1914 int16_t m = (int16_t)(int8_t)READ_IMM;
1916 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1917 regs.pc += m * (flagC);
1924 static void Op27(void) // BEQ
1926 int16_t m = (int16_t)(int8_t)READ_IMM;
1928 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1929 regs.pc += m * (flagZ);
1936 static void Op2C(void) // BGE
1938 int16_t m = (int16_t)(int8_t)READ_IMM;
1940 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1941 regs.pc += m * ((flagN ^ flagV) ^ 0x01);
1943 if (!(flagN ^ flagV))
1948 static void Op2E(void) // BGT
1950 int16_t m = (int16_t)(int8_t)READ_IMM;
1952 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1953 regs.pc += m * ((flagZ | (flagN ^ flagV)) ^ 0x01);
1955 if (!(flagZ | (flagN ^ flagV)))
1960 static void Op22(void) // BHI
1962 int16_t m = (int16_t)(int8_t)READ_IMM;
1964 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1965 regs.pc += m * ((flagZ | flagC) ^ 0x01);
1967 if (!(flagZ | flagC))
1972 static void Op2F(void) // BLE
1974 int16_t m = (int16_t)(int8_t)READ_IMM;
1976 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1977 regs.pc += m * (flagZ | (flagN ^ flagV));
1979 if (flagZ | (flagN ^ flagV))
1984 static void Op23(void) // BLS
1986 int16_t m = (int16_t)(int8_t)READ_IMM;
1988 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1989 regs.pc += m * (flagZ | flagC);
1996 static void Op2D(void) // BLT
1998 int16_t m = (int16_t)(int8_t)READ_IMM;
2000 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2001 regs.pc += m * (flagN ^ flagV);
2008 static void Op2B(void) // BMI
2010 int16_t m = (int16_t)(int8_t)READ_IMM;
2012 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2013 regs.pc += m * (flagN);
2020 static void Op26(void) // BNE
2022 int16_t m = (int16_t)(int8_t)READ_IMM;
2024 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2025 regs.pc += m * (flagZ ^ 0x01);
2032 static void Op28(void) // BVC
2034 int16_t m = (int16_t)(int8_t)READ_IMM;
2036 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2037 regs.pc += m * (flagV ^ 0x01);
2044 static void Op29(void) // BVS
2046 int16_t m = (int16_t)(int8_t)READ_IMM;
2048 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2049 regs.pc += m * (flagV);
2056 static void Op2A(void) // BPL
2058 int16_t m = (int16_t)(int8_t)READ_IMM;
2060 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
2061 regs.pc += m * (flagN ^ 0x01);
2069 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
2070 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
2071 Branch to Subroutine |BSR | |8D 8 2| | | | | |
2072 Jump |JMP | | |6E 4 2|7E 3 3| | | |
2073 Jump to Subroutine |JSR | | |AD 8 2|BD 9 3| | | |
2076 static void Op8D(void) // BSR
2078 int16_t m = (int16_t)(int8_t)READ_IMM;
2083 static void Op6E(void) // JMP ZP, X
2085 uint16_t m = EA_ZP_X;
2089 static void Op7E(void) // JMP ABS
2094 static void Op9D(void) // JSR ZP
2096 uint16_t m = (uint16_t)EA_ZP;
2101 static void OpAD(void) // JSR ZP, X
2103 uint16_t m = EA_ZP_X;
2108 static void OpBD(void) // JSR ABS
2110 uint16_t m = EA_ABS;
2116 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
2117 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
2118 No Operation |NOP | | | | |01 2 1| | |
2119 Return from Interrupt |RTI | | | | |3B A 1| |AAAAAA|
2120 Return from Subroutine |RTS | | | | |39 5 1| | |
2121 Software Interrupt |SWI | | | | |3F C 1| | S |
2122 Wait For Interrupt |WAI | | | | |3E 9 1| | B |
2125 static void Op01(void) // NOP
2129 static void Op3B(void) // RTI
2132 regs.d.acc.b = PULL;
2133 regs.d.acc.a = PULL;
2139 static void Op39(void) // RTS
2144 static void Op3F(void) // SWI
2146 // It seems that the SWI is non-maskable, unlike the IRQ...
2148 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2149 PUSH16(regs.pc); // Save all regs...
2154 regs.pc = RdMemW(0xFFFA); // And do it!
2155 flagI = 1; // Also, set IRQ inhibit
2157 HandleInterrupt(0xFFFA);
2160 static void Op3E(void) // WAI
2163 WriteLog("*** WAI STATE ASSERTED ***\n");
2165 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2166 PUSH16(regs.pc); // Save all regs...
2171 regs.cpuFlags |= V63701_STATE_WAI; // And signal that we're in WAI mode
2176 static void Op3D(void) // MUL
2178 regs.d.word = (uint16_t)regs.d.acc.a * (uint16_t)regs.d.acc.b;
2179 flagC = regs.d.acc.b >> 7; // bug? No, this is how it really does it
2182 // Exchange X and D opcode
2184 static void Op18(void) // XGDX
2186 // This doesn't affect flags apparently
2187 uint16_t temp = regs.x;
2188 regs.x = regs.d.word;
2192 // Sleep opcode (similar to WAI)
2194 static void Op1A(void) // SLP
2196 // Apparently doesn't stack the state, so no need for RTI
2197 // It would seem that this opcode is intended for use in interrupt
2198 // routines, as it prevents stacking the state when one happens.
2199 // (Actually, this is used to put the MCU into a low power "sleep" mode,
2200 // where it stays until an interrupt or RESET occurs.)
2201 regs.cpuFlags |= V63701_STATE_WAI;
2204 // Undocumented opcode ($12 & $13)
2206 static void OpUN(void) // Undocumented
2208 regs.x += regs.RdMem(regs.s + 1);
2212 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
2213 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
2214 Clear Carry |CLC | | | | |0C 2 1|C=0 | R|
2215 Clear Interrupt |CLI | | | | |0E 2 1|I=0 | R |
2216 Clear Overflow |CLV | | | | |0A 2 1|V=0 | R |
2217 Set Carry |SEC | | | | |0D 2 1|C=1 | S|
2218 Set Interrupt |SEI | | | | |0F 2 1|I=1 | S |
2219 Set Overflow |SEV | | | | |0B 2 1|V=1 | S |
2220 CCR=Accumulator A |TAP | | | | |06 2 1|CCR=A |CCCCCC|
2221 Accumlator A=CCR |TPA | | | | |07 2 1|A=CCR | |
2224 static void Op0C(void) // CLC
2229 static void Op0E(void) // CLI
2234 static void Op0A(void) // CLV
2239 static void Op0D(void) // SEC
2244 static void Op0F(void) // SEI
2249 static void Op0B(void) // SEV
2254 static void Op06(void) // TAP
2256 regs.cc = regs.d.acc.a;
2260 static void Op07(void) // TPA
2262 regs.d.acc.a = PACK_FLAGS;
2266 OP Operation Code, in Hexadecimal
2267 ~ Number of MPU cycles required
2268 # Number of program bytes required
2272 Msp Contents of Memory pointed to be Stack Pointer
2273 + Boolean Inclusive OR
2274 (+) Boolean Exclusive OR (XOR)
2275 * Converts Binary Addition of BCD Characters into BCD Format
2279 Condition Code Register Legend
2283 T Tests and sets if True, cleared otherise
2284 1 Test: Result=10000000?
2285 2 Test: Result=00000000?
2286 3 Test: Decimal value of most significant BCD character greater than nine?
2287 (Not cleared if previously set)
2288 4 Test: Operand=10000000 prior to execution?
2289 5 Test: Operand=01111111 prior to execution?
2290 6 Test: Set equal to result or N(+)C after shift has occurred.
2291 7 Test: Sign bit of most significant byte or result=1?
2292 8 Test: 2's compliment overflow from subtraction of least
2294 9 Test: Result less than zero? (Bit 15=1)
2295 A Load Condition Code Register from Stack.
2296 B Set when interrupt occurs. If previously set, a NMI is
2297 required to exit the wait state.
2298 C Set according to the contents of Accumulator A.
2300 *x SHIFT AND ROTATION DIAGRAMS
2301 *1 +-----------------+ C to LSB
2304 *2 +-----------------+
2307 *3 C <- 76543210 <- 0(Data)
2310 *4 �>76543210 -> C
2312 *5 (Data)0 -> 76543210 -> C
2321 static void Op__(void)
2323 // TRAP is non-maskable, unlike the IRQ... Also, highest priority after
2325 HandleInterrupt(0xFFEE);
2326 // regs.cpuFlags |= V63701_STATE_ILLEGAL_INST;
2330 // Ok, the exec_op[] array is globally defined here basically to save
2331 // a LOT of unnecessary typing. Sure it's ugly, but hey, it works!
2333 static void (* exec_op[256])() = {
2334 Op__, Op01, Op__, Op__, Op04, Op05, Op06, Op07, Op08, Op09, Op0A, Op0B, Op0C, Op0D, Op0E, Op0F,
2335 Op10, Op11, OpUN, OpUN, Op__, Op__, Op16, Op17, Op18, Op19, Op1A, Op1B, Op__, Op__, Op__, Op__,
2336 Op20, Op21, Op22, Op23, Op24, Op25, Op26, Op27, Op28, Op29, Op2A, Op2B, Op2C, Op2D, Op2E, Op2F,
2337 Op30, Op31, Op32, Op33, Op34, Op35, Op36, Op37, Op38, Op39, Op3A, Op3B, Op3C, Op3D, Op3E, Op3F,
2338 Op40, Op__, Op__, Op43, Op44, Op__, Op46, Op47, Op48, Op49, Op4A, Op__, Op4C, Op4D, Op__, Op4F,
2339 Op50, Op__, Op__, Op53, Op54, Op__, Op56, Op57, Op58, Op59, Op5A, Op__, Op5C, Op5D, Op__, Op5F,
2340 Op60, Op61, Op62, Op63, Op64, Op65, Op66, Op67, Op68, Op69, Op6A, Op6B, Op6C, Op6D, Op6E, Op6F,
2341 Op70, Op71, Op72, Op73, Op74, Op75, Op76, Op77, Op78, Op79, Op7A, Op7B, Op7C, Op7D, Op7E, Op7F,
2342 Op80, Op81, Op82, Op83, Op84, Op85, Op86, Op__, Op88, Op89, Op8A, Op8B, Op8C, Op8D, Op8E, Op__,
2343 Op90, Op91, Op92, Op93, Op94, Op95, Op96, Op97, Op98, Op99, Op9A, Op9B, Op9C, Op9D, Op9E, Op9F,
2344 OpA0, OpA1, OpA2, OpA3, OpA4, OpA5, OpA6, OpA7, OpA8, OpA9, OpAA, OpAB, OpAC, OpAD, OpAE, OpAF,
2345 OpB0, OpB1, OpB2, OpB3, OpB4, OpB5, OpB6, OpB7, OpB8, OpB9, OpBA, OpBB, OpBC, OpBD, OpBE, OpBF,
2346 OpC0, OpC1, OpC2, OpC3, OpC4, OpC5, OpC6, Op__, OpC8, OpC9, OpCA, OpCB, OpCC, Op__, OpCE, Op__,
2347 OpD0, OpD1, OpD2, OpD3, OpD4, OpD5, OpD6, OpD7, OpD8, OpD9, OpDA, OpDB, OpDC, OpDD, OpDE, OpDF,
2348 OpE0, OpE1, OpE2, OpE3, OpE4, OpE5, OpE6, OpE7, OpE8, OpE9, OpEA, OpEB, OpEC, OpED, OpEE, OpEF,
2349 OpF0, OpF1, OpF2, OpF3, OpF4, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, OpFB, OpFC, OpFD, OpFE, OpFF
2353 // Internal "memcpy" (so we don't have to link with any external libraries!)
2355 static void myMemcpy(void * dst, void * src, uint32_t size)
2357 uint8_t * d = (uint8_t *)dst, * s = (uint8_t *)src;
2359 for(uint32_t i=0; i<size; i++)
2364 //int instCount[256];
2365 bool V63701LogGo = false;
2366 //static bool V63701LogGo = true;
2368 extern uint8_t mcuMem[];
2369 uint8_t * memory = mcuMem;
2372 // Function to execute 63701 for "cycles" cycles
2374 void Execute63701(V63701REGS * context, uint32_t cycles)
2376 //#warning "V63701_STATE_WAI is not properly handled yet! !!! FIX !!!"
2377 //#warning "Need to convert from destructive clock to non-destructive. !!! FIX !!!"
2378 regsPointer = context;
2379 myMemcpy(®s, context, sizeof(V63701REGS));
2380 // Explode flags register into individual uint8_ts
2385 while (regs.clock < cycles)
2388 uint64_t endCycles = regs.clock + (uint64_t)cycles - regs.clockOverrun;
2390 while (regs.clock < endCycles)
2394 if (regs.pc == 0x8236)
2396 printf("V63701: $8236 called by $%04X...\n", RdMemW(regs.s));
2402 Decode63701(memory, regs.pc, instBuf);
2403 WriteLog("%s\n", instBuf);
2406 if (regs.cpuFlags & V63701_STATE_WAI)
2408 // Only bail out if no interrupts/resets are pending
2409 if (!(regs.cpuFlags & (V63701_LINE_IRQ | V63701_LINE_NMI | V63701_LINE_RESET | V63701_TIMER_OVERFLOW | V63701_OUTPUT_COMPARE | V63701_INPUT_CAPTURE)))
2410 // Burn any remaining cycles...
2411 regs.clock = endCycles;
2415 uint8_t opcode = regs.RdMem(regs.pc++);
2416 exec_op[opcode](); // Execute that opcode...
2417 regs.clock += CPUCycles[opcode];
2418 uint16_t oldCounter = regs.counter.word;
2419 regs.counter.word += CPUCycles[opcode];
2421 // We fake the free running counter above, by adding cycle counts
2422 // to it; this means we can never be sure that the counter will
2423 // be equal to the output compare register. So we have to check
2424 // for two cases: 1st, look for the previous counter value and see
2425 // if we went past it, and 2nd, do the same but check to see if we
2426 // overflowed in the meantime.
2427 if (((oldCounter < regs.outputCompare.word)
2428 && (regs.counter.word >= regs.outputCompare.word))
2429 || ((oldCounter > regs.counter.word)
2430 && (regs.counter.word >= regs.outputCompare.word)))
2432 // Set the output compare flag bit
2433 regs.tcsr.bit.ocf = 1;
2435 if (regs.tcsr.bit.eoci)
2437 regs.cpuFlags |= V63701_OUTPUT_COMPARE;
2438 regsPointer->cpuFlags |= V63701_OUTPUT_COMPARE;
2442 // Check for counter overflow
2443 if (regs.counter.word < oldCounter)
2445 // Set the timer overflow flag bit
2446 regs.tcsr.bit.tof = 1;
2448 if (regs.tcsr.bit.etoi)
2450 regs.cpuFlags |= V63701_TIMER_OVERFLOW;
2451 regsPointer->cpuFlags |= V63701_TIMER_OVERFLOW;
2456 // 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" : " "));
2457 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);
2461 if (regs.cpuFlags & V63701_LINE_RESET)
2465 WriteLog("*** RESET LINE ASSERTED ***\n");
2468 regs.tcsrWasRead = false;
2469 regs.counter.word = 0;
2470 regs.outputCompare.word = 0xFFFF;
2472 regs.pc = RdMemW(0xFFFE); // And load PC with the RESET vector
2473 context->cpuFlags = 0; // Clear all lingering flags...
2476 else if (regs.cpuFlags & V63701_LINE_NMI)
2480 WriteLog("*** NMI LINE ASSERTED ***\n");
2482 HandleInterrupt(0xFFFC, V63701_LINE_NMI);
2484 else if (regs.cpuFlags & V63701_LINE_IRQ)
2488 WriteLog("*** IRQ LINE ASSERTED ***\n");
2490 // if (!(regs.cc & FLAG_I)) // Process an interrupt (I=0)?
2491 if (!flagI) // Process an interrupt (I=0)?
2495 WriteLog(" IRQ TAKEN!\n");
2496 //V63701LogGo = true;
2498 HandleInterrupt(0xFFF8, V63701_LINE_IRQ);
2501 else if (regs.cpuFlags & V63701_INPUT_CAPTURE)
2505 WriteLog("*** INPUT CAPTURE ASSERTED ***\n");
2507 // Process interrupt if no I inhibit set, & enable in TCSR is set
2508 if (!flagI && regs.tcsr.bit.eici)
2512 WriteLog(" IC TAKEN!\n");
2513 //V63701LogGo = true;
2515 HandleInterrupt(0xFFF6, V63701_INPUT_CAPTURE);
2518 else if (regs.cpuFlags & V63701_OUTPUT_COMPARE)
2522 WriteLog("*** OUTPUT COMPARE ASSERTED ***\n");
2524 // Process interrupt if no I inhibit set, & enable in TCSR is set
2525 if (!flagI && regs.tcsr.bit.eoci)
2529 WriteLog(" OC TAKEN!\n");
2530 //V63701LogGo = true;
2532 HandleInterrupt(0xFFF4, V63701_OUTPUT_COMPARE);
2535 else if (regs.cpuFlags & V63701_TIMER_OVERFLOW)
2539 WriteLog("*** TIMER OVER ASSERTED ***\n");
2541 // Process interrupt if no I inhibit set, & enable in TCSR is set
2542 if (!flagI && regs.tcsr.bit.etoi)
2546 WriteLog(" TO TAKEN!\n");
2547 //V63701LogGo = true;
2549 HandleInterrupt(0xFFF2, V63701_TIMER_OVERFLOW);
2554 // If we went longer than the passed in cycles, make a note of it so we can
2555 // subtract it out from a subsequent run. It's guaranteed to be positive,
2556 // because the condition that exits the main loop above is written such
2557 // that regs.clock has to be larger than endCycles to exit from it.
2558 regs.clockOverrun = regs.clock - endCycles;
2560 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2561 myMemcpy(context, ®s, sizeof(V63701REGS));
2565 // Get the clock of the currently executing CPU
2567 uint64_t GetCurrentV63701Clock(void)
2572 static inline void HandleInterrupt(uint16_t vector, uint16_t flag/*= 0*/)
2574 if (regs.cpuFlags & V63701_STATE_WAI)
2578 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2579 PUSH16(regs.pc); // Save all regs...
2587 regs.pc = RdMemW(vector); // And do it!
2590 // Clear the passed in flag + WAI state
2591 regs.cpuFlags &= ~(flag | V63701_STATE_WAI);
2592 regsPointer->cpuFlags &= ~(flag | V63701_STATE_WAI);
2595 uint8_t InternalRegisterRead(uint16_t address)
2597 switch (address & 0x1F)
2604 return (V63701ReadPort1() & ~regs.ddr1) | (regs.port1data & regs.ddr1);
2605 // return /*(regs.port1read & ~regs.ddr1) |*/ (regs.port1r & ~regs.ddr1);
2607 // Top 3 bits are MCU mode bits.
2608 return (V63701ReadPort2() & ~regs.ddr2) | (regs.port2data & regs.ddr2);
2609 // return /*(regs.port1read & ~regs.ddr1) |*/ (regs.port2r & ~regs.ddr2 & 0x1F);
2610 // Timer Control and Status Register
2612 regs.tcsrWasRead = true;
2613 return regs.tcsr.byte;
2614 // Counter high byte
2616 if (regs.tcsrWasRead)
2618 regs.tcsr.bit.tof = 0;
2619 regs.tcsrWasRead = false;
2622 regs.cReadLatch = regs.counter.byte.lo;
2623 return regs.counter.byte.hi;
2626 return regs.cReadLatch;
2627 // Output compare high byte
2629 return regs.outputCompare.byte.hi;
2630 // Output compare low byte
2632 return regs.outputCompare.byte.lo;
2633 // RAM Control register (only bits 6 & 7 are valid)
2635 return (regs.ramCtrl & 0xC0) | 0x3F;
2638 printf("V63701: Unhandled register read @ $%02X...\n", address);
2647 void InternalRegisterWrite(uint16_t address, uint8_t data)
2651 switch (address & 0x1F)
2660 regs.port1data = data;
2661 writeData = (V63701ReadPort1() & ~regs.ddr1) | (data & regs.ddr1);
2662 V63701WritePort1(writeData);
2665 // Port 2 only has 5 bits of output, top 3 are the MCU mode bits
2666 regs.port2data = ((regs.port2data & ~regs.ddr2) | (data & regs.ddr2)) & 0x1F;
2669 // Timer Control and Status Register
2671 // Top 3 bits are RO, so protect them
2672 regs.tcsr.byte = (data & 0x1F) | (regs.tcsr.byte & 0xE0);
2674 // Counter (High Byte)
2676 regs.cWriteLatch = data;
2677 regs.counter.word = 0xFFF8;
2679 // Counter (Low Byte)
2681 regs.counter.word = (regs.cWriteLatch << 8) | data;
2683 // Output Compare Register (High Byte)
2685 regs.outputCompare.byte.hi = data;
2687 if (regs.tcsrWasRead)
2689 regs.tcsr.bit.ocf = 0;
2690 regs.tcsrWasRead = false;
2694 // Output Compare Register (Low Byte)
2696 regs.outputCompare.byte.lo = data;
2698 if (regs.tcsrWasRead)
2700 regs.tcsr.bit.ocf = 0;
2701 regs.tcsrWasRead = false;
2705 // RAM Control register
2707 regs.ramCtrl = data;
2711 WriteLog("V63701: Unhandled register write @ $%02X...\n", address);