2 // Virtual 6808 Emulator v2.0
5 // (C) 2006 Underground Software
7 // JLH = James L. 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
19 // NOTE: V6808_STATE_WAI is not handled in the main loop correctly. !!! FIX !!!
21 // Some random thoughts: Could there be a performance gain by breaking
22 // out the flags in regs.cc into separate uint8 variables (or bools)?
23 // You'd have to convert on entering and exiting the emulation loop, but I
24 // think the perfomance hit would be negligible compared to the gain in not
25 // having to mask and shift flags all the time. Investigate after the
26 // conversion to macro style opcodes is completed. :-)
27 // [DONE--remain to be seen if there is any performance increase]
30 #define TEST_DONT_BRANCH_OPTIMIZATION
41 #define CLR_Z (flagZ = 0)
42 #define CLR_ZN (flagZ = flagN = 0)
43 #define CLR_ZNC (flagZ = flagN = flagC = 0)
44 #define CLR_NVC (flagN = flagV = flagC = 0)
45 #define CLR_VC (flagV = flagC = 0)
46 #define CLR_V (flagV = 0)
47 #define CLR_N (flagN = 0)
48 #define SET_Z(r) (flagZ = ((r) == 0 ? 1 : 0))
49 #define SET_N(r) (flagN = ((r) & 0x80) >> 7)
50 #define SET_V(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x80) >> 7)
52 #define SET_C_CMP(a,b) (flagC = ((uint8)(b) < (uint8)(a) ? 1 : 0))
53 #define SET_ZN(r) SET_N(r); SET_Z(r)
54 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
55 #define SET_ZNVC_CMP(a,b,r) SET_N(r); SET_Z(r); SET_C_CMP(a,b); SET_V(a,b,r)
57 #define SET_N16(r) (flagN = ((r) & 0x8000) >> 15)
58 #define SET_V16(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x8000) >> 15)
59 #define SET_C_CMP16(a,b) (flagC = ((uint16)(b) < (uint16)(a) ? 1 : 0))
60 #define SET_ZNVC_CMP16(a,b,r) SET_N16(r); SET_Z(r); SET_C_CMP16(a,b); SET_V16(a,b,r)
62 //Small problem with the EA_ macros: ABS macros don't increment the PC!!! !!! FIX !!! [DONE, kinda]
63 //Can't fix for reading...
64 #define EA_IMM regs.pc++
65 #define EA_ZP regs.RdMem(regs.pc++)
66 #define EA_ZP_X (regs.RdMem(regs.pc++) + regs.x)
67 #define EA_ABS RdMemW(regs.pc)
69 #define READ_IMM regs.RdMem(EA_IMM)
70 #define READ_ZP regs.RdMem(EA_ZP)
71 #define READ_ZP_X regs.RdMem(EA_ZP_X)
72 #define READ_ABS regs.RdMem(EA_ABS); regs.pc += 2
74 #define READ_IMM16 RdMemW(regs.pc); regs.pc += 2
75 #define READ_ZP16 RdMemW(EA_ZP)
76 #define READ_ZP_X16 RdMemW(EA_ZP_X)
77 #define READ_ABS16 RdMemW(EA_ABS); regs.pc += 2
79 #define READ_IMM_WB(v) uint16 addr = EA_IMM; v = regs.RdMem(addr)
80 #define READ_ZP_WB(v) uint16 addr = EA_ZP; v = regs.RdMem(addr)
81 #define READ_ZP_X_WB(v) uint16 addr = EA_ZP_X; v = regs.RdMem(addr)
82 #define READ_ABS_WB(v) uint16 addr = EA_ABS; v = regs.RdMem(addr); regs.pc += 2
84 #define WRITE_BACK(d) regs.WrMem(addr, (d))
86 #define PULL regs.RdMem(regs.s++)
87 #define PUSH(r) regs.WrMem(--regs.s, (r))
88 #define PULL16 RdMemW(regs.s); regs.s += 2
89 #define PUSH16(r) regs.WrMem(--regs.s, (r) & 0xFF); regs.WrMem(--regs.s, (r) >> 8)
91 #define PACK_FLAGS ((regs.cc & 0xC0) | (flagH << 5) | (flagI << 4) | (flagN << 3) | (flagZ << 2) | (flagV << 1) | flagC)
92 #define UNPACK_FLAGS flagH = (regs.cc & FLAG_H) >> 5; \
93 flagI = (regs.cc & FLAG_I) >> 4; \
94 flagN = (regs.cc & FLAG_N) >> 3; \
95 flagZ = (regs.cc & FLAG_Z) >> 2; \
96 flagV = (regs.cc & FLAG_V) >> 1; \
97 flagC = (regs.cc & FLAG_C)
99 // Private global variables
101 static V6808REGS regs;
102 static uint8 flagH, flagI, flagN, flagZ, flagV, flagC;
104 static uint8 CPUCycles[256] = {
105 1, 2, 1, 1, 1, 1, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2,
106 2, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 1, 1, 1, 1,
107 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
108 4, 4, 4, 4, 4, 4, 4, 4, 1, 5, 1, 10, 1, 1, 9, 12,
109 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2,
110 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2,
111 7, 1, 1, 8, 7, 1, 7, 7, 7, 7, 7, 1, 7, 7, 4, 7,
112 6, 1, 1, 7, 6, 1, 6, 6, 6, 6, 6, 1, 6, 6, 3, 6,
113 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 3, 8, 3, 1,
114 3, 3, 3, 1, 3, 3, 3, 4, 3, 3, 3, 3, 4, 1, 4, 5,
115 5, 5, 5, 1, 5, 5, 5, 6, 5, 5, 5, 5, 6, 8, 6, 7,
116 4, 4, 4, 1, 4, 4, 4, 5, 4, 4, 4, 4, 5, 9, 5, 6,
117 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 3, 1,
118 3, 3, 3, 1, 3, 3, 3, 4, 3, 3, 3, 3, 1, 1, 4, 5,
119 5, 5, 5, 1, 5, 5, 5, 6, 5, 5, 5, 5, 1, 1, 6, 7,
120 4, 4, 4, 1, 4, 4, 4, 5, 4, 4, 4, 4, 1, 1, 5, 6
123 // Private function prototypes
125 static uint16 RdMemW(uint16);
128 // Read a word out of 6808 memory (little endian format)
130 static inline uint16 RdMemW(uint16 address)
132 return (uint16)(regs.RdMem(address) << 8) | regs.RdMem(address + 1);
136 // 6808 OPCODE IMPLEMENTATION
138 // NOTE: Lots of macros are used here to save a LOT of typing. Also
139 // helps speed the debugging process. :-) Because of this, combining
140 // certain lines may look like a good idea but would end in disaster.
141 // You have been warned! ;-)
145 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
146 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
147 Add |ADDA |8B 2 2|9B 3 2|AB 5 2|BB 4 3| |A=A+M |T TTTT|
148 |ADDB |CB 2 2|DB 3 2|EB 5 2|FB 4 3| |B=B+M |T TTTT|
149 Add Accumulators |ABA | | | | |1B 2 1|A=A+B |T TTTT|
154 #define OP_ADD_HANDLER(m, acc) \
155 uint16 sum = (uint16)(acc) + (m); \
157 flagH = (sum >> 4) & 0x01; \
158 SET_V(m, acc, sum); \
159 (acc) = sum & 0xFF; \
162 static void Op8B(void) // ADDA #
165 OP_ADD_HANDLER(m, regs.a);
168 static void Op9B(void) // ADDA ZP
171 OP_ADD_HANDLER(m, regs.a);
174 static void OpAB(void) // ADDA ZP, X
176 uint16 m = READ_ZP_X;
177 OP_ADD_HANDLER(m, regs.a);
180 static void OpBB(void) // ADDA ABS
183 OP_ADD_HANDLER(m, regs.a);
186 static void OpCB(void) // ADDB #
189 OP_ADD_HANDLER(m, regs.b);
192 static void OpDB(void) // ADDB ZP
195 OP_ADD_HANDLER(m, regs.b);
198 static void OpEB(void) // ADDB ZP, X
200 uint16 m = READ_ZP_X;
201 OP_ADD_HANDLER(m, regs.b);
204 static void OpFB(void) // ADDB ABS
207 OP_ADD_HANDLER(m, regs.b);
210 static void Op1B(void) // ABA
212 OP_ADD_HANDLER(regs.b, regs.a);
216 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
217 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
218 Add with Carry |ADCA |89 2 2|99 3 2|A9 5 2|B9 4 3| |A=A+M+C |T TTTT|
219 |ADCB |C9 2 2|D9 3 2|E9 5 2|F9 4 3| |B=B+M+C |T TTTT|
224 #define OP_ADC_HANDLER(m, acc) \
225 uint16 sum = (uint16)acc + (m) + (uint16)flagC; \
227 flagH = (sum >> 4) & 0x01; \
228 SET_V(m, acc, sum); \
232 static void Op89(void) // ADCA #
235 OP_ADC_HANDLER(m, regs.a);
238 static void Op99(void) // ADCA ZP
241 OP_ADC_HANDLER(m, regs.a);
244 static void OpA9(void) // ADCA ZP, X
246 uint16 m = READ_ZP_X;
247 OP_ADC_HANDLER(m, regs.a);
250 static void OpB9(void) // ADCA ABS
253 OP_ADC_HANDLER(m, regs.a);
256 static void OpC9(void) // ADCB #
259 OP_ADC_HANDLER(m, regs.b);
262 static void OpD9(void) // ADCB ZP
265 OP_ADC_HANDLER(m, regs.b);
268 static void OpE9(void) // ADCB ZP, X
270 uint16 m = READ_ZP_X;
271 OP_ADC_HANDLER(m, regs.b);
274 static void OpF9(void) // ADCB ABS
277 OP_ADC_HANDLER(m, regs.b);
281 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
282 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
283 And |ANDA |84 2 2|94 3 2|A4 5 2|B4 4 3| |A=A+M | TTR |
284 |ANDB |C4 2 2|D4 3 2|E4 5 2|F4 4 3| |B=B+M | TTR |
289 #define OP_AND_HANDLER(m, acc) \
294 static void Op84(void) // ANDA #
297 OP_AND_HANDLER(m, regs.a);
300 static void Op94(void) // ANDA ZP
303 OP_AND_HANDLER(m, regs.a);
306 static void OpA4(void) // ANDA ZP, X
308 uint16 m = READ_ZP_X;
309 OP_AND_HANDLER(m, regs.a);
312 static void OpB4(void) // ANDA ABS
315 OP_AND_HANDLER(m, regs.a);
318 static void OpC4(void) // ANDB #
321 OP_AND_HANDLER(m, regs.b);
324 static void OpD4(void) // ANDB ZP
327 OP_AND_HANDLER(m, regs.b);
330 static void OpE4(void) // ANDB ZP, X
332 uint16 m = READ_ZP_X;
333 OP_AND_HANDLER(m, regs.b);
336 static void OpF4(void) // ANDB ABS
339 OP_AND_HANDLER(m, regs.b);
343 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
344 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
345 Bit Test |BITA |85 2 2|95 3 2|A5 5 2|B5 4 3| |A+M | TTR |
346 |BITB |C5 2 2|D5 3 2|E5 5 2|F5 4 3| |B+M | TTR |
351 #define OP_BIT_HANDLER(m, acc) \
352 int8 result = acc & (m); \
355 static void Op85(void) // BITA #
358 OP_BIT_HANDLER(m, regs.a);
361 static void Op95(void) // BITA ZP
364 OP_BIT_HANDLER(m, regs.a);
367 static void OpA5(void) // BITA ZP, X
370 OP_BIT_HANDLER(m, regs.a);
373 static void OpB5(void) // BITA ABS
376 OP_BIT_HANDLER(m, regs.a);
379 static void OpC5(void) // BITB #
382 OP_BIT_HANDLER(m, regs.b);
385 static void OpD5(void) // BITB ZP
388 OP_BIT_HANDLER(m, regs.b);
391 static void OpE5(void) // BITB ZP, X
394 OP_BIT_HANDLER(m, regs.b);
397 static void OpF5(void) // BITB ABS
400 OP_BIT_HANDLER(m, regs.b);
404 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
405 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
406 Clear |CLR | | |6F 7 2|7F 6 3| |M=00 | RSRR|
407 |CLRA | | | | |4F 2 1|A=00 | RSRR|
408 |CLRB | | | | |5F 2 1|B=00 | RSRR|
413 static void Op6F(void) // CLR ZP, X
415 regs.WrMem(EA_ZP_X, 0);
420 static void Op7F(void) // CLR ABS
422 regs.WrMem(EA_ABS, 0);
428 static void Op4F(void) // CLRA
435 static void Op5F(void) // CLRB
443 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
444 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
445 Compare |CMPA |81 2 2|91 3 2|A1 5 2|B1 4 3| |A-M | TTTT|
446 |CMPB |C1 2 2|D1 3 2|E1 5 2|F1 4 3| |B-M | TTTT|
447 Compare Accumulators |CBA | | | | |11 2 1|A-B | TTTT|
453 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.
456 #define OP_CMP_HANDLER(m, acc) \
457 uint16 result = acc - (m); \
458 SET_ZNVC_CMP(m, acc, result)
460 static void Op81(void) // CMPA #
463 OP_CMP_HANDLER(m, regs.a);
466 static void Op91(void) // CMPA ZP
469 OP_CMP_HANDLER(m, regs.a);
472 static void OpA1(void) // CMPA ZP, X
475 OP_CMP_HANDLER(m, regs.a);
478 static void OpB1(void) // CMPA ABS
481 OP_CMP_HANDLER(m, regs.a);
484 static void OpC1(void) // CMPB #
487 OP_CMP_HANDLER(m, regs.b);
490 static void OpD1(void) // CMPB ZP
493 OP_CMP_HANDLER(m, regs.b);
496 static void OpE1(void) // CMPB ZP, X
499 OP_CMP_HANDLER(m, regs.b);
502 static void OpF1(void) // CMPB ABS
505 OP_CMP_HANDLER(m, regs.b);
508 static void Op11(void) // CBA
510 OP_CMP_HANDLER(regs.b, regs.a);
514 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
515 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
516 Complement 1's |COM | | |63 7 2|73 6 3| |M=-M | TTRS|
517 |COMA | | | | |43 2 1|A=-A | TTRS|
518 |COMB | | | | |53 2 1|B=-B | TTRS|
523 #define OP_COM_HANDLER(m) \
529 static void Op63(void) // COM ZP, X
537 static void Op73(void) // COM ABS
545 static void Op43(void) // COMA
547 OP_COM_HANDLER(regs.a);
550 static void Op53(void) // COMB
552 OP_COM_HANDLER(regs.b);
556 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
557 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
558 Complement 2's |NEG | | |60 7 2|70 6 3| |M=00-M | TT12|
559 |NEGA | | | | |40 2 1|A=00-A | TT12|
560 |NEGB | | | | |50 2 1|B=00-B | TT12|
565 #define OP_NEG_HANDLER(m) \
568 flagV = (m == 0x80 ? 1 : 0); \
569 flagC = (m == 0x00 ? 1 : 0)
571 static void Op60(void) // NEG ZP, X
579 static void Op70(void) // NEG ABS
587 static void Op40(void) // NEGA
589 OP_NEG_HANDLER(regs.a);
592 static void Op50(void) // NEGB
594 OP_NEG_HANDLER(regs.b);
598 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
599 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
600 Decimal Adjust |DAA | | | | |19 2 1|* | TTT3|
603 static void Op19(void) // DAA
605 uint16 result = (uint16)regs.a;
607 if ((regs.a & 0x0F) > 0x09 || flagH)
610 if ((regs.a & 0xF0) > 0x90 || flagC || ((regs.a & 0xF0) > 0x80 && (regs.a & 0x0F) > 0x09))
613 regs.a = (uint8)result;
615 CLR_V; // Not sure this is correct...
616 flagC |= (result & 0x100) >> 8; // Overwrite carry if it was 0, otherwise, ignore
620 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
621 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
622 Decrement |DEC | | |6A 7 2|7A 6 3| |M=M-1 | TT4 |
623 |DECA | | | | |4A 2 1|A=A-1 | TT4 |
624 |DECB | | | | |5A 2 1|B=B-1 | TT4 |
629 #define OP_DEC_HANDLER(m) \
632 flagV = (m == 0x7F ? 1 : 0)
634 static void Op6A(void) // DEC ZP, X
642 static void Op7A(void) // DEC ABS
650 static void Op4A(void) // DECA
652 OP_DEC_HANDLER(regs.a);
655 static void Op5A(void) // DECB
657 OP_DEC_HANDLER(regs.b);
661 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
662 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
663 Exclusive OR |EORA |88 2 2|98 3 2|A8 5 2|B8 4 3| |A=A(+)M | TTR |
664 |EORB |C8 2 2|D8 3 2|E8 5 2|F8 4 3| |B=B(+)M | TTR |
669 #define OP_EOR_HANDLER(m, acc) \
674 static void Op88(void) // EORA #
677 OP_EOR_HANDLER(m, regs.a);
680 static void Op98(void) // EORA ZP
683 OP_EOR_HANDLER(m, regs.a);
686 static void OpA8(void) // EORA ZP, X
689 OP_EOR_HANDLER(m, regs.a);
692 static void OpB8(void) // EORA ABS
695 OP_EOR_HANDLER(m, regs.a);
698 static void OpC8(void) // EORB #
701 OP_EOR_HANDLER(m, regs.b);
704 static void OpD8(void) // EORB ZP
707 OP_EOR_HANDLER(m, regs.b);
710 static void OpE8(void) // EORB ZP, X
713 OP_EOR_HANDLER(m, regs.b);
716 static void OpF8(void) // EORB ABS
719 OP_EOR_HANDLER(m, regs.b);
723 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
724 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
725 Increment |INC | | |6C 7 2|7C 6 3| |M=M+1 | TT5 |
726 |INCA | | | | |4C 2 1|A=A+1 | TT5 |
727 |INCB | | | | |5C 2 1|B=B+1 | TT5 |
732 #define OP_INC_HANDLER(m) \
735 flagV = (m == 0x80 ? 1 : 0)
737 static void Op6C(void) // INC ZP, X
745 static void Op7C(void) // INC ABS
753 static void Op4C(void) // INCA
755 OP_INC_HANDLER(regs.a);
758 static void Op5C(void) // INCB
760 OP_INC_HANDLER(regs.b);
764 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
765 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
766 Load Accumulator |LDAA |86 2 2|96 3 2|A6 5 2|B6 4 3| |A=M | TTR |
767 |LDAB |C6 2 2|D6 3 2|E6 5 2|F6 4 3| |B=M | TTR |
772 #define OP_LDA_HANDLER(m, acc) \
777 static void Op86(void) // LDAA #
780 OP_LDA_HANDLER(m, regs.a);
783 static void Op96(void) // LDAA ZP
786 OP_LDA_HANDLER(m, regs.a);
789 static void OpA6(void) // LDAA ZP, X
792 OP_LDA_HANDLER(m, regs.a);
795 static void OpB6(void) // LDAA ABS
798 OP_LDA_HANDLER(m, regs.a);
801 static void OpC6(void) // LDAB #
804 OP_LDA_HANDLER(m, regs.b);
807 static void OpD6(void) // LDAB ZP
810 OP_LDA_HANDLER(m, regs.b);
813 static void OpE6(void) // LDAB ZP, X
816 OP_LDA_HANDLER(m, regs.b);
819 static void OpF6(void) // LDAB ABS
822 OP_LDA_HANDLER(m, regs.b);
826 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
827 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
828 OR, Inclusive |ORAA |8A 2 2|9A 3 2|AA 5 2|BA 4 3| |A=A+M | TTR |
829 |ORAB |CA 2 2|DA 3 2|EA 5 2|FA 4 3| |B=B+M | TTR |
834 #define OP_ORA_HANDLER(m, acc) \
839 static void Op8A(void) // ORAA #
842 OP_ORA_HANDLER(m, regs.a);
845 static void Op9A(void) // ORAA ZP
848 OP_ORA_HANDLER(m, regs.a);
851 static void OpAA(void) // ORAA ZP, X
854 OP_ORA_HANDLER(m, regs.a);
857 static void OpBA(void) // ORAA ABS
860 OP_ORA_HANDLER(m, regs.a);
863 static void OpCA(void) // ORAB #
866 OP_ORA_HANDLER(m, regs.b);
869 static void OpDA(void) // ORAB ZP
872 OP_ORA_HANDLER(m, regs.b);
875 static void OpEA(void) // ORAB ZP, X
878 OP_ORA_HANDLER(m, regs.b);
881 static void OpFA(void) // ORAB ABS
884 OP_ORA_HANDLER(m, regs.b);
888 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
889 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
890 Push Data |PSHA | | | | |36 4 1|Msp=A, *- | |
891 |PSHB | | | | |37 4 1|Msp=B, *- | |
892 Pull Data |PULA | | | | |32 4 1|A=Msp, *+ | |
893 |PULB | | | | |33 4 1|B=Msp, *+ | |
896 static void Op36(void) // PSHA
901 static void Op37(void) // PSHB
906 static void Op32(void) // PULA
911 static void Op33(void) // PULB
917 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
918 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
919 Rotate Left |ROL | | |69 7 2|79 6 3| |Memory *1| TT6T|
920 |ROLA | | | | |49 2 1|Accum A *1| TT6T|
921 |ROLB | | | | |59 2 1|Accum B *1| TT6T|
926 #define OP_ROL_HANDLER(m) \
927 uint8 newCarry = (m & 0x80) >> 7; \
928 m = (m << 1) | flagC; \
931 flagV = flagN ^ flagC
933 static void Op69(void) // ROL ZP, X
941 static void Op79(void) // ROL ABS
949 static void Op49(void) // ROLA
951 OP_ROL_HANDLER(regs.a);
954 static void Op59(void) // ROLB
956 OP_ROL_HANDLER(regs.b);
960 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
961 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
962 Rotate Right |ROR | | |66 7 2|76 6 3| |Memory *2| TT6T|
963 |RORA | | | | |46 2 1|Accum A *2| TT6T|
964 |RORB | | | | |56 2 1|Accum B *2| TT6T|
969 #define OP_ROR_HANDLER(m) \
970 uint8 newCarry = m & 0x01; \
971 m = (m >> 1) | (flagC << 7); \
974 flagV = flagN ^ flagC
976 static void Op66(void) // ROR ZP, X
984 static void Op76(void) // ROR ABS
992 static void Op46(void) // RORA
994 OP_ROR_HANDLER(regs.a);
997 static void Op56(void) // RORB
999 OP_ROR_HANDLER(regs.b);
1003 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1004 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1005 Arithmetic Shift Left |ASL | | |68 7 2|78 6 3| |Memory *3| TT6T|
1006 |ASLA | | | | |48 2 1|Accum A *3| TT6T|
1007 |ASLB | | | | |58 2 1|Accum B *3| TT6T|
1012 #define OP_ASL_HANDLER(m) \
1013 uint8 newCarry = (m & 0x80) >> 7; \
1017 flagV = flagN ^ flagC
1019 static void Op68(void) // ASL ZP, X
1027 static void Op78(void) // ASL ABS
1035 static void Op48(void) // ASLA
1037 OP_ASL_HANDLER(regs.a);
1040 static void Op58(void) // ASLB
1042 OP_ASL_HANDLER(regs.b);
1046 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1047 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1048 Arithmetic Shift Right |ASR | | |67 7 2|77 6 3| |Memory *4| TT6T|
1049 |ASRA | | | | |47 2 1|Accum A *4| TT6T|
1050 |ASRB | | | | |57 2 1|Accum B *4| TT6T|
1055 #define OP_ASR_HANDLER(m) \
1056 uint8 newCarry = m & 0x01; \
1057 m = (m >> 1) | (m & 0x80); \
1060 flagV = flagN ^ flagC
1062 static void Op67(void) // ASR ZP, X
1070 static void Op77(void) // ASR ABS
1078 static void Op47(void) // ASRA
1080 OP_ASR_HANDLER(regs.a);
1083 static void Op57(void) // ASRB
1085 OP_ASR_HANDLER(regs.b);
1089 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1090 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1091 Logic Shift Right |LSR | | |64 7 2|74 6 3| |Memory *5| TT6T|
1092 |LSRA | | | | |44 2 1|Accum A *5| TT6T|
1093 |LSRB | | | | |54 2 1|Accum B *5| TT6T|
1098 #define OP_LSR_HANDLER(m) \
1099 uint8 newCarry = m & 0x01; \
1103 flagV = flagN ^ flagC
1105 static void Op64(void) // LSR ZP, X
1113 static void Op74(void) // LSR ABS
1121 static void Op44(void) // LSRA
1123 OP_LSR_HANDLER(regs.a);
1126 static void Op54(void) // LSRB
1128 OP_LSR_HANDLER(regs.b);
1132 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1133 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1134 Store Accumulator |STAA | |97 4 2|A7 6 2|B7 5 3| |M=A | TTR |
1135 |STAB | |D7 4 2|E7 6 2|F7 5 3| |M=B | TTR |
1138 static void Op97(void) // STAA ZP
1140 regs.WrMem(EA_ZP, regs.a);
1143 static void OpA7(void) // STAA ZP, X
1145 regs.WrMem(EA_ZP_X, regs.a);
1148 static void OpB7(void) // STAA ABS
1150 regs.WrMem(EA_ABS, regs.a);
1154 static void OpD7(void) // STAB ZP
1156 regs.WrMem(EA_ZP, regs.b);
1159 static void OpE7(void) // STAB ZP, X
1161 regs.WrMem(EA_ZP_X, regs.b);
1164 static void OpF7(void) // STAB ABS
1166 regs.WrMem(EA_ABS, regs.b);
1171 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1172 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1173 Subtract |SUBA |80 2 2|90 3 2|A0 5 2|B0 4 3| |A=A-M | TTTT|
1174 |SUBB |C0 2 2|D0 3 2|E0 5 2|F0 4 3| |B=B-M | TTTT|
1175 Subtract Accumulators |SBA | | | | |10 2 1|A=A-B | TTTT|
1180 #define OP_SUB_HANDLER(m, acc) \
1181 uint16 sum = (uint16)acc - (m); \
1182 flagC = sum >> 15; \
1183 SET_V(m, acc, sum); \
1187 static void Op80(void) // SUBA #
1189 uint16 m = READ_IMM;
1190 OP_SUB_HANDLER(m, regs.a);
1193 static void Op90(void) // SUBA ZP
1196 OP_SUB_HANDLER(m, regs.a);
1199 static void OpA0(void) // SUBA ZP, X
1201 uint16 m = READ_ZP_X;
1202 OP_SUB_HANDLER(m, regs.a);
1205 static void OpB0(void) // SUBA ABS
1207 uint16 m = READ_ABS;
1208 OP_SUB_HANDLER(m, regs.a);
1211 static void OpC0(void) // SUBB #
1213 uint16 m = READ_IMM;
1214 OP_SUB_HANDLER(m, regs.b);
1217 static void OpD0(void) // SUBB ZP
1220 OP_SUB_HANDLER(m, regs.b);
1223 static void OpE0(void) // SUBB ZP, X
1225 uint16 m = READ_ZP_X;
1226 OP_SUB_HANDLER(m, regs.b);
1229 static void OpF0(void) // SUBB ABS
1231 uint16 m = READ_ABS;
1232 OP_SUB_HANDLER(m, regs.b);
1235 static void Op10(void) // SBA
1237 OP_SUB_HANDLER(regs.b, regs.a);
1241 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1242 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1243 Subtract with Carry |SBCA |82 2 2|92 3 2|A2 5 2|B2 4 3| |A=A-M-C | TTTT|
1244 |SBCB |C2 2 2|D2 3 2|E2 5 2|F2 4 3| |B=B-M-C | TTTT|
1249 #define OP_SBC_HANDLER(m, acc) \
1250 uint16 sum = (uint16)acc - (m) - (uint16)flagC; \
1251 flagC = sum >> 15; \
1252 SET_V(m, acc, sum); \
1256 static void Op82(void) // SBCA #
1258 uint16 m = READ_IMM;
1259 OP_SBC_HANDLER(m, regs.a);
1262 static void Op92(void) // SBCA ZP
1265 OP_SBC_HANDLER(m, regs.a);
1268 static void OpA2(void) // SBCA ZP, X
1270 uint16 m = READ_ZP_X;
1271 OP_SBC_HANDLER(m, regs.a);
1274 static void OpB2(void) // SBCA ABS
1276 uint16 m = READ_ABS;
1277 OP_SBC_HANDLER(m, regs.a);
1280 static void OpC2(void) // SBCB #
1282 uint16 m = READ_IMM;
1283 OP_SBC_HANDLER(m, regs.b);
1286 static void OpD2(void) // SBCB ZP
1289 OP_SBC_HANDLER(m, regs.b);
1292 static void OpE2(void) // SBCB ZP, X
1294 uint16 m = READ_ZP_X;
1295 OP_SBC_HANDLER(m, regs.b);
1298 static void OpF2(void) // SBCB ABS
1300 uint16 m = READ_ABS;
1301 OP_SBC_HANDLER(m, regs.b);
1305 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1306 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1307 Transfer Accumulators |TAB | | | | |16 2 1|B=A | TTR |
1308 |TBA | | | | |17 2 1|A=B | TTR |
1311 static void Op16(void) // TAB
1318 static void Op17(void) // TBA
1326 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1327 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1328 Test, Zero/Minus |TST | | |6D 7 2|7D 6 3| |M-00 | TTRR|
1329 |TSTA | | | | |4D 2 1|A-00 | TTRR|
1330 |TSTB | | | | |5D 2 1|B-00 | TTRR|
1335 #define OP_TST_HANDLER(m) \
1339 static void Op6D(void) // TST ZP, X
1347 static void Op7D(void) // TST ABS
1355 static void Op4D(void) // TSTA
1357 OP_TST_HANDLER(regs.a);
1360 static void Op5D(void) // TSTB
1362 OP_TST_HANDLER(regs.b);
1366 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1367 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1368 Compare Index Register |CPX |8C 3 3|9C 4 2|AC 6 2|BC 5 3| |Formula 1 | 7T8 |
1374 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.
1377 #define OP_CPX_HANDLER(m) \
1378 uint32 result = regs.x - (m); \
1379 SET_ZNVC_CMP16(m, regs.x, result)
1381 static void Op8C(void) // CPX #
1383 uint16 m = READ_IMM16;
1387 static void Op9C(void) // CPX ZP
1389 uint16 m = READ_ZP16;
1393 static void OpAC(void) // CPX ZP, X
1395 uint16 m = READ_ZP_X16;
1399 static void OpBC(void) // CPX ABS
1401 uint16 m = READ_ABS16;
1406 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1407 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1408 Decrement Index Register|DEX | | | | |09 4 1|X=X-1 | T |
1409 Dec Stack Pointer |DES | | | | |34 4 1|SP=SP-1 | |
1410 Inc Index Regster |INX | | | | |08 4 1|X=X+1 | T |
1411 Inc Stack Pointer |INS | | | | |31 4 1|SP=SP+1 | |
1414 static void Op09(void) // DEX
1420 static void Op34(void) // DES
1425 static void Op08(void) // INX
1431 static void Op31(void) // INS
1437 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1438 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1439 Load Index Register |LDX |CE 3 3|DE 4 2|EE 6 2|FE 5 3| |Formula 2 | 9TR |
1440 Load Stack Pointer |LDS |8E 3 3|9E 4 2|AE 6 2|BE 5 3| |Formula 3 | 9TR |
1443 // LD* opcode handler
1445 #define OP_LD_HANDLER(acc) \
1450 static void OpCE(void) // LDX #
1452 regs.x = READ_IMM16;
1453 OP_LD_HANDLER(regs.x);
1456 static void OpDE(void) // LDX ZP
1459 OP_LD_HANDLER(regs.x);
1462 static void OpEE(void) // LDX ZP, X
1464 regs.x = READ_ZP_X16;
1465 OP_LD_HANDLER(regs.x);
1468 static void OpFE(void) // LDX ABS
1470 regs.x = READ_ABS16;
1471 OP_LD_HANDLER(regs.x);
1474 static void Op8E(void) // LDS #
1476 regs.s = READ_IMM16;
1477 OP_LD_HANDLER(regs.s);
1480 static void Op9E(void) // LDS ZP
1483 OP_LD_HANDLER(regs.s);
1486 static void OpAE(void) // LDS ZP, X
1488 regs.s = READ_ZP_X16;
1489 OP_LD_HANDLER(regs.s);
1492 static void OpBE(void) // LDS ABS
1494 regs.s = READ_ABS16;
1495 OP_LD_HANDLER(regs.s);
1499 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1500 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1501 Store Index Register |STX | |DF 5 2|EF 7 2|FF 6 3| |Formula 4 | 9TR |
1502 Store Stack Pointer |STS | |9F 5 2|AF 7 2|BF 6 3| |Formula 5 | 9TR |
1505 // ST* opcode handler
1507 #define OP_ST_HANDLER(m, acc) \
1508 regs.WrMem(m + 0, acc >> 8); \
1509 regs.WrMem(m + 1, acc & 0xFF); \
1514 static void OpDF(void) // STX ZP
1517 OP_ST_HANDLER(m, regs.x);
1520 static void OpEF(void) // STX ZP, X
1523 OP_ST_HANDLER(m, regs.x);
1526 static void OpFF(void) // STX ABS
1530 OP_ST_HANDLER(m, regs.x);
1533 static void Op9F(void) // STS ZP
1536 OP_ST_HANDLER(m, regs.s);
1539 static void OpAF(void) // STS ZP, X
1542 OP_ST_HANDLER(m, regs.s);
1545 static void OpBF(void) // STS ABS
1549 OP_ST_HANDLER(m, regs.s);
1553 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1554 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1555 Index Reg > Stack Pnter |TXS | | | | |35 4 1|SP=X-1 | |
1556 Stack Ptr > Index Regtr |TSX | | | | |30 4 1|X=SP+1 | |
1559 static void Op35(void) // TXS
1561 regs.s = regs.x - 1;
1564 static void Op30(void) // TSX
1566 regs.x = regs.s + 1;
1570 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1571 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1572 Always |BRA | |20 4 2| | | |none | |
1573 Carry is Clear |BCC | |24 4 2| | | |C=0 | |
1574 Carry is Set |BCS | |25 4 2| | | |C=1 | |
1575 Equals Zero |BEQ | |27 4 2| | | |Z=1 | |
1576 Greater or Equal to Zero|BGE | |2C 4 2| | | |N(+)V=0 | |
1577 Greater than Zero |BGT | |2E 4 2| | | |Z+N(+)V=0 | |
1578 Higher |BHI | |22 4 2| | | |C+Z=0 | |
1579 Less or Equal than Zero |BLE | |2F 4 2| | | |Z+N(+)V=1 | |
1580 Lower or Same |BLS | |23 4 2| | | |C+Z=1 | |
1581 Less Than Zero |BLT | |2D 4 2| | | |N(+)V=1 | |
1582 Minus |BMI | |2B 4 2| | | |N=1 | |
1583 Not Zero |BNE | |26 4 2| | | |Z=0 | |
1584 Overflow Clear |BVC | |28 4 2| | | |V=0 | |
1585 Overflow Set |BVS | |29 4 2| | | |V=1 | |
1586 Plus |BPL | |2A 4 2| | | |N=0 | |
1589 static void Op20(void) // BRA
1591 int16 m = (int16)(int8)READ_IMM;
1595 static void Op24(void) // BCC
1597 // NOTE: We can optimize this by following the maxim: "Don't branch!" by converting the boolean
1598 // result into a multiplication. The only way to know if this is a win is to do some profiling
1599 // both with and without the optimization.
1600 int16 m = (int16)(int8)READ_IMM;
1602 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1603 //Note sure if the ! operator will do what we want, so we use ^ 1
1604 regs.pc += m * (flagC ^ 0x01);
1611 static void Op25(void) // BCS
1613 int16 m = (int16)(int8)READ_IMM;
1615 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1616 regs.pc += m * (flagC);
1623 static void Op27(void) // BEQ
1625 int16 m = (int16)(int8)READ_IMM;
1627 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1628 regs.pc += m * (flagZ);
1635 static void Op2C(void) // BGE
1637 int16 m = (int16)(int8)READ_IMM;
1639 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1640 regs.pc += m * ((flagN ^ flagV) ^ 0x01);
1642 if (!(flagN ^ flagV))
1647 static void Op2E(void) // BGT
1649 int16 m = (int16)(int8)READ_IMM;
1651 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1652 regs.pc += m * ((flagZ | (flagN ^ flagV)) ^ 0x01);
1654 if (!(flagZ | (flagN ^ flagV)))
1659 static void Op22(void) // BHI
1661 int16 m = (int16)(int8)READ_IMM;
1663 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1664 regs.pc += m * ((flagZ | flagC) ^ 0x01);
1666 if (!(flagZ | flagC))
1671 static void Op2F(void) // BLE
1673 int16 m = (int16)(int8)READ_IMM;
1675 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1676 regs.pc += m * (flagZ | (flagN ^ flagV));
1678 if (flagZ | (flagN ^ flagV))
1683 static void Op23(void) // BLS
1685 int16 m = (int16)(int8)READ_IMM;
1687 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1688 regs.pc += m * (flagZ | flagC);
1695 static void Op2D(void) // BLT
1697 int16 m = (int16)(int8)READ_IMM;
1699 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1700 regs.pc += m * (flagN ^ flagV);
1707 static void Op2B(void) // BMI
1709 int16 m = (int16)(int8)READ_IMM;
1711 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1712 regs.pc += m * (flagN);
1719 static void Op26(void) // BNE
1721 int16 m = (int16)(int8)READ_IMM;
1723 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1724 regs.pc += m * (flagZ ^ 0x01);
1731 static void Op28(void) // BVC
1733 int16 m = (int16)(int8)READ_IMM;
1735 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1736 regs.pc += m * (flagV ^ 0x01);
1743 static void Op29(void) // BVS
1745 int16 m = (int16)(int8)READ_IMM;
1747 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1748 regs.pc += m * (flagV);
1755 static void Op2A(void) // BPL
1757 int16 m = (int16)(int8)READ_IMM;
1759 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1760 regs.pc += m * (flagN ^ 0x01);
1768 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1769 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1770 Branch to Subroutine |BSR | |8D 8 2| | | | | |
1771 Jump |JMP | | |6E 4 2|7E 3 3| | | |
1772 Jump to Subroutine |JSR | | |AD 8 2|BD 9 3| | | |
1775 static void Op8D(void) // BSR
1777 int16 m = (int16)(int8)READ_IMM;
1782 static void Op6E(void) // JMP ZP, X
1787 static void Op7E(void) // JMP ABS
1792 static void OpAD(void) // JSR ZP, X
1799 static void OpBD(void) // JSR ABS
1808 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1809 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1810 No Operation |NOP | | | | |01 2 1| | |
1811 Return from Interrupt |RTI | | | | |3B A 1| |AAAAAA|
1812 Return from Subroutine |RTS | | | | |39 5 1| | |
1813 Software Interrupt |SWI | | | | |3F C 1| | S |
1814 Wait For Interrupt |WAI | | | | |3E 9 1| | B |
1817 static void Op01(void) // NOP
1821 static void Op3B(void) // RTI
1831 static void Op39(void) // RTS
1836 static void Op3F(void) // SWI
1838 // It seems that the SWI is non-maskable, unlike the IRQ...
1839 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
1840 PUSH16(regs.pc); // Save all regs...
1845 regs.pc = RdMemW(0xFFFA); // And do it!
1846 flagI = 1; // Also, set IRQ inhibit
1849 static void Op3E(void) // WAI
1852 WriteLog("*** WAI STATE ASSERTED ***\n");
1854 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
1855 PUSH16(regs.pc); // Save all regs...
1860 regs.cpuFlags |= V6808_STATE_WAI; // And signal that we're in WAI mode
1864 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1865 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1866 Clear Carry |CLC | | | | |0C 2 1|C=0 | R|
1867 Clear Interrupt |CLI | | | | |0E 2 1|I=0 | R |
1868 Clear Overflow |CLV | | | | |0A 2 1|V=0 | R |
1869 Set Carry |SEC | | | | |0D 2 1|C=1 | S|
1870 Set Interrupt |SEI | | | | |0F 2 1|I=1 | S |
1871 Set Overflow |SEV | | | | |0B 2 1|V=1 | S |
1872 CCR=Accumulator A |TAP | | | | |06 2 1|CCR=A |CCCCCC|
1873 Accumlator A=CCR |TPA | | | | |07 2 1|A=CCR | |
1876 static void Op0C(void) // CLC
1881 static void Op0E(void) // CLI
1886 static void Op0A(void) // CLV
1891 static void Op0D(void) // SEC
1896 static void Op0F(void) // SEI
1901 static void Op0B(void) // SEV
1906 static void Op06(void) // TAP
1912 static void Op07(void) // TPA
1914 regs.a = PACK_FLAGS;
1918 OP Operation Code, in Hexadecimal
1919 ~ Number of MPU cycles required
1920 # Number of program bytes required
1924 Msp Contents of Memory pointed to be Stack Pointer
1925 + Boolean Inclusive OR
1926 (+) Boolean Exclusive OR (XOR)
1927 * Converts Binary Addition of BCD Characters into BCD Format
1931 Condition Code Register Legend
1935 T Tests and sets if True, cleared otherise
1936 1 Test: Result=10000000?
1937 2 Test: Result=00000000?
1938 3 Test: Decimal value of most significant BCD character greater than nine?
1939 (Not cleared if previously set)
1940 4 Test: Operand=10000000 prior to execution?
1941 5 Test: Operand=01111111 prior to execution?
1942 6 Test: Set equal to result or N(+)C after shift has occurred.
1943 7 Test: Sign bit of most significant byte or result=1?
1944 8 Test: 2's compliment overflow from subtraction of least
1946 9 Test: Result less than zero? (Bit 15=1)
1947 A Load Condition Code Register from Stack.
1948 B Set when interrupt occurs. If previously set, a NMI is
1949 required to exit the wait state.
1950 C Set according to the contents of Accumulator A.
1952 *x SHIFT AND ROTATION DIAGRAMS
1953 *1 +-----------------+ C to LSB
1956 *2 +-----------------+
1959 *3 C <- 76543210 <- 0(Data)
1964 *5 (Data)0 -> 76543210 -> C
1973 static void Op__(void)
1975 regs.cpuFlags |= V6808_STATE_ILLEGAL_INST;
1980 // Ok, the exec_op[] array is globally defined here basically to save
1981 // a LOT of unnecessary typing. Sure it's ugly, but hey, it works!
1983 void (* exec_op[256])() = {
1984 Op__, Op01, Op__, Op__, Op__, Op__, Op06, Op07, Op08, Op09, Op0A, Op0B, Op0C, Op0D, Op0E, Op0F,
1985 Op10, Op11, Op__, Op__, Op__, Op__, Op16, Op17, Op__, Op19, Op__, Op1B, Op__, Op__, Op__, Op__,
1986 Op20, Op__, Op22, Op23, Op24, Op25, Op26, Op27, Op28, Op29, Op2A, Op2B, Op2C, Op2D, Op2E, Op2F,
1987 Op30, Op31, Op32, Op33, Op34, Op35, Op36, Op37, Op__, Op39, Op__, Op3B, Op__, Op__, Op3E, Op3F,
1988 Op40, Op__, Op__, Op43, Op44, Op__, Op46, Op47, Op48, Op49, Op4A, Op__, Op4C, Op4D, Op__, Op4F,
1989 Op50, Op__, Op__, Op53, Op54, Op__, Op56, Op57, Op58, Op59, Op5A, Op__, Op5C, Op5D, Op__, Op5F,
1990 Op60, Op__, Op__, Op63, Op64, Op__, Op66, Op67, Op68, Op69, Op6A, Op__, Op6C, Op6D, Op6E, Op6F,
1991 Op70, Op__, Op__, Op73, Op74, Op__, Op76, Op77, Op78, Op79, Op7A, Op__, Op7C, Op7D, Op7E, Op7F,
1992 Op80, Op81, Op82, Op__, Op84, Op85, Op86, Op__, Op88, Op89, Op8A, Op8B, Op8C, Op8D, Op8E, Op__,
1993 Op90, Op91, Op92, Op__, Op94, Op95, Op96, Op97, Op98, Op99, Op9A, Op9B, Op9C, Op__, Op9E, Op9F,
1994 OpA0, OpA1, OpA2, Op__, OpA4, OpA5, OpA6, OpA7, OpA8, OpA9, OpAA, OpAB, OpAC, OpAD, OpAE, OpAF,
1995 OpB0, OpB1, OpB2, Op__, OpB4, OpB5, OpB6, OpB7, OpB8, OpB9, OpBA, OpBB, OpBC, OpBD, OpBE, OpBF,
1996 OpC0, OpC1, OpC2, Op__, OpC4, OpC5, OpC6, Op__, OpC8, OpC9, OpCA, OpCB, Op__, Op__, OpCE, Op__,
1997 OpD0, OpD1, OpD2, Op__, OpD4, OpD5, OpD6, OpD7, OpD8, OpD9, OpDA, OpDB, Op__, Op__, OpDE, OpDF,
1998 OpE0, OpE1, OpE2, Op__, OpE4, OpE5, OpE6, OpE7, OpE8, OpE9, OpEA, OpEB, Op__, Op__, OpEE, OpEF,
1999 OpF0, OpF1, OpF2, Op__, OpF4, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, OpFB, Op__, Op__, OpFE, OpFF
2004 // Internal "memcpy" (so we don't have to link with any external libraries!)
2006 static void myMemcpy(void * dst, void * src, uint32 size)
2008 uint8 * d = (uint8 *)dst, * s = (uint8 *)src;
2010 for(uint32 i=0; i<size; i++)
2015 //int instCount[256];
2016 static bool logGo = false;
2019 // Function to execute 6808 for "cycles" cycles
2021 void Execute6808(V6808REGS * context, uint32 cycles)
2023 #warning "V6808_STATE_WAI is not properly handled yet! !!! FIX !!!"
2024 #warning "Need to convert from destructive clock to non-destructive. !!! FIX !!!"
2026 myMemcpy(®s, context, sizeof(V6808REGS));
2027 UNPACK_FLAGS; // Explode flags register into individual uint8s
2030 while (regs.clock < cycles)
2034 Decode6808(regs.pc);
2036 uint8 opcode = regs.RdMem(regs.pc++);
2039 //if (!(regs.cpuFlags & V6808_STATE_ILLEGAL_INST))
2040 //instCount[opcode]++;
2043 exec_op[opcode](); // Execute that opcode...
2044 regs.clock += CPUCycles[opcode];
2047 // 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.a, regs.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" : " "));
2048 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.a, regs.b, (regs.cc & FLAG_E ? "E" : " "), (regs.cc & FLAG_F ? "F" : " "), (flagH ? "H" : " "), (flagI ? "I" : " "), (flagN ? "N" : " "), (flagZ ? "Z" : " "), (flagV ? "V" : " "), (flagC ? "C" : " "));
2051 if (regs.cpuFlags & V6808_ASSERT_LINE_RESET)
2054 WriteLog("*** RESET LINE ASSERTED ***\n");
2057 regs.pc = RdMemW(0xFFFE); // And load PC with the RESET vector
2059 context->cpuFlags &= ~V6808_ASSERT_LINE_RESET;
2060 regs.cpuFlags &= ~V6808_ASSERT_LINE_RESET;
2062 else if (regs.cpuFlags & V6808_ASSERT_LINE_NMI)
2065 WriteLog("*** NMI LINE ASSERTED ***\n");
2067 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2068 PUSH16(regs.pc); // Save all regs...
2073 regs.pc = RdMemW(0xFFFC); // And do it!
2075 #warning "# of clock cycles for NMI unknown. !!! FIX !!!"
2076 regs.clock += 0; // How many???
2077 context->cpuFlags &= ~V6808_ASSERT_LINE_NMI;// Reset the asserted line (NMI)...
2078 regs.cpuFlags &= ~V6808_ASSERT_LINE_NMI; // Reset the asserted line (NMI)...
2080 else if (regs.cpuFlags & V6808_ASSERT_LINE_IRQ)
2083 WriteLog("*** IRQ LINE ASSERTED ***\n");
2085 // if (!(regs.cc & FLAG_I)) // Process an interrupt (I=0)?
2086 if (!flagI) // Process an interrupt (I=0)?
2089 WriteLog(" IRQ TAKEN!\n");
2092 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2093 PUSH16(regs.pc); // Save all regs...
2098 regs.pc = RdMemW(0xFFF8); // And do it!
2100 #warning "# of clock cycles for IRQ unknown. !!! FIX !!!"
2101 regs.clock += 0; // How many???
2102 #warning "IRQ/NMI lines should not be cleared here... !!! FIX !!!"
2103 context->cpuFlags &= ~V6808_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
2104 regs.cpuFlags &= ~V6808_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
2109 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2110 myMemcpy(context, ®s, sizeof(V6808REGS));
2114 // Get the clock of the currently executing CPU
2116 uint64 GetCurrentV6808Clock(void)