Implement 386 instruction table, improve 8086/186/286 instruction table
[multi_emu.git] / cpu_6800.h
1 #ifndef _CPU_6800_H
2 #define _CPU_6800_H
3
4 #include <endian.h>
5 #include <stdbool.h>
6 #include <stdint.h>
7
8 // gcc specific
9 #ifndef ALWAYS_INLINE
10 #define ALWAYS_INLINE __attribute__((always_inline))
11 #endif
12
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
17
18 // bits within REG_P
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
25
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)
34
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)
38 union cpu_6800_regs {
39 #if __BYTE_ORDER == __BIG_ENDIAN
40   struct {
41     uint16_t _fill_pc;
42     uint8_t _fill_a;
43     uint8_t _fill_b;
44     uint16_t _fill_s;
45     uint16_t _fill_x;
46     uint8_t _fill_p : 2;
47     uint8_t hf : 1;
48     uint8_t _if : 1;
49     uint8_t nf : 1;
50     uint8_t zf : 1;
51     uint8_t vf : 1;
52     uint8_t cf : 1;
53     uint8_t _fill_iflags : 5;
54     uint8_t wai_flag : 1;
55     uint8_t irq_pending : 1;
56     uint8_t nmi_pending : 1;
57   } bit;
58   struct {
59     uint16_t _fill_pc;
60     uint8_t a;
61     uint8_t b;
62     uint16_t _fill_s;
63     uint16_t _fill_x;
64     uint8_t p;
65     uint8_t iflags;
66   } byte;
67   struct {
68     uint16_t pc;
69     uint8_t _fill_a;
70     uint8_t _fill_b;
71     uint16_t s;
72     uint16_t x;
73     uint8_t _fill_p;
74     uint8_t _fill_iflags;
75   } word;
76   uint8_t mem_be[0xa];
77 #else
78   struct {
79     uint8_t nmi_pending : 1;
80     uint8_t irq_pending : 1;
81     uint8_t wai_flag : 1;
82     uint8_t _fill_iflags : 5;
83     uint8_t cf : 1;
84     uint8_t vf : 1;
85     uint8_t zf : 1;
86     uint8_t nf : 1;
87     uint8_t _if : 1;
88     uint8_t hf : 1;
89     uint8_t _fill_p : 2;
90     uint16_t _fill_x;
91     uint16_t _fill_s;
92     uint8_t _fill_b;
93     uint8_t _fill_a;
94     uint16_t _fill_pc;
95   } bit;
96   struct {
97     uint8_t iflags;
98     uint8_t p;
99     uint16_t _fill_x;
100     uint16_t _fill_s;
101     uint8_t b;
102     uint8_t a;
103     uint16_t _fill_pc;
104   } byte;
105   struct {
106     uint8_t _fill_iflags;
107     uint8_t _fill_p;
108     uint16_t x;
109     uint16_t s;
110     uint8_t _fill_b;
111     uint8_t _fill_a;
112     uint16_t pc;
113   } word;
114   uint8_t mem_le[0xa];
115 #endif
116 };
117
118 struct cpu_6800 {
119   int cycles;
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;
125 };
126
127 // memory or special memory access
128 static ALWAYS_INLINE int cpu_6800_read_byte(struct cpu_6800 *self, int addr) {
129   if (addr < 0)
130 #if __BYTE_ORDER == __BIG_ENDIAN
131     return self->regs.mem_be[sizeof(union cpu_6800_regs) + addr];
132 #else
133     return self->regs.mem_le[~addr];
134 #endif
135   self->cycles += 1;
136   return self->read_byte(self->read_byte_context, addr & 0xffff);
137 }
138
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);
142 }
143
144 static ALWAYS_INLINE void cpu_6800_write_byte(struct cpu_6800 *self, int addr, int data) {
145   self->cycles += 1;
146   if (addr < 0)
147 #if __BYTE_ORDER == __BIG_ENDIAN
148     self->regs.mem_be[sizeof(union cpu_6800_regs) + addr] = data;
149 #else
150     self->regs.mem_le[~addr] = data;
151 #endif
152   else
153     self->write_byte(self->write_byte_context, addr, data);
154 }
155
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);
159 }
160
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++);
163   return data;
164 }
165
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);
169 }
170
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);
173 }
174
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);
178 }
179
180 static ALWAYS_INLINE int cpu_6800_pop_byte(struct cpu_6800 *self) {
181   return cpu_6800_read_byte(self, ++self->regs.word.s);
182 }
183
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);
187 }
188
189 // effective address calculation
190 static ALWAYS_INLINE int cpu_6800_ea_extended(struct cpu_6800 *self) {
191   return cpu_6800_fetch_word(self);
192 }
193
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;
198 }
199
200 static ALWAYS_INLINE int cpu_6800_ea_relative(struct cpu_6800 *self) {
201   return (int8_t)cpu_6800_fetch_byte(self);
202 }
203
204 static ALWAYS_INLINE int cpu_6800_ea_direct(struct cpu_6800 *self) {
205   return cpu_6800_fetch_byte(self);
206 }
207
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;
212 }
213
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);
217
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);
221
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;
228 }
229
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);
232
233   int result0 = (data & 0xf) + (rvalue & 0xf);
234   int result1 = result0 + (data & 0x70) + (rvalue & 0x70);
235   int result2 = result1 + (data & 0x80) + (rvalue & 0x80);
236
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;
243 }
244
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;
247
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;
252 }
253
254 static ALWAYS_INLINE void cpu_6800_asl(struct cpu_6800 *self, int lvalue) {
255   int result = cpu_6800_read_byte(self, lvalue) << 1;
256   ++self->cycles;
257
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;
263 }
264
265 static ALWAYS_INLINE void cpu_6800_asr(struct cpu_6800 *self, int lvalue) {
266   int data = cpu_6800_read_byte(self, lvalue);
267
268   int result = data | ((data << 1) & 0x100);
269   ++self->cycles;
270
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;
276 }
277
278 static ALWAYS_INLINE void cpu_6800_bit(struct cpu_6800 *self, int rvalue0, int rvalue1) {
279   int result = rvalue0 & rvalue1;
280
281   self->regs.bit.nf = result >> 7;
282   self->regs.bit.zf = result == 0;
283   self->regs.bit.vf = false;
284 }
285
286 static ALWAYS_INLINE void cpu_6800_bra(struct cpu_6800 *self, bool pred, int lvalue) {
287   if (pred) {
288     self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
289     self->regs.word.pc += lvalue;
290   }
291 }
292
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;
297 }
298
299 static ALWAYS_INLINE void cpu_6800_cl(struct cpu_6800 *self, int n) {
300   self->regs.byte.p &= ~(1 << n);
301 }
302
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);
306
307   self->regs.bit.nf = false;
308   self->regs.bit.zf = true;
309   self->regs.bit.vf = false;
310   self->regs.bit.cf = false;
311 }
312
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);
316
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;
321 }
322
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);
326
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;
330 }
331
332 static ALWAYS_INLINE void cpu_6800_com(struct cpu_6800 *self, int lvalue) {
333   int result = cpu_6800_read_byte(self, lvalue) ^ 0xff;
334
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;
340 }
341
342 static ALWAYS_INLINE void cpu_6800_daa(struct cpu_6800 *self) {
343   int correction = 0;
344   if (self->regs.bit.hf || (self->regs.byte.a & 0xf) >= 0xa)
345     correction = 6;
346   if (self->regs.bit.cf || self->regs.byte.a >= 0x9a) {
347     correction |= 0x60;
348     self->regs.bit.cf = true;
349   }
350
351   int result0 = (self->regs.byte.a & 0x7f) + correction;
352   int result1 = result0 + (self->regs.byte.a & 0x80);
353
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;
359 }
360
361 static ALWAYS_INLINE void cpu_6800_dec_byte(struct cpu_6800 *self, int lvalue) {
362   int data = cpu_6800_read_byte(self, lvalue);
363
364   int result0 = (data & 0x7f) - 1;
365   int result1 = result0 + (data & 0x80);
366   ++self->cycles;
367
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;
372 }
373
374 static ALWAYS_INLINE void cpu_6800_dec_word(struct cpu_6800 *self, int lvalue) {
375   cpu_6800_write_word(
376     self,
377     lvalue,
378     (cpu_6800_read_word(self, lvalue) - 1) & 0xffff
379   );
380   ++self->cycles;
381 }
382
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;
385   ++self->cycles;
386
387   self->regs.word.x = result;
388   self->regs.bit.zf = result == 0;
389 }
390
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;
393
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;
398 }
399
400 static ALWAYS_INLINE void cpu_6800_illegal_opcode(struct cpu_6800 *self) {
401   abort();
402 }
403
404 static ALWAYS_INLINE void cpu_6800_inc_byte(struct cpu_6800 *self, int lvalue) {
405   int data = cpu_6800_read_byte(self, lvalue);
406
407   int result0 = (data & 0x7f) + 1;
408   int result1 = result0 + (data & 0x80);
409   ++self->cycles;
410
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;
415 }
416
417 static ALWAYS_INLINE void cpu_6800_inc_word(struct cpu_6800 *self, int lvalue) {
418   cpu_6800_write_word(
419     self,
420     lvalue,
421     (cpu_6800_read_word(self, lvalue) + 1) & 0xffff
422   );
423   ++self->cycles;
424 }
425
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;
428   ++self->cycles;
429
430   self->regs.word.x = result;
431   self->regs.bit.zf = result == 0;
432 }
433
434 static ALWAYS_INLINE void cpu_6800_jmp(struct cpu_6800 *self, int lvalue) {
435   self->regs.word.pc = lvalue;
436 }
437
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;
441 }
442
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);
445
446   self->regs.bit.nf = (rvalue >> 15) & 1;
447   self->regs.bit.zf = rvalue == 0;
448   self->regs.bit.vf = false;
449 }
450
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);
453
454   self->regs.bit.nf = (rvalue >> 7) & 1;
455   self->regs.bit.zf = rvalue == 0;
456   self->regs.bit.vf = false;
457 }
458
459 static ALWAYS_INLINE void cpu_6800_lsr(struct cpu_6800 *self, int lvalue) {
460   int data = cpu_6800_read_byte(self, lvalue);
461
462   int result = data;
463   ++self->cycles;
464
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;
470 }
471
472 static ALWAYS_INLINE void cpu_6800_neg(struct cpu_6800 *self, int lvalue) {
473   int data = cpu_6800_read_byte(self, lvalue);
474
475   int result0 = -(data & 0x7f);
476   int result1 = result0 - (data & 0x80);
477
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;
483 }
484
485 static ALWAYS_INLINE void cpu_6800_nop(struct cpu_6800 *self) {
486 }
487
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;
490
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;
495 }
496
497 static ALWAYS_INLINE void cpu_6800_psh(struct cpu_6800 *self, int rvalue) {
498   cpu_6800_push_byte(self, rvalue);
499 }
500
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));
503 }
504
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);
507   ++self->cycles;
508
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;
514 }
515
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);
518   ++self->cycles;
519   cpu_6800_write_byte(self, lvalue, result >> 1);
520
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;
525 }
526
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);
533 }
534
535 static ALWAYS_INLINE void cpu_6800_rts(struct cpu_6800 *self) {
536   self->regs.word.pc = cpu_6800_pop_word(self);
537 }
538
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);
541
542   int result0 = (data & 0x7f) - (rvalue & 0x7f) - self->regs.bit.cf;
543   int result1 = result0 + (data & 0x80) - (rvalue & 0x80);
544
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;
550 }
551
552 static ALWAYS_INLINE void cpu_6800_se(struct cpu_6800 *self, int n) {
553   self->regs.byte.p |= 1 << n;
554 }
555
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);
558
559   self->regs.bit.nf = (rvalue >> 15) & 1;
560   self->regs.bit.zf = rvalue == 0;
561   self->regs.bit.vf = false;
562 }
563
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);
566
567   self->regs.bit.nf = (rvalue >> 7) & 1;
568   self->regs.bit.zf = rvalue == 0;
569   self->regs.bit.vf = false;
570 }
571
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);
574
575   int result0 = (data & 0x7f) - (rvalue & 0x7f);
576   int result1 = result0 + (data & 0x80) - (rvalue & 0x80);
577
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;
583 }
584
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;
593 }
594
595 static ALWAYS_INLINE void cpu_6800_tap(struct cpu_6800 *self) {
596   self->regs.byte.p = self->regs.byte.a | 0xc0;
597 }
598
599 static ALWAYS_INLINE void cpu_6800_tpa(struct cpu_6800 *self) {
600   self->regs.byte.a = self->regs.byte.p;
601 }
602
603 static ALWAYS_INLINE void cpu_6800_tsx(struct cpu_6800 *self) {
604   self->regs.word.x = (self->regs.word.s + 1) & 0xffff;
605 }
606
607 static ALWAYS_INLINE void cpu_6800_txs(struct cpu_6800 *self) {
608   self->regs.word.s = (self->regs.word.x - 1) & 0xffff;
609 }
610
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;
618 }
619
620 // prototypes
621 void cpu_6800_init(
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
627 );
628 void cpu_6800_reset(struct cpu_6800 *self);
629 void cpu_6800_execute(struct cpu_6800 *self);
630  
631 #endif