10 #define ALWAYS_INLINE __attribute__((always_inline))
13 #define CPU_6800_IRQ_VECTOR 0xfff8
14 #define CPU_6800_SWI_VECTOR 0xfffa
15 #define CPU_6800_NMI_VECTOR 0xfffc
16 #define CPU_6800_RESET_VECTOR 0xfffe
19 #define CPU_6800_REG_P_BIT_H 5
20 #define CPU_6800_REG_P_BIT_I 4
21 #define CPU_6800_REG_P_BIT_N 3
22 #define CPU_6800_REG_P_BIT_Z 2
23 #define CPU_6800_REG_P_BIT_V 1
24 #define CPU_6800_REG_P_BIT_C 0
26 // special memory locations (negative address)
27 #define CPU_6800_EA_PC (-0xa)
28 #define CPU_6800_EA_A (-8)
29 #define CPU_6800_EA_B (-7)
30 #define CPU_6800_EA_S (-6)
31 #define CPU_6800_EA_X (-4)
32 #define CPU_6800_EA_P (-2)
33 #define CPU_6800_EA_IFLAGS (-1)
35 // registers, in same order as special memory locations, but reversed on
36 // little endian hardware where special memory address will be complemented
37 // (this allows special memory to always look like it is big endian)
39 #if __BYTE_ORDER == __BIG_ENDIAN
53 uint8_t _fill_iflags : 5;
55 uint8_t irq_pending : 1;
56 uint8_t nmi_pending : 1;
79 uint8_t nmi_pending : 1;
80 uint8_t irq_pending : 1;
82 uint8_t _fill_iflags : 5;
106 uint8_t _fill_iflags;
120 int (*read_byte)(void *context, int addr);
121 void *read_byte_context;
122 void (*write_byte)(void *context, int addr, int data);
123 void *write_byte_context;
124 union cpu_6800_regs regs;
127 // memory or special memory access
128 static ALWAYS_INLINE int cpu_6800_read_byte(struct cpu_6800 *self, int addr) {
130 #if __BYTE_ORDER == __BIG_ENDIAN
131 return self->regs.mem_be[sizeof(union cpu_6800_regs) + addr];
133 return self->regs.mem_le[~addr];
136 return self->read_byte(self->read_byte_context, addr & 0xffff);
139 static ALWAYS_INLINE int cpu_6800_read_word(struct cpu_6800 *self, int addr) {
140 int data = cpu_6800_read_byte(self, addr) << 8;
141 return data | cpu_6800_read_byte(self, addr + 1);
144 static ALWAYS_INLINE void cpu_6800_write_byte(struct cpu_6800 *self, int addr, int data) {
147 #if __BYTE_ORDER == __BIG_ENDIAN
148 self->regs.mem_be[sizeof(union cpu_6800_regs) + addr] = data;
150 self->regs.mem_le[~addr] = data;
153 self->write_byte(self->write_byte_context, addr, data);
156 static ALWAYS_INLINE void cpu_6800_write_word(struct cpu_6800 *self, int addr, int data) {
157 cpu_6800_write_byte(self, addr, data >> 8);
158 cpu_6800_write_byte(self, addr + 1, data & 0xff);
161 static ALWAYS_INLINE int cpu_6800_fetch_byte(struct cpu_6800 *self) {
162 int data = cpu_6800_read_byte(self, self->regs.word.pc++);
166 static ALWAYS_INLINE int cpu_6800_fetch_word(struct cpu_6800 *self) {
167 int data = cpu_6800_fetch_byte(self) << 8;
168 return data | cpu_6800_fetch_byte(self);
171 static ALWAYS_INLINE void cpu_6800_push_byte(struct cpu_6800 *self, int data) {
172 cpu_6800_write_byte(self, self->regs.word.s--, data);
175 static ALWAYS_INLINE void cpu_6800_push_word(struct cpu_6800 *self, int data) {
176 cpu_6800_push_byte(self, data & 0xff);
177 cpu_6800_push_byte(self, data >> 8);
180 static ALWAYS_INLINE int cpu_6800_pop_byte(struct cpu_6800 *self) {
181 return cpu_6800_read_byte(self, ++self->regs.word.s);
184 static ALWAYS_INLINE int cpu_6800_pop_word(struct cpu_6800 *self) {
185 int data = cpu_6800_pop_byte(self) << 8;
186 return data | cpu_6800_pop_byte(self);
189 // effective address calculation
190 static ALWAYS_INLINE int cpu_6800_ea_extended(struct cpu_6800 *self) {
191 return cpu_6800_fetch_word(self);
194 static ALWAYS_INLINE int cpu_6800_ea_extended_indexed(struct cpu_6800 *self, int rvalue) {
195 int addr = cpu_6800_ea_extended(self);
196 self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8;
197 return addr + rvalue;
200 static ALWAYS_INLINE int cpu_6800_ea_relative(struct cpu_6800 *self) {
201 return (int8_t)cpu_6800_fetch_byte(self);
204 static ALWAYS_INLINE int cpu_6800_ea_direct(struct cpu_6800 *self) {
205 return cpu_6800_fetch_byte(self);
208 static ALWAYS_INLINE int cpu_6800_ea_direct_indexed(struct cpu_6800 *self, int rvalue) {
209 int addr = cpu_6800_ea_direct(self);
210 self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8;
211 return addr + rvalue;
214 // instruction execute
215 static ALWAYS_INLINE void cpu_6800_adc(struct cpu_6800 *self, int lvalue, int rvalue) {
216 int data = cpu_6800_read_byte(self, lvalue);
218 int result0 = (data & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
219 int result1 = result0 + (data & 0x70) + (rvalue & 0x70);
220 int result2 = result1 + (data & 0x80) + (rvalue & 0x80);
222 cpu_6800_write_byte(self, lvalue, result2 & 0xff);
223 self->regs.bit.hf = result0 >> 4;
224 self->regs.bit.nf = (result2 >> 7) & 1;
225 self->regs.bit.zf = (result2 & 0xff) == 0;
226 self->regs.bit.vf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
227 self->regs.bit.cf = result2 >> 8;
230 static ALWAYS_INLINE void cpu_6800_add(struct cpu_6800 *self, int lvalue, int rvalue) {
231 int data = cpu_6800_read_byte(self, lvalue);
233 int result0 = (data & 0xf) + (rvalue & 0xf);
234 int result1 = result0 + (data & 0x70) + (rvalue & 0x70);
235 int result2 = result1 + (data & 0x80) + (rvalue & 0x80);
237 cpu_6800_write_byte(self, lvalue, result2 & 0xff);
238 self->regs.bit.hf = result0 >> 4;
239 self->regs.bit.nf = (result2 >> 7) & 1;
240 self->regs.bit.zf = (result2 & 0xff) == 0;
241 self->regs.bit.vf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
242 self->regs.bit.cf = result2 >> 8;
245 static ALWAYS_INLINE void cpu_6800_and(struct cpu_6800 *self, int lvalue, int rvalue) {
246 int result = cpu_6800_read_byte(self, lvalue) & rvalue;
248 cpu_6800_write_byte(self, lvalue, result);
249 self->regs.bit.nf = result >> 7;
250 self->regs.bit.zf = result == 0;
251 self->regs.bit.vf = false;
254 static ALWAYS_INLINE void cpu_6800_asl(struct cpu_6800 *self, int lvalue) {
255 int result = cpu_6800_read_byte(self, lvalue) << 1;
258 cpu_6800_write_byte(self, lvalue, result & 0xff);
259 self->regs.bit.nf = (result >> 7) & 1;
260 self->regs.bit.zf = (result & 0xff) == 0;
261 self->regs.bit.vf = ((result >> 7) ^ (result >> 8)) & 1;
262 self->regs.bit.cf = result >> 8;
265 static ALWAYS_INLINE void cpu_6800_asr(struct cpu_6800 *self, int lvalue) {
266 int data = cpu_6800_read_byte(self, lvalue);
268 int result = data | ((data << 1) & 0x100);
271 cpu_6800_write_byte(self, lvalue, result >> 1);
272 self->regs.bit.nf = result >> 8;
273 self->regs.bit.zf = (result & 0xfe) == 0;
274 self->regs.bit.vf = (result ^ (result >> 8)) & 1;
275 self->regs.bit.cf = result & 1;
278 static ALWAYS_INLINE void cpu_6800_bit(struct cpu_6800 *self, int rvalue0, int rvalue1) {
279 int result = rvalue0 & rvalue1;
281 self->regs.bit.nf = result >> 7;
282 self->regs.bit.zf = result == 0;
283 self->regs.bit.vf = false;
286 static ALWAYS_INLINE void cpu_6800_bra(struct cpu_6800 *self, bool pred, int lvalue) {
288 self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
289 self->regs.word.pc += lvalue;
293 static ALWAYS_INLINE void cpu_6800_bsr(struct cpu_6800 *self, int lvalue) {
294 cpu_6800_push_word(self, self->regs.word.pc);
295 self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
296 self->regs.word.pc += lvalue;
299 static ALWAYS_INLINE void cpu_6800_cl(struct cpu_6800 *self, int n) {
300 self->regs.byte.p &= ~(1 << n);
303 static ALWAYS_INLINE void cpu_6800_clr(struct cpu_6800 *self, int lvalue) {
304 cpu_6800_read_byte(self, lvalue); // clr is implemented as RMW like inc/dec
305 cpu_6800_write_byte(self, lvalue, 0);
307 self->regs.bit.nf = false;
308 self->regs.bit.zf = true;
309 self->regs.bit.vf = false;
310 self->regs.bit.cf = false;
313 static ALWAYS_INLINE void cpu_6800_cmp_byte(struct cpu_6800 *self, int rvalue0, int rvalue1) {
314 int result0 = (rvalue0 & 0x7f) - (rvalue1 & 0x7f);
315 int result1 = result0 + (rvalue0 & 0x80) - (rvalue1 & 0x80);
317 self->regs.bit.nf = (result1 >> 7) & 1;
318 self->regs.bit.zf = (result1 & 0xff) == 0;
319 self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
320 self->regs.bit.cf = (result1 >> 8) & 1;
323 static ALWAYS_INLINE void cpu_6800_cmp_word(struct cpu_6800 *self, int rvalue0, int rvalue1) {
324 int result0 = (rvalue0 & 0x7fff) - (rvalue1 & 0x7fff);
325 int result1 = result0 + (rvalue0 & 0x8000) - (rvalue1 & 0x8000);
327 self->regs.bit.nf = (result1 >> 15) & 1;
328 self->regs.bit.zf = (result1 & 0xffff) == 0;
329 self->regs.bit.vf = ((result0 >> 15) ^ (result1 >> 16)) & 1;
332 static ALWAYS_INLINE void cpu_6800_com(struct cpu_6800 *self, int lvalue) {
333 int result = cpu_6800_read_byte(self, lvalue) ^ 0xff;
335 cpu_6800_write_byte(self, lvalue, result);
336 self->regs.bit.nf = result >> 7;
337 self->regs.bit.zf = result == 0;
338 self->regs.bit.vf = false;
339 self->regs.bit.cf = true;
342 static ALWAYS_INLINE void cpu_6800_daa(struct cpu_6800 *self) {
344 if (self->regs.bit.hf || (self->regs.byte.a & 0xf) >= 0xa)
346 if (self->regs.bit.cf || self->regs.byte.a >= 0x9a) {
348 self->regs.bit.cf = true;
351 int result0 = (self->regs.byte.a & 0x7f) + correction;
352 int result1 = result0 + (self->regs.byte.a & 0x80);
354 self->regs.byte.a = result1 & 0xff;
355 self->regs.bit.nf = (result1 >> 7) & 1;
356 self->regs.bit.zf = (result1 & 0xff) == 0;
357 self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
358 //self->regs.bit.cf |= result1 >> 8;
361 static ALWAYS_INLINE void cpu_6800_dec_byte(struct cpu_6800 *self, int lvalue) {
362 int data = cpu_6800_read_byte(self, lvalue);
364 int result0 = (data & 0x7f) - 1;
365 int result1 = result0 + (data & 0x80);
368 cpu_6800_write_byte(self, lvalue, result1 & 0xff);
369 self->regs.bit.nf = (result1 >> 7) & 1;
370 self->regs.bit.zf = (result1 & 0xff) == 0;
371 self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
374 static ALWAYS_INLINE void cpu_6800_dec_word(struct cpu_6800 *self, int lvalue) {
378 (cpu_6800_read_word(self, lvalue) - 1) & 0xffff
383 static ALWAYS_INLINE void cpu_6800_dec_word_zf(struct cpu_6800 *self, int lvalue) {
384 int result = (cpu_6800_read_word(self, lvalue) - 1) & 0xffff;
387 self->regs.word.x = result;
388 self->regs.bit.zf = result == 0;
391 static ALWAYS_INLINE void cpu_6800_eor(struct cpu_6800 *self, int lvalue, int rvalue) {
392 int result = cpu_6800_read_byte(self, lvalue) ^ rvalue;
394 cpu_6800_write_byte(self, lvalue, result);
395 self->regs.bit.nf = result >> 7;
396 self->regs.bit.zf = result == 0;
397 self->regs.bit.vf = false;
400 static ALWAYS_INLINE void cpu_6800_illegal_opcode(struct cpu_6800 *self) {
404 static ALWAYS_INLINE void cpu_6800_inc_byte(struct cpu_6800 *self, int lvalue) {
405 int data = cpu_6800_read_byte(self, lvalue);
407 int result0 = (data & 0x7f) + 1;
408 int result1 = result0 + (data & 0x80);
411 cpu_6800_write_byte(self, lvalue, result1 & 0xff);
412 self->regs.bit.nf = (result1 >> 7) & 1;
413 self->regs.bit.zf = (result1 & 0xff) == 0;
414 self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
417 static ALWAYS_INLINE void cpu_6800_inc_word(struct cpu_6800 *self, int lvalue) {
421 (cpu_6800_read_word(self, lvalue) + 1) & 0xffff
426 static ALWAYS_INLINE void cpu_6800_inc_word_zf(struct cpu_6800 *self, int lvalue) {
427 int result = (cpu_6800_read_word(self, lvalue) + 1) & 0xffff;
430 self->regs.word.x = result;
431 self->regs.bit.zf = result == 0;
434 static ALWAYS_INLINE void cpu_6800_jmp(struct cpu_6800 *self, int lvalue) {
435 self->regs.word.pc = lvalue;
438 static ALWAYS_INLINE void cpu_6800_jsr(struct cpu_6800 *self, int lvalue) {
439 cpu_6800_push_word(self, self->regs.word.pc);
440 self->regs.word.pc = lvalue;
443 static ALWAYS_INLINE void cpu_6800_ld_word(struct cpu_6800 *self, int lvalue, int rvalue) {
444 cpu_6800_write_word(self, lvalue, rvalue);
446 self->regs.bit.nf = (rvalue >> 15) & 1;
447 self->regs.bit.zf = rvalue == 0;
448 self->regs.bit.vf = false;
451 static ALWAYS_INLINE void cpu_6800_ld_byte(struct cpu_6800 *self, int lvalue, int rvalue) {
452 cpu_6800_write_byte(self, lvalue, rvalue);
454 self->regs.bit.nf = (rvalue >> 7) & 1;
455 self->regs.bit.zf = rvalue == 0;
456 self->regs.bit.vf = false;
459 static ALWAYS_INLINE void cpu_6800_lsr(struct cpu_6800 *self, int lvalue) {
460 int data = cpu_6800_read_byte(self, lvalue);
465 cpu_6800_write_byte(self, lvalue, result >> 1);
466 self->regs.bit.nf = result >> 8;
467 self->regs.bit.zf = (result & 0xfe) == 0;
468 self->regs.bit.vf = (result ^ (result >> 8)) & 1;
469 self->regs.bit.cf = result & 1;
472 static ALWAYS_INLINE void cpu_6800_neg(struct cpu_6800 *self, int lvalue) {
473 int data = cpu_6800_read_byte(self, lvalue);
475 int result0 = -(data & 0x7f);
476 int result1 = result0 - (data & 0x80);
478 cpu_6800_write_byte(self, lvalue, result1 & 0xff);
479 self->regs.bit.nf = (result1 >> 7) & 1;
480 self->regs.bit.zf = (result1 & 0xff) == 0;
481 self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
482 self->regs.bit.cf = (result1 >> 8) & 1;
485 static ALWAYS_INLINE void cpu_6800_nop(struct cpu_6800 *self) {
488 static ALWAYS_INLINE void cpu_6800_ora(struct cpu_6800 *self, int lvalue, int rvalue) {
489 int result = cpu_6800_read_byte(self, lvalue) | rvalue;
491 cpu_6800_write_byte(self, lvalue, result);
492 self->regs.bit.nf = result >> 7;
493 self->regs.bit.zf = result == 0;
494 self->regs.bit.vf = false;
497 static ALWAYS_INLINE void cpu_6800_psh(struct cpu_6800 *self, int rvalue) {
498 cpu_6800_push_byte(self, rvalue);
501 static ALWAYS_INLINE void cpu_6800_pul(struct cpu_6800 *self, int lvalue) {
502 cpu_6800_write_byte(self, lvalue, cpu_6800_pop_byte(self));
505 static ALWAYS_INLINE void cpu_6800_rol(struct cpu_6800 *self, int lvalue) {
506 int result = self->regs.bit.cf | (cpu_6800_read_byte(self, lvalue) << 1);
509 cpu_6800_write_byte(self, lvalue, result & 0xff);
510 self->regs.bit.nf = (result >> 7) & 1;
511 self->regs.bit.zf = (result & 0xff) == 0;
512 self->regs.bit.vf = ((result >> 7) ^ (result >> 8)) & 1;
513 self->regs.bit.cf = result >> 8;
516 static ALWAYS_INLINE void cpu_6800_ror(struct cpu_6800 *self, int lvalue) {
517 int result = cpu_6800_read_byte(self, lvalue) | (self->regs.bit.cf << 8);
519 cpu_6800_write_byte(self, lvalue, result >> 1);
521 self->regs.bit.nf = result >> 8;
522 self->regs.bit.zf = (result & 0x1fe) == 0;
523 self->regs.bit.vf = (result ^ (result >> 8)) & 1;
524 self->regs.bit.cf = result & 1;
527 static ALWAYS_INLINE void cpu_6800_rti(struct cpu_6800 *self) {
528 self->regs.byte.p = cpu_6800_pop_byte(self) | 0xc0;
529 self->regs.byte.b = cpu_6800_pop_byte(self);
530 self->regs.byte.a = cpu_6800_pop_byte(self);
531 self->regs.word.x = cpu_6800_pop_word(self);
532 self->regs.word.pc = cpu_6800_pop_word(self);
535 static ALWAYS_INLINE void cpu_6800_rts(struct cpu_6800 *self) {
536 self->regs.word.pc = cpu_6800_pop_word(self);
539 static ALWAYS_INLINE void cpu_6800_sbc(struct cpu_6800 *self, int lvalue, int rvalue) {
540 int data = cpu_6800_read_byte(self, lvalue);
542 int result0 = (data & 0x7f) - (rvalue & 0x7f) - self->regs.bit.cf;
543 int result1 = result0 + (data & 0x80) - (rvalue & 0x80);
545 cpu_6800_write_byte(self, lvalue, result1 & 0xff);
546 self->regs.bit.nf = (result1 >> 7) & 1;
547 self->regs.bit.zf = (result1 & 0xff) == 0;
548 self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
549 self->regs.bit.cf = (result1 >> 8) & 1;
552 static ALWAYS_INLINE void cpu_6800_se(struct cpu_6800 *self, int n) {
553 self->regs.byte.p |= 1 << n;
556 static ALWAYS_INLINE void cpu_6800_st_word(struct cpu_6800 *self, int rvalue, int lvalue) {
557 cpu_6800_write_word(self, lvalue, rvalue);
559 self->regs.bit.nf = (rvalue >> 15) & 1;
560 self->regs.bit.zf = rvalue == 0;
561 self->regs.bit.vf = false;
564 static ALWAYS_INLINE void cpu_6800_st_byte(struct cpu_6800 *self, int rvalue, int lvalue) {
565 cpu_6800_write_byte(self, lvalue, rvalue);
567 self->regs.bit.nf = (rvalue >> 7) & 1;
568 self->regs.bit.zf = rvalue == 0;
569 self->regs.bit.vf = false;
572 static ALWAYS_INLINE void cpu_6800_sub(struct cpu_6800 *self, int lvalue, int rvalue) {
573 int data = cpu_6800_read_byte(self, lvalue);
575 int result0 = (data & 0x7f) - (rvalue & 0x7f);
576 int result1 = result0 + (data & 0x80) - (rvalue & 0x80);
578 cpu_6800_write_byte(self, lvalue, result1 & 0xff);
579 self->regs.bit.nf = (result1 >> 7) & 1;
580 self->regs.bit.zf = (result1 & 0xff) == 0;
581 self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
582 self->regs.bit.cf = (result1 >> 8) & 1;
585 static ALWAYS_INLINE void cpu_6800_swi(struct cpu_6800 *self) {
586 cpu_6800_push_word(self, self->regs.word.pc);
587 cpu_6800_push_word(self, self->regs.word.x);
588 cpu_6800_push_byte(self, self->regs.byte.a);
589 cpu_6800_push_byte(self, self->regs.byte.b);
590 cpu_6800_push_byte(self, self->regs.byte.p);
591 self->regs.word.pc = cpu_6800_read_word(self, CPU_6800_SWI_VECTOR);
592 self->regs.bit._if = true;
595 static ALWAYS_INLINE void cpu_6800_tap(struct cpu_6800 *self) {
596 self->regs.byte.p = self->regs.byte.a | 0xc0;
599 static ALWAYS_INLINE void cpu_6800_tpa(struct cpu_6800 *self) {
600 self->regs.byte.a = self->regs.byte.p;
603 static ALWAYS_INLINE void cpu_6800_tsx(struct cpu_6800 *self) {
604 self->regs.word.x = (self->regs.word.s + 1) & 0xffff;
607 static ALWAYS_INLINE void cpu_6800_txs(struct cpu_6800 *self) {
608 self->regs.word.s = (self->regs.word.x - 1) & 0xffff;
611 static ALWAYS_INLINE void cpu_6800_wai(struct cpu_6800 *self) {
612 cpu_6800_push_word(self, self->regs.word.pc);
613 cpu_6800_push_word(self, self->regs.word.x);
614 cpu_6800_push_byte(self, self->regs.byte.a);
615 cpu_6800_push_byte(self, self->regs.byte.b);
616 cpu_6800_push_byte(self, self->regs.byte.p);
617 self->regs.bit.wai_flag = true;
622 struct cpu_6800 *self,
623 int (*read_byte)(void *context, int addr),
624 void *read_byte_context,
625 void (*write_byte)(void *context, int addr, int data),
626 void *write_byte_context
628 void cpu_6800_reset(struct cpu_6800 *self);
629 void cpu_6800_execute(struct cpu_6800 *self);