10 #define ALWAYS_INLINE __attribute__((always_inline))
13 #define CPU_65C02_NMI_VECTOR 0xfffa
14 #define CPU_65C02_RESET_VECTOR 0xfffc
15 #define CPU_65C02_IRQ_VECTOR 0xfffe
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
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)
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
41 uint8_t _fill_iflags : 4;
44 uint8_t irq_pending : 1;
45 uint8_t nmi_pending : 1;
94 uint8_t nmi_pending : 1;
95 uint8_t irq_pending : 1;
98 uint8_t _fill_iflags : 4;
116 uint8_t _fill_iflags;
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;
131 // memory or special memory access
132 static ALWAYS_INLINE int cpu_65c02_read_byte(struct cpu_65c02 *self, int addr) {
134 #if __BYTE_ORDER == __BIG_ENDIAN
135 return self->regs.mem_be[~addr];
137 return self->regs.mem_le[sizeof(union cpu_65c02_regs) + addr];
140 return self->read_byte(self->read_byte_context, addr & 0xffff);
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);
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);
153 static ALWAYS_INLINE void cpu_65c02_write_byte(struct cpu_65c02 *self, int addr, int data) {
156 #if __BYTE_ORDER == __BIG_ENDIAN
157 self->regs.mem_be[~addr] = data;
159 self->regs.mem_le[sizeof(union cpu_65c02_regs) + addr] = data;
162 self->write_byte(self->write_byte_context, addr, data);
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);
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++);
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);
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);
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);
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);
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);
198 // effective address calculation
199 static ALWAYS_INLINE int cpu_65c02_ea_absolute(struct cpu_65c02 *self) {
200 return cpu_65c02_fetch_word(self);
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;
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));
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));
217 static ALWAYS_INLINE int cpu_65c02_ea_relative(struct cpu_65c02 *self) {
218 return (int8_t)cpu_65c02_fetch_byte(self);
221 static ALWAYS_INLINE int cpu_65c02_ea_zero_page(struct cpu_65c02 *self) {
222 return cpu_65c02_fetch_byte(self);
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;
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));
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));
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;
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);
249 result0 = (result0 + 6) & 0x1f;
250 result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70);
251 result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
254 result2 = (result2 + 0x60) & 0x1ff;
257 result0 = self->regs.bit.cf + (self->regs.byte.a & 0x7f) + (rvalue & 0x7f);
258 result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
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;
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;
275 static ALWAYS_INLINE void cpu_65c02_asl(struct cpu_65c02 *self, int lvalue) {
276 int result = cpu_65c02_read_byte(self, lvalue) << 1;
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;
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;
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;
296 static ALWAYS_INLINE void cpu_65c02_bra(struct cpu_65c02 *self, bool pred, int lvalue) {
298 self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
299 self->regs.word.pc += lvalue;
303 static ALWAYS_INLINE void cpu_65c02_cl(struct cpu_65c02 *self, int n) {
304 self->regs.byte.p &= ~(1 << n);
307 static ALWAYS_INLINE void cpu_65c02_cmp(struct cpu_65c02 *self, int rvalue0, int rvalue1) {
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;
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;
318 cpu_65c02_write_byte(self, lvalue, result);
319 self->regs.bit.zf = result == 0;
320 self->regs.bit.nf = result >> 7;
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;
330 static ALWAYS_INLINE void cpu_65c02_illegal_opcode11(struct cpu_65c02 *self) {
333 static ALWAYS_INLINE void cpu_65c02_illegal_opcode22(struct cpu_65c02 *self) {
335 self->regs.word.pc += 1;
338 static ALWAYS_INLINE void cpu_65c02_illegal_opcode23(struct cpu_65c02 *self) {
340 self->regs.word.pc += 1;
343 static ALWAYS_INLINE void cpu_65c02_illegal_opcode24(struct cpu_65c02 *self) {
345 self->regs.word.pc += 1;
348 static ALWAYS_INLINE void cpu_65c02_illegal_opcode34(struct cpu_65c02 *self) {
350 self->regs.word.pc += 2;
353 static ALWAYS_INLINE void cpu_65c02_illegal_opcode38(struct cpu_65c02 *self) {
355 self->regs.word.pc += 2;
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;
361 cpu_65c02_write_byte(self, lvalue, result);
362 self->regs.bit.zf = result == 0;
363 self->regs.bit.nf = result >> 7;
366 static ALWAYS_INLINE void cpu_65c02_irq(struct cpu_65c02 *self, bool brk, int lvalue) {
368 cpu_65c02_push_word(self, self->regs.word.pc);
371 ((self->regs.byte.p) & ~(1 << CPU_65C02_REG_P_BIT_B)) |
372 (brk << CPU_65C02_REG_P_BIT_B)
374 self->regs.word.pc = cpu_65c02_read_word(self, lvalue);
375 self->regs.bit._if = true;
376 self->regs.bit.df = false;
379 static ALWAYS_INLINE void cpu_65c02_jmp(struct cpu_65c02 *self, int lvalue) {
380 self->regs.word.pc = lvalue;
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;
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;
394 static ALWAYS_INLINE void cpu_65c02_lsr(struct cpu_65c02 *self, int lvalue) {
395 int result = cpu_65c02_read_byte(self, lvalue);
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;
403 static ALWAYS_INLINE void cpu_65c02_nop(struct cpu_65c02 *self) {
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;
413 static ALWAYS_INLINE void cpu_65c02_ph(struct cpu_65c02 *self, int rvalue) {
414 cpu_65c02_push_byte(self, rvalue);
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;
424 static ALWAYS_INLINE void cpu_65c02_plp(struct cpu_65c02 *self) {
425 self->regs.byte.p = cpu_65c02_pop_byte(self) | 0x30;
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);
431 cpu_65c02_write_byte(self, lvalue, result);
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);
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;
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);
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;
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);
457 static ALWAYS_INLINE void cpu_65c02_rts(struct cpu_65c02 *self) {
458 self->regs.word.pc = (cpu_65c02_pop_word(self) + 1) & 0xffff;
461 static ALWAYS_INLINE void cpu_65c02_sbc(struct cpu_65c02 *self, int rvalue) {
463 int result0, result1, result2;
464 if (self->regs.bit.df) {
465 result0 = self->regs.bit.cf + (self->regs.byte.a & 0xf) + (rvalue & 0xf);
467 result0 = (result0 - 6) & 0x1f;
468 result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70);
469 result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
472 result2 = (result2 - 0x60) & 0x1ff;
475 result0 = self->regs.bit.cf + (self->regs.byte.a & 0x7f) + (rvalue & 0x7f);
476 result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
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;
486 static ALWAYS_INLINE void cpu_65c02_se(struct cpu_65c02 *self, int n) {
487 self->regs.byte.p |= 1 << n;
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);
493 cpu_65c02_write_byte(self, lvalue, result);
496 static ALWAYS_INLINE void cpu_65c02_st(struct cpu_65c02 *self, int rvalue, int lvalue) {
497 cpu_65c02_write_byte(self, lvalue, rvalue);
500 static ALWAYS_INLINE void cpu_65c02_stp(struct cpu_65c02 *self) {
501 self->regs.bit.stp_flag = true;
504 static ALWAYS_INLINE void cpu_65c02_trb(struct cpu_65c02 *self, int lvalue) {
505 int result = cpu_65c02_read_byte(self, lvalue);
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;
512 static ALWAYS_INLINE void cpu_65c02_tsb(struct cpu_65c02 *self, int lvalue) {
513 int result = cpu_65c02_read_byte(self, lvalue);
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;
520 static ALWAYS_INLINE void cpu_65c02_wai(struct cpu_65c02 *self) {
521 self->regs.bit.wai_flag = true;
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
532 void cpu_65c02_reset(struct cpu_65c02 *self);
533 void cpu_65c02_execute(struct cpu_65c02 *self);