2 // Virtual 6808 Emulator v2.1
5 // (C) 2006 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
20 // NOTE: V6808_STATE_WAI is not handled in the main loop correctly. !!! FIX !!!
22 #define TEST_DONT_BRANCH_OPTIMIZATION
33 #define CLR_Z (flagZ = 0)
34 #define CLR_ZN (flagZ = flagN = 0)
35 #define CLR_ZNC (flagZ = flagN = flagC = 0)
36 #define CLR_NVC (flagN = flagV = flagC = 0)
37 #define CLR_VC (flagV = flagC = 0)
38 #define CLR_V (flagV = 0)
39 #define CLR_N (flagN = 0)
40 #define SET_Z(r) (flagZ = ((r) == 0 ? 1 : 0))
41 #define SET_N(r) (flagN = ((r) & 0x80) >> 7)
42 #define SET_V(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x80) >> 7)
44 #define SET_C_CMP(a,b) (flagC = ((uint8_t)(b) < (uint8_t)(a) ? 1 : 0))
45 #define SET_ZN(r) SET_N(r); SET_Z(r)
46 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
47 #define SET_ZNVC_CMP(a,b,r) SET_N(r); SET_Z(r); SET_C_CMP(a,b); SET_V(a,b,r)
49 #define SET_N16(r) (flagN = ((r) & 0x8000) >> 15)
50 #define SET_V16(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x8000) >> 15)
51 #define SET_C_CMP16(a,b) (flagC = ((uint16_t)(b) < (uint16_t)(a) ? 1 : 0))
52 #define SET_ZNVC_CMP16(a,b,r) SET_N16(r); SET_Z(r); SET_C_CMP16(a,b); SET_V16(a,b,r)
54 #define EA_IMM regs.pc++
55 #define EA_ZP regs.RdMem(regs.pc++)
56 #define EA_ZP_X (regs.RdMem(regs.pc++) + regs.x)
57 #define EA_ABS FetchMemW(regs.pc)
59 #define READ_IMM regs.RdMem(EA_IMM)
60 #define READ_ZP regs.RdMem(EA_ZP)
61 #define READ_ZP_X regs.RdMem(EA_ZP_X)
62 #define READ_ABS regs.RdMem(EA_ABS)
64 #define READ_IMM16 FetchMemW(regs.pc);
65 #define READ_ZP16 RdMemW(EA_ZP)
66 #define READ_ZP_X16 RdMemW(EA_ZP_X)
67 #define READ_ABS16 RdMemW(EA_ABS)
69 #define READ_IMM_WB(v) uint16_t addr = EA_IMM; v = regs.RdMem(addr)
70 #define READ_ZP_WB(v) uint16_t addr = EA_ZP; v = regs.RdMem(addr)
71 #define READ_ZP_X_WB(v) uint16_t addr = EA_ZP_X; v = regs.RdMem(addr)
72 #define READ_ABS_WB(v) uint16_t addr = EA_ABS; v = regs.RdMem(addr)
74 #define WRITE_BACK(d) regs.WrMem(addr, (d))
76 #define PULL regs.RdMem(regs.s++)
77 #define PUSH(r) regs.WrMem(--regs.s, (r))
78 #define PULL16 RdMemW(regs.s); regs.s += 2
79 #define PUSH16(r) regs.WrMem(--regs.s, (r) & 0xFF); regs.WrMem(--regs.s, (r) >> 8)
81 #define PACK_FLAGS ((regs.cc & 0xC0) | (flagH << 5) | (flagI << 4) | (flagN << 3) | (flagZ << 2) | (flagV << 1) | flagC)
82 #define UNPACK_FLAGS flagH = (regs.cc & FLAG_H) >> 5; \
83 flagI = (regs.cc & FLAG_I) >> 4; \
84 flagN = (regs.cc & FLAG_N) >> 3; \
85 flagZ = (regs.cc & FLAG_Z) >> 2; \
86 flagV = (regs.cc & FLAG_V) >> 1; \
87 flagC = (regs.cc & FLAG_C)
89 // Private global variables
91 static V6808REGS regs;
92 static uint8_t flagH, flagI, flagN, flagZ, flagV, flagC;
94 static uint8_t CPUCycles[256] = {
95 1, 2, 1, 1, 1, 1, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2,
96 2, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 1, 1, 1, 1,
97 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
98 4, 4, 4, 4, 4, 4, 4, 4, 1, 5, 1, 10, 1, 1, 9, 12,
99 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2,
100 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2,
101 7, 1, 1, 8, 7, 1, 7, 7, 7, 7, 7, 1, 7, 7, 4, 7,
102 6, 1, 1, 7, 6, 1, 6, 6, 6, 6, 6, 1, 6, 6, 3, 6,
103 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 3, 8, 3, 1,
104 3, 3, 3, 1, 3, 3, 3, 4, 3, 3, 3, 3, 4, 1, 4, 5,
105 5, 5, 5, 1, 5, 5, 5, 6, 5, 5, 5, 5, 6, 8, 6, 7,
106 4, 4, 4, 1, 4, 4, 4, 5, 4, 4, 4, 4, 5, 9, 5, 6,
107 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 3, 1,
108 3, 3, 3, 1, 3, 3, 3, 4, 3, 3, 3, 3, 1, 1, 4, 5,
109 5, 5, 5, 1, 5, 5, 5, 6, 5, 5, 5, 5, 1, 1, 6, 7,
110 4, 4, 4, 1, 4, 4, 4, 5, 4, 4, 4, 4, 1, 1, 5, 6
113 // Private function prototypes
115 static uint16_t RdMemW(uint16_t);
116 static uint16_t FetchMemW(uint16_t);
119 // Read a word out of 6808 memory (little endian format)
121 static inline uint16_t RdMemW(uint16_t address)
123 return (uint16_t)(regs.RdMem(address) << 8) | regs.RdMem(address + 1);
127 // Fetch a word out of 6808 memory (little endian format). Increments PC
129 static inline uint16_t FetchMemW(uint16_t address)
132 return (uint16_t)(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_t sum = (uint16_t)(acc) + (m); \
157 flagH = (sum >> 4) & 0x01; \
158 SET_V(m, acc, sum); \
159 (acc) = sum & 0xFF; \
162 static void Op8B(void) // ADDA #
164 uint16_t m = READ_IMM;
165 OP_ADD_HANDLER(m, regs.a);
168 static void Op9B(void) // ADDA ZP
170 uint16_t m = READ_ZP;
171 OP_ADD_HANDLER(m, regs.a);
174 static void OpAB(void) // ADDA ZP, X
176 uint16_t m = READ_ZP_X;
177 OP_ADD_HANDLER(m, regs.a);
180 static void OpBB(void) // ADDA ABS
182 uint16_t m = READ_ABS;
183 OP_ADD_HANDLER(m, regs.a);
186 static void OpCB(void) // ADDB #
188 uint16_t m = READ_IMM;
189 OP_ADD_HANDLER(m, regs.b);
192 static void OpDB(void) // ADDB ZP
194 uint16_t m = READ_ZP;
195 OP_ADD_HANDLER(m, regs.b);
198 static void OpEB(void) // ADDB ZP, X
200 uint16_t m = READ_ZP_X;
201 OP_ADD_HANDLER(m, regs.b);
204 static void OpFB(void) // ADDB ABS
206 uint16_t m = READ_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_t sum = (uint16_t)acc + (m) + (uint16_t)flagC; \
227 flagH = (sum >> 4) & 0x01; \
228 SET_V(m, acc, sum); \
232 static void Op89(void) // ADCA #
234 uint16_t m = READ_IMM;
235 OP_ADC_HANDLER(m, regs.a);
238 static void Op99(void) // ADCA ZP
240 uint16_t m = READ_ZP;
241 OP_ADC_HANDLER(m, regs.a);
244 static void OpA9(void) // ADCA ZP, X
246 uint16_t m = READ_ZP_X;
247 OP_ADC_HANDLER(m, regs.a);
250 static void OpB9(void) // ADCA ABS
252 uint16_t m = READ_ABS;
253 OP_ADC_HANDLER(m, regs.a);
256 static void OpC9(void) // ADCB #
258 uint16_t m = READ_IMM;
259 OP_ADC_HANDLER(m, regs.b);
262 static void OpD9(void) // ADCB ZP
264 uint16_t m = READ_ZP;
265 OP_ADC_HANDLER(m, regs.b);
268 static void OpE9(void) // ADCB ZP, X
270 uint16_t m = READ_ZP_X;
271 OP_ADC_HANDLER(m, regs.b);
274 static void OpF9(void) // ADCB ABS
276 uint16_t m = READ_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 #
296 uint8_t m = READ_IMM;
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_t m = READ_ZP_X;
309 OP_AND_HANDLER(m, regs.a);
312 static void OpB4(void) // ANDA ABS
314 uint16_t m = READ_ABS;
315 OP_AND_HANDLER(m, regs.a);
318 static void OpC4(void) // ANDB #
320 uint8_t m = READ_IMM;
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_t m = READ_ZP_X;
333 OP_AND_HANDLER(m, regs.b);
336 static void OpF4(void) // ANDB ABS
338 uint16_t m = READ_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_t result = acc & (m); \
355 static void Op85(void) // BITA #
357 uint8_t m = READ_IMM;
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
369 uint8_t m = READ_ZP_X;
370 OP_BIT_HANDLER(m, regs.a);
373 static void OpB5(void) // BITA ABS
375 uint8_t m = READ_ABS;
376 OP_BIT_HANDLER(m, regs.a);
379 static void OpC5(void) // BITB #
381 uint8_t m = READ_IMM;
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
393 uint8_t m = READ_ZP_X;
394 OP_BIT_HANDLER(m, regs.b);
397 static void OpF5(void) // BITB ABS
399 uint8_t m = READ_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);
427 static void Op4F(void) // CLRA
434 static void Op5F(void) // CLRB
442 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
443 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
444 Compare |CMPA |81 2 2|91 3 2|A1 5 2|B1 4 3| |A-M | TTTT|
445 |CMPB |C1 2 2|D1 3 2|E1 5 2|F1 4 3| |B-M | TTTT|
446 Compare Accumulators|CBA | | | | |11 2 1|A-B | TTTT|
452 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.
455 #define OP_CMP_HANDLER(m, acc) \
456 uint16_t result = acc - (m); \
457 SET_ZNVC_CMP(m, acc, result)
459 static void Op81(void) // CMPA #
461 uint8_t m = READ_IMM;
462 OP_CMP_HANDLER(m, regs.a);
465 static void Op91(void) // CMPA ZP
468 OP_CMP_HANDLER(m, regs.a);
471 static void OpA1(void) // CMPA ZP, X
473 uint8_t m = READ_ZP_X;
474 OP_CMP_HANDLER(m, regs.a);
477 static void OpB1(void) // CMPA ABS
479 uint8_t m = READ_ABS;
480 OP_CMP_HANDLER(m, regs.a);
483 static void OpC1(void) // CMPB #
485 uint8_t m = READ_IMM;
486 OP_CMP_HANDLER(m, regs.b);
489 static void OpD1(void) // CMPB ZP
492 OP_CMP_HANDLER(m, regs.b);
495 static void OpE1(void) // CMPB ZP, X
497 uint8_t m = READ_ZP_X;
498 OP_CMP_HANDLER(m, regs.b);
501 static void OpF1(void) // CMPB ABS
503 uint8_t m = READ_ABS;
504 OP_CMP_HANDLER(m, regs.b);
507 static void Op11(void) // CBA
509 OP_CMP_HANDLER(regs.b, regs.a);
513 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
514 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
515 Complement 1's |COM | | |63 7 2|73 6 3| |M=-M | TTRS|
516 |COMA | | | | |43 2 1|A=-A | TTRS|
517 |COMB | | | | |53 2 1|B=-B | TTRS|
522 #define OP_COM_HANDLER(m) \
528 static void Op63(void) // COM ZP, X
536 static void Op73(void) // COM ABS
544 static void Op43(void) // COMA
546 OP_COM_HANDLER(regs.a);
549 static void Op53(void) // COMB
551 OP_COM_HANDLER(regs.b);
555 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
556 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
557 Complement 2's |NEG | | |60 7 2|70 6 3| |M=00-M | TT12|
558 |NEGA | | | | |40 2 1|A=00-A | TT12|
559 |NEGB | | | | |50 2 1|B=00-B | TT12|
564 #define OP_NEG_HANDLER(m) \
567 flagV = (m == 0x80 ? 1 : 0); \
568 flagC = (m == 0x00 ? 1 : 0)
570 static void Op60(void) // NEG ZP, X
578 static void Op70(void) // NEG ABS
586 static void Op40(void) // NEGA
588 OP_NEG_HANDLER(regs.a);
591 static void Op50(void) // NEGB
593 OP_NEG_HANDLER(regs.b);
597 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
598 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
599 Decimal Adjust |DAA | | | | |19 2 1|* | TTT3|
602 static void Op19(void) // DAA
604 uint16_t result = (uint16_t)regs.a;
606 if ((regs.a & 0x0F) > 0x09 || flagH)
609 if ((regs.a & 0xF0) > 0x90 || flagC || ((regs.a & 0xF0) > 0x80 && (regs.a & 0x0F) > 0x09))
612 regs.a = (uint8_t)result;
614 CLR_V; // Not sure this is correct...
615 flagC |= (result & 0x100) >> 8; // Overwrite carry if it was 0, otherwise, ignore
619 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
620 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
621 Decrement |DEC | | |6A 7 2|7A 6 3| |M=M-1 | TT4 |
622 |DECA | | | | |4A 2 1|A=A-1 | TT4 |
623 |DECB | | | | |5A 2 1|B=B-1 | TT4 |
628 #define OP_DEC_HANDLER(m) \
631 flagV = (m == 0x7F ? 1 : 0)
633 static void Op6A(void) // DEC ZP, X
641 static void Op7A(void) // DEC ABS
649 static void Op4A(void) // DECA
651 OP_DEC_HANDLER(regs.a);
654 static void Op5A(void) // DECB
656 OP_DEC_HANDLER(regs.b);
660 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
661 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
662 Exclusive OR |EORA |88 2 2|98 3 2|A8 5 2|B8 4 3| |A=A(+)M | TTR |
663 |EORB |C8 2 2|D8 3 2|E8 5 2|F8 4 3| |B=B(+)M | TTR |
668 #define OP_EOR_HANDLER(m, acc) \
673 static void Op88(void) // EORA #
675 uint8_t m = READ_IMM;
676 OP_EOR_HANDLER(m, regs.a);
679 static void Op98(void) // EORA ZP
682 OP_EOR_HANDLER(m, regs.a);
685 static void OpA8(void) // EORA ZP, X
687 uint8_t m = READ_ZP_X;
688 OP_EOR_HANDLER(m, regs.a);
691 static void OpB8(void) // EORA ABS
693 uint8_t m = READ_ABS;
694 OP_EOR_HANDLER(m, regs.a);
697 static void OpC8(void) // EORB #
699 uint8_t m = READ_IMM;
700 OP_EOR_HANDLER(m, regs.b);
703 static void OpD8(void) // EORB ZP
706 OP_EOR_HANDLER(m, regs.b);
709 static void OpE8(void) // EORB ZP, X
711 uint8_t m = READ_ZP_X;
712 OP_EOR_HANDLER(m, regs.b);
715 static void OpF8(void) // EORB ABS
717 uint8_t m = READ_ABS;
718 OP_EOR_HANDLER(m, regs.b);
722 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
723 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
724 Increment |INC | | |6C 7 2|7C 6 3| |M=M+1 | TT5 |
725 |INCA | | | | |4C 2 1|A=A+1 | TT5 |
726 |INCB | | | | |5C 2 1|B=B+1 | TT5 |
731 #define OP_INC_HANDLER(m) \
734 flagV = (m == 0x80 ? 1 : 0)
736 static void Op6C(void) // INC ZP, X
744 static void Op7C(void) // INC ABS
752 static void Op4C(void) // INCA
754 OP_INC_HANDLER(regs.a);
757 static void Op5C(void) // INCB
759 OP_INC_HANDLER(regs.b);
763 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
764 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
765 Load Accumulator |LDAA |86 2 2|96 3 2|A6 5 2|B6 4 3| |A=M | TTR |
766 |LDAB |C6 2 2|D6 3 2|E6 5 2|F6 4 3| |B=M | TTR |
771 #define OP_LDA_HANDLER(m, acc) \
776 static void Op86(void) // LDAA #
778 uint8_t m = READ_IMM;
779 OP_LDA_HANDLER(m, regs.a);
782 static void Op96(void) // LDAA ZP
785 OP_LDA_HANDLER(m, regs.a);
788 static void OpA6(void) // LDAA ZP, X
790 uint8_t m = READ_ZP_X;
791 OP_LDA_HANDLER(m, regs.a);
794 static void OpB6(void) // LDAA ABS
796 uint8_t m = READ_ABS;
797 OP_LDA_HANDLER(m, regs.a);
800 static void OpC6(void) // LDAB #
802 uint8_t m = READ_IMM;
803 OP_LDA_HANDLER(m, regs.b);
806 static void OpD6(void) // LDAB ZP
809 OP_LDA_HANDLER(m, regs.b);
812 static void OpE6(void) // LDAB ZP, X
814 uint8_t m = READ_ZP_X;
815 OP_LDA_HANDLER(m, regs.b);
818 static void OpF6(void) // LDAB ABS
820 uint8_t m = READ_ABS;
821 OP_LDA_HANDLER(m, regs.b);
825 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
826 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
827 OR, Inclusive |ORAA |8A 2 2|9A 3 2|AA 5 2|BA 4 3| |A=A+M | TTR |
828 |ORAB |CA 2 2|DA 3 2|EA 5 2|FA 4 3| |B=B+M | TTR |
833 #define OP_ORA_HANDLER(m, acc) \
838 static void Op8A(void) // ORAA #
840 uint8_t m = READ_IMM;
841 OP_ORA_HANDLER(m, regs.a);
844 static void Op9A(void) // ORAA ZP
847 OP_ORA_HANDLER(m, regs.a);
850 static void OpAA(void) // ORAA ZP, X
852 uint8_t m = READ_ZP_X;
853 OP_ORA_HANDLER(m, regs.a);
856 static void OpBA(void) // ORAA ABS
858 uint8_t m = READ_ABS;
859 OP_ORA_HANDLER(m, regs.a);
862 static void OpCA(void) // ORAB #
864 uint8_t m = READ_IMM;
865 OP_ORA_HANDLER(m, regs.b);
868 static void OpDA(void) // ORAB ZP
871 OP_ORA_HANDLER(m, regs.b);
874 static void OpEA(void) // ORAB ZP, X
876 uint8_t m = READ_ZP_X;
877 OP_ORA_HANDLER(m, regs.b);
880 static void OpFA(void) // ORAB ABS
882 uint8_t m = READ_ABS;
883 OP_ORA_HANDLER(m, regs.b);
887 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
888 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
889 Push Data |PSHA | | | | |36 4 1|Msp=A, *- | |
890 |PSHB | | | | |37 4 1|Msp=B, *- | |
891 Pull Data |PULA | | | | |32 4 1|A=Msp, *+ | |
892 |PULB | | | | |33 4 1|B=Msp, *+ | |
895 static void Op36(void) // PSHA
900 static void Op37(void) // PSHB
905 static void Op32(void) // PULA
910 static void Op33(void) // PULB
916 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
917 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
918 Rotate Left |ROL | | |69 7 2|79 6 3| |Memory *1| TT6T|
919 |ROLA | | | | |49 2 1|Accum A *1| TT6T|
920 |ROLB | | | | |59 2 1|Accum B *1| TT6T|
925 #define OP_ROL_HANDLER(m) \
926 uint8_t newCarry = (m & 0x80) >> 7; \
927 m = (m << 1) | flagC; \
930 flagV = flagN ^ flagC
932 static void Op69(void) // ROL ZP, X
940 static void Op79(void) // ROL ABS
948 static void Op49(void) // ROLA
950 OP_ROL_HANDLER(regs.a);
953 static void Op59(void) // ROLB
955 OP_ROL_HANDLER(regs.b);
959 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
960 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
961 Rotate Right |ROR | | |66 7 2|76 6 3| |Memory *2| TT6T|
962 |RORA | | | | |46 2 1|Accum A *2| TT6T|
963 |RORB | | | | |56 2 1|Accum B *2| TT6T|
968 #define OP_ROR_HANDLER(m) \
969 uint8_t newCarry = m & 0x01; \
970 m = (m >> 1) | (flagC << 7); \
973 flagV = flagN ^ flagC
975 static void Op66(void) // ROR ZP, X
983 static void Op76(void) // ROR ABS
991 static void Op46(void) // RORA
993 OP_ROR_HANDLER(regs.a);
996 static void Op56(void) // RORB
998 OP_ROR_HANDLER(regs.b);
1002 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1003 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1004 Arithmetic Shft Left|ASL | | |68 7 2|78 6 3| |Memory *3| TT6T|
1005 |ASLA | | | | |48 2 1|Accum A *3| TT6T|
1006 |ASLB | | | | |58 2 1|Accum B *3| TT6T|
1011 #define OP_ASL_HANDLER(m) \
1012 uint8_t newCarry = (m & 0x80) >> 7; \
1016 flagV = flagN ^ flagC
1018 static void Op68(void) // ASL ZP, X
1026 static void Op78(void) // ASL ABS
1034 static void Op48(void) // ASLA
1036 OP_ASL_HANDLER(regs.a);
1039 static void Op58(void) // ASLB
1041 OP_ASL_HANDLER(regs.b);
1045 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1046 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1047 Arithmetic Shft Rght|ASR | | |67 7 2|77 6 3| |Memory *4| TT6T|
1048 |ASRA | | | | |47 2 1|Accum A *4| TT6T|
1049 |ASRB | | | | |57 2 1|Accum B *4| TT6T|
1054 #define OP_ASR_HANDLER(m) \
1055 uint8_t newCarry = m & 0x01; \
1056 m = (m >> 1) | (m & 0x80); \
1059 flagV = flagN ^ flagC
1061 static void Op67(void) // ASR ZP, X
1069 static void Op77(void) // ASR ABS
1077 static void Op47(void) // ASRA
1079 OP_ASR_HANDLER(regs.a);
1082 static void Op57(void) // ASRB
1084 OP_ASR_HANDLER(regs.b);
1088 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1089 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1090 Logic Shift Right |LSR | | |64 7 2|74 6 3| |Memory *5| TT6T|
1091 |LSRA | | | | |44 2 1|Accum A *5| TT6T|
1092 |LSRB | | | | |54 2 1|Accum B *5| TT6T|
1097 #define OP_LSR_HANDLER(m) \
1098 uint8_t newCarry = m & 0x01; \
1102 flagV = flagN ^ flagC
1104 static void Op64(void) // LSR ZP, X
1112 static void Op74(void) // LSR ABS
1120 static void Op44(void) // LSRA
1122 OP_LSR_HANDLER(regs.a);
1125 static void Op54(void) // LSRB
1127 OP_LSR_HANDLER(regs.b);
1131 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1132 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1133 Store Accumulator |STAA | |97 4 2|A7 6 2|B7 5 3| |M=A | TTR |
1134 |STAB | |D7 4 2|E7 6 2|F7 5 3| |M=B | TTR |
1137 static void Op97(void) // STAA ZP
1139 regs.WrMem(EA_ZP, regs.a);
1142 static void OpA7(void) // STAA ZP, X
1144 regs.WrMem(EA_ZP_X, regs.a);
1147 static void OpB7(void) // STAA ABS
1149 regs.WrMem(EA_ABS, regs.a);
1152 static void OpD7(void) // STAB ZP
1154 regs.WrMem(EA_ZP, regs.b);
1157 static void OpE7(void) // STAB ZP, X
1159 regs.WrMem(EA_ZP_X, regs.b);
1162 static void OpF7(void) // STAB ABS
1164 regs.WrMem(EA_ABS, regs.b);
1168 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1169 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1170 Subtract |SUBA |80 2 2|90 3 2|A0 5 2|B0 4 3| |A=A-M | TTTT|
1171 |SUBB |C0 2 2|D0 3 2|E0 5 2|F0 4 3| |B=B-M | TTTT|
1172 Subtract Accumulatrs|SBA | | | | |10 2 1|A=A-B | TTTT|
1177 #define OP_SUB_HANDLER(m, acc) \
1178 uint16_t sum = (uint16_t)acc - (m); \
1179 flagC = sum >> 15; \
1180 SET_V(m, acc, sum); \
1181 acc = (uint8_t)sum; \
1184 static void Op80(void) // SUBA #
1186 uint16_t m = READ_IMM;
1187 OP_SUB_HANDLER(m, regs.a);
1190 static void Op90(void) // SUBA ZP
1192 uint16_t m = READ_ZP;
1193 OP_SUB_HANDLER(m, regs.a);
1196 static void OpA0(void) // SUBA ZP, X
1198 uint16_t m = READ_ZP_X;
1199 OP_SUB_HANDLER(m, regs.a);
1202 static void OpB0(void) // SUBA ABS
1204 uint16_t m = READ_ABS;
1205 OP_SUB_HANDLER(m, regs.a);
1208 static void OpC0(void) // SUBB #
1210 uint16_t m = READ_IMM;
1211 OP_SUB_HANDLER(m, regs.b);
1214 static void OpD0(void) // SUBB ZP
1216 uint16_t m = READ_ZP;
1217 OP_SUB_HANDLER(m, regs.b);
1220 static void OpE0(void) // SUBB ZP, X
1222 uint16_t m = READ_ZP_X;
1223 OP_SUB_HANDLER(m, regs.b);
1226 static void OpF0(void) // SUBB ABS
1228 uint16_t m = READ_ABS;
1229 OP_SUB_HANDLER(m, regs.b);
1232 static void Op10(void) // SBA
1234 OP_SUB_HANDLER(regs.b, regs.a);
1238 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1239 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1240 Subtract with Carry |SBCA |82 2 2|92 3 2|A2 5 2|B2 4 3| |A=A-M-C | TTTT|
1241 |SBCB |C2 2 2|D2 3 2|E2 5 2|F2 4 3| |B=B-M-C | TTTT|
1246 #define OP_SBC_HANDLER(m, acc) \
1247 uint16_t sum = (uint16_t)acc - (m) - (uint16_t)flagC; \
1248 flagC = sum >> 15; \
1249 SET_V(m, acc, sum); \
1250 acc = (uint8_t)sum; \
1253 static void Op82(void) // SBCA #
1255 uint16_t m = READ_IMM;
1256 OP_SBC_HANDLER(m, regs.a);
1259 static void Op92(void) // SBCA ZP
1261 uint16_t m = READ_ZP;
1262 OP_SBC_HANDLER(m, regs.a);
1265 static void OpA2(void) // SBCA ZP, X
1267 uint16_t m = READ_ZP_X;
1268 OP_SBC_HANDLER(m, regs.a);
1271 static void OpB2(void) // SBCA ABS
1273 uint16_t m = READ_ABS;
1274 OP_SBC_HANDLER(m, regs.a);
1277 static void OpC2(void) // SBCB #
1279 uint16_t m = READ_IMM;
1280 OP_SBC_HANDLER(m, regs.b);
1283 static void OpD2(void) // SBCB ZP
1285 uint16_t m = READ_ZP;
1286 OP_SBC_HANDLER(m, regs.b);
1289 static void OpE2(void) // SBCB ZP, X
1291 uint16_t m = READ_ZP_X;
1292 OP_SBC_HANDLER(m, regs.b);
1295 static void OpF2(void) // SBCB ABS
1297 uint16_t m = READ_ABS;
1298 OP_SBC_HANDLER(m, regs.b);
1302 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1303 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1304 Transfer Accumulatrs|TAB | | | | |16 2 1|B=A | TTR |
1305 |TBA | | | | |17 2 1|A=B | TTR |
1308 static void Op16(void) // TAB
1315 static void Op17(void) // TBA
1323 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1324 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1325 Test, Zero/Minus |TST | | |6D 7 2|7D 6 3| |M-00 | TTRR|
1326 |TSTA | | | | |4D 2 1|A-00 | TTRR|
1327 |TSTB | | | | |5D 2 1|B-00 | TTRR|
1332 #define OP_TST_HANDLER(m) \
1336 static void Op6D(void) // TST ZP, X
1344 static void Op7D(void) // TST ABS
1352 static void Op4D(void) // TSTA
1354 OP_TST_HANDLER(regs.a);
1357 static void Op5D(void) // TSTB
1359 OP_TST_HANDLER(regs.b);
1363 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1364 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1365 Compare Index Regstr|CPX |8C 3 3|9C 4 2|AC 6 2|BC 5 3| |Formula 1 | 7T8 |
1371 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.
1374 #define OP_CPX_HANDLER(m) \
1375 uint32_t result = regs.x - (m); \
1376 SET_ZNVC_CMP16(m, regs.x, result)
1378 static void Op8C(void) // CPX #
1380 uint16_t m = READ_IMM16;
1384 static void Op9C(void) // CPX ZP
1386 uint16_t m = READ_ZP16;
1390 static void OpAC(void) // CPX ZP, X
1392 uint16_t m = READ_ZP_X16;
1396 static void OpBC(void) // CPX ABS
1398 uint16_t m = READ_ABS16;
1403 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1404 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1405 Decrement Index Regr|DEX | | | | |09 4 1|X=X-1 | T |
1406 Dec Stack Pointer |DES | | | | |34 4 1|SP=SP-1 | |
1407 Inc Index Regster |INX | | | | |08 4 1|X=X+1 | T |
1408 Inc Stack Pointer |INS | | | | |31 4 1|SP=SP+1 | |
1411 static void Op09(void) // DEX
1417 static void Op34(void) // DES
1422 static void Op08(void) // INX
1428 static void Op31(void) // INS
1434 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1435 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1436 Load Index Register |LDX |CE 3 3|DE 4 2|EE 6 2|FE 5 3| |Formula 2 | 9TR |
1437 Load Stack Pointer |LDS |8E 3 3|9E 4 2|AE 6 2|BE 5 3| |Formula 3 | 9TR |
1440 // LD* opcode handler
1442 #define OP_LD_HANDLER(acc) \
1447 static void OpCE(void) // LDX #
1449 regs.x = READ_IMM16;
1450 OP_LD_HANDLER(regs.x);
1453 static void OpDE(void) // LDX ZP
1456 OP_LD_HANDLER(regs.x);
1459 static void OpEE(void) // LDX ZP, X
1461 regs.x = READ_ZP_X16;
1462 OP_LD_HANDLER(regs.x);
1465 static void OpFE(void) // LDX ABS
1467 regs.x = READ_ABS16;
1468 OP_LD_HANDLER(regs.x);
1471 static void Op8E(void) // LDS #
1473 regs.s = READ_IMM16;
1474 OP_LD_HANDLER(regs.s);
1477 static void Op9E(void) // LDS ZP
1480 OP_LD_HANDLER(regs.s);
1483 static void OpAE(void) // LDS ZP, X
1485 regs.s = READ_ZP_X16;
1486 OP_LD_HANDLER(regs.s);
1489 static void OpBE(void) // LDS ABS
1491 regs.s = READ_ABS16;
1492 OP_LD_HANDLER(regs.s);
1496 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1497 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1498 Store Index Register|STX | |DF 5 2|EF 7 2|FF 6 3| |Formula 4 | 9TR |
1499 Store Stack Pointer |STS | |9F 5 2|AF 7 2|BF 6 3| |Formula 5 | 9TR |
1502 // ST* opcode handler
1504 #define OP_ST_HANDLER(m, acc) \
1505 regs.WrMem(m + 0, acc >> 8); \
1506 regs.WrMem(m + 1, acc & 0xFF); \
1511 static void OpDF(void) // STX ZP
1514 OP_ST_HANDLER(m, regs.x);
1517 static void OpEF(void) // STX ZP, X
1519 uint16_t m = EA_ZP_X;
1520 OP_ST_HANDLER(m, regs.x);
1523 static void OpFF(void) // STX ABS
1525 uint16_t m = EA_ABS;
1526 OP_ST_HANDLER(m, regs.x);
1529 static void Op9F(void) // STS ZP
1532 OP_ST_HANDLER(m, regs.s);
1535 static void OpAF(void) // STS ZP, X
1537 uint16_t m = EA_ZP_X;
1538 OP_ST_HANDLER(m, regs.s);
1541 static void OpBF(void) // STS ABS
1543 uint16_t m = EA_ABS;
1544 OP_ST_HANDLER(m, regs.s);
1548 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1549 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1550 Indx Reg > Stack Ptr|TXS | | | | |35 4 1|SP=X-1 | |
1551 Stack Ptr > Indx Reg|TSX | | | | |30 4 1|X=SP+1 | |
1554 static void Op35(void) // TXS
1556 regs.s = regs.x - 1;
1559 static void Op30(void) // TSX
1561 regs.x = regs.s + 1;
1565 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1566 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1567 Always |BRA | |20 4 2| | | |none | |
1568 Carry is Clear |BCC | |24 4 2| | | |C=0 | |
1569 Carry is Set |BCS | |25 4 2| | | |C=1 | |
1570 Equals Zero |BEQ | |27 4 2| | | |Z=1 | |
1571 Greater / Equal to 0|BGE | |2C 4 2| | | |N(+)V=0 | |
1572 Greater than Zero |BGT | |2E 4 2| | | |Z+N(+)V=0 | |
1573 Higher |BHI | |22 4 2| | | |C+Z=0 | |
1574 Less / Equal than 0 |BLE | |2F 4 2| | | |Z+N(+)V=1 | |
1575 Lower or Same |BLS | |23 4 2| | | |C+Z=1 | |
1576 Less Than Zero |BLT | |2D 4 2| | | |N(+)V=1 | |
1577 Minus |BMI | |2B 4 2| | | |N=1 | |
1578 Not Zero |BNE | |26 4 2| | | |Z=0 | |
1579 Overflow Clear |BVC | |28 4 2| | | |V=0 | |
1580 Overflow Set |BVS | |29 4 2| | | |V=1 | |
1581 Plus |BPL | |2A 4 2| | | |N=0 | |
1584 static void Op20(void) // BRA
1586 int16_t m = (int16_t)(int8_t)READ_IMM;
1590 static void Op24(void) // BCC
1592 // NOTE: We can optimize this by following the maxim: "Don't branch!" by converting the boolean
1593 // result into a multiplication. The only way to know if this is a win is to do some profiling
1594 // both with and without the optimization.
1595 int16_t m = (int16_t)(int8_t)READ_IMM;
1597 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1598 //Note sure if the ! operator will do what we want, so we use ^ 1
1599 regs.pc += m * (flagC ^ 0x01);
1606 static void Op25(void) // BCS
1608 int16_t m = (int16_t)(int8_t)READ_IMM;
1610 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1611 regs.pc += m * (flagC);
1618 static void Op27(void) // BEQ
1620 int16_t m = (int16_t)(int8_t)READ_IMM;
1622 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1623 regs.pc += m * (flagZ);
1630 static void Op2C(void) // BGE
1632 int16_t m = (int16_t)(int8_t)READ_IMM;
1634 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1635 regs.pc += m * ((flagN ^ flagV) ^ 0x01);
1637 if (!(flagN ^ flagV))
1642 static void Op2E(void) // BGT
1644 int16_t m = (int16_t)(int8_t)READ_IMM;
1646 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1647 regs.pc += m * ((flagZ | (flagN ^ flagV)) ^ 0x01);
1649 if (!(flagZ | (flagN ^ flagV)))
1654 static void Op22(void) // BHI
1656 int16_t m = (int16_t)(int8_t)READ_IMM;
1658 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1659 regs.pc += m * ((flagZ | flagC) ^ 0x01);
1661 if (!(flagZ | flagC))
1666 static void Op2F(void) // BLE
1668 int16_t m = (int16_t)(int8_t)READ_IMM;
1670 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1671 regs.pc += m * (flagZ | (flagN ^ flagV));
1673 if (flagZ | (flagN ^ flagV))
1678 static void Op23(void) // BLS
1680 int16_t m = (int16_t)(int8_t)READ_IMM;
1682 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1683 regs.pc += m * (flagZ | flagC);
1690 static void Op2D(void) // BLT
1692 int16_t m = (int16_t)(int8_t)READ_IMM;
1694 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1695 regs.pc += m * (flagN ^ flagV);
1702 static void Op2B(void) // BMI
1704 int16_t m = (int16_t)(int8_t)READ_IMM;
1706 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1707 regs.pc += m * (flagN);
1714 static void Op26(void) // BNE
1716 int16_t m = (int16_t)(int8_t)READ_IMM;
1718 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1719 regs.pc += m * (flagZ ^ 0x01);
1726 static void Op28(void) // BVC
1728 int16_t m = (int16_t)(int8_t)READ_IMM;
1730 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1731 regs.pc += m * (flagV ^ 0x01);
1738 static void Op29(void) // BVS
1740 int16_t m = (int16_t)(int8_t)READ_IMM;
1742 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1743 regs.pc += m * (flagV);
1750 static void Op2A(void) // BPL
1752 int16_t m = (int16_t)(int8_t)READ_IMM;
1754 #ifdef TEST_DONT_BRANCH_OPTIMIZATION
1755 regs.pc += m * (flagN ^ 0x01);
1763 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1764 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1765 Branch to Subroutine|BSR | |8D 8 2| | | | | |
1766 Jump |JMP | | |6E 4 2|7E 3 3| | | |
1767 Jump to Subroutine |JSR | | |AD 8 2|BD 9 3| | | |
1770 static void Op8D(void) // BSR
1772 int16_t m = (int16_t)(int8_t)READ_IMM;
1777 static void Op6E(void) // JMP ZP, X
1779 uint16_t m = EA_ZP_X;
1783 static void Op7E(void) // JMP ABS
1788 static void OpAD(void) // JSR ZP, X
1790 uint16_t m = EA_ZP_X;
1795 static void OpBD(void) // JSR ABS
1797 uint16_t m = EA_ABS;
1803 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1804 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1805 No Operation |NOP | | | | |01 2 1| | |
1806 Return from Interrpt|RTI | | | | |3B A 1| |AAAAAA|
1807 Return from Subrtine|RTS | | | | |39 5 1| | |
1808 Software Interrupt |SWI | | | | |3F C 1| | S |
1809 Wait For Interrupt |WAI | | | | |3E 9 1| | B |
1812 static void Op01(void) // NOP
1816 static void Op3B(void) // RTI
1826 static void Op39(void) // RTS
1831 static void Op3F(void) // SWI
1833 // It seems that the SWI is non-maskable, unlike the IRQ...
1834 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
1835 PUSH16(regs.pc); // Save all regs...
1840 regs.pc = RdMemW(0xFFFA); // And do it!
1841 flagI = 1; // Also, set IRQ inhibit
1844 static void Op3E(void) // WAI
1847 WriteLog("*** WAI STATE ASSERTED ***\n");
1849 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
1850 PUSH16(regs.pc); // Save all regs...
1855 regs.cpuFlags |= V6808_STATE_WAI; // And signal that we're in WAI mode
1859 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1860 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1861 Clear Carry |CLC | | | | |0C 2 1|C=0 | R|
1862 Clear Interrupt |CLI | | | | |0E 2 1|I=0 | R |
1863 Clear Overflow |CLV | | | | |0A 2 1|V=0 | R |
1864 Set Carry |SEC | | | | |0D 2 1|C=1 | S|
1865 Set Interrupt |SEI | | | | |0F 2 1|I=1 | S |
1866 Set Overflow |SEV | | | | |0B 2 1|V=1 | S |
1867 CCR=Accumulator A |TAP | | | | |06 2 1|CCR=A |CCCCCC|
1868 Accumlator A=CCR |TPA | | | | |07 2 1|A=CCR | |
1871 static void Op0C(void) // CLC
1876 static void Op0E(void) // CLI
1881 static void Op0A(void) // CLV
1886 static void Op0D(void) // SEC
1891 static void Op0F(void) // SEI
1896 static void Op0B(void) // SEV
1901 static void Op06(void) // TAP
1907 static void Op07(void) // TPA
1909 regs.a = PACK_FLAGS;
1913 OP Operation Code, in Hexadecimal
1914 ~ Number of MPU cycles required
1915 # Number of program bytes required
1919 Msp Contents of Memory pointed to be Stack Pointer
1920 + Boolean Inclusive OR
1921 (+) Boolean Exclusive OR (XOR)
1922 * Converts Binary Addition of BCD Characters into BCD Format
1926 Condition Code Register Legend
1930 T Tests and sets if True, cleared otherise
1931 1 Test: Result=10000000?
1932 2 Test: Result=00000000?
1933 3 Test: Decimal value of most significant BCD character greater than nine?
1934 (Not cleared if previously set)
1935 4 Test: Operand=10000000 prior to execution?
1936 5 Test: Operand=01111111 prior to execution?
1937 6 Test: Set equal to result or N(+)C after shift has occurred.
1938 7 Test: Sign bit of most significant byte or result=1?
1939 8 Test: 2's compliment overflow from subtraction of least
1941 9 Test: Result less than zero? (Bit 15=1)
1942 A Load Condition Code Register from Stack.
1943 B Set when interrupt occurs. If previously set, a NMI is
1944 required to exit the wait state.
1945 C Set according to the contents of Accumulator A.
1947 *x SHIFT AND ROTATION DIAGRAMS
1948 *1 +-----------------+ C to LSB
1951 *2 +-----------------+
1954 *3 C <- 76543210 <- 0(Data)
1959 *5 (Data)0 -> 76543210 -> C
1968 static void Op__(void)
1970 regs.cpuFlags |= V6808_STATE_ILLEGAL_INST;
1974 // Ok, the exec_op[] array is globally defined here basically to save
1975 // a LOT of unnecessary typing. Sure it's ugly, but hey, it works!
1977 void (* exec_op[256])() = {
1978 Op__, Op01, Op__, Op__, Op__, Op__, Op06, Op07, Op08, Op09, Op0A, Op0B, Op0C, Op0D, Op0E, Op0F,
1979 Op10, Op11, Op__, Op__, Op__, Op__, Op16, Op17, Op__, Op19, Op__, Op1B, Op__, Op__, Op__, Op__,
1980 Op20, Op__, Op22, Op23, Op24, Op25, Op26, Op27, Op28, Op29, Op2A, Op2B, Op2C, Op2D, Op2E, Op2F,
1981 Op30, Op31, Op32, Op33, Op34, Op35, Op36, Op37, Op__, Op39, Op__, Op3B, Op__, Op__, Op3E, Op3F,
1982 Op40, Op__, Op__, Op43, Op44, Op__, Op46, Op47, Op48, Op49, Op4A, Op__, Op4C, Op4D, Op__, Op4F,
1983 Op50, Op__, Op__, Op53, Op54, Op__, Op56, Op57, Op58, Op59, Op5A, Op__, Op5C, Op5D, Op__, Op5F,
1984 Op60, Op__, Op__, Op63, Op64, Op__, Op66, Op67, Op68, Op69, Op6A, Op__, Op6C, Op6D, Op6E, Op6F,
1985 Op70, Op__, Op__, Op73, Op74, Op__, Op76, Op77, Op78, Op79, Op7A, Op__, Op7C, Op7D, Op7E, Op7F,
1986 Op80, Op81, Op82, Op__, Op84, Op85, Op86, Op__, Op88, Op89, Op8A, Op8B, Op8C, Op8D, Op8E, Op__,
1987 Op90, Op91, Op92, Op__, Op94, Op95, Op96, Op97, Op98, Op99, Op9A, Op9B, Op9C, Op__, Op9E, Op9F,
1988 OpA0, OpA1, OpA2, Op__, OpA4, OpA5, OpA6, OpA7, OpA8, OpA9, OpAA, OpAB, OpAC, OpAD, OpAE, OpAF,
1989 OpB0, OpB1, OpB2, Op__, OpB4, OpB5, OpB6, OpB7, OpB8, OpB9, OpBA, OpBB, OpBC, OpBD, OpBE, OpBF,
1990 OpC0, OpC1, OpC2, Op__, OpC4, OpC5, OpC6, Op__, OpC8, OpC9, OpCA, OpCB, Op__, Op__, OpCE, Op__,
1991 OpD0, OpD1, OpD2, Op__, OpD4, OpD5, OpD6, OpD7, OpD8, OpD9, OpDA, OpDB, Op__, Op__, OpDE, OpDF,
1992 OpE0, OpE1, OpE2, Op__, OpE4, OpE5, OpE6, OpE7, OpE8, OpE9, OpEA, OpEB, Op__, Op__, OpEE, OpEF,
1993 OpF0, OpF1, OpF2, Op__, OpF4, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, OpFB, Op__, Op__, OpFE, OpFF
1997 // Internal "memcpy" (so we don't have to link with any external libraries!)
1999 static void myMemcpy(void * dst, void * src, uint32_t size)
2001 uint8_t * d = (uint8_t *)dst, * s = (uint8_t *)src;
2003 for(uint32_t i=0; i<size; i++)
2008 // Function to execute 6808 for "cycles" cycles
2010 void Execute6808(V6808REGS * context, uint32_t cycles)
2012 #warning "V6808_STATE_WAI is not properly handled yet! !!! FIX !!!"
2013 #warning "Need to convert from destructive clock to non-destructive. !!! FIX !!!"
2014 myMemcpy(®s, context, sizeof(V6808REGS));
2015 UNPACK_FLAGS; // Explode flags register into individual uint8_ts
2018 while (regs.clock < cycles)
2020 uint8_t opcode = regs.RdMem(regs.pc++);
2021 exec_op[opcode](); // Execute that opcode...
2022 regs.clock += CPUCycles[opcode];
2024 if (regs.cpuFlags & V6808_LINE_RESET)
2027 regs.pc = RdMemW(0xFFFE); // And load PC with the RESET vector
2029 context->cpuFlags &= ~V6808_LINE_RESET;
2030 regs.cpuFlags &= ~V6808_LINE_RESET;
2032 else if (regs.cpuFlags & V6808_LINE_NMI)
2034 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2035 PUSH16(regs.pc); // Save all regs...
2040 regs.pc = RdMemW(0xFFFC); // And do it!
2042 #warning "# of clock cycles for NMI unknown. !!! FIX !!!"
2043 regs.clock += 0; // How many???
2044 context->cpuFlags &= ~V6808_LINE_NMI;// Reset the asserted line (NMI)...
2045 regs.cpuFlags &= ~V6808_LINE_NMI; // Reset the asserted line (NMI)...
2047 else if (regs.cpuFlags & V6808_LINE_IRQ)
2049 if (!flagI) // Process an interrupt (I=0)?
2051 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2052 PUSH16(regs.pc); // Save all regs...
2057 regs.pc = RdMemW(0xFFF8);// And do it!
2059 #warning "# of clock cycles for IRQ unknown. !!! FIX !!!"
2060 regs.clock += 0; // How many???
2061 #warning "IRQ/NMI lines should not be cleared here... !!! FIX !!!"
2062 context->cpuFlags &= ~V6808_LINE_IRQ; // Reset the asserted line (IRQ)...
2063 regs.cpuFlags &= ~V6808_LINE_IRQ; // Reset the asserted line (IRQ)...
2068 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2069 myMemcpy(context, ®s, sizeof(V6808REGS));
2073 // Get the clock of the currently executing CPU
2075 uint64_t GetCurrentV6808Clock(void)