2 // Virtual 6808 Emulator v2.1
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
17 // JLH 09/21/2009 Fixed EA_ABS macros
20 // NOTE: V6808_STATE_WAI is not handled in the main loop correctly. !!! FIX !!!
22 // Some random thoughts: Could there be a performance gain by breaking
23 // out the flags in regs.cc into separate uint8 variables (or bools)?
24 // You'd have to convert on entering and exiting the emulation loop, but I
25 // think the perfomance hit would be negligible compared to the gain in not
26 // having to mask and shift flags all the time. Investigate after the
27 // conversion to macro style opcodes is completed. :-)
28 // [DONE--remain to be seen if there is any performance increase]
31 #define TEST_DONT_BRANCH_OPTIMIZATION
42 #define CLR_Z (flagZ = 0)
43 #define CLR_ZN (flagZ = flagN = 0)
44 #define CLR_ZNC (flagZ = flagN = flagC = 0)
45 #define CLR_NVC (flagN = flagV = flagC = 0)
46 #define CLR_VC (flagV = flagC = 0)
47 #define CLR_V (flagV = 0)
48 #define CLR_N (flagN = 0)
49 #define SET_Z(r) (flagZ = ((r) == 0 ? 1 : 0))
50 #define SET_N(r) (flagN = ((r) & 0x80) >> 7)
51 #define SET_V(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x80) >> 7)
53 #define SET_C_CMP(a,b) (flagC = ((uint8)(b) < (uint8)(a) ? 1 : 0))
54 #define SET_ZN(r) SET_N(r); SET_Z(r)
55 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
56 #define SET_ZNVC_CMP(a,b,r) SET_N(r); SET_Z(r); SET_C_CMP(a,b); SET_V(a,b,r)
58 #define SET_N16(r) (flagN = ((r) & 0x8000) >> 15)
59 #define SET_V16(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x8000) >> 15)
60 #define SET_C_CMP16(a,b) (flagC = ((uint16)(b) < (uint16)(a) ? 1 : 0))
61 #define SET_ZNVC_CMP16(a,b,r) SET_N16(r); SET_Z(r); SET_C_CMP16(a,b); SET_V16(a,b,r)
63 #define EA_IMM regs.pc++
64 #define EA_ZP regs.RdMem(regs.pc++)
65 #define EA_ZP_X (regs.RdMem(regs.pc++) + regs.x)
66 #define EA_ABS FetchMemW(regs.pc)
68 #define READ_IMM regs.RdMem(EA_IMM)
69 #define READ_ZP regs.RdMem(EA_ZP)
70 #define READ_ZP_X regs.RdMem(EA_ZP_X)
71 #define READ_ABS regs.RdMem(EA_ABS)
73 #define READ_IMM16 FetchMemW(regs.pc);
74 #define READ_ZP16 RdMemW(EA_ZP)
75 #define READ_ZP_X16 RdMemW(EA_ZP_X)
76 #define READ_ABS16 RdMemW(EA_ABS)
78 #define READ_IMM_WB(v) uint16 addr = EA_IMM; v = regs.RdMem(addr)
79 #define READ_ZP_WB(v) uint16 addr = EA_ZP; v = regs.RdMem(addr)
80 #define READ_ZP_X_WB(v) uint16 addr = EA_ZP_X; v = regs.RdMem(addr)
81 #define READ_ABS_WB(v) uint16 addr = EA_ABS; v = regs.RdMem(addr)
83 #define WRITE_BACK(d) regs.WrMem(addr, (d))
85 #define PULL regs.RdMem(regs.s++)
86 #define PUSH(r) regs.WrMem(--regs.s, (r))
87 #define PULL16 RdMemW(regs.s); regs.s += 2
88 #define PUSH16(r) regs.WrMem(--regs.s, (r) & 0xFF); regs.WrMem(--regs.s, (r) >> 8)
90 #define PACK_FLAGS ((regs.cc & 0xC0) | (flagH << 5) | (flagI << 4) | (flagN << 3) | (flagZ << 2) | (flagV << 1) | flagC)
91 #define UNPACK_FLAGS flagH = (regs.cc & FLAG_H) >> 5; \
92 flagI = (regs.cc & FLAG_I) >> 4; \
93 flagN = (regs.cc & FLAG_N) >> 3; \
94 flagZ = (regs.cc & FLAG_Z) >> 2; \
95 flagV = (regs.cc & FLAG_V) >> 1; \
96 flagC = (regs.cc & FLAG_C)
98 // Private global variables
100 static V6808REGS regs;
101 static uint8 flagH, flagI, flagN, flagZ, flagV, flagC;
103 static uint8 CPUCycles[256] = {
104 1, 2, 1, 1, 1, 1, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2,
105 2, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 1, 1, 1, 1,
106 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
107 4, 4, 4, 4, 4, 4, 4, 4, 1, 5, 1, 10, 1, 1, 9, 12,
108 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2,
109 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2,
110 7, 1, 1, 8, 7, 1, 7, 7, 7, 7, 7, 1, 7, 7, 4, 7,
111 6, 1, 1, 7, 6, 1, 6, 6, 6, 6, 6, 1, 6, 6, 3, 6,
112 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 3, 8, 3, 1,
113 3, 3, 3, 1, 3, 3, 3, 4, 3, 3, 3, 3, 4, 1, 4, 5,
114 5, 5, 5, 1, 5, 5, 5, 6, 5, 5, 5, 5, 6, 8, 6, 7,
115 4, 4, 4, 1, 4, 4, 4, 5, 4, 4, 4, 4, 5, 9, 5, 6,
116 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 3, 1,
117 3, 3, 3, 1, 3, 3, 3, 4, 3, 3, 3, 3, 1, 1, 4, 5,
118 5, 5, 5, 1, 5, 5, 5, 6, 5, 5, 5, 5, 1, 1, 6, 7,
119 4, 4, 4, 1, 4, 4, 4, 5, 4, 4, 4, 4, 1, 1, 5, 6
122 // Private function prototypes
124 static uint16 RdMemW(uint16);
125 static uint16 FetchMemW(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 // Fetch a word out of 6808 memory (little endian format). Increments PC
138 static inline uint16 FetchMemW(uint16 address)
141 return (uint16)(regs.RdMem(address) << 8) | regs.RdMem(address + 1);
145 // 6808 OPCODE IMPLEMENTATION
147 // NOTE: Lots of macros are used here to save a LOT of typing. Also
148 // helps speed the debugging process. :-) Because of this, combining
149 // certain lines may look like a good idea but would end in disaster.
150 // You have been warned! ;-)
154 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
155 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
156 Add |ADDA |8B 2 2|9B 3 2|AB 5 2|BB 4 3| |A=A+M |T TTTT|
157 |ADDB |CB 2 2|DB 3 2|EB 5 2|FB 4 3| |B=B+M |T TTTT|
158 Add Accumulators |ABA | | | | |1B 2 1|A=A+B |T TTTT|
163 #define OP_ADD_HANDLER(m, acc) \
164 uint16 sum = (uint16)(acc) + (m); \
166 flagH = (sum >> 4) & 0x01; \
167 SET_V(m, acc, sum); \
168 (acc) = sum & 0xFF; \
171 static void Op8B(void) // ADDA #
174 OP_ADD_HANDLER(m, regs.a);
177 static void Op9B(void) // ADDA ZP
180 OP_ADD_HANDLER(m, regs.a);
183 static void OpAB(void) // ADDA ZP, X
185 uint16 m = READ_ZP_X;
186 OP_ADD_HANDLER(m, regs.a);
189 static void OpBB(void) // ADDA ABS
192 OP_ADD_HANDLER(m, regs.a);
195 static void OpCB(void) // ADDB #
198 OP_ADD_HANDLER(m, regs.b);
201 static void OpDB(void) // ADDB ZP
204 OP_ADD_HANDLER(m, regs.b);
207 static void OpEB(void) // ADDB ZP, X
209 uint16 m = READ_ZP_X;
210 OP_ADD_HANDLER(m, regs.b);
213 static void OpFB(void) // ADDB ABS
216 OP_ADD_HANDLER(m, regs.b);
219 static void Op1B(void) // ABA
221 OP_ADD_HANDLER(regs.b, regs.a);
225 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
226 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
227 Add with Carry |ADCA |89 2 2|99 3 2|A9 5 2|B9 4 3| |A=A+M+C |T TTTT|
228 |ADCB |C9 2 2|D9 3 2|E9 5 2|F9 4 3| |B=B+M+C |T TTTT|
233 #define OP_ADC_HANDLER(m, acc) \
234 uint16 sum = (uint16)acc + (m) + (uint16)flagC; \
236 flagH = (sum >> 4) & 0x01; \
237 SET_V(m, acc, sum); \
241 static void Op89(void) // ADCA #
244 OP_ADC_HANDLER(m, regs.a);
247 static void Op99(void) // ADCA ZP
250 OP_ADC_HANDLER(m, regs.a);
253 static void OpA9(void) // ADCA ZP, X
255 uint16 m = READ_ZP_X;
256 OP_ADC_HANDLER(m, regs.a);
259 static void OpB9(void) // ADCA ABS
262 OP_ADC_HANDLER(m, regs.a);
265 static void OpC9(void) // ADCB #
268 OP_ADC_HANDLER(m, regs.b);
271 static void OpD9(void) // ADCB ZP
274 OP_ADC_HANDLER(m, regs.b);
277 static void OpE9(void) // ADCB ZP, X
279 uint16 m = READ_ZP_X;
280 OP_ADC_HANDLER(m, regs.b);
283 static void OpF9(void) // ADCB ABS
286 OP_ADC_HANDLER(m, regs.b);
290 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
291 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
292 And |ANDA |84 2 2|94 3 2|A4 5 2|B4 4 3| |A=A+M | TTR |
293 |ANDB |C4 2 2|D4 3 2|E4 5 2|F4 4 3| |B=B+M | TTR |
298 #define OP_AND_HANDLER(m, acc) \
303 static void Op84(void) // ANDA #
306 OP_AND_HANDLER(m, regs.a);
309 static void Op94(void) // ANDA ZP
312 OP_AND_HANDLER(m, regs.a);
315 static void OpA4(void) // ANDA ZP, X
317 uint16 m = READ_ZP_X;
318 OP_AND_HANDLER(m, regs.a);
321 static void OpB4(void) // ANDA ABS
324 OP_AND_HANDLER(m, regs.a);
327 static void OpC4(void) // ANDB #
330 OP_AND_HANDLER(m, regs.b);
333 static void OpD4(void) // ANDB ZP
336 OP_AND_HANDLER(m, regs.b);
339 static void OpE4(void) // ANDB ZP, X
341 uint16 m = READ_ZP_X;
342 OP_AND_HANDLER(m, regs.b);
345 static void OpF4(void) // ANDB ABS
348 OP_AND_HANDLER(m, regs.b);
352 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
353 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
354 Bit Test |BITA |85 2 2|95 3 2|A5 5 2|B5 4 3| |A+M | TTR |
355 |BITB |C5 2 2|D5 3 2|E5 5 2|F5 4 3| |B+M | TTR |
360 #define OP_BIT_HANDLER(m, acc) \
361 int8 result = acc & (m); \
364 static void Op85(void) // BITA #
367 OP_BIT_HANDLER(m, regs.a);
370 static void Op95(void) // BITA ZP
373 OP_BIT_HANDLER(m, regs.a);
376 static void OpA5(void) // BITA ZP, X
379 OP_BIT_HANDLER(m, regs.a);
382 static void OpB5(void) // BITA ABS
385 OP_BIT_HANDLER(m, regs.a);
388 static void OpC5(void) // BITB #
391 OP_BIT_HANDLER(m, regs.b);
394 static void OpD5(void) // BITB ZP
397 OP_BIT_HANDLER(m, regs.b);
400 static void OpE5(void) // BITB ZP, X
403 OP_BIT_HANDLER(m, regs.b);
406 static void OpF5(void) // BITB ABS
409 OP_BIT_HANDLER(m, regs.b);
413 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
414 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
415 Clear |CLR | | |6F 7 2|7F 6 3| |M=00 | RSRR|
416 |CLRA | | | | |4F 2 1|A=00 | RSRR|
417 |CLRB | | | | |5F 2 1|B=00 | RSRR|
422 static void Op6F(void) // CLR ZP, X
424 regs.WrMem(EA_ZP_X, 0);
429 static void Op7F(void) // CLR ABS
431 regs.WrMem(EA_ABS, 0);
436 static void Op4F(void) // CLRA
443 static void Op5F(void) // CLRB
451 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
452 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
453 Compare |CMPA |81 2 2|91 3 2|A1 5 2|B1 4 3| |A-M | TTTT|
454 |CMPB |C1 2 2|D1 3 2|E1 5 2|F1 4 3| |B-M | TTTT|
455 Compare Accumulators |CBA | | | | |11 2 1|A-B | TTTT|
461 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.
464 #define OP_CMP_HANDLER(m, acc) \
465 uint16 result = acc - (m); \
466 SET_ZNVC_CMP(m, acc, result)
468 static void Op81(void) // CMPA #
471 OP_CMP_HANDLER(m, regs.a);
474 static void Op91(void) // CMPA ZP
477 OP_CMP_HANDLER(m, regs.a);
480 static void OpA1(void) // CMPA ZP, X
483 OP_CMP_HANDLER(m, regs.a);
486 static void OpB1(void) // CMPA ABS
489 OP_CMP_HANDLER(m, regs.a);
492 static void OpC1(void) // CMPB #
495 OP_CMP_HANDLER(m, regs.b);
498 static void OpD1(void) // CMPB ZP
501 OP_CMP_HANDLER(m, regs.b);
504 static void OpE1(void) // CMPB ZP, X
507 OP_CMP_HANDLER(m, regs.b);
510 static void OpF1(void) // CMPB ABS
513 OP_CMP_HANDLER(m, regs.b);
516 static void Op11(void) // CBA
518 OP_CMP_HANDLER(regs.b, regs.a);
522 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
523 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
524 Complement 1's |COM | | |63 7 2|73 6 3| |M=-M | TTRS|
525 |COMA | | | | |43 2 1|A=-A | TTRS|
526 |COMB | | | | |53 2 1|B=-B | TTRS|
531 #define OP_COM_HANDLER(m) \
537 static void Op63(void) // COM ZP, X
545 static void Op73(void) // COM ABS
553 static void Op43(void) // COMA
555 OP_COM_HANDLER(regs.a);
558 static void Op53(void) // COMB
560 OP_COM_HANDLER(regs.b);
564 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
565 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
566 Complement 2's |NEG | | |60 7 2|70 6 3| |M=00-M | TT12|
567 |NEGA | | | | |40 2 1|A=00-A | TT12|
568 |NEGB | | | | |50 2 1|B=00-B | TT12|
573 #define OP_NEG_HANDLER(m) \
576 flagV = (m == 0x80 ? 1 : 0); \
577 flagC = (m == 0x00 ? 1 : 0)
579 static void Op60(void) // NEG ZP, X
587 static void Op70(void) // NEG ABS
595 static void Op40(void) // NEGA
597 OP_NEG_HANDLER(regs.a);
600 static void Op50(void) // NEGB
602 OP_NEG_HANDLER(regs.b);
606 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
607 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
608 Decimal Adjust |DAA | | | | |19 2 1|* | TTT3|
611 static void Op19(void) // DAA
613 uint16 result = (uint16)regs.a;
615 if ((regs.a & 0x0F) > 0x09 || flagH)
618 if ((regs.a & 0xF0) > 0x90 || flagC || ((regs.a & 0xF0) > 0x80 && (regs.a & 0x0F) > 0x09))
621 regs.a = (uint8)result;
623 CLR_V; // Not sure this is correct...
624 flagC |= (result & 0x100) >> 8; // Overwrite carry if it was 0, otherwise, ignore
628 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
629 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
630 Decrement |DEC | | |6A 7 2|7A 6 3| |M=M-1 | TT4 |
631 |DECA | | | | |4A 2 1|A=A-1 | TT4 |
632 |DECB | | | | |5A 2 1|B=B-1 | TT4 |
637 #define OP_DEC_HANDLER(m) \
640 flagV = (m == 0x7F ? 1 : 0)
642 static void Op6A(void) // DEC ZP, X
650 static void Op7A(void) // DEC ABS
658 static void Op4A(void) // DECA
660 OP_DEC_HANDLER(regs.a);
663 static void Op5A(void) // DECB
665 OP_DEC_HANDLER(regs.b);
669 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
670 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
671 Exclusive OR |EORA |88 2 2|98 3 2|A8 5 2|B8 4 3| |A=A(+)M | TTR |
672 |EORB |C8 2 2|D8 3 2|E8 5 2|F8 4 3| |B=B(+)M | TTR |
677 #define OP_EOR_HANDLER(m, acc) \
682 static void Op88(void) // EORA #
685 OP_EOR_HANDLER(m, regs.a);
688 static void Op98(void) // EORA ZP
691 OP_EOR_HANDLER(m, regs.a);
694 static void OpA8(void) // EORA ZP, X
697 OP_EOR_HANDLER(m, regs.a);
700 static void OpB8(void) // EORA ABS
703 OP_EOR_HANDLER(m, regs.a);
706 static void OpC8(void) // EORB #
709 OP_EOR_HANDLER(m, regs.b);
712 static void OpD8(void) // EORB ZP
715 OP_EOR_HANDLER(m, regs.b);
718 static void OpE8(void) // EORB ZP, X
721 OP_EOR_HANDLER(m, regs.b);
724 static void OpF8(void) // EORB ABS
727 OP_EOR_HANDLER(m, regs.b);
731 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
732 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
733 Increment |INC | | |6C 7 2|7C 6 3| |M=M+1 | TT5 |
734 |INCA | | | | |4C 2 1|A=A+1 | TT5 |
735 |INCB | | | | |5C 2 1|B=B+1 | TT5 |
740 #define OP_INC_HANDLER(m) \
743 flagV = (m == 0x80 ? 1 : 0)
745 static void Op6C(void) // INC ZP, X
753 static void Op7C(void) // INC ABS
761 static void Op4C(void) // INCA
763 OP_INC_HANDLER(regs.a);
766 static void Op5C(void) // INCB
768 OP_INC_HANDLER(regs.b);
772 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
773 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
774 Load Accumulator |LDAA |86 2 2|96 3 2|A6 5 2|B6 4 3| |A=M | TTR |
775 |LDAB |C6 2 2|D6 3 2|E6 5 2|F6 4 3| |B=M | TTR |
780 #define OP_LDA_HANDLER(m, acc) \
785 static void Op86(void) // LDAA #
788 OP_LDA_HANDLER(m, regs.a);
791 static void Op96(void) // LDAA ZP
794 OP_LDA_HANDLER(m, regs.a);
797 static void OpA6(void) // LDAA ZP, X
800 OP_LDA_HANDLER(m, regs.a);
803 static void OpB6(void) // LDAA ABS
806 OP_LDA_HANDLER(m, regs.a);
809 static void OpC6(void) // LDAB #
812 OP_LDA_HANDLER(m, regs.b);
815 static void OpD6(void) // LDAB ZP
818 OP_LDA_HANDLER(m, regs.b);
821 static void OpE6(void) // LDAB ZP, X
824 OP_LDA_HANDLER(m, regs.b);
827 static void OpF6(void) // LDAB ABS
830 OP_LDA_HANDLER(m, regs.b);
834 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
835 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
836 OR, Inclusive |ORAA |8A 2 2|9A 3 2|AA 5 2|BA 4 3| |A=A+M | TTR |
837 |ORAB |CA 2 2|DA 3 2|EA 5 2|FA 4 3| |B=B+M | TTR |
842 #define OP_ORA_HANDLER(m, acc) \
847 static void Op8A(void) // ORAA #
850 OP_ORA_HANDLER(m, regs.a);
853 static void Op9A(void) // ORAA ZP
856 OP_ORA_HANDLER(m, regs.a);
859 static void OpAA(void) // ORAA ZP, X
862 OP_ORA_HANDLER(m, regs.a);
865 static void OpBA(void) // ORAA ABS
868 OP_ORA_HANDLER(m, regs.a);
871 static void OpCA(void) // ORAB #
874 OP_ORA_HANDLER(m, regs.b);
877 static void OpDA(void) // ORAB ZP
880 OP_ORA_HANDLER(m, regs.b);
883 static void OpEA(void) // ORAB ZP, X
886 OP_ORA_HANDLER(m, regs.b);
889 static void OpFA(void) // ORAB ABS
892 OP_ORA_HANDLER(m, regs.b);
896 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
897 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
898 Push Data |PSHA | | | | |36 4 1|Msp=A, *- | |
899 |PSHB | | | | |37 4 1|Msp=B, *- | |
900 Pull Data |PULA | | | | |32 4 1|A=Msp, *+ | |
901 |PULB | | | | |33 4 1|B=Msp, *+ | |
904 static void Op36(void) // PSHA
909 static void Op37(void) // PSHB
914 static void Op32(void) // PULA
919 static void Op33(void) // PULB
925 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
926 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
927 Rotate Left |ROL | | |69 7 2|79 6 3| |Memory *1| TT6T|
928 |ROLA | | | | |49 2 1|Accum A *1| TT6T|
929 |ROLB | | | | |59 2 1|Accum B *1| TT6T|
934 #define OP_ROL_HANDLER(m) \
935 uint8 newCarry = (m & 0x80) >> 7; \
936 m = (m << 1) | flagC; \
939 flagV = flagN ^ flagC
941 static void Op69(void) // ROL ZP, X
949 static void Op79(void) // ROL ABS
957 static void Op49(void) // ROLA
959 OP_ROL_HANDLER(regs.a);
962 static void Op59(void) // ROLB
964 OP_ROL_HANDLER(regs.b);
968 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
969 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
970 Rotate Right |ROR | | |66 7 2|76 6 3| |Memory *2| TT6T|
971 |RORA | | | | |46 2 1|Accum A *2| TT6T|
972 |RORB | | | | |56 2 1|Accum B *2| TT6T|
977 #define OP_ROR_HANDLER(m) \
978 uint8 newCarry = m & 0x01; \
979 m = (m >> 1) | (flagC << 7); \
982 flagV = flagN ^ flagC
984 static void Op66(void) // ROR ZP, X
992 static void Op76(void) // ROR ABS
1000 static void Op46(void) // RORA
1002 OP_ROR_HANDLER(regs.a);
1005 static void Op56(void) // RORB
1007 OP_ROR_HANDLER(regs.b);
1011 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1012 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1013 Arithmetic Shift Left |ASL | | |68 7 2|78 6 3| |Memory *3| TT6T|
1014 |ASLA | | | | |48 2 1|Accum A *3| TT6T|
1015 |ASLB | | | | |58 2 1|Accum B *3| TT6T|
1020 #define OP_ASL_HANDLER(m) \
1021 uint8 newCarry = (m & 0x80) >> 7; \
1025 flagV = flagN ^ flagC
1027 static void Op68(void) // ASL ZP, X
1035 static void Op78(void) // ASL ABS
1043 static void Op48(void) // ASLA
1045 OP_ASL_HANDLER(regs.a);
1048 static void Op58(void) // ASLB
1050 OP_ASL_HANDLER(regs.b);
1054 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1055 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1056 Arithmetic Shift Right |ASR | | |67 7 2|77 6 3| |Memory *4| TT6T|
1057 |ASRA | | | | |47 2 1|Accum A *4| TT6T|
1058 |ASRB | | | | |57 2 1|Accum B *4| TT6T|
1063 #define OP_ASR_HANDLER(m) \
1064 uint8 newCarry = m & 0x01; \
1065 m = (m >> 1) | (m & 0x80); \
1068 flagV = flagN ^ flagC
1070 static void Op67(void) // ASR ZP, X
1078 static void Op77(void) // ASR ABS
1086 static void Op47(void) // ASRA
1088 OP_ASR_HANDLER(regs.a);
1091 static void Op57(void) // ASRB
1093 OP_ASR_HANDLER(regs.b);
1097 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1098 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1099 Logic Shift Right |LSR | | |64 7 2|74 6 3| |Memory *5| TT6T|
1100 |LSRA | | | | |44 2 1|Accum A *5| TT6T|
1101 |LSRB | | | | |54 2 1|Accum B *5| TT6T|
1106 #define OP_LSR_HANDLER(m) \
1107 uint8 newCarry = m & 0x01; \
1111 flagV = flagN ^ flagC
1113 static void Op64(void) // LSR ZP, X
1121 static void Op74(void) // LSR ABS
1129 static void Op44(void) // LSRA
1131 OP_LSR_HANDLER(regs.a);
1134 static void Op54(void) // LSRB
1136 OP_LSR_HANDLER(regs.b);
1140 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1141 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1142 Store Accumulator |STAA | |97 4 2|A7 6 2|B7 5 3| |M=A | TTR |
1143 |STAB | |D7 4 2|E7 6 2|F7 5 3| |M=B | TTR |
1146 static void Op97(void) // STAA ZP
1148 regs.WrMem(EA_ZP, regs.a);
1151 static void OpA7(void) // STAA ZP, X
1153 regs.WrMem(EA_ZP_X, regs.a);
1156 static void OpB7(void) // STAA ABS
1158 regs.WrMem(EA_ABS, regs.a);
1161 static void OpD7(void) // STAB ZP
1163 regs.WrMem(EA_ZP, regs.b);
1166 static void OpE7(void) // STAB ZP, X
1168 regs.WrMem(EA_ZP_X, regs.b);
1171 static void OpF7(void) // STAB ABS
1173 regs.WrMem(EA_ABS, regs.b);
1177 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1178 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1179 Subtract |SUBA |80 2 2|90 3 2|A0 5 2|B0 4 3| |A=A-M | TTTT|
1180 |SUBB |C0 2 2|D0 3 2|E0 5 2|F0 4 3| |B=B-M | TTTT|
1181 Subtract Accumulators |SBA | | | | |10 2 1|A=A-B | TTTT|
1186 #define OP_SUB_HANDLER(m, acc) \
1187 uint16 sum = (uint16)acc - (m); \
1188 flagC = sum >> 15; \
1189 SET_V(m, acc, sum); \
1193 static void Op80(void) // SUBA #
1195 uint16 m = READ_IMM;
1196 OP_SUB_HANDLER(m, regs.a);
1199 static void Op90(void) // SUBA ZP
1202 OP_SUB_HANDLER(m, regs.a);
1205 static void OpA0(void) // SUBA ZP, X
1207 uint16 m = READ_ZP_X;
1208 OP_SUB_HANDLER(m, regs.a);
1211 static void OpB0(void) // SUBA ABS
1213 uint16 m = READ_ABS;
1214 OP_SUB_HANDLER(m, regs.a);
1217 static void OpC0(void) // SUBB #
1219 uint16 m = READ_IMM;
1220 OP_SUB_HANDLER(m, regs.b);
1223 static void OpD0(void) // SUBB ZP
1226 OP_SUB_HANDLER(m, regs.b);
1229 static void OpE0(void) // SUBB ZP, X
1231 uint16 m = READ_ZP_X;
1232 OP_SUB_HANDLER(m, regs.b);
1235 static void OpF0(void) // SUBB ABS
1237 uint16 m = READ_ABS;
1238 OP_SUB_HANDLER(m, regs.b);
1241 static void Op10(void) // SBA
1243 OP_SUB_HANDLER(regs.b, regs.a);
1247 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1248 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1249 Subtract with Carry |SBCA |82 2 2|92 3 2|A2 5 2|B2 4 3| |A=A-M-C | TTTT|
1250 |SBCB |C2 2 2|D2 3 2|E2 5 2|F2 4 3| |B=B-M-C | TTTT|
1255 #define OP_SBC_HANDLER(m, acc) \
1256 uint16 sum = (uint16)acc - (m) - (uint16)flagC; \
1257 flagC = sum >> 15; \
1258 SET_V(m, acc, sum); \
1262 static void Op82(void) // SBCA #
1264 uint16 m = READ_IMM;
1265 OP_SBC_HANDLER(m, regs.a);
1268 static void Op92(void) // SBCA ZP
1271 OP_SBC_HANDLER(m, regs.a);
1274 static void OpA2(void) // SBCA ZP, X
1276 uint16 m = READ_ZP_X;
1277 OP_SBC_HANDLER(m, regs.a);
1280 static void OpB2(void) // SBCA ABS
1282 uint16 m = READ_ABS;
1283 OP_SBC_HANDLER(m, regs.a);
1286 static void OpC2(void) // SBCB #
1288 uint16 m = READ_IMM;
1289 OP_SBC_HANDLER(m, regs.b);
1292 static void OpD2(void) // SBCB ZP
1295 OP_SBC_HANDLER(m, regs.b);
1298 static void OpE2(void) // SBCB ZP, X
1300 uint16 m = READ_ZP_X;
1301 OP_SBC_HANDLER(m, regs.b);
1304 static void OpF2(void) // SBCB ABS
1306 uint16 m = READ_ABS;
1307 OP_SBC_HANDLER(m, regs.b);
1311 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1312 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1313 Transfer Accumulators |TAB | | | | |16 2 1|B=A | TTR |
1314 |TBA | | | | |17 2 1|A=B | TTR |
1317 static void Op16(void) // TAB
1324 static void Op17(void) // TBA
1332 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1333 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1334 Test, Zero/Minus |TST | | |6D 7 2|7D 6 3| |M-00 | TTRR|
1335 |TSTA | | | | |4D 2 1|A-00 | TTRR|
1336 |TSTB | | | | |5D 2 1|B-00 | TTRR|
1341 #define OP_TST_HANDLER(m) \
1345 static void Op6D(void) // TST ZP, X
1353 static void Op7D(void) // TST ABS
1361 static void Op4D(void) // TSTA
1363 OP_TST_HANDLER(regs.a);
1366 static void Op5D(void) // TSTB
1368 OP_TST_HANDLER(regs.b);
1372 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1373 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1374 Compare Index Register |CPX |8C 3 3|9C 4 2|AC 6 2|BC 5 3| |Formula 1 | 7T8 |
1380 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.
1383 #define OP_CPX_HANDLER(m) \
1384 uint32 result = regs.x - (m); \
1385 SET_ZNVC_CMP16(m, regs.x, result)
1387 static void Op8C(void) // CPX #
1389 uint16 m = READ_IMM16;
1393 static void Op9C(void) // CPX ZP
1395 uint16 m = READ_ZP16;
1399 static void OpAC(void) // CPX ZP, X
1401 uint16 m = READ_ZP_X16;
1405 static void OpBC(void) // CPX ABS
1407 uint16 m = READ_ABS16;
1412 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1413 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1414 Decrement Index Register|DEX | | | | |09 4 1|X=X-1 | T |
1415 Dec Stack Pointer |DES | | | | |34 4 1|SP=SP-1 | |
1416 Inc Index Regster |INX | | | | |08 4 1|X=X+1 | T |
1417 Inc Stack Pointer |INS | | | | |31 4 1|SP=SP+1 | |
1420 static void Op09(void) // DEX
1426 static void Op34(void) // DES
1431 static void Op08(void) // INX
1437 static void Op31(void) // INS
1443 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1444 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1445 Load Index Register |LDX |CE 3 3|DE 4 2|EE 6 2|FE 5 3| |Formula 2 | 9TR |
1446 Load Stack Pointer |LDS |8E 3 3|9E 4 2|AE 6 2|BE 5 3| |Formula 3 | 9TR |
1449 // LD* opcode handler
1451 #define OP_LD_HANDLER(acc) \
1456 static void OpCE(void) // LDX #
1458 regs.x = READ_IMM16;
1459 OP_LD_HANDLER(regs.x);
1462 static void OpDE(void) // LDX ZP
1465 OP_LD_HANDLER(regs.x);
1468 static void OpEE(void) // LDX ZP, X
1470 regs.x = READ_ZP_X16;
1471 OP_LD_HANDLER(regs.x);
1474 static void OpFE(void) // LDX ABS
1476 regs.x = READ_ABS16;
1477 OP_LD_HANDLER(regs.x);
1480 static void Op8E(void) // LDS #
1482 regs.s = READ_IMM16;
1483 OP_LD_HANDLER(regs.s);
1486 static void Op9E(void) // LDS ZP
1489 OP_LD_HANDLER(regs.s);
1492 static void OpAE(void) // LDS ZP, X
1494 regs.s = READ_ZP_X16;
1495 OP_LD_HANDLER(regs.s);
1498 static void OpBE(void) // LDS ABS
1500 regs.s = READ_ABS16;
1501 OP_LD_HANDLER(regs.s);
1505 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1506 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1507 Store Index Register |STX | |DF 5 2|EF 7 2|FF 6 3| |Formula 4 | 9TR |
1508 Store Stack Pointer |STS | |9F 5 2|AF 7 2|BF 6 3| |Formula 5 | 9TR |
1511 // ST* opcode handler
1513 #define OP_ST_HANDLER(m, acc) \
1514 regs.WrMem(m + 0, acc >> 8); \
1515 regs.WrMem(m + 1, acc & 0xFF); \
1520 static void OpDF(void) // STX ZP
1523 OP_ST_HANDLER(m, regs.x);
1526 static void OpEF(void) // STX ZP, X
1529 OP_ST_HANDLER(m, regs.x);
1532 static void OpFF(void) // STX ABS
1535 OP_ST_HANDLER(m, regs.x);
1538 static void Op9F(void) // STS ZP
1541 OP_ST_HANDLER(m, regs.s);
1544 static void OpAF(void) // STS ZP, X
1547 OP_ST_HANDLER(m, regs.s);
1550 static void OpBF(void) // STS ABS
1553 OP_ST_HANDLER(m, regs.s);
1557 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1558 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1559 Index Reg > Stack Pnter |TXS | | | | |35 4 1|SP=X-1 | |
1560 Stack Ptr > Index Regtr |TSX | | | | |30 4 1|X=SP+1 | |
1563 static void Op35(void) // TXS
1565 regs.s = regs.x - 1;
1568 static void Op30(void) // TSX
1570 regs.x = regs.s + 1;
1574 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1575 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1576 Always |BRA | |20 4 2| | | |none | |
1577 Carry is Clear |BCC | |24 4 2| | | |C=0 | |
1578 Carry is Set |BCS | |25 4 2| | | |C=1 | |
1579 Equals Zero |BEQ | |27 4 2| | | |Z=1 | |
1580 Greater or Equal to Zero|BGE | |2C 4 2| | | |N(+)V=0 | |
1581 Greater than Zero |BGT | |2E 4 2| | | |Z+N(+)V=0 | |
1582 Higher |BHI | |22 4 2| | | |C+Z=0 | |
1583 Less or Equal than Zero |BLE | |2F 4 2| | | |Z+N(+)V=1 | |
1584 Lower or Same |BLS | |23 4 2| | | |C+Z=1 | |
1585 Less Than Zero |BLT | |2D 4 2| | | |N(+)V=1 | |
1586 Minus |BMI | |2B 4 2| | | |N=1 | |
1587 Not Zero |BNE | |26 4 2| | | |Z=0 | |
1588 Overflow Clear |BVC | |28 4 2| | | |V=0 | |
1589 Overflow Set |BVS | |29 4 2| | | |V=1 | |
1590 Plus |BPL | |2A 4 2| | | |N=0 | |
1593 static void Op20(void) // BRA
1595 int16 m = (int16)(int8)READ_IMM;
1599 static void Op24(void) // BCC
1601 // NOTE: We can optimize this by following the maxim: "Don't branch!" by converting the boolean
1602 // result into a multiplication. The only way to know if this is a win is to do some profiling
1603 // both with and without the optimization.
1604 int16 m = (int16)(int8)READ_IMM;
1606 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1607 //Note sure if the ! operator will do what we want, so we use ^ 1
1608 regs.pc += m * (flagC ^ 0x01);
1615 static void Op25(void) // BCS
1617 int16 m = (int16)(int8)READ_IMM;
1619 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1620 regs.pc += m * (flagC);
1627 static void Op27(void) // BEQ
1629 int16 m = (int16)(int8)READ_IMM;
1631 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1632 regs.pc += m * (flagZ);
1639 static void Op2C(void) // BGE
1641 int16 m = (int16)(int8)READ_IMM;
1643 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1644 regs.pc += m * ((flagN ^ flagV) ^ 0x01);
1646 if (!(flagN ^ flagV))
1651 static void Op2E(void) // BGT
1653 int16 m = (int16)(int8)READ_IMM;
1655 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1656 regs.pc += m * ((flagZ | (flagN ^ flagV)) ^ 0x01);
1658 if (!(flagZ | (flagN ^ flagV)))
1663 static void Op22(void) // BHI
1665 int16 m = (int16)(int8)READ_IMM;
1667 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1668 regs.pc += m * ((flagZ | flagC) ^ 0x01);
1670 if (!(flagZ | flagC))
1675 static void Op2F(void) // BLE
1677 int16 m = (int16)(int8)READ_IMM;
1679 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1680 regs.pc += m * (flagZ | (flagN ^ flagV));
1682 if (flagZ | (flagN ^ flagV))
1687 static void Op23(void) // BLS
1689 int16 m = (int16)(int8)READ_IMM;
1691 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1692 regs.pc += m * (flagZ | flagC);
1699 static void Op2D(void) // BLT
1701 int16 m = (int16)(int8)READ_IMM;
1703 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1704 regs.pc += m * (flagN ^ flagV);
1711 static void Op2B(void) // BMI
1713 int16 m = (int16)(int8)READ_IMM;
1715 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1716 regs.pc += m * (flagN);
1723 static void Op26(void) // BNE
1725 int16 m = (int16)(int8)READ_IMM;
1727 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1728 regs.pc += m * (flagZ ^ 0x01);
1735 static void Op28(void) // BVC
1737 int16 m = (int16)(int8)READ_IMM;
1739 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1740 regs.pc += m * (flagV ^ 0x01);
1747 static void Op29(void) // BVS
1749 int16 m = (int16)(int8)READ_IMM;
1751 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1752 regs.pc += m * (flagV);
1759 static void Op2A(void) // BPL
1761 int16 m = (int16)(int8)READ_IMM;
1763 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1764 regs.pc += m * (flagN ^ 0x01);
1772 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1773 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1774 Branch to Subroutine |BSR | |8D 8 2| | | | | |
1775 Jump |JMP | | |6E 4 2|7E 3 3| | | |
1776 Jump to Subroutine |JSR | | |AD 8 2|BD 9 3| | | |
1779 static void Op8D(void) // BSR
1781 int16 m = (int16)(int8)READ_IMM;
1786 static void Op6E(void) // JMP ZP, X
1791 static void Op7E(void) // JMP ABS
1796 static void OpAD(void) // JSR ZP, X
1803 static void OpBD(void) // JSR ABS
1811 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1812 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1813 No Operation |NOP | | | | |01 2 1| | |
1814 Return from Interrupt |RTI | | | | |3B A 1| |AAAAAA|
1815 Return from Subroutine |RTS | | | | |39 5 1| | |
1816 Software Interrupt |SWI | | | | |3F C 1| | S |
1817 Wait For Interrupt |WAI | | | | |3E 9 1| | B |
1820 static void Op01(void) // NOP
1824 static void Op3B(void) // RTI
1834 static void Op39(void) // RTS
1839 static void Op3F(void) // SWI
1841 // It seems that the SWI is non-maskable, unlike the IRQ...
1842 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
1843 PUSH16(regs.pc); // Save all regs...
1848 regs.pc = RdMemW(0xFFFA); // And do it!
1849 flagI = 1; // Also, set IRQ inhibit
1852 static void Op3E(void) // WAI
1855 WriteLog("*** WAI STATE ASSERTED ***\n");
1857 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
1858 PUSH16(regs.pc); // Save all regs...
1863 regs.cpuFlags |= V6808_STATE_WAI; // And signal that we're in WAI mode
1867 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1868 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1869 Clear Carry |CLC | | | | |0C 2 1|C=0 | R|
1870 Clear Interrupt |CLI | | | | |0E 2 1|I=0 | R |
1871 Clear Overflow |CLV | | | | |0A 2 1|V=0 | R |
1872 Set Carry |SEC | | | | |0D 2 1|C=1 | S|
1873 Set Interrupt |SEI | | | | |0F 2 1|I=1 | S |
1874 Set Overflow |SEV | | | | |0B 2 1|V=1 | S |
1875 CCR=Accumulator A |TAP | | | | |06 2 1|CCR=A |CCCCCC|
1876 Accumlator A=CCR |TPA | | | | |07 2 1|A=CCR | |
1879 static void Op0C(void) // CLC
1884 static void Op0E(void) // CLI
1889 static void Op0A(void) // CLV
1894 static void Op0D(void) // SEC
1899 static void Op0F(void) // SEI
1904 static void Op0B(void) // SEV
1909 static void Op06(void) // TAP
1915 static void Op07(void) // TPA
1917 regs.a = PACK_FLAGS;
1921 OP Operation Code, in Hexadecimal
1922 ~ Number of MPU cycles required
1923 # Number of program bytes required
1927 Msp Contents of Memory pointed to be Stack Pointer
1928 + Boolean Inclusive OR
1929 (+) Boolean Exclusive OR (XOR)
1930 * Converts Binary Addition of BCD Characters into BCD Format
1934 Condition Code Register Legend
1938 T Tests and sets if True, cleared otherise
1939 1 Test: Result=10000000?
1940 2 Test: Result=00000000?
1941 3 Test: Decimal value of most significant BCD character greater than nine?
1942 (Not cleared if previously set)
1943 4 Test: Operand=10000000 prior to execution?
1944 5 Test: Operand=01111111 prior to execution?
1945 6 Test: Set equal to result or N(+)C after shift has occurred.
1946 7 Test: Sign bit of most significant byte or result=1?
1947 8 Test: 2's compliment overflow from subtraction of least
1949 9 Test: Result less than zero? (Bit 15=1)
1950 A Load Condition Code Register from Stack.
1951 B Set when interrupt occurs. If previously set, a NMI is
1952 required to exit the wait state.
1953 C Set according to the contents of Accumulator A.
1955 *x SHIFT AND ROTATION DIAGRAMS
1956 *1 +-----------------+ C to LSB
1959 *2 +-----------------+
1962 *3 C <- 76543210 <- 0(Data)
1967 *5 (Data)0 -> 76543210 -> C
1976 static void Op__(void)
1978 regs.cpuFlags |= V6808_STATE_ILLEGAL_INST;
1983 // Ok, the exec_op[] array is globally defined here basically to save
1984 // a LOT of unnecessary typing. Sure it's ugly, but hey, it works!
1986 void (* exec_op[256])() = {
1987 Op__, Op01, Op__, Op__, Op__, Op__, Op06, Op07, Op08, Op09, Op0A, Op0B, Op0C, Op0D, Op0E, Op0F,
1988 Op10, Op11, Op__, Op__, Op__, Op__, Op16, Op17, Op__, Op19, Op__, Op1B, Op__, Op__, Op__, Op__,
1989 Op20, Op__, Op22, Op23, Op24, Op25, Op26, Op27, Op28, Op29, Op2A, Op2B, Op2C, Op2D, Op2E, Op2F,
1990 Op30, Op31, Op32, Op33, Op34, Op35, Op36, Op37, Op__, Op39, Op__, Op3B, Op__, Op__, Op3E, Op3F,
1991 Op40, Op__, Op__, Op43, Op44, Op__, Op46, Op47, Op48, Op49, Op4A, Op__, Op4C, Op4D, Op__, Op4F,
1992 Op50, Op__, Op__, Op53, Op54, Op__, Op56, Op57, Op58, Op59, Op5A, Op__, Op5C, Op5D, Op__, Op5F,
1993 Op60, Op__, Op__, Op63, Op64, Op__, Op66, Op67, Op68, Op69, Op6A, Op__, Op6C, Op6D, Op6E, Op6F,
1994 Op70, Op__, Op__, Op73, Op74, Op__, Op76, Op77, Op78, Op79, Op7A, Op__, Op7C, Op7D, Op7E, Op7F,
1995 Op80, Op81, Op82, Op__, Op84, Op85, Op86, Op__, Op88, Op89, Op8A, Op8B, Op8C, Op8D, Op8E, Op__,
1996 Op90, Op91, Op92, Op__, Op94, Op95, Op96, Op97, Op98, Op99, Op9A, Op9B, Op9C, Op__, Op9E, Op9F,
1997 OpA0, OpA1, OpA2, Op__, OpA4, OpA5, OpA6, OpA7, OpA8, OpA9, OpAA, OpAB, OpAC, OpAD, OpAE, OpAF,
1998 OpB0, OpB1, OpB2, Op__, OpB4, OpB5, OpB6, OpB7, OpB8, OpB9, OpBA, OpBB, OpBC, OpBD, OpBE, OpBF,
1999 OpC0, OpC1, OpC2, Op__, OpC4, OpC5, OpC6, Op__, OpC8, OpC9, OpCA, OpCB, Op__, Op__, OpCE, Op__,
2000 OpD0, OpD1, OpD2, Op__, OpD4, OpD5, OpD6, OpD7, OpD8, OpD9, OpDA, OpDB, Op__, Op__, OpDE, OpDF,
2001 OpE0, OpE1, OpE2, Op__, OpE4, OpE5, OpE6, OpE7, OpE8, OpE9, OpEA, OpEB, Op__, Op__, OpEE, OpEF,
2002 OpF0, OpF1, OpF2, Op__, OpF4, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, OpFB, Op__, Op__, OpFE, OpFF
2007 // Internal "memcpy" (so we don't have to link with any external libraries!)
2009 static void myMemcpy(void * dst, void * src, uint32 size)
2011 uint8 * d = (uint8 *)dst, * s = (uint8 *)src;
2013 for(uint32 i=0; i<size; i++)
2018 //int instCount[256];
2019 static bool logGo = false;
2022 // Function to execute 6808 for "cycles" cycles
2024 void Execute6808(V6808REGS * context, uint32 cycles)
2026 #warning "V6808_STATE_WAI is not properly handled yet! !!! FIX !!!"
2027 #warning "Need to convert from destructive clock to non-destructive. !!! FIX !!!"
2029 myMemcpy(®s, context, sizeof(V6808REGS));
2030 UNPACK_FLAGS; // Explode flags register into individual uint8s
2033 while (regs.clock < cycles)
2037 Decode6808(regs.pc);
2039 uint8 opcode = regs.RdMem(regs.pc++);
2042 //if (!(regs.cpuFlags & V6808_STATE_ILLEGAL_INST))
2043 //instCount[opcode]++;
2046 exec_op[opcode](); // Execute that opcode...
2047 regs.clock += CPUCycles[opcode];
2050 // 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" : " "));
2051 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" : " "));
2054 if (regs.cpuFlags & V6808_ASSERT_LINE_RESET)
2057 WriteLog("*** RESET LINE ASSERTED ***\n");
2060 regs.pc = RdMemW(0xFFFE); // And load PC with the RESET vector
2062 context->cpuFlags &= ~V6808_ASSERT_LINE_RESET;
2063 regs.cpuFlags &= ~V6808_ASSERT_LINE_RESET;
2065 else if (regs.cpuFlags & V6808_ASSERT_LINE_NMI)
2068 WriteLog("*** NMI LINE ASSERTED ***\n");
2070 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2071 PUSH16(regs.pc); // Save all regs...
2076 regs.pc = RdMemW(0xFFFC); // And do it!
2078 #warning "# of clock cycles for NMI unknown. !!! FIX !!!"
2079 regs.clock += 0; // How many???
2080 context->cpuFlags &= ~V6808_ASSERT_LINE_NMI;// Reset the asserted line (NMI)...
2081 regs.cpuFlags &= ~V6808_ASSERT_LINE_NMI; // Reset the asserted line (NMI)...
2083 else if (regs.cpuFlags & V6808_ASSERT_LINE_IRQ)
2086 WriteLog("*** IRQ LINE ASSERTED ***\n");
2088 // if (!(regs.cc & FLAG_I)) // Process an interrupt (I=0)?
2089 if (!flagI) // Process an interrupt (I=0)?
2092 WriteLog(" IRQ TAKEN!\n");
2095 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2096 PUSH16(regs.pc); // Save all regs...
2101 regs.pc = RdMemW(0xFFF8); // And do it!
2103 #warning "# of clock cycles for IRQ unknown. !!! FIX !!!"
2104 regs.clock += 0; // How many???
2105 #warning "IRQ/NMI lines should not be cleared here... !!! FIX !!!"
2106 context->cpuFlags &= ~V6808_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
2107 regs.cpuFlags &= ~V6808_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
2112 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2113 myMemcpy(context, ®s, sizeof(V6808REGS));
2117 // Get the clock of the currently executing CPU
2119 uint64 GetCurrentV6808Clock(void)