Implement 386 instruction table, improve 8086/186/286 instruction table
[multi_emu.git] / cpu_65c02.h
1 #ifndef _CPU_65C02_H
2 #define _CPU_65C02_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_65C02_NMI_VECTOR 0xfffa
14 #define CPU_65C02_RESET_VECTOR 0xfffc
15 #define CPU_65C02_IRQ_VECTOR 0xfffe
16
17 // bits within REG_P
18 #define CPU_65C02_REG_P_BIT_C 0
19 #define CPU_65C02_REG_P_BIT_Z 1
20 #define CPU_65C02_REG_P_BIT_I 2
21 #define CPU_65C02_REG_P_BIT_D 3
22 #define CPU_65C02_REG_P_BIT_B 4
23 #define CPU_65C02_REG_P_BIT_V 6
24 #define CPU_65C02_REG_P_BIT_N 7
25
26 // special memory locations (negative address)
27 #define CPU_65C02_EA_PC (-8)
28 #define CPU_65C02_EA_A (-6)
29 #define CPU_65C02_EA_X (-5)
30 #define CPU_65C02_EA_Y (-4)
31 #define CPU_65C02_EA_S (-3)
32 #define CPU_65C02_EA_P (-2)
33 #define CPU_65C02_EA_IFLAGS (-1)
34
35 // registers, in same order as special memory locations, but reversed on
36 // big endian hardware where special memory address will be complemented
37 // (this allows special memory to always look like it is little endian)
38 union cpu_65c02_regs {
39 #if __BYTE_ORDER == __BIG_ENDIAN
40   struct {
41     uint8_t _fill_iflags : 4;
42     uint8_t stp_flag : 1;
43     uint8_t wai_flag : 1;
44     uint8_t irq_pending : 1;
45     uint8_t nmi_pending : 1;
46     uint8_t nf : 1;
47     uint8_t vf : 1;
48     uint8_t _fill_5f: 1;
49     uint8_t _fill_4f: 1;
50     uint8_t df : 1;
51     uint8_t _if : 1;
52     uint8_t zf : 1;
53     uint8_t cf : 1;
54     uint8_t _fill_s;
55     uint8_t _fill_y;
56     uint8_t _fill_x;
57     uint8_t _fill_a;
58     uint16_t _fill_pc;
59   } bit;
60   struct {
61     uint8_t iflags;
62     uint8_t p;
63     uint8_t s;
64     uint8_t y;
65     uint8_t x;
66     uint8_t a;
67     uint16_t _fill_pc;
68   } byte;
69   struct {
70     uint8_t _fill_iflags;
71     uint8_t _fill_p;
72     uint8_t _fill_s;
73     uint8_t _fill_y;
74     uint8_t _fill_x;
75     uint8_t _fill_a;
76     uint16_t pc;
77   } word;
78   uint8_t mem_be[8];
79 #else
80   struct {
81     uint16_t _fill_pc;
82     uint8_t _fill_a;
83     uint8_t _fill_x;
84     uint8_t _fill_y;
85     uint8_t _fill_s;
86     uint8_t cf : 1;
87     uint8_t zf : 1;
88     uint8_t _if : 1;
89     uint8_t df : 1;
90     uint8_t _fill_4f: 1;
91     uint8_t _fill_5f: 1;
92     uint8_t vf : 1;
93     uint8_t nf : 1;
94     uint8_t nmi_pending : 1;
95     uint8_t irq_pending : 1;
96     uint8_t wai_flag : 1;
97     uint8_t stp_flag : 1;
98     uint8_t _fill_iflags : 4;
99   } bit;
100   struct {
101     uint16_t _fill_pc;
102     uint8_t a;
103     uint8_t x;
104     uint8_t y;
105     uint8_t s;
106     uint8_t p;
107     uint8_t iflags;
108   } byte;
109   struct {
110     uint16_t pc;
111     uint8_t _fill_a;
112     uint8_t _fill_x;
113     uint8_t _fill_y;
114     uint8_t _fill_s;
115     uint8_t _fill_p;
116     uint8_t _fill_iflags;
117   } word;
118   uint8_t mem_le[8];
119 #endif
120 };
121
122 struct cpu_65c02 {
123   int cycles;
124   int (*read_byte)(void *context, int addr);
125   void *read_byte_context;
126   void (*write_byte)(void *context, int addr, int data);
127   void *write_byte_context;
128   union cpu_65c02_regs regs;
129 };
130
131 // memory or special memory access
132 static ALWAYS_INLINE int cpu_65c02_read_byte(struct cpu_65c02 *self, int addr) {
133   if (addr < 0)
134 #if __BYTE_ORDER == __BIG_ENDIAN
135     return self->regs.mem_be[~addr];
136 #else
137     return self->regs.mem_le[sizeof(union cpu_65c02_regs) + addr];
138 #endif
139   self->cycles += 1;
140   return self->read_byte(self->read_byte_context, addr & 0xffff);
141 }
142
143 static ALWAYS_INLINE int cpu_65c02_read_word(struct cpu_65c02 *self, int addr) {
144   int data = cpu_65c02_read_byte(self, addr);
145   return data | (cpu_65c02_read_byte(self, addr + 1) << 8);
146 }
147
148 static ALWAYS_INLINE int cpu_65c02_read_word_zero_page(struct cpu_65c02 *self, int addr) {
149   int data = cpu_65c02_read_byte(self, addr & 0xff);
150   return data | (cpu_65c02_read_byte(self, (addr + 1) & 0xff) << 8);
151 }
152
153 static ALWAYS_INLINE void cpu_65c02_write_byte(struct cpu_65c02 *self, int addr, int data) {
154   self->cycles += 1;
155   if (addr < 0)
156 #if __BYTE_ORDER == __BIG_ENDIAN
157     self->regs.mem_be[~addr] = data;
158 #else
159     self->regs.mem_le[sizeof(union cpu_65c02_regs) + addr] = data;
160 #endif
161   else
162     self->write_byte(self->write_byte_context, addr, data);
163 }
164
165 static ALWAYS_INLINE void cpu_65c02_write_word(struct cpu_65c02 *self, int addr, int data) {
166   cpu_65c02_write_byte(self, addr, data & 0xff);
167   cpu_65c02_write_byte(self, addr + 1, data >> 8);
168 }
169
170 static ALWAYS_INLINE int cpu_65c02_fetch_byte(struct cpu_65c02 *self) {
171   int data = cpu_65c02_read_byte(self, self->regs.word.pc++);
172   return data;
173 }
174
175 static ALWAYS_INLINE int cpu_65c02_fetch_word(struct cpu_65c02 *self) {
176   int data = cpu_65c02_fetch_byte(self);
177   return data | (cpu_65c02_fetch_byte(self) << 8);
178 }
179
180 static ALWAYS_INLINE void cpu_65c02_push_byte(struct cpu_65c02 *self, int data) {
181   cpu_65c02_write_byte(self, self->regs.byte.s-- | 0x100, data);
182 }
183
184 static ALWAYS_INLINE void cpu_65c02_push_word(struct cpu_65c02 *self, int data) {
185   cpu_65c02_push_byte(self, data >> 8);
186   cpu_65c02_push_byte(self, data & 0xff);
187 }
188
189 static ALWAYS_INLINE int cpu_65c02_pop_byte(struct cpu_65c02 *self) {
190   return cpu_65c02_read_byte(self, ++self->regs.byte.s | 0x100);
191 }
192
193 static ALWAYS_INLINE int cpu_65c02_pop_word(struct cpu_65c02 *self) {
194   int data = cpu_65c02_pop_byte(self);
195   return data | (cpu_65c02_pop_byte(self) << 8);
196 }
197
198 // effective address calculation
199 static ALWAYS_INLINE int cpu_65c02_ea_absolute(struct cpu_65c02 *self) {
200   return cpu_65c02_fetch_word(self);
201 }
202
203 static ALWAYS_INLINE int cpu_65c02_ea_absolute_indexed(struct cpu_65c02 *self, int rvalue) {
204   int addr = cpu_65c02_ea_absolute(self);
205   self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8;
206   return addr + rvalue;
207 }
208
209 static ALWAYS_INLINE int cpu_65c02_ea_absolute_indexed_indirect(struct cpu_65c02 *self, int rvalue) {
210   return cpu_65c02_read_word(self, cpu_65c02_ea_absolute_indexed(self, rvalue));
211 }
212
213 static ALWAYS_INLINE int cpu_65c02_ea_absolute_indirect(struct cpu_65c02 *self) {
214   return cpu_65c02_read_word(self, cpu_65c02_ea_absolute(self));
215 }
216
217 static ALWAYS_INLINE int cpu_65c02_ea_relative(struct cpu_65c02 *self) {
218   return (int8_t)cpu_65c02_fetch_byte(self);
219 }
220
221 static ALWAYS_INLINE int cpu_65c02_ea_zero_page(struct cpu_65c02 *self) {
222   return cpu_65c02_fetch_byte(self);
223 }
224
225 static ALWAYS_INLINE int cpu_65c02_ea_zero_page_indexed(struct cpu_65c02 *self, int rvalue) {
226   return (cpu_65c02_ea_zero_page(self) + rvalue) & 0xff;
227 }
228
229 static ALWAYS_INLINE int cpu_65c02_ea_zero_page_indexed_indirect(struct cpu_65c02 *self, int rvalue) {
230   return cpu_65c02_read_word_zero_page(self, cpu_65c02_ea_zero_page_indexed(self, rvalue));
231 }
232
233 static ALWAYS_INLINE int cpu_65c02_ea_zero_page_indirect(struct cpu_65c02 *self) {
234   return cpu_65c02_read_word_zero_page(self, cpu_65c02_ea_zero_page(self));
235 }
236
237 static ALWAYS_INLINE int cpu_65c02_ea_zero_page_indirect_indexed(struct cpu_65c02 *self, int rvalue) {
238   int addr = cpu_65c02_read_word_zero_page(self, cpu_65c02_ea_zero_page(self));
239   self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8;
240   return addr + rvalue;
241 }
242
243 // instruction execute
244 static ALWAYS_INLINE void cpu_65c02_adc(struct cpu_65c02 *self, int rvalue) {
245   int result0, result1, result2;
246   if (self->regs.bit.df) {
247     result0 = self->regs.bit.cf + (self->regs.byte.a & 0xf) + (rvalue & 0xf);
248     if (result0 >= 0xa)
249       result0 = (result0 + 6) & 0x1f;
250     result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70);
251     result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
252     result2 = result1;
253     if (result2 >= 0xa0)
254       result2 = (result2 + 0x60) & 0x1ff;
255   }
256   else {
257     result0 = self->regs.bit.cf + (self->regs.byte.a & 0x7f) + (rvalue & 0x7f);
258     result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
259     result2 = result1;
260   }
261   self->regs.byte.a = result2 & 0xff;
262   self->regs.bit.cf = result2 >> 8;
263   self->regs.bit.zf = (result2 & 0xff) == 0;
264   self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
265   self->regs.bit.nf = (result2 >> 7) & 1;
266 }
267
268 static ALWAYS_INLINE void cpu_65c02_and(struct cpu_65c02 *self, int rvalue) {
269   int result = self->regs.byte.a & rvalue;
270   self->regs.byte.a = result;
271   self->regs.bit.zf = result == 0;
272   self->regs.bit.nf = result >> 7;
273 }
274
275 static ALWAYS_INLINE void cpu_65c02_asl(struct cpu_65c02 *self, int lvalue) {
276   int result = cpu_65c02_read_byte(self, lvalue) << 1;
277   ++self->cycles;
278   cpu_65c02_write_byte(self, lvalue, result & 0xff);
279   self->regs.bit.cf = result >> 8;
280   self->regs.bit.zf = (result & 0xff) == 0;
281   self->regs.bit.nf = (result >> 7) & 1;
282 }
283
284 static ALWAYS_INLINE void cpu_65c02_bit(struct cpu_65c02 *self, int rvalue) {
285   int result = self->regs.byte.a & rvalue;
286   self->regs.bit.zf = result == 0;
287   self->regs.bit.vf = (rvalue >> 6) & 1;
288   self->regs.bit.nf = (rvalue >> 7) & 1;
289 }
290
291 static ALWAYS_INLINE void cpu_65c02_bit_imm(struct cpu_65c02 *self, int rvalue) {
292   int result = self->regs.byte.a & rvalue;
293   self->regs.bit.zf = result == 0;
294 }
295
296 static ALWAYS_INLINE void cpu_65c02_bra(struct cpu_65c02 *self, bool pred, int lvalue) {
297   if (pred) {
298     self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
299     self->regs.word.pc += lvalue;
300   }
301 }
302
303 static ALWAYS_INLINE void cpu_65c02_cl(struct cpu_65c02 *self, int n) {
304   self->regs.byte.p &= ~(1 << n);
305 }
306
307 static ALWAYS_INLINE void cpu_65c02_cmp(struct cpu_65c02 *self, int rvalue0, int rvalue1) {
308   rvalue1 ^= 0xff;
309   int result = 1 + rvalue0 + rvalue1;
310   self->regs.bit.cf = result >> 8;
311   self->regs.bit.zf = (result & 0xff) == 0;
312   self->regs.bit.nf = (result >> 7) & 1;
313 }
314
315 static ALWAYS_INLINE void cpu_65c02_dec(struct cpu_65c02 *self, int lvalue) {
316   int result = (cpu_65c02_read_byte(self, lvalue) - 1) & 0xff;
317   ++self->cycles;
318   cpu_65c02_write_byte(self, lvalue, result);
319   self->regs.bit.zf = result == 0;
320   self->regs.bit.nf = result >> 7;
321 }
322
323 static ALWAYS_INLINE void cpu_65c02_eor(struct cpu_65c02 *self, int rvalue) {
324   int result = self->regs.byte.a ^ rvalue;
325   self->regs.byte.a = result;
326   self->regs.bit.zf = result == 0;
327   self->regs.bit.nf = result >> 7;
328 }
329
330 static ALWAYS_INLINE void cpu_65c02_illegal_opcode11(struct cpu_65c02 *self) {
331 }
332
333 static ALWAYS_INLINE void cpu_65c02_illegal_opcode22(struct cpu_65c02 *self) {
334   ++self->cycles;
335   self->regs.word.pc += 1;
336 }
337
338 static ALWAYS_INLINE void cpu_65c02_illegal_opcode23(struct cpu_65c02 *self) {
339   self->cycles += 2;
340   self->regs.word.pc += 1;
341 }
342
343 static ALWAYS_INLINE void cpu_65c02_illegal_opcode24(struct cpu_65c02 *self) {
344   self->cycles += 3;
345   self->regs.word.pc += 1;
346 }
347
348 static ALWAYS_INLINE void cpu_65c02_illegal_opcode34(struct cpu_65c02 *self) {
349   self->cycles += 3;
350   self->regs.word.pc += 2;
351 }
352
353 static ALWAYS_INLINE void cpu_65c02_illegal_opcode38(struct cpu_65c02 *self) {
354   self->cycles += 7;
355   self->regs.word.pc += 2;
356 }
357
358 static ALWAYS_INLINE void cpu_65c02_inc(struct cpu_65c02 *self, int lvalue) {
359   int result = (cpu_65c02_read_byte(self, lvalue) + 1) & 0xff;
360   ++self->cycles;
361   cpu_65c02_write_byte(self, lvalue, result);
362   self->regs.bit.zf = result == 0;
363   self->regs.bit.nf = result >> 7;
364 }
365
366 static ALWAYS_INLINE void cpu_65c02_irq(struct cpu_65c02 *self, bool brk, int lvalue) {
367   ++self->cycles;
368   cpu_65c02_push_word(self, self->regs.word.pc);
369   cpu_65c02_push_byte(
370     self,
371     ((self->regs.byte.p) & ~(1 << CPU_65C02_REG_P_BIT_B)) |
372     (brk << CPU_65C02_REG_P_BIT_B)
373   );
374   self->regs.word.pc = cpu_65c02_read_word(self, lvalue);
375   self->regs.bit._if = true;
376   self->regs.bit.df = false;
377 }
378
379 static ALWAYS_INLINE void cpu_65c02_jmp(struct cpu_65c02 *self, int lvalue) {
380   self->regs.word.pc = lvalue;
381 }
382
383 static ALWAYS_INLINE void cpu_65c02_jsr(struct cpu_65c02 *self, int lvalue) {
384   cpu_65c02_push_word(self, (self->regs.word.pc - 1) & 0xffff);
385   self->regs.word.pc = lvalue;
386 }
387
388 static ALWAYS_INLINE void cpu_65c02_ld(struct cpu_65c02 *self, int lvalue, int rvalue) {
389   cpu_65c02_write_byte(self, lvalue, rvalue);
390   self->regs.bit.zf = rvalue == 0;
391   self->regs.bit.nf = (rvalue >> 7) & 1;
392 }
393
394 static ALWAYS_INLINE void cpu_65c02_lsr(struct cpu_65c02 *self, int lvalue) {
395   int result = cpu_65c02_read_byte(self, lvalue);
396   ++self->cycles;
397   cpu_65c02_write_byte(self, lvalue, result >> 1);
398   self->regs.bit.cf = result & 1;
399   self->regs.bit.zf = (result & 0xfe) == 0;
400   self->regs.bit.nf = false;
401 }
402
403 static ALWAYS_INLINE void cpu_65c02_nop(struct cpu_65c02 *self) {
404 }
405
406 static ALWAYS_INLINE void cpu_65c02_ora(struct cpu_65c02 *self, int rvalue) {
407   int result = self->regs.byte.a | rvalue;
408   self->regs.byte.a = result;
409   self->regs.bit.zf = result == 0;
410   self->regs.bit.nf = result >> 7;
411 }
412
413 static ALWAYS_INLINE void cpu_65c02_ph(struct cpu_65c02 *self, int rvalue) {
414   cpu_65c02_push_byte(self, rvalue);
415 }
416
417 static ALWAYS_INLINE void cpu_65c02_pl(struct cpu_65c02 *self, int lvalue) {
418   int result = cpu_65c02_pop_byte(self);
419   cpu_65c02_write_byte(self, lvalue, result);
420   self->regs.bit.zf = result == 0;
421   self->regs.bit.nf = result >> 7;
422 }
423
424 static ALWAYS_INLINE void cpu_65c02_plp(struct cpu_65c02 *self) {
425   self->regs.byte.p = cpu_65c02_pop_byte(self) | 0x30;
426 }
427
428 static ALWAYS_INLINE void cpu_65c02_rmb(struct cpu_65c02 *self, int n, int lvalue) {
429   int result = cpu_65c02_read_byte(self, lvalue) & ~(1 << n);
430   ++self->cycles;
431   cpu_65c02_write_byte(self, lvalue, result);
432 }
433
434 static ALWAYS_INLINE void cpu_65c02_rol(struct cpu_65c02 *self, int lvalue) {
435   int result = self->regs.bit.cf | (cpu_65c02_read_byte(self, lvalue) << 1);
436   ++self->cycles;
437   cpu_65c02_write_byte(self, lvalue, result & 0xff);
438   self->regs.bit.cf = result >> 8;
439   self->regs.bit.zf = (result & 0xff) == 0;
440   self->regs.bit.nf = (result >> 7) & 1;
441 }
442
443 static ALWAYS_INLINE void cpu_65c02_ror(struct cpu_65c02 *self, int lvalue) {
444   int result = cpu_65c02_read_byte(self, lvalue) | (self->regs.bit.cf << 8);
445   ++self->cycles;
446   cpu_65c02_write_byte(self, lvalue, result >> 1);
447   self->regs.bit.cf = result & 1;
448   self->regs.bit.zf = (result & 0x1fe) == 0;
449   self->regs.bit.nf = (result >> 8) & 1;
450 }
451
452 static ALWAYS_INLINE void cpu_65c02_rti(struct cpu_65c02 *self) {
453   self->regs.byte.p = cpu_65c02_pop_byte(self) | 0x30;
454   self->regs.word.pc = cpu_65c02_pop_word(self);
455 }
456
457 static ALWAYS_INLINE void cpu_65c02_rts(struct cpu_65c02 *self) {
458   self->regs.word.pc = (cpu_65c02_pop_word(self) + 1) & 0xffff;
459 }
460
461 static ALWAYS_INLINE void cpu_65c02_sbc(struct cpu_65c02 *self, int rvalue) {
462   rvalue ^= 0xff;
463   int result0, result1, result2;
464   if (self->regs.bit.df) {
465     result0 = self->regs.bit.cf + (self->regs.byte.a & 0xf) + (rvalue & 0xf);
466     if (result0 < 0x10)
467       result0 = (result0 - 6) & 0x1f;
468     result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70);
469     result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
470     result2 = result1;
471     if (result2 < 0x100)
472       result2 = (result2 - 0x60) & 0x1ff;
473   }
474   else {
475     result0 = self->regs.bit.cf + (self->regs.byte.a & 0x7f) + (rvalue & 0x7f);
476     result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
477     result2 = result1;
478   }
479   self->regs.byte.a = result2 & 0xff;
480   self->regs.bit.cf = result2 >> 8;
481   self->regs.bit.zf = (result2 & 0xff) == 0;
482   self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
483   self->regs.bit.nf = (result2 >> 7) & 1;
484 }
485
486 static ALWAYS_INLINE void cpu_65c02_se(struct cpu_65c02 *self, int n) {
487   self->regs.byte.p |= 1 << n;
488 }
489
490 static ALWAYS_INLINE void cpu_65c02_smb(struct cpu_65c02 *self, int n, int lvalue) {
491   int result = cpu_65c02_read_byte(self, lvalue) | (1 << n);
492   ++self->cycles;
493   cpu_65c02_write_byte(self, lvalue, result);
494 }
495
496 static ALWAYS_INLINE void cpu_65c02_st(struct cpu_65c02 *self, int rvalue, int lvalue) {
497   cpu_65c02_write_byte(self, lvalue, rvalue);
498 }
499
500 static ALWAYS_INLINE void cpu_65c02_stp(struct cpu_65c02 *self) {
501   self->regs.bit.stp_flag = true;
502 }
503
504 static ALWAYS_INLINE void cpu_65c02_trb(struct cpu_65c02 *self, int lvalue) {
505   int result = cpu_65c02_read_byte(self, lvalue);
506   ++self->cycles;
507   cpu_65c02_write_byte(self, lvalue, result & ~self->regs.byte.a);
508   result &= self->regs.byte.a;
509   self->regs.bit.zf = result == 0;
510 }
511
512 static ALWAYS_INLINE void cpu_65c02_tsb(struct cpu_65c02 *self, int lvalue) {
513   int result = cpu_65c02_read_byte(self, lvalue);
514   ++self->cycles;
515   cpu_65c02_write_byte(self, lvalue, result | self->regs.byte.a);
516   result &= self->regs.byte.a;
517   self->regs.bit.zf = result == 0;
518 }
519
520 static ALWAYS_INLINE void cpu_65c02_wai(struct cpu_65c02 *self) {
521   self->regs.bit.wai_flag = true;
522 }
523
524 // prototypes
525 void cpu_65c02_init(
526   struct cpu_65c02 *self,
527   int (*read_byte)(void *context, int addr),
528   void *read_byte_context,
529   void (*write_byte)(void *context, int addr, int data),
530   void *write_byte_context
531 );
532 void cpu_65c02_reset(struct cpu_65c02 *self);
533 void cpu_65c02_execute(struct cpu_65c02 *self);
534  
535 #endif