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
17 // NOTE: V6808_STATE_WAI is not handled in the main loop correctly. !!! FIX !!!
19 // Some random thoughts: Could there be a performance gain by breaking
20 // out the flags in regs.cc into separate uint8 variables (or bools)?
21 // You'd have to convert on entering and exiting the emulation loop, but I
22 // think the perfomance hit would be negligible compared to the gain in not
23 // having to mask and shift flags all the time. Investigate after the
24 // conversion to macro style opcodes is completed. :-)
25 // [DONE--remain to be seen if there is any performance increase]
39 #define CLR_Z (regs.cc &= ~FLAG_Z)
40 #define CLR_ZN (regs.cc &= ~(FLAG_Z | FLAG_N))
41 #define CLR_ZNC (regs.cc &= ~(FLAG_Z | FLAG_N | FLAG_C))
42 #define CLR_NVC (regs.cc &= ~(FLAG_N | FLAG_V | FLAG_C))
43 #define CLR_VC (regs.cc &= ~(FLAG_V | FLAG_C))
44 #define CLR_V (regs.cc &= ~FLAG_V)
45 #define CLR_N (regs.cc &= ~FLAG_N)
46 #define SET_Z(r) (regs.cc = ((r) == 0 ? regs.cc | FLAG_Z : regs.cc & ~FLAG_Z))
47 #define SET_N(r) (regs.cc = ((r) & 0x80 ? regs.cc | FLAG_N : regs.cc & ~FLAG_N))
48 #define SET_V(a,b,r) (regs.cc = ((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V)
50 //Not sure that this code is computing the carry correctly... Investigate! [Seems to be]
51 #define SET_C_ADD(a,b) (regs.cc = ((uint8)(b) > (uint8)(~(a)) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
52 #define SET_C_CMP(a,b) (regs.cc = ((uint8)(b) < (uint8)(a) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
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) (regs.cc = ((r) & 0x8000 ? regs.cc | FLAG_N : regs.cc & ~FLAG_N))
58 #define SET_V16(a,b,r) (regs.cc = ((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x8000 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V)
59 #define SET_C_CMP16(a,b) (regs.cc = ((uint16)(b) < (uint16)(a) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
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 #define CLR_Z (flagZ = 0)
63 #define CLR_ZN (flagZ = flagN = 0)
64 #define CLR_ZNC (flagZ = flagN = flagC = 0)
65 #define CLR_NVC (flagN = flagV = flagC = 0)
66 #define CLR_VC (flagV = flagC = 0)
67 #define CLR_V (flagV = 0)
68 #define CLR_N (flagN = 0)
69 #define SET_Z(r) (flagZ = ((r) == 0 ? 1 : 0))
70 #define SET_N(r) (flagN = ((r) & 0x80) >> 7)
71 #define SET_V(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x80) >> 7)
73 #define SET_C_CMP(a,b) (flagC = ((uint8)(b) < (uint8)(a) ? 1 : 0))
74 #define SET_ZN(r) SET_N(r); SET_Z(r)
75 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
76 #define SET_ZNVC_CMP(a,b,r) SET_N(r); SET_Z(r); SET_C_CMP(a,b); SET_V(a,b,r)
78 #define SET_N16(r) (flagN = ((r) & 0x8000) >> 15)
79 #define SET_V16(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x8000) >> 15)
80 #define SET_C_CMP16(a,b) (flagC = ((uint16)(b) < (uint16)(a) ? 1 : 0))
81 #define SET_ZNVC_CMP16(a,b,r) SET_N16(r); SET_Z(r); SET_C_CMP16(a,b); SET_V16(a,b,r)
84 //Small problem with the EA_ macros: ABS macros don't increment the PC!!! !!! FIX !!! [DONE, kinda]
85 #define EA_IMM regs.pc++
86 #define EA_ZP regs.RdMem(regs.pc++)
87 #define EA_ZP_X (regs.RdMem(regs.pc++) + regs.x)
88 #define EA_ABS RdMemW(regs.pc)
90 #define READ_IMM regs.RdMem(EA_IMM)
91 #define READ_ZP regs.RdMem(EA_ZP)
92 #define READ_ZP_X regs.RdMem(EA_ZP_X)
93 #define READ_ABS regs.RdMem(EA_ABS); regs.pc += 2
95 #define READ_IMM16 RdMemW(regs.pc); regs.pc += 2
96 #define READ_ZP16 RdMemW(EA_ZP)
97 #define READ_ZP_X16 RdMemW(EA_ZP_X)
98 #define READ_ABS16 RdMemW(EA_ABS); regs.pc += 2
100 #define READ_IMM_WB(v) uint16 addr = EA_IMM; v = regs.RdMem(addr)
101 #define READ_ZP_WB(v) uint16 addr = EA_ZP; v = regs.RdMem(addr)
102 #define READ_ZP_X_WB(v) uint16 addr = EA_ZP_X; v = regs.RdMem(addr)
103 #define READ_ABS_WB(v) uint16 addr = EA_ABS; v = regs.RdMem(addr); regs.pc += 2
105 #define WRITE_BACK(d) regs.WrMem(addr, (d))
107 #define PULL regs.RdMem(regs.s++)
108 #define PUSH(r) regs.WrMem(--regs.s, (r))
109 #define PULL16 RdMemW(regs.s); regs.s += 2
110 #define PUSH16(r) regs.WrMem(--regs.s, (r) & 0xFF); regs.WrMem(--regs.s, (r) >> 8)
112 #define PACK_FLAGS ((regs.cc & 0xC0) | (flagH << 5) | (flagI << 4) | (flagN << 3) | (flagZ << 2) | (flagV << 1) | flagC)
113 #define UNPACK_FLAGS flagH = (regs.cc & FLAG_H) >> 5; \
114 flagI = (regs.cc & FLAG_I) >> 4; \
115 flagN = (regs.cc & FLAG_N) >> 3; \
116 flagZ = (regs.cc & FLAG_Z) >> 2; \
117 flagV = (regs.cc & FLAG_V) >> 1; \
118 flagC = (regs.cc & FLAG_C)
120 // Private global variables
122 static V6808REGS regs;
123 static uint8 flagH, flagI, flagN, flagZ, flagV, flagC;
125 static uint8 CPUCycles[256] = {
126 1, 2, 1, 1, 1, 1, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2,
127 2, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 1, 1, 1, 1,
128 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
129 4, 4, 4, 4, 4, 4, 4, 4, 1, 5, 1, 10, 1, 1, 9, 12,
130 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2,
131 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2,
132 7, 1, 1, 8, 7, 1, 7, 7, 7, 7, 7, 1, 7, 7, 4, 7,
133 6, 1, 1, 7, 6, 1, 6, 6, 6, 6, 6, 1, 6, 6, 3, 6,
134 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 3, 8, 3, 1,
135 3, 3, 3, 1, 3, 3, 3, 4, 3, 3, 3, 3, 4, 1, 4, 5,
136 5, 5, 5, 1, 5, 5, 5, 6, 5, 5, 5, 5, 6, 8, 6, 7,
137 4, 4, 4, 1, 4, 4, 4, 5, 4, 4, 4, 4, 5, 9, 5, 6,
138 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 3, 1,
139 3, 3, 3, 1, 3, 3, 3, 4, 3, 3, 3, 3, 1, 1, 4, 5,
140 5, 5, 5, 1, 5, 5, 5, 6, 5, 5, 5, 5, 1, 1, 6, 7,
141 4, 4, 4, 1, 4, 4, 4, 5, 4, 4, 4, 4, 1, 1, 5, 6
144 // Private function prototypes
146 static uint16 RdMemW(uint16);
149 // Read a word out of 6808 memory (little endian format)
151 static inline uint16 RdMemW(uint16 address)
153 return (uint16)(regs.RdMem(address) << 8) | regs.RdMem(address + 1);
157 // 6808 OPCODE IMPLEMENTATION
159 // NOTE: Lots of macros are used here to save a LOT of typing. Also
160 // helps speed the debugging process. :-) Because of this, combining
161 // certain lines may look like a good idea but would end in disaster.
162 // You have been warned! ;-)
166 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
167 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
168 Add |ADDA |8B 2 2|9B 3 2|AB 5 2|BB 4 3| |A=A+M |T TTTT|
169 |ADDB |CB 2 2|DB 3 2|EB 5 2|FB 4 3| |B=B+M |T TTTT|
170 Add Accumulators |ABA | | | | |1B 2 1|A=A+B |T TTTT|
175 //#define OP_ADD_HANDLER(m, acc) \
176 uint16 sum = (uint16)(acc) + (m); \
177 regs.cc = (regs.cc & ~FLAG_C) | (sum >> 8); \
178 regs.cc = (regs.cc & ~FLAG_H) | ((sum << 1) & FLAG_H); \
179 SET_V(m, acc, sum); \
180 (acc) = sum & 0xFF; \
182 #define OP_ADD_HANDLER(m, acc) \
183 uint16 sum = (uint16)(acc) + (m); \
185 flagH = (sum >> 4) & 0x01; \
186 SET_V(m, acc, sum); \
187 (acc) = sum & 0xFF; \
190 static void Op8B(void) // ADDA #
193 OP_ADD_HANDLER(m, regs.a);
196 static void Op9B(void) // ADDA ZP
199 OP_ADD_HANDLER(m, regs.a);
202 static void OpAB(void) // ADDA ZP, X
204 uint16 m = READ_ZP_X;
205 OP_ADD_HANDLER(m, regs.a);
208 static void OpBB(void) // ADDA ABS
211 OP_ADD_HANDLER(m, regs.a);
214 static void OpCB(void) // ADDB #
217 OP_ADD_HANDLER(m, regs.b);
220 static void OpDB(void) // ADDB ZP
223 OP_ADD_HANDLER(m, regs.b);
226 static void OpEB(void) // ADDB ZP, X
228 uint16 m = READ_ZP_X;
229 OP_ADD_HANDLER(m, regs.b);
232 static void OpFB(void) // ADDB ABS
235 OP_ADD_HANDLER(m, regs.b);
238 static void Op1B(void) // ABA
240 OP_ADD_HANDLER(regs.b, regs.a);
244 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
245 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
246 Add with Carry |ADCA |89 2 2|99 3 2|A9 5 2|B9 4 3| |A=A+M+C |T TTTT|
247 |ADCB |C9 2 2|D9 3 2|E9 5 2|F9 4 3| |B=B+M+C |T TTTT|
252 //#define OP_ADC_HANDLER(m, acc) \
253 uint16 sum = (uint16)acc + (m) + (uint16)(regs.cc & FLAG_C); \
254 regs.cc = (regs.cc & ~FLAG_C) | (sum >> 8); \
255 regs.cc = (regs.cc & ~FLAG_H) | ((sum << 1) & FLAG_H); \
256 SET_V(m, acc, sum); \
259 #define OP_ADC_HANDLER(m, acc) \
260 uint16 sum = (uint16)acc + (m) + (uint16)flagC; \
262 flagH = (sum >> 4) & 0x01; \
263 SET_V(m, acc, sum); \
267 static void Op89(void) // ADCA #
270 OP_ADC_HANDLER(m, regs.a);
273 static void Op99(void) // ADCA ZP
276 OP_ADC_HANDLER(m, regs.a);
279 static void OpA9(void) // ADCA ZP, X
281 uint16 m = READ_ZP_X;
282 OP_ADC_HANDLER(m, regs.a);
285 static void OpB9(void) // ADCA ABS
288 OP_ADC_HANDLER(m, regs.a);
291 static void OpC9(void) // ADCB #
294 OP_ADC_HANDLER(m, regs.b);
297 static void OpD9(void) // ADCB ZP
300 OP_ADC_HANDLER(m, regs.b);
303 static void OpE9(void) // ADCB ZP, X
305 uint16 m = READ_ZP_X;
306 OP_ADC_HANDLER(m, regs.b);
309 static void OpF9(void) // ADCB ABS
312 OP_ADC_HANDLER(m, regs.b);
316 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
317 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
318 And |ANDA |84 2 2|94 3 2|A4 5 2|B4 4 3| |A=A+M | TTR |
319 |ANDB |C4 2 2|D4 3 2|E4 5 2|F4 4 3| |B=B+M | TTR |
324 #define OP_AND_HANDLER(m, acc) \
329 static void Op84(void) // ANDA #
332 OP_AND_HANDLER(m, regs.a);
335 static void Op94(void) // ANDA ZP
338 OP_AND_HANDLER(m, regs.a);
341 static void OpA4(void) // ANDA ZP, X
343 uint16 m = READ_ZP_X;
344 OP_AND_HANDLER(m, regs.a);
347 static void OpB4(void) // ANDA ABS
350 OP_AND_HANDLER(m, regs.a);
353 static void OpC4(void) // ANDB #
356 OP_AND_HANDLER(m, regs.b);
359 static void OpD4(void) // ANDB ZP
362 OP_AND_HANDLER(m, regs.b);
365 static void OpE4(void) // ANDB ZP, X
367 uint16 m = READ_ZP_X;
368 OP_AND_HANDLER(m, regs.b);
371 static void OpF4(void) // ANDB ABS
374 OP_AND_HANDLER(m, regs.b);
378 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
379 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
380 Bit Test |BITA |85 2 2|95 3 2|A5 5 2|B5 4 3| |A+M | TTR |
381 |BITB |C5 2 2|D5 3 2|E5 5 2|F5 4 3| |B+M | TTR |
386 #define OP_BIT_HANDLER(m, acc) \
387 int8 result = acc & (m); \
390 static void Op85(void) // BITA #
393 OP_BIT_HANDLER(m, regs.a);
396 static void Op95(void) // BITA ZP
399 OP_BIT_HANDLER(m, regs.a);
402 static void OpA5(void) // BITA ZP, X
405 OP_BIT_HANDLER(m, regs.a);
408 static void OpB5(void) // BITA ABS
411 OP_BIT_HANDLER(m, regs.a);
414 static void OpC5(void) // BITB #
417 OP_BIT_HANDLER(m, regs.b);
420 static void OpD5(void) // BITB ZP
423 OP_BIT_HANDLER(m, regs.b);
426 static void OpE5(void) // BITB ZP, X
429 OP_BIT_HANDLER(m, regs.b);
432 static void OpF5(void) // BITB ABS
435 OP_BIT_HANDLER(m, regs.b);
439 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
440 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
441 Clear |CLR | | |6F 7 2|7F 6 3| |M=00 | RSRR|
442 |CLRA | | | | |4F 2 1|A=00 | RSRR|
443 |CLRB | | | | |5F 2 1|B=00 | RSRR|
448 static void Op6F(void) // CLR ZP, X
450 regs.WrMem(EA_ZP_X, 0);
455 static void Op7F(void) // CLR ABS
457 regs.WrMem(EA_ABS, 0);
463 static void Op4F(void) // CLRA
470 static void Op5F(void) // CLRB
478 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
479 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
480 Compare |CMPA |81 2 2|91 3 2|A1 5 2|B1 4 3| |A-M | TTTT|
481 |CMPB |C1 2 2|D1 3 2|E1 5 2|F1 4 3| |B-M | TTTT|
482 Compare Accumulators |CBA | | | | |11 2 1|A-B | TTTT|
488 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.
491 #define OP_CMP_HANDLER(m, acc) \
492 uint16 result = acc - (m); \
493 SET_ZNVC_CMP(m, acc, result)
495 static void Op81(void) // CMPA #
498 OP_CMP_HANDLER(m, regs.a);
501 static void Op91(void) // CMPA ZP
504 OP_CMP_HANDLER(m, regs.a);
507 static void OpA1(void) // CMPA ZP, X
510 OP_CMP_HANDLER(m, regs.a);
513 static void OpB1(void) // CMPA ABS
516 OP_CMP_HANDLER(m, regs.a);
519 static void OpC1(void) // CMPB #
522 OP_CMP_HANDLER(m, regs.b);
525 static void OpD1(void) // CMPB ZP
528 OP_CMP_HANDLER(m, regs.b);
531 static void OpE1(void) // CMPB ZP, X
534 OP_CMP_HANDLER(m, regs.b);
537 static void OpF1(void) // CMPB ABS
540 OP_CMP_HANDLER(m, regs.b);
543 static void Op11(void) // CBA
545 OP_CMP_HANDLER(regs.b, regs.a);
549 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
550 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
551 Complement 1's |COM | | |63 7 2|73 6 3| |M=-M | TTRS|
552 |COMA | | | | |43 2 1|A=-A | TTRS|
553 |COMB | | | | |53 2 1|B=-B | TTRS|
558 //#define OP_COM_HANDLER(m) \
563 #define OP_COM_HANDLER(m) \
569 static void Op63(void) // COM ZP, X
577 static void Op73(void) // COM ABS
585 static void Op43(void) // COMA
587 OP_COM_HANDLER(regs.a);
590 static void Op53(void) // COMB
592 OP_COM_HANDLER(regs.b);
596 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
597 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
598 Complement 2's |NEG | | |60 7 2|70 6 3| |M=00-M | TT12|
599 |NEGA | | | | |40 2 1|A=00-A | TT12|
600 |NEGB | | | | |50 2 1|B=00-B | TT12|
605 //#define OP_NEG_HANDLER(m) \
608 regs.cc = (m == 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V); \
609 regs.cc = (m == 0x00 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C)
610 #define OP_NEG_HANDLER(m) \
613 flagV = (m == 0x80 ? 1 : 0); \
614 flagC = (m == 0x00 ? 1 : 0)
616 static void Op60(void) // NEG ZP, X
624 static void Op70(void) // NEG ABS
632 static void Op40(void) // NEGA
634 OP_NEG_HANDLER(regs.a);
637 static void Op50(void) // NEGB
639 OP_NEG_HANDLER(regs.b);
643 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
644 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
645 Decimal Adjust |DAA | | | | |19 2 1|* | TTT3|
648 static void Op19(void) // DAA
650 #if 0 // Just because we can optimize a little here, we will... ;-)
653 if ((regs.a & 0x0F) > 0x09 || (regs.cc & FLAG_H))
656 if ((regs.a & 0xF0) > 0x90 || (regs.cc & FLAG_C) || ((regs.a & 0xF0) > 0x80 && (regs.a & 0x0F) > 0x09))
659 uint16 result = regs.a + adjust;
660 regs.a = (uint8)result;
662 CLR_V; // Not sure this is correct...
663 regs.cc |= (result & 0x100) >> 8; // Overwrite carry if it was 0, otherwise, ignore
665 uint16 result = (uint16)regs.a;
667 // if ((regs.a & 0x0F) > 0x09 || (regs.cc & FLAG_H))
668 if ((regs.a & 0x0F) > 0x09 || flagH)
671 // if ((regs.a & 0xF0) > 0x90 || (regs.cc & FLAG_C) || ((regs.a & 0xF0) > 0x80 && (regs.a & 0x0F) > 0x09))
672 if ((regs.a & 0xF0) > 0x90 || flagC || ((regs.a & 0xF0) > 0x80 && (regs.a & 0x0F) > 0x09))
675 regs.a = (uint8)result;
677 CLR_V; // Not sure this is correct...
678 // regs.cc |= (result & 0x100) >> 8; // Overwrite carry if it was 0, otherwise, ignore
679 flagC |= (result & 0x100) >> 8; // Overwrite carry if it was 0, otherwise, ignore
684 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
685 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
686 Decrement |DEC | | |6A 7 2|7A 6 3| |M=M-1 | TT4 |
687 |DECA | | | | |4A 2 1|A=A-1 | TT4 |
688 |DECB | | | | |5A 2 1|B=B-1 | TT4 |
693 //#define OP_DEC_HANDLER(m) \
696 regs.cc = (m == 0x7F ? regs.cc | FLAG_V : regs.cc & ~FLAG_V)
697 #define OP_DEC_HANDLER(m) \
700 flagV = (m == 0x7F ? 1 : 0)
702 static void Op6A(void) // DEC ZP, X
710 static void Op7A(void) // DEC ABS
718 static void Op4A(void) // DECA
720 OP_DEC_HANDLER(regs.a);
723 static void Op5A(void) // DECB
725 OP_DEC_HANDLER(regs.b);
729 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
730 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
731 Exclusive OR |EORA |88 2 2|98 3 2|A8 5 2|B8 4 3| |A=A(+)M | TTR |
732 |EORB |C8 2 2|D8 3 2|E8 5 2|F8 4 3| |B=B(+)M | TTR |
737 #define OP_EOR_HANDLER(m, acc) \
742 static void Op88(void) // EORA #
745 OP_EOR_HANDLER(m, regs.a);
748 static void Op98(void) // EORA ZP
751 OP_EOR_HANDLER(m, regs.a);
754 static void OpA8(void) // EORA ZP, X
757 OP_EOR_HANDLER(m, regs.a);
760 static void OpB8(void) // EORA ABS
763 OP_EOR_HANDLER(m, regs.a);
766 static void OpC8(void) // EORB #
769 OP_EOR_HANDLER(m, regs.b);
772 static void OpD8(void) // EORB ZP
775 OP_EOR_HANDLER(m, regs.b);
778 static void OpE8(void) // EORB ZP, X
781 OP_EOR_HANDLER(m, regs.b);
784 static void OpF8(void) // EORB ABS
787 OP_EOR_HANDLER(m, regs.b);
791 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
792 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
793 Increment |INC | | |6C 7 2|7C 6 3| |M=M+1 | TT5 |
794 |INCA | | | | |4C 2 1|A=A+1 | TT5 |
795 |INCB | | | | |5C 2 1|B=B+1 | TT5 |
800 //#define OP_INC_HANDLER(m) \
803 regs.cc = (m == 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V)
804 #define OP_INC_HANDLER(m) \
807 flagV = (m == 0x80 ? 1 : 0)
809 static void Op6C(void) // INC ZP, X
817 static void Op7C(void) // INC ABS
825 static void Op4C(void) // INCA
827 OP_INC_HANDLER(regs.a);
830 static void Op5C(void) // INCB
832 OP_INC_HANDLER(regs.b);
836 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
837 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
838 Load Accumulator |LDAA |86 2 2|96 3 2|A6 5 2|B6 4 3| |A=M | TTR |
839 |LDAB |C6 2 2|D6 3 2|E6 5 2|F6 4 3| |B=M | TTR |
844 #define OP_LDA_HANDLER(m, acc) \
849 static void Op86(void) // LDAA #
852 OP_LDA_HANDLER(m, regs.a);
855 static void Op96(void) // LDAA ZP
858 OP_LDA_HANDLER(m, regs.a);
861 static void OpA6(void) // LDAA ZP, X
864 OP_LDA_HANDLER(m, regs.a);
867 static void OpB6(void) // LDAA ABS
870 OP_LDA_HANDLER(m, regs.a);
873 static void OpC6(void) // LDAB #
876 OP_LDA_HANDLER(m, regs.b);
879 static void OpD6(void) // LDAB ZP
882 OP_LDA_HANDLER(m, regs.b);
885 static void OpE6(void) // LDAB ZP, X
888 OP_LDA_HANDLER(m, regs.b);
891 static void OpF6(void) // LDAB ABS
894 OP_LDA_HANDLER(m, regs.b);
898 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
899 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
900 OR, Inclusive |ORAA |8A 2 2|9A 3 2|AA 5 2|BA 4 3| |A=A+M | TTR |
901 |ORAB |CA 2 2|DA 3 2|EA 5 2|FA 4 3| |B=B+M | TTR |
906 #define OP_ORA_HANDLER(m, acc) \
911 static void Op8A(void) // ORAA #
914 OP_ORA_HANDLER(m, regs.a);
917 static void Op9A(void) // ORAA ZP
920 OP_ORA_HANDLER(m, regs.a);
923 static void OpAA(void) // ORAA ZP, X
926 OP_ORA_HANDLER(m, regs.a);
929 static void OpBA(void) // ORAA ABS
932 OP_ORA_HANDLER(m, regs.a);
935 static void OpCA(void) // ORAB #
938 OP_ORA_HANDLER(m, regs.b);
941 static void OpDA(void) // ORAB ZP
944 OP_ORA_HANDLER(m, regs.b);
947 static void OpEA(void) // ORAB ZP, X
950 OP_ORA_HANDLER(m, regs.b);
953 static void OpFA(void) // ORAB ABS
956 OP_ORA_HANDLER(m, regs.b);
960 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
961 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
962 Push Data |PSHA | | | | |36 4 1|Msp=A, *- | |
963 |PSHB | | | | |37 4 1|Msp=B, *- | |
964 Pull Data |PULA | | | | |32 4 1|A=Msp, *+ | |
965 |PULB | | | | |33 4 1|B=Msp, *+ | |
968 static void Op36(void) // PSHA
970 // regs.WrMem(--regs.s, regs.a);
974 static void Op37(void) // PSHB
976 // regs.WrMem(--regs.s, regs.b);
980 static void Op32(void) // PULA
982 // regs.a = regs.RdMem(regs.s++);
986 static void Op33(void) // PULB
988 // regs.b = regs.RdMem(regs.s++);
993 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
994 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
995 Rotate Left |ROL | | |69 7 2|79 6 3| |Memory *1| TT6T|
996 |ROLA | | | | |49 2 1|Accum A *1| TT6T|
997 |ROLB | | | | |59 2 1|Accum B *1| TT6T|
1002 //#define OP_ROL_HANDLER(m) \
1003 uint8 newCarry = (m & 0x80) >> 7; \
1004 m = (m << 1) | (regs.cc & FLAG_C); \
1006 regs.cc = (regs.cc & ~FLAG_C) | newCarry; \
1007 regs.cc = (regs.cc & ~FLAG_V) | ((regs.cc & FLAG_N) >> 2) ^ ((regs.cc & FLAG_C) << 1)
1008 #define OP_ROL_HANDLER(m) \
1009 uint8 newCarry = (m & 0x80) >> 7; \
1010 m = (m << 1) | flagC; \
1013 flagV = flagN ^ flagC
1015 static void Op69(void) // ROL ZP, X
1023 static void Op79(void) // ROL ABS
1031 static void Op49(void) // ROLA
1033 OP_ROL_HANDLER(regs.a);
1036 static void Op59(void) // ROLB
1038 OP_ROL_HANDLER(regs.b);
1042 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1043 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1044 Rotate Right |ROR | | |66 7 2|76 6 3| |Memory *2| TT6T|
1045 |RORA | | | | |46 2 1|Accum A *2| TT6T|
1046 |RORB | | | | |56 2 1|Accum B *2| TT6T|
1051 //#define OP_ROR_HANDLER(m) \
1052 uint8 newCarry = m & 0x01; \
1053 m = (m >> 1) | ((regs.cc & FLAG_C) << 7); \
1055 regs.cc = (regs.cc & ~FLAG_C) | newCarry; \
1056 regs.cc = (regs.cc & ~FLAG_V) | ((regs.cc & FLAG_N) >> 2) ^ ((regs.cc & FLAG_C) << 1)
1057 #define OP_ROR_HANDLER(m) \
1058 uint8 newCarry = m & 0x01; \
1059 m = (m >> 1) | (flagC << 7); \
1062 flagV = flagN ^ flagC
1064 static void Op66(void) // ROR ZP, X
1072 static void Op76(void) // ROR ABS
1080 static void Op46(void) // RORA
1082 OP_ROR_HANDLER(regs.a);
1085 static void Op56(void) // RORB
1087 OP_ROR_HANDLER(regs.b);
1091 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1092 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1093 Arithmetic Shift Left |ASL | | |68 7 2|78 6 3| |Memory *3| TT6T|
1094 |ASLA | | | | |48 2 1|Accum A *3| TT6T|
1095 |ASLB | | | | |58 2 1|Accum B *3| TT6T|
1100 //#define OP_ASL_HANDLER(m) \
1101 uint8 newCarry = (m & 0x80) >> 7; \
1104 regs.cc = (regs.cc & ~FLAG_C) | newCarry; \
1105 regs.cc = (regs.cc & ~FLAG_V) | ((regs.cc & FLAG_N) >> 2) ^ ((regs.cc & FLAG_C) << 1)
1106 #define OP_ASL_HANDLER(m) \
1107 uint8 newCarry = (m & 0x80) >> 7; \
1111 flagV = flagN ^ flagC
1113 static void Op68(void) // ASL ZP, X
1121 static void Op78(void) // ASL ABS
1129 static void Op48(void) // ASLA
1131 OP_ASL_HANDLER(regs.a);
1134 static void Op58(void) // ASLB
1136 OP_ASL_HANDLER(regs.b);
1140 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1141 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1142 Arithmetic Shift Right |ASR | | |67 7 2|77 6 3| |Memory *4| TT6T|
1143 |ASRA | | | | |47 2 1|Accum A *4| TT6T|
1144 |ASRB | | | | |57 2 1|Accum B *4| TT6T|
1149 //#define OP_ASR_HANDLER(m) \
1150 uint8 newCarry = m & 0x01; \
1151 m = (m >> 1) | (m & 0x80); \
1153 regs.cc = (regs.cc & ~FLAG_C) | newCarry; \
1154 regs.cc = (regs.cc & ~FLAG_V) | ((regs.cc & FLAG_N) >> 2) ^ ((regs.cc & FLAG_C) << 1)
1155 #define OP_ASR_HANDLER(m) \
1156 uint8 newCarry = m & 0x01; \
1157 m = (m >> 1) | (m & 0x80); \
1160 flagV = flagN ^ flagC
1162 static void Op67(void) // ASR ZP, X
1170 static void Op77(void) // ASR ABS
1178 static void Op47(void) // ASRA
1180 OP_ASR_HANDLER(regs.a);
1183 static void Op57(void) // ASRB
1185 OP_ASR_HANDLER(regs.b);
1189 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1190 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1191 Logic Shift Right |LSR | | |64 7 2|74 6 3| |Memory *5| TT6T|
1192 |LSRA | | | | |44 2 1|Accum A *5| TT6T|
1193 |LSRB | | | | |54 2 1|Accum B *5| TT6T|
1198 //#define OP_LSR_HANDLER(m) \
1199 uint8 newCarry = m & 0x01; \
1202 regs.cc = (regs.cc & ~FLAG_C) | newCarry; \
1203 regs.cc = (regs.cc & ~FLAG_V) | ((regs.cc & FLAG_N) >> 2) ^ ((regs.cc & FLAG_C) << 1)
1204 #define OP_LSR_HANDLER(m) \
1205 uint8 newCarry = m & 0x01; \
1209 flagV = flagN ^ flagC
1211 static void Op64(void) // LSR ZP, X
1219 static void Op74(void) // LSR ABS
1227 static void Op44(void) // LSRA
1229 OP_LSR_HANDLER(regs.a);
1232 static void Op54(void) // LSRB
1234 OP_LSR_HANDLER(regs.b);
1238 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1239 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1240 Store Accumulator |STAA | |97 4 2|A7 6 2|B7 5 3| |M=A | TTR |
1241 |STAB | |D7 4 2|E7 6 2|F7 5 3| |M=B | TTR |
1244 static void Op97(void) // STAA ZP
1246 regs.WrMem(EA_ZP, regs.a);
1249 static void OpA7(void) // STAA ZP, X
1251 regs.WrMem(EA_ZP_X, regs.a);
1254 static void OpB7(void) // STAA ABS
1256 regs.WrMem(EA_ABS, regs.a);
1260 static void OpD7(void) // STAB ZP
1262 regs.WrMem(EA_ZP, regs.b);
1265 static void OpE7(void) // STAB ZP, X
1267 regs.WrMem(EA_ZP_X, regs.b);
1270 static void OpF7(void) // STAB ABS
1272 regs.WrMem(EA_ABS, regs.b);
1277 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1278 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1279 Subtract |SUBA |80 2 2|90 3 2|A0 5 2|B0 4 3| |A=A-M | TTTT|
1280 |SUBB |C0 2 2|D0 3 2|E0 5 2|F0 4 3| |B=B-M | TTTT|
1281 Subtract Accumulators |SBA | | | | |10 2 1|A=A-B | TTTT|
1286 //#define OP_SUB_HANDLER(m, acc) \
1287 uint16 sum = (uint16)acc - (m); \
1288 regs.cc = (regs.cc & ~FLAG_C) | (sum >> 15); \
1289 SET_V(m, acc, sum); \
1292 #define OP_SUB_HANDLER(m, acc) \
1293 uint16 sum = (uint16)acc - (m); \
1294 flagC = sum >> 15; \
1295 SET_V(m, acc, sum); \
1299 static void Op80(void) // SUBA #
1301 uint16 m = READ_IMM;
1302 OP_SUB_HANDLER(m, regs.a);
1305 static void Op90(void) // SUBA ZP
1308 OP_SUB_HANDLER(m, regs.a);
1311 static void OpA0(void) // SUBA ZP, X
1313 uint16 m = READ_ZP_X;
1314 OP_SUB_HANDLER(m, regs.a);
1317 static void OpB0(void) // SUBA ABS
1319 uint16 m = READ_ABS;
1320 OP_SUB_HANDLER(m, regs.a);
1323 static void OpC0(void) // SUBB #
1325 uint16 m = READ_IMM;
1326 OP_SUB_HANDLER(m, regs.b);
1329 static void OpD0(void) // SUBB ZP
1332 OP_SUB_HANDLER(m, regs.b);
1335 static void OpE0(void) // SUBB ZP, X
1337 uint16 m = READ_ZP_X;
1338 OP_SUB_HANDLER(m, regs.b);
1341 static void OpF0(void) // SUBB ABS
1343 uint16 m = READ_ABS;
1344 OP_SUB_HANDLER(m, regs.b);
1347 static void Op10(void) // SBA
1349 OP_SUB_HANDLER(regs.b, regs.a);
1353 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1354 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1355 Subtract with Carry |SBCA |82 2 2|92 3 2|A2 5 2|B2 4 3| |A=A-M-C | TTTT|
1356 |SBCB |C2 2 2|D2 3 2|E2 5 2|F2 4 3| |B=B-M-C | TTTT|
1361 //#define OP_SBC_HANDLER(m, acc) \
1362 uint16 sum = (uint16)acc - (m) - (uint16)(regs.cc & FLAG_C); \
1363 regs.cc = (regs.cc & ~FLAG_C) | (sum >> 15); \
1364 SET_V(m, acc, sum); \
1367 #define OP_SBC_HANDLER(m, acc) \
1368 uint16 sum = (uint16)acc - (m) - (uint16)flagC; \
1369 flagC = sum >> 15; \
1370 SET_V(m, acc, sum); \
1374 static void Op82(void) // SBCA #
1376 uint16 m = READ_IMM;
1377 OP_SBC_HANDLER(m, regs.a);
1380 static void Op92(void) // SBCA ZP
1383 OP_SBC_HANDLER(m, regs.a);
1386 static void OpA2(void) // SBCA ZP, X
1388 uint16 m = READ_ZP_X;
1389 OP_SBC_HANDLER(m, regs.a);
1392 static void OpB2(void) // SBCA ABS
1394 uint16 m = READ_ABS;
1395 OP_SBC_HANDLER(m, regs.a);
1398 static void OpC2(void) // SBCB #
1400 uint16 m = READ_IMM;
1401 OP_SBC_HANDLER(m, regs.b);
1404 static void OpD2(void) // SBCB ZP
1407 OP_SBC_HANDLER(m, regs.b);
1410 static void OpE2(void) // SBCB ZP, X
1412 uint16 m = READ_ZP_X;
1413 OP_SBC_HANDLER(m, regs.b);
1416 static void OpF2(void) // SBCB ABS
1418 uint16 m = READ_ABS;
1419 OP_SBC_HANDLER(m, regs.b);
1423 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1424 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1425 Transfer Accumulators |TAB | | | | |16 2 1|B=A | TTR |
1426 |TBA | | | | |17 2 1|A=B | TTR |
1429 static void Op16(void) // TAB
1436 static void Op17(void) // TBA
1444 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1445 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1446 Test, Zero/Minus |TST | | |6D 7 2|7D 6 3| |M-00 | TTRR|
1447 |TSTA | | | | |4D 2 1|A-00 | TTRR|
1448 |TSTB | | | | |5D 2 1|B-00 | TTRR|
1453 #define OP_TST_HANDLER(m) \
1457 static void Op6D(void) // TST ZP, X
1465 static void Op7D(void) // TST ABS
1473 static void Op4D(void) // TSTA
1475 OP_TST_HANDLER(regs.a);
1478 static void Op5D(void) // TSTB
1480 OP_TST_HANDLER(regs.b);
1484 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1485 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1486 Compare Index Register |CPX |8C 3 3|9C 4 2|AC 6 2|BC 5 3| |Formula 1 | 7T8 |
1492 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.
1495 #define OP_CPX_HANDLER(m) \
1496 uint32 result = regs.x - (m); \
1497 SET_ZNVC_CMP16(m, regs.x, result)
1499 static void Op8C(void) // CPX #
1501 uint16 m = READ_IMM16;
1505 static void Op9C(void) // CPX ZP
1507 uint16 m = READ_ZP16;
1511 static void OpAC(void) // CPX ZP, X
1513 uint16 m = READ_ZP_X16;
1517 static void OpBC(void) // CPX ABS
1519 uint16 m = READ_ABS16;
1524 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1525 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1526 Decrement Index Register|DEX | | | | |09 4 1|X=X-1 | T |
1527 Dec Stack Pointer |DES | | | | |34 4 1|SP=SP-1 | |
1528 Inc Index Regster |INX | | | | |08 4 1|X=X+1 | T |
1529 Inc Stack Pointer |INS | | | | |31 4 1|SP=SP+1 | |
1532 static void Op09(void) // DEX
1538 static void Op34(void) // DES
1543 static void Op08(void) // INX
1549 static void Op31(void) // INS
1555 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1556 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1557 Load Index Register |LDX |CE 3 3|DE 4 2|EE 6 2|FE 5 3| |Formula 2 | 9TR |
1558 Load Stack Pointer |LDS |8E 3 3|9E 4 2|AE 6 2|BE 5 3| |Formula 3 | 9TR |
1561 // LD* opcode handler
1563 #define OP_LD_HANDLER(acc) \
1568 static void OpCE(void) // LDX #
1570 regs.x = READ_IMM16;
1571 OP_LD_HANDLER(regs.x);
1574 static void OpDE(void) // LDX ZP
1577 OP_LD_HANDLER(regs.x);
1580 static void OpEE(void) // LDX ZP, X
1582 regs.x = READ_ZP_X16;
1583 OP_LD_HANDLER(regs.x);
1586 static void OpFE(void) // LDX ABS
1588 regs.x = READ_ABS16;
1589 OP_LD_HANDLER(regs.x);
1592 static void Op8E(void) // LDS #
1594 regs.s = READ_IMM16;
1595 OP_LD_HANDLER(regs.s);
1598 static void Op9E(void) // LDS ZP
1601 OP_LD_HANDLER(regs.s);
1604 static void OpAE(void) // LDS ZP, X
1606 regs.s = READ_ZP_X16;
1607 OP_LD_HANDLER(regs.s);
1610 static void OpBE(void) // LDS ABS
1612 regs.s = READ_ABS16;
1613 OP_LD_HANDLER(regs.s);
1617 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1618 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1619 Store Index Register |STX | |DF 5 2|EF 7 2|FF 6 3| |Formula 4 | 9TR |
1620 Store Stack Pointer |STS | |9F 5 2|AF 7 2|BF 6 3| |Formula 5 | 9TR |
1623 // ST* opcode handler
1625 #define OP_ST_HANDLER(m, acc) \
1626 regs.WrMem(m + 0, acc >> 8); \
1627 regs.WrMem(m + 1, acc & 0xFF); \
1632 static void OpDF(void) // STX ZP
1635 OP_ST_HANDLER(m, regs.x);
1638 static void OpEF(void) // STX ZP, X
1641 OP_ST_HANDLER(m, regs.x);
1644 static void OpFF(void) // STX ABS
1648 OP_ST_HANDLER(m, regs.x);
1651 static void Op9F(void) // STS ZP
1654 OP_ST_HANDLER(m, regs.s);
1657 static void OpAF(void) // STS ZP, X
1660 OP_ST_HANDLER(m, regs.s);
1663 static void OpBF(void) // STS ABS
1667 OP_ST_HANDLER(m, regs.s);
1671 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1672 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1673 Index Reg > Stack Pnter |TXS | | | | |35 4 1|SP=X-1 | |
1674 Stack Ptr > Index Regtr |TSX | | | | |30 4 1|X=SP+1 | |
1677 static void Op35(void) // TXS
1679 regs.s = regs.x - 1;
1682 static void Op30(void) // TSX
1684 regs.x = regs.s + 1;
1688 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1689 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1690 Always |BRA | |20 4 2| | | |none | |
1691 Carry is Clear |BCC | |24 4 2| | | |C=0 | |
1692 Carry is Set |BCS | |25 4 2| | | |C=1 | |
1693 Equals Zero |BEQ | |27 4 2| | | |Z=1 | |
1694 Greater or Equal to Zero|BGE | |2C 4 2| | | |N(+)V=0 | |
1695 Greater than Zero |BGT | |2E 4 2| | | |Z+N(+)V=0 | |
1696 Higher |BHI | |22 4 2| | | |C+Z=0 | |
1697 Less or Equal than Zero |BLE | |2F 4 2| | | |Z+N(+)V=1 | |
1698 Lower or Same |BLS | |23 4 2| | | |C+Z=1 | |
1699 Less Than Zero |BLT | |2D 4 2| | | |N(+)V=1 | |
1700 Minus |BMI | |2B 4 2| | | |N=1 | |
1701 Not Zero |BNE | |26 4 2| | | |Z=0 | |
1702 Overflow Clear |BVC | |28 4 2| | | |V=0 | |
1703 Overflow Set |BVS | |29 4 2| | | |V=1 | |
1704 Plus |BPL | |2A 4 2| | | |N=0 | |
1707 static void Op20(void) // BRA
1709 int16 m = (int16)(int8)READ_IMM;
1713 static void Op24(void) // BCC
1715 int16 m = (int16)(int8)READ_IMM;
1717 // if (!(regs.cc & FLAG_C))
1722 static void Op25(void) // BCS
1724 int16 m = (int16)(int8)READ_IMM;
1726 // if (regs.cc & FLAG_C)
1731 static void Op27(void) // BEQ
1733 int16 m = (int16)(int8)READ_IMM;
1735 // if (regs.cc & FLAG_Z)
1740 static void Op2C(void) // BGE
1742 int16 m = (int16)(int8)READ_IMM;
1744 // if (!(((regs.cc & FLAG_N) >> 2) ^ (regs.cc & FLAG_V)))
1745 if (!(flagN ^ flagV))
1749 static void Op2E(void) // BGT
1751 int16 m = (int16)(int8)READ_IMM;
1753 // if (!(((regs.cc & FLAG_Z) >> 1) | (((regs.cc & FLAG_N) >> 2) ^ (regs.cc & FLAG_V))))
1754 if (!(flagZ | (flagN ^ flagV)))
1758 static void Op22(void) // BHI
1760 int16 m = (int16)(int8)READ_IMM;
1762 // if (!(((regs.cc & FLAG_Z) >> 2) | (regs.cc & FLAG_C)))
1763 if (!(flagZ | flagC))
1767 static void Op2F(void) // BLE
1769 int16 m = (int16)(int8)READ_IMM;
1771 // if (((regs.cc & FLAG_Z) >> 1) | (((regs.cc & FLAG_N) >> 2) ^ (regs.cc & FLAG_V)))
1772 if (flagZ | (flagN ^ flagV))
1776 static void Op23(void) // BLS
1778 int16 m = (int16)(int8)READ_IMM;
1780 // if (((regs.cc & FLAG_Z) >> 2) | (regs.cc & FLAG_C))
1785 static void Op2D(void) // BLT
1787 int16 m = (int16)(int8)READ_IMM;
1789 // if (((regs.cc & FLAG_N) >> 2) ^ (regs.cc & FLAG_V))
1794 static void Op2B(void) // BMI
1796 int16 m = (int16)(int8)READ_IMM;
1798 // if (regs.cc & FLAG_N)
1803 static void Op26(void) // BNE
1805 int16 m = (int16)(int8)READ_IMM;
1807 // if (!(regs.cc & FLAG_Z))
1812 static void Op28(void) // BVC
1814 int16 m = (int16)(int8)READ_IMM;
1816 // if (!(regs.cc & FLAG_V))
1821 static void Op29(void) // BVS
1823 int16 m = (int16)(int8)READ_IMM;
1825 // if (regs.cc & FLAG_V)
1830 static void Op2A(void) // BPL
1832 int16 m = (int16)(int8)READ_IMM;
1834 // if (!(regs.cc & FLAG_N))
1840 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1841 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1842 Branch to Subroutine |BSR | |8D 8 2| | | | | |
1843 Jump |JMP | | |6E 4 2|7E 3 3| | | |
1844 Jump to Subroutine |JSR | | |AD 8 2|BD 9 3| | | |
1847 static void Op8D(void) // BSR
1849 int16 m = (int16)(int8)READ_IMM;
1854 static void Op6E(void) // JMP ZP, X
1859 static void Op7E(void) // JMP ABS
1864 static void OpAD(void) // JSR ZP, X
1871 static void OpBD(void) // JSR ABS
1880 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1881 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1882 No Operation |NOP | | | | |01 2 1| | |
1883 Return from Interrupt |RTI | | | | |3B A 1| |AAAAAA|
1884 Return from Subroutine |RTS | | | | |39 5 1| | |
1885 Software Interrupt |SWI | | | | |3F C 1| | S |
1886 Wait For Interrupt |WAI | | | | |3E 9 1| | B |
1889 static void Op01(void) // NOP
1893 static void Op3B(void) // RTI
1903 static void Op39(void) // RTS
1908 static void Op3F(void) // SWI
1910 // It seems that the SWI is non-maskable, unlike the IRQ...
1911 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
1912 PUSH16(regs.pc); // Save all regs...
1917 regs.pc = RdMemW(0xFFFA); // And do it!
1918 // regs.cc |= FLAG_I; // Also, set IRQ inhibit
1919 flagI = 1; // Also, set IRQ inhibit
1922 static void Op3E(void) // WAI
1925 WriteLog("*** WAI STATE ASSERTED ***\n");
1927 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
1928 PUSH16(regs.pc); // Save all regs...
1933 regs.cpuFlags |= V6808_STATE_WAI; // And signal that we're in WAI mode
1937 Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
1938 | |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
1939 Clear Carry |CLC | | | | |0C 2 1|C=0 | R|
1940 Clear Interrupt |CLI | | | | |0E 2 1|I=0 | R |
1941 Clear Overflow |CLV | | | | |0A 2 1|V=0 | R |
1942 Set Carry |SEC | | | | |0D 2 1|C=1 | S|
1943 Set Interrupt |SEI | | | | |0F 2 1|I=1 | S |
1944 Set Overflow |SEV | | | | |0B 2 1|V=1 | S |
1945 CCR=Accumulator A |TAP | | | | |06 2 1|CCR=A |CCCCCC|
1946 Accumlator A=CCR |TPA | | | | |07 2 1|A=CCR | |
1949 static void Op0C(void) // CLC
1951 // regs.cc &= ~FLAG_C;
1955 static void Op0E(void) // CLI
1957 // regs.cc &= ~FLAG_I;
1961 static void Op0A(void) // CLV
1963 // regs.cc &= ~FLAG_V;
1967 static void Op0D(void) // SEC
1969 // regs.cc |= FLAG_C;
1973 static void Op0F(void) // SEI
1975 // regs.cc |= FLAG_I;
1979 static void Op0B(void) // SEV
1981 // regs.cc |= FLAG_V;
1985 static void Op06(void) // TAP
1991 static void Op07(void) // TPA
1993 // regs.a = regs.cc;
1994 regs.a = PACK_FLAGS;
1998 OP Operation Code, in Hexadecimal
1999 ~ Number of MPU cycles required
2000 # Number of program bytes required
2004 Msp Contents of Memory pointed to be Stack Pointer
2005 + Boolean Inclusive OR
2006 (+) Boolean Exclusive OR (XOR)
2007 * Converts Binary Addition of BCD Characters into BCD Format
2011 Condition Code Register Legend
2015 T Tests and sets if True, cleared otherise
2016 1 Test: Result=10000000?
2017 2 Test: Result=00000000?
2018 3 Test: Decimal value of most significant BCD character greater than nine?
2019 (Not cleared if previously set)
2020 4 Test: Operand=10000000 prior to execution?
2021 5 Test: Operand=01111111 prior to execution?
2022 6 Test: Set equal to result or N(+)C after shift has occurred.
2023 7 Test: Sign bit of most significant byte or result=1?
2024 8 Test: 2's compliment overflow from subtraction of least
2026 9 Test: Result less than zero? (Bit 15=1)
2027 A Load Condition Code Register from Stack.
2028 B Set when interrupt occurs. If previously set, a NMI is
2029 required to exit the wait state.
2030 C Set according to the contents of Accumulator A.
2032 *x SHIFT AND ROTATION DIAGRAMS
2033 *1 +-----------------+ C to LSB
2036 *2 +-----------------+
2039 *3 C <- 76543210 <- 0(Data)
2044 *5 (Data)0 -> 76543210 -> C
2053 static void Op__(void)
2055 regs.cpuFlags |= V6808_STATE_ILLEGAL_INST;
2060 // Ok, the exec_op[] array is globally defined here basically to save
2061 // a LOT of unnecessary typing. Sure it's ugly, but hey, it works!
2063 void (* exec_op[256])() = {
2064 Op__, Op01, Op__, Op__, Op__, Op__, Op06, Op07, Op08, Op09, Op0A, Op0B, Op0C, Op0D, Op0E, Op0F,
2065 Op10, Op11, Op__, Op__, Op__, Op__, Op16, Op17, Op__, Op19, Op__, Op1B, Op__, Op__, Op__, Op__,
2066 Op20, Op__, Op22, Op23, Op24, Op25, Op26, Op27, Op28, Op29, Op2A, Op2B, Op2C, Op2D, Op2E, Op2F,
2067 Op30, Op31, Op32, Op33, Op34, Op35, Op36, Op37, Op__, Op39, Op__, Op3B, Op__, Op__, Op3E, Op3F,
2068 Op40, Op__, Op__, Op43, Op44, Op__, Op46, Op47, Op48, Op49, Op4A, Op__, Op4C, Op4D, Op__, Op4F,
2069 Op50, Op__, Op__, Op53, Op54, Op__, Op56, Op57, Op58, Op59, Op5A, Op__, Op5C, Op5D, Op__, Op5F,
2070 Op60, Op__, Op__, Op63, Op64, Op__, Op66, Op67, Op68, Op69, Op6A, Op__, Op6C, Op6D, Op6E, Op6F,
2071 Op70, Op__, Op__, Op73, Op74, Op__, Op76, Op77, Op78, Op79, Op7A, Op__, Op7C, Op7D, Op7E, Op7F,
2072 Op80, Op81, Op82, Op__, Op84, Op85, Op86, Op__, Op88, Op89, Op8A, Op8B, Op8C, Op8D, Op8E, Op__,
2073 Op90, Op91, Op92, Op__, Op94, Op95, Op96, Op97, Op98, Op99, Op9A, Op9B, Op9C, Op__, Op9E, Op9F,
2074 OpA0, OpA1, OpA2, Op__, OpA4, OpA5, OpA6, OpA7, OpA8, OpA9, OpAA, OpAB, OpAC, OpAD, OpAE, OpAF,
2075 OpB0, OpB1, OpB2, Op__, OpB4, OpB5, OpB6, OpB7, OpB8, OpB9, OpBA, OpBB, OpBC, OpBD, OpBE, OpBF,
2076 OpC0, OpC1, OpC2, Op__, OpC4, OpC5, OpC6, Op__, OpC8, OpC9, OpCA, OpCB, Op__, Op__, OpCE, Op__,
2077 OpD0, OpD1, OpD2, Op__, OpD4, OpD5, OpD6, OpD7, OpD8, OpD9, OpDA, OpDB, Op__, Op__, OpDE, OpDF,
2078 OpE0, OpE1, OpE2, Op__, OpE4, OpE5, OpE6, OpE7, OpE8, OpE9, OpEA, OpEB, Op__, Op__, OpEE, OpEF,
2079 OpF0, OpF1, OpF2, Op__, OpF4, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, OpFB, Op__, Op__, OpFE, OpFF
2084 // Internal "memcpy" (so we don't have to link with any external libraries!)
2086 static void myMemcpy(void * dst, void * src, uint32 size)
2088 uint8 * d = (uint8 *)dst, * s = (uint8 *)src;
2090 for(uint32 i=0; i<size; i++)
2095 //int instCount[256];
2096 static bool logGo = false;
2099 // Function to execute 6808 for "cycles" cycles
2101 void Execute6808(V6808REGS * context, uint32 cycles)
2103 #warning V6808_STATE_WAI is not properly handled yet!
2105 myMemcpy(®s, context, sizeof(V6808REGS));
2106 UNPACK_FLAGS; // Explode flags register into individual uint8s
2109 while (regs.clock < cycles)
2113 Decode6808(regs.pc);
2115 uint8 opcode = regs.RdMem(regs.pc++);
2118 //if (!(regs.cpuFlags & V6808_STATE_ILLEGAL_INST))
2119 //instCount[opcode]++;
2122 exec_op[opcode](); // Execute that opcode...
2123 regs.clock += CPUCycles[opcode];
2126 // 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" : " "));
2127 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" : " "));
2130 if (regs.cpuFlags & V6808_ASSERT_LINE_RESET)
2133 WriteLog("*** RESET LINE ASSERTED ***\n");
2135 // regs.cc |= FLAG_I; // Set I
2137 regs.pc = RdMemW(0xFFFE); // And load PC with the RESET vector
2139 context->cpuFlags &= ~V6808_ASSERT_LINE_RESET;
2140 regs.cpuFlags &= ~V6808_ASSERT_LINE_RESET;
2142 else if (regs.cpuFlags & V6808_ASSERT_LINE_NMI)
2145 WriteLog("*** NMI LINE ASSERTED ***\n");
2147 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2148 PUSH16(regs.pc); // Save all regs...
2153 regs.pc = RdMemW(0xFFFC); // And do it!
2155 regs.clock += 0; // How many???
2156 context->cpuFlags &= ~V6808_ASSERT_LINE_NMI;// Reset the asserted line (NMI)...
2157 regs.cpuFlags &= ~V6808_ASSERT_LINE_NMI; // Reset the asserted line (NMI)...
2159 else if (regs.cpuFlags & V6808_ASSERT_LINE_IRQ)
2162 WriteLog("*** IRQ LINE ASSERTED ***\n");
2164 // if (!(regs.cc & FLAG_I)) // Process an interrupt (I=0)?
2165 if (!flagI) // Process an interrupt (I=0)?
2168 WriteLog(" IRQ TAKEN!\n");
2171 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2172 PUSH16(regs.pc); // Save all regs...
2177 regs.pc = RdMemW(0xFFF8); // And do it!
2179 regs.clock += 0; // How many???
2180 context->cpuFlags &= ~V6808_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
2181 regs.cpuFlags &= ~V6808_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
2186 regs.cc = PACK_FLAGS; // Mash flags back into the CC register
2187 myMemcpy(context, ®s, sizeof(V6808REGS));
2191 // Get the clock of the currently executing CPU
2193 uint32 GetCurrentV6808Clock(void)