) {
memset(self, 0, sizeof(struct cpu_65c02));
self->regs.byte.p = 0x30; // unused bits are hard coded to 1
- self->regs.word.sp = 0x1ff; // unused byte is hard coded to 01
self->read_byte = read_byte;
self->read_byte_context = read_byte_context;
self->write_byte = write_byte;
// instruction decode
void cpu_65c02_execute(struct cpu_65c02 *self) {
+ if (self->regs.bit.stp_flag) {
+ ++self->cycles;
+ return;
+ }
+
+ if (self->regs.bit.nmi_pending) {
+ self->regs.bit.nmi_pending = false;
+ self->regs.bit.wai_flag = false;
+ cpu_65c02_irq(self, false, CPU_65C02_NMI_VECTOR);
+ return;
+ }
+
+ if (self->regs.bit.irq_pending) {
+ if (self->regs.bit._if == 0) {
+ self->regs.bit.irq_pending = false;
+ self->regs.bit.wai_flag = false;
+ cpu_65c02_irq(self, false, CPU_65C02_IRQ_VECTOR);
+ return;
+ }
+ if (self->regs.bit.wai_flag) {
+ self->regs.bit.irq_pending = false;
+ self->regs.bit.wai_flag = false;
+ }
+ }
+ else if (self->regs.bit.wai_flag) {
+ ++self->cycles;
+ return;
+ }
+
switch (cpu_65c02_fetch_byte(self)) {
case 0x00:
- cpu_65c02_brk(self);
+ ++self->regs.word.pc;
+ cpu_65c02_irq(self, true, CPU_65C02_IRQ_VECTOR);
break;
case 0x01:
cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x)));
#include <stdbool.h>
#include <stdint.h>
-#include <stdlib.h>
// gcc specific
#ifndef ALWAYS_INLINE
#define CPU_65C02_REG_P_BIT_Z 1
#define CPU_65C02_REG_P_BIT_I 2
#define CPU_65C02_REG_P_BIT_D 3
+#define CPU_65C02_REG_P_BIT_B 4
#define CPU_65C02_REG_P_BIT_V 6
#define CPU_65C02_REG_P_BIT_N 7
#define CPU_65C02_EA_A (-8)
#define CPU_65C02_EA_X (-7)
#define CPU_65C02_EA_Y (-6)
-#define CPU_65C02_EA_P (-5)
-#define CPU_65C02_EA_S (-4)
+#define CPU_65C02_EA_S (-5)
+#define CPU_65C02_EA_P (-4)
// registers, in same order as special memory locations, but reversed on
// big endian hardware where special memory address will be complemented
#if __BYTE_ORDER == __BIG_ENDIAN
struct {
uint16_t _fill_pc;
- uint16_t _fill_sp;
+ uint8_t _fill_iflags : 4;
+ uint8_t stp_flag : 1;
+ uint8_t wai_flag : 1;
+ uint8_t irq_pending : 1;
+ uint8_t nmi_pending : 1;
uint8_t nf : 1;
uint8_t vf : 1;
uint8_t _fill_5f: 1;
uint8_t _if : 1;
uint8_t zf : 1;
uint8_t cf : 1;
+ uint8_t _fill_s;
uint8_t _fill_y;
uint8_t _fill_x;
uint8_t _fill_a;
} bit;
struct {
uint16_t _fill_pc;
- uint8_t _fill_sph;
- uint8_t s;
+ uint8_t iflags;
uint8_t p;
+ uint8_t s;
uint8_t y;
uint8_t x;
uint8_t a;
} byte;
struct {
uint16_t pc;
- uint16_t sp;
+ uint8_t _fill_iflags;
uint8_t _fill_p;
+ uint8_t _fill_s;
uint8_t _fill_y;
uint8_t _fill_x;
uint8_t _fill_a;
uint8_t _fill_a;
uint8_t _fill_x;
uint8_t _fill_y;
+ uint8_t _fill_s;
uint8_t cf : 1;
uint8_t zf : 1;
uint8_t _if : 1;
uint8_t _fill_5f: 1;
uint8_t vf : 1;
uint8_t nf : 1;
- uint16_t _fill_sp;
+ uint8_t nmi_pending : 1;
+ uint8_t irq_pending : 1;
+ uint8_t wai_flag : 1;
+ uint8_t stp_flag : 1;
+ uint8_t _fill_iflags : 4;
uint16_t _fill_pc;
} bit;
struct {
uint8_t a;
uint8_t x;
uint8_t y;
- uint8_t p;
uint8_t s;
- uint8_t _fill_sph;
+ uint8_t p;
+ uint8_t iflags;
uint16_t _fill_pc;
} byte;
struct {
uint8_t _fill_a;
uint8_t _fill_x;
uint8_t _fill_y;
+ uint8_t _fill_s;
uint8_t _fill_p;
- uint16_t sp;
+ uint8_t _fill_iflags;
uint16_t pc;
} word;
uint8_t mem_le[8];
}
static ALWAYS_INLINE void cpu_65c02_push_byte(struct cpu_65c02 *self, int data) {
- cpu_65c02_write_byte(self, self->regs.word.sp, data);
+ cpu_65c02_write_byte(self, self->regs.byte.s | 0x100, data);
--self->regs.byte.s;
}
static ALWAYS_INLINE int cpu_65c02_pop_byte(struct cpu_65c02 *self) {
++self->regs.byte.s;
- return cpu_65c02_read_byte(self, self->regs.word.sp);
+ return cpu_65c02_read_byte(self, self->regs.byte.s | 0x100);
}
static ALWAYS_INLINE int cpu_65c02_pop_word(struct cpu_65c02 *self) {
}
}
-static ALWAYS_INLINE void cpu_65c02_brk(struct cpu_65c02 *self) {
- ++self->cycles;
- cpu_65c02_push_word(self, (self->regs.word.pc + 1) & 0xffff);
- cpu_65c02_push_byte(self, self->regs.byte.p);
- self->regs.word.pc = cpu_65c02_read_word(self, CPU_65C02_IRQ_VECTOR);
- self->regs.bit._if = true;
- self->regs.bit.df = false;
-}
-
static ALWAYS_INLINE void cpu_65c02_cl(struct cpu_65c02 *self, int n) {
self->regs.byte.p &= ~(1 << n);
}
self->regs.bit.nf = result >> 7;
}
+static ALWAYS_INLINE void cpu_65c02_irq(struct cpu_65c02 *self, bool brk, int lvalue) {
+ ++self->cycles;
+ cpu_65c02_push_word(self, self->regs.word.pc);
+ cpu_65c02_push_byte(
+ self,
+ ((self->regs.byte.p) & ~(1 << CPU_65C02_REG_P_BIT_B)) |
+ (brk << CPU_65C02_REG_P_BIT_B)
+ );
+ self->regs.word.pc = cpu_65c02_read_word(self, lvalue);
+ self->regs.bit._if = true;
+ self->regs.bit.df = false;
+}
+
static ALWAYS_INLINE void cpu_65c02_jmp(struct cpu_65c02 *self, int lvalue) {
self->regs.word.pc = lvalue;
}
}
static ALWAYS_INLINE void cpu_65c02_stp(struct cpu_65c02 *self) {
- abort();
+ self->regs.bit.stp_flag = true;
}
static ALWAYS_INLINE void cpu_65c02_trb(struct cpu_65c02 *self, int lvalue) {
}
static ALWAYS_INLINE void cpu_65c02_wai(struct cpu_65c02 *self) {
- abort();
+ self->regs.bit.wai_flag = true;
}
// prototypes