|
|
@@ -0,0 +1,842 @@ |
|
|
|
|
|
#include "e6502.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Instruction Addressing |
|
|
|
|
|
|
|
|
|
|
|
typedef uint8_t* e6502_Address; |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address e6502_mem_adr(e6502_Core* core, |
|
|
|
|
|
e6502_Mem_Addr adr) { |
|
|
|
|
|
return &core->memory[adr]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Mem_Addr e6502_adr_mem(e6502_Core* core, |
|
|
|
|
|
e6502_Address adr) { |
|
|
|
|
|
return (adr - core->memory); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline uint8_t e6502_adr_r8(e6502_Core*, |
|
|
|
|
|
e6502_Address adr) { |
|
|
|
|
|
return *adr; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline uint8_t e6502_adr_r16(e6502_Core*, |
|
|
|
|
|
e6502_Address adr) { |
|
|
|
|
|
return *(uint16_t*)adr; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void e6502_adr_w8(e6502_Core*, |
|
|
|
|
|
e6502_Address adr, |
|
|
|
|
|
uint8_t val) { |
|
|
|
|
|
*adr = val; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void e6502_adr_w16(e6502_Core*, |
|
|
|
|
|
e6502_Address adr, |
|
|
|
|
|
uint16_t val) { |
|
|
|
|
|
*(uint16_t*)adr = val; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Read values after opcodes |
|
|
|
|
|
|
|
|
|
|
|
static inline uint8_t arg8(e6502_Core* core) { |
|
|
|
|
|
return e6502_r8(core, core->registers.PC++); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline uint16_t arg16(e6502_Core* core) { |
|
|
|
|
|
return (arg8(core) | ((uint16_t)arg8(core) << 8)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Interpret opcode values |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_none(e6502_Core*) { |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_ind(e6502_Core* core) { |
|
|
|
|
|
return e6502_mem_adr(core, e6502_r16(core, arg16(core))); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_ind_x(e6502_Core* core) { |
|
|
|
|
|
return e6502_mem_adr(core, e6502_r16( |
|
|
|
|
|
core, |
|
|
|
|
|
(uint8_t)(core->registers.X + arg8(core)) |
|
|
|
|
|
)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_ind_y(e6502_Core* core) { |
|
|
|
|
|
uint16_t zp_adr = e6502_r16(core, arg8(core)); |
|
|
|
|
|
uint8_t old_page = zp_adr >> 8; |
|
|
|
|
|
uint16_t new_adr = core->registers.Y + zp_adr; |
|
|
|
|
|
if (new_adr >> 8 != old_page) core->cycle++; |
|
|
|
|
|
return e6502_mem_adr(core, new_adr); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_abs_i(e6502_Core* core, |
|
|
|
|
|
uint8_t i) { |
|
|
|
|
|
uint16_t abs_adr = arg16(core); |
|
|
|
|
|
uint8_t old_page = abs_adr >> 8; |
|
|
|
|
|
uint16_t new_adr = i + abs_adr; |
|
|
|
|
|
if (new_adr >> 8 != old_page) core->cycle++; |
|
|
|
|
|
return e6502_mem_adr(core, new_adr); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_abs_x(e6502_Core* core) { |
|
|
|
|
|
return adr_abs_i(core, core->registers.X); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_abs_y(e6502_Core* core) { |
|
|
|
|
|
return adr_abs_i(core, core->registers.Y); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_zp(e6502_Core* core) { |
|
|
|
|
|
return e6502_mem_adr(core, arg8(core)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_zp_x(e6502_Core* core) { |
|
|
|
|
|
return e6502_mem_adr( |
|
|
|
|
|
core, (uint8_t)(arg8(core) + core->registers.X) |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_zp_y(e6502_Core* core) { |
|
|
|
|
|
return e6502_mem_adr( |
|
|
|
|
|
core, (uint8_t)(arg8(core) + core->registers.Y) |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_abs(e6502_Core* core) { |
|
|
|
|
|
return e6502_mem_adr(core, arg16(core)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_imm(e6502_Core* core) { |
|
|
|
|
|
return e6502_mem_adr(core, core->registers.PC++); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_rel(e6502_Core* core) { |
|
|
|
|
|
return e6502_mem_adr( |
|
|
|
|
|
core, (int8_t)arg8(core) + core->registers.PC |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_reg_a (e6502_Core* core) { |
|
|
|
|
|
return &core->registers.A; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_reg_x (e6502_Core* core) { |
|
|
|
|
|
return &core->registers.X; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_reg_y (e6502_Core* core) { |
|
|
|
|
|
return &core->registers.Y; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_reg_s (e6502_Core* core) { |
|
|
|
|
|
return &core->registers.S; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline e6502_Address adr_reg_sp (e6502_Core* core) { |
|
|
|
|
|
return &core->registers.SP; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Instructions |
|
|
|
|
|
|
|
|
|
|
|
static inline void nop(e6502_Core*, e6502_Address) { |
|
|
|
|
|
// NOP |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void brk(e6502_Core *core, e6502_Address) { |
|
|
|
|
|
e6502_push16(core, core->registers.PC + 1); |
|
|
|
|
|
e6502_push8(core, core->registers.S | |
|
|
|
|
|
e6502_Status_1 | |
|
|
|
|
|
e6502_Status_B); |
|
|
|
|
|
core->registers.S |= e6502_Status_I; |
|
|
|
|
|
core->registers.PC = e6502_r16(core, e6502_IRQ_Vec); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void rti(e6502_Core *core, e6502_Address) { |
|
|
|
|
|
core->registers.S = e6502_pop8(core) & ~(e6502_Status_B); |
|
|
|
|
|
core->registers.PC = e6502_pop16(core); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void ora(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
core->registers.A |= e6502_adr_r8(core, adr); |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N); |
|
|
|
|
|
core->registers.S |= (core->registers.A & e6502_Status_N); |
|
|
|
|
|
if (!core->registers.A) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void eor(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
core->registers.A ^= e6502_adr_r8(core, adr); |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N); |
|
|
|
|
|
core->registers.S |= (core->registers.A & e6502_Status_N); |
|
|
|
|
|
if (!core->registers.A) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void asl(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
uint8_t val = e6502_adr_r8(core, adr); |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_C | |
|
|
|
|
|
e6502_Status_Z | |
|
|
|
|
|
e6502_Status_N); |
|
|
|
|
|
if (val & 0x80) core->registers.S |= e6502_Status_C; |
|
|
|
|
|
val <<= 1; |
|
|
|
|
|
core->registers.S |= (val & e6502_Status_N); |
|
|
|
|
|
if (!val) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
e6502_adr_w8(core, adr, val); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void lsr(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
uint8_t val = e6502_adr_r8(core, adr); |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_C | |
|
|
|
|
|
e6502_Status_Z | |
|
|
|
|
|
e6502_Status_N); |
|
|
|
|
|
core->registers.S |= (val & e6502_Status_C); |
|
|
|
|
|
val >>= 1; |
|
|
|
|
|
core->registers.S |= (val & e6502_Status_N); |
|
|
|
|
|
if (!val) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
e6502_adr_w8(core, adr, val); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void rol(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
uint8_t val = e6502_adr_r8(core, adr); |
|
|
|
|
|
uint8_t new_c = (val & 0x80) ? e6502_Status_C : 0; |
|
|
|
|
|
val <<= 1; |
|
|
|
|
|
val |= (core->registers.S & e6502_Status_C); |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_C | |
|
|
|
|
|
e6502_Status_Z | |
|
|
|
|
|
e6502_Status_N); |
|
|
|
|
|
core->registers.S |= new_c; |
|
|
|
|
|
if (!val) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
core->registers.S |= (val & e6502_Status_N); |
|
|
|
|
|
e6502_adr_w8(core, adr, val); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void ror(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
uint8_t val = e6502_adr_r8(core, adr); |
|
|
|
|
|
uint8_t new_c = (val & e6502_Status_C); |
|
|
|
|
|
val >>= 1; |
|
|
|
|
|
if (core->registers.S & e6502_Status_C) val |= e6502_Status_N; |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_C | |
|
|
|
|
|
e6502_Status_Z | |
|
|
|
|
|
e6502_Status_N); |
|
|
|
|
|
core->registers.S |= new_c; |
|
|
|
|
|
if (!val) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
core->registers.S |= (val & e6502_Status_N); |
|
|
|
|
|
e6502_adr_w8(core, adr, val); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void pha(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
e6502_push8(core, core->registers.A); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void php(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
e6502_push8(core, core->registers.S | |
|
|
|
|
|
e6502_Status_1 | |
|
|
|
|
|
e6502_Status_B); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void pla(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
core->registers.A = e6502_pop8(core); |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N); |
|
|
|
|
|
if (!core->registers.A) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
core->registers.S |= (core->registers.A & e6502_Status_N); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void plp(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
core->registers.S = (e6502_pop8(core) | |
|
|
|
|
|
e6502_Status_1 | |
|
|
|
|
|
e6502_Status_B); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void b(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
uint8_t old_page = core->registers.PC >> 8; |
|
|
|
|
|
uint16_t new_addr = e6502_adr_mem(core, adr); |
|
|
|
|
|
if (old_page != (new_addr >> 8)) core->cycle++; |
|
|
|
|
|
core->registers.PC = new_addr; |
|
|
|
|
|
core->cycle++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void bpl(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
if (!(core->registers.S & e6502_Status_N)) { |
|
|
|
|
|
b(core, adr); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void bmi(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
if (core->registers.S & e6502_Status_N) { |
|
|
|
|
|
b(core, adr); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void bcc(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
if (!(core->registers.S & e6502_Status_C)) { |
|
|
|
|
|
b(core, adr); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void bcs(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
if (core->registers.S & e6502_Status_C) { |
|
|
|
|
|
b(core, adr); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void bvc(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
if (!(core->registers.S & e6502_Status_V)) { |
|
|
|
|
|
b(core, adr); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void bvs(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
if (core->registers.S & e6502_Status_V) { |
|
|
|
|
|
b(core, adr); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void bne(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
if (!(core->registers.S & e6502_Status_Z)) { |
|
|
|
|
|
b(core, adr); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void beq(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
if (core->registers.S & e6502_Status_Z) { |
|
|
|
|
|
b(core, adr); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void clc(e6502_Core *core, e6502_Address) { |
|
|
|
|
|
core->registers.S &= ~e6502_Status_C; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void cli(e6502_Core *core, e6502_Address) { |
|
|
|
|
|
core->registers.S &= ~e6502_Status_I; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void cld(e6502_Core *core, e6502_Address) { |
|
|
|
|
|
core->registers.S &= ~e6502_Status_D; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void clv(e6502_Core *core, e6502_Address) { |
|
|
|
|
|
core->registers.S &= ~e6502_Status_V; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void sec(e6502_Core *core, e6502_Address) { |
|
|
|
|
|
core->registers.S |= e6502_Status_C; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void sei(e6502_Core *core, e6502_Address) { |
|
|
|
|
|
core->registers.S |= e6502_Status_I; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void sed(e6502_Core *core, e6502_Address) { |
|
|
|
|
|
core->registers.S |= e6502_Status_D; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void jsr(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
e6502_push16(core, core->registers.PC - 1); |
|
|
|
|
|
core->registers.PC = e6502_adr_mem(core, adr); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void rts(e6502_Core *core, e6502_Address) { |
|
|
|
|
|
core->registers.PC = e6502_pop16(core) + 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void jmp(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
core->registers.PC = e6502_adr_mem(core, adr); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void bit(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
uint8_t val = e6502_adr_r8(core, adr); |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_Z | |
|
|
|
|
|
e6502_Status_V | |
|
|
|
|
|
e6502_Status_N); |
|
|
|
|
|
core->registers.S |= (val & (e6502_Status_V | |
|
|
|
|
|
e6502_Status_N)); |
|
|
|
|
|
if (!(val & core->registers.A)) { |
|
|
|
|
|
core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void cmp(e6502_Core *core, |
|
|
|
|
|
e6502_Address adr, |
|
|
|
|
|
uint8_t minuend) { |
|
|
|
|
|
uint8_t val = e6502_adr_r8(core, adr); |
|
|
|
|
|
uint8_t diff = minuend - val; |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_C | |
|
|
|
|
|
e6502_Status_Z | |
|
|
|
|
|
e6502_Status_N); |
|
|
|
|
|
if (minuend >= val) core->registers.S |= e6502_Status_C; |
|
|
|
|
|
if (diff == 0) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
core->registers.S |= (diff & e6502_Status_N); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void cpa(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
cmp(core, adr, core->registers.A); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void cpx(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
cmp(core, adr, core->registers.X); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void cpy(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
cmp(core, adr, core->registers.Y); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void and(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
core->registers.A &= e6502_adr_r8(core, adr); |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N); |
|
|
|
|
|
core->registers.S |= (core->registers.A & e6502_Status_N); |
|
|
|
|
|
if (!core->registers.A) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void adc(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
uint8_t addend = e6502_adr_r8(core, adr); |
|
|
|
|
|
uint32_t sum = core->registers.A + |
|
|
|
|
|
addend + |
|
|
|
|
|
(core->registers.S & e6502_Status_C); |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_C | e6502_Status_Z | |
|
|
|
|
|
e6502_Status_V | e6502_Status_N); |
|
|
|
|
|
if (sum > 0xFF) core->registers.S |= e6502_Status_C; |
|
|
|
|
|
if (!(uint8_t)sum) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
if ( (addend & 0x80) == (core->registers.A & 0x80) && |
|
|
|
|
|
(sum & 0x80) != (addend & 0x80)) { |
|
|
|
|
|
core->registers.S |= e6502_Status_V; |
|
|
|
|
|
} |
|
|
|
|
|
core->registers.S |= (sum & e6502_Status_N); |
|
|
|
|
|
core->registers.A = sum; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void sbc(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
uint8_t addend = e6502_adr_r8(core, adr); |
|
|
|
|
|
uint32_t sum = core->registers.A - |
|
|
|
|
|
addend - |
|
|
|
|
|
(1 - (core->registers.S & e6502_Status_C)); |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_C | e6502_Status_Z | |
|
|
|
|
|
e6502_Status_V | e6502_Status_N); |
|
|
|
|
|
if (sum < 0x100) core->registers.S |= e6502_Status_C; |
|
|
|
|
|
if (!(uint8_t)sum) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
if ( (sum & 0x80) != (core->registers.A & 0x80) && |
|
|
|
|
|
(addend & 0x80) != (core->registers.A & 0x80)) { |
|
|
|
|
|
core->registers.S |= e6502_Status_V; |
|
|
|
|
|
} |
|
|
|
|
|
core->registers.S |= (sum & e6502_Status_N); |
|
|
|
|
|
core->registers.A = sum; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void inc(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
uint8_t val = e6502_adr_r8(core, adr) + 1; |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N); |
|
|
|
|
|
core->registers.S |= (val & e6502_Status_N); |
|
|
|
|
|
if (!val) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
e6502_adr_w8(core, adr, val); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void dec(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
uint8_t val = e6502_adr_r8(core, adr) - 1; |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N); |
|
|
|
|
|
core->registers.S |= (val & e6502_Status_N); |
|
|
|
|
|
if (!val) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
e6502_adr_w8(core, adr, val); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void sta(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
e6502_adr_w8(core, adr, core->registers.A); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void stx(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
e6502_adr_w8(core, adr, core->registers.X); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void sty(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
e6502_adr_w8(core, adr, core->registers.Y); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void t(e6502_Core *core, |
|
|
|
|
|
e6502_Address adr, |
|
|
|
|
|
uint8_t reg) { |
|
|
|
|
|
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N); |
|
|
|
|
|
core->registers.S |= (reg & e6502_Status_N); |
|
|
|
|
|
if (!reg) core->registers.S |= e6502_Status_Z; |
|
|
|
|
|
e6502_adr_w8(core, adr, reg); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void ta(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
t(core, adr, core->registers.A); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void txs(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
core->registers.SP = core->registers.X; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void txa(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
t(core, &core->registers.A, core->registers.X); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void ty(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
t(core, adr, core->registers.Y); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void ts(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
t(core, adr, core->registers.SP); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void lda(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
t(core, &core->registers.A, e6502_adr_r8(core, adr)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void ldx(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
t(core, &core->registers.X, e6502_adr_r8(core, adr)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void ldy(e6502_Core *core, e6502_Address adr) { |
|
|
|
|
|
t(core, &core->registers.Y, e6502_adr_r8(core, adr)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
|
void(*operator)(e6502_Core*, e6502_Address); |
|
|
|
|
|
e6502_Address(*address)(e6502_Core*); |
|
|
|
|
|
uint16_t cycles; |
|
|
|
|
|
} e6502_Instruction; |
|
|
|
|
|
|
|
|
|
|
|
static e6502_Instruction e6502_instructions[256] = { |
|
|
|
|
|
// 0x00 |
|
|
|
|
|
[0b00000000] = {brk, adr_none, 7}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00000001] = {ora, adr_ind_x, 6}, |
|
|
|
|
|
[0b00000101] = {ora, adr_zp, 3}, |
|
|
|
|
|
[0b00001001] = {ora, adr_imm, 2}, |
|
|
|
|
|
[0b00001101] = {ora, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00000110] = {asl, adr_zp, 5}, |
|
|
|
|
|
[0b00001010] = {asl, adr_reg_a, 2}, |
|
|
|
|
|
[0b00001110] = {asl, adr_abs, 6}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00001000] = {php, adr_none, 3}, |
|
|
|
|
|
|
|
|
|
|
|
// 0x10 |
|
|
|
|
|
[0b00010000] = {bpl, adr_rel, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00010001] = {ora, adr_ind_y, 5}, |
|
|
|
|
|
[0b00010101] = {ora, adr_zp_x, 4}, |
|
|
|
|
|
[0b00011001] = {ora, adr_abs_y, 4}, |
|
|
|
|
|
[0b00011101] = {ora, adr_abs_x, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00011000] = {clc, adr_none, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00010110] = {asl, adr_zp_x, 6}, |
|
|
|
|
|
[0b00011110] = {asl, adr_abs_x, 7}, |
|
|
|
|
|
|
|
|
|
|
|
// 0x20 |
|
|
|
|
|
[0b00100000] = {jsr, adr_abs, 6}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00100100] = {bit, adr_zp, 3}, |
|
|
|
|
|
[0b00101100] = {bit, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00100001] = {and, adr_ind_x, 6}, |
|
|
|
|
|
[0b00100101] = {and, adr_zp, 3}, |
|
|
|
|
|
[0b00101001] = {and, adr_imm, 2}, |
|
|
|
|
|
[0b00101101] = {and, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00100110] = {rol, adr_zp, 5}, |
|
|
|
|
|
[0b00101010] = {rol, adr_reg_a, 2}, |
|
|
|
|
|
[0b00101110] = {rol, adr_abs, 6}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00101000] = {plp, adr_none, 4}, |
|
|
|
|
|
|
|
|
|
|
|
// 0x30 |
|
|
|
|
|
[0b00110000] = {bmi, adr_rel, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00110001] = {and, adr_ind_y, 5}, |
|
|
|
|
|
[0b00110101] = {and, adr_zp_x, 4}, |
|
|
|
|
|
[0b00111001] = {and, adr_abs_y, 3}, |
|
|
|
|
|
[0b00111101] = {and, adr_abs_x, 3}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00110110] = {rol, adr_zp_x, 6}, |
|
|
|
|
|
[0b00111110] = {rol, adr_abs_x, 7}, |
|
|
|
|
|
|
|
|
|
|
|
[0b00111000] = {sec, adr_none, 2}, |
|
|
|
|
|
|
|
|
|
|
|
// 0x40 |
|
|
|
|
|
[0b01000000] = {rti, adr_none, 6}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01000001] = {eor, adr_ind_x, 6}, |
|
|
|
|
|
[0b01000101] = {eor, adr_zp, 3}, |
|
|
|
|
|
[0b01001001] = {eor, adr_imm, 2}, |
|
|
|
|
|
[0b01001101] = {eor, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01000110] = {lsr, adr_zp, 5}, |
|
|
|
|
|
[0b01001010] = {lsr, adr_reg_a, 2}, |
|
|
|
|
|
[0b01001110] = {lsr, adr_abs, 6}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01001000] = {pha, adr_none, 3}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01001100] = {jmp, adr_abs, 3}, |
|
|
|
|
|
|
|
|
|
|
|
// 0x50 |
|
|
|
|
|
[0b01010000] = {bvc, adr_rel, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01010001] = {eor, adr_ind_y, 5}, |
|
|
|
|
|
[0b01010101] = {eor, adr_zp_x, 4}, |
|
|
|
|
|
[0b01011001] = {eor, adr_abs_y, 4}, |
|
|
|
|
|
[0b01011101] = {eor, adr_abs_x, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01010110] = {lsr, adr_zp_x, 6}, |
|
|
|
|
|
[0b01011110] = {lsr, adr_abs_x, 7}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01011000] = {cli, adr_none, 2}, |
|
|
|
|
|
|
|
|
|
|
|
// 0x60 |
|
|
|
|
|
[0b01100000] = {rts, adr_none, 6}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01100001] = {adc, adr_ind_x, 6}, |
|
|
|
|
|
[0b01100101] = {adc, adr_zp, 3}, |
|
|
|
|
|
[0b01101001] = {adc, adr_imm, 2}, |
|
|
|
|
|
[0b01101101] = {adc, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01100110] = {ror, adr_zp, 5}, |
|
|
|
|
|
[0b01101010] = {ror, adr_reg_a, 2}, |
|
|
|
|
|
[0b01101110] = {ror, adr_abs, 6}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01101000] = {pla, adr_none, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01101100] = {jmp, adr_ind, 5}, |
|
|
|
|
|
|
|
|
|
|
|
// 0x70 |
|
|
|
|
|
[0b01110000] = {bvs, adr_rel, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01110001] = {adc, adr_ind_y, 5}, |
|
|
|
|
|
[0b01110101] = {adc, adr_zp_x, 4}, |
|
|
|
|
|
[0b01111001] = {adc, adr_abs_y, 4}, |
|
|
|
|
|
[0b01111101] = {adc, adr_abs_x, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01110110] = {ror, adr_zp_x, 6}, |
|
|
|
|
|
[0b01111110] = {ror, adr_abs_x, 7}, |
|
|
|
|
|
|
|
|
|
|
|
[0b01111000] = {sei, adr_none, 2}, |
|
|
|
|
|
|
|
|
|
|
|
// 0x80 |
|
|
|
|
|
[0b10000001] = {sta, adr_ind_x, 6}, |
|
|
|
|
|
[0b10000101] = {sta, adr_zp, 3}, |
|
|
|
|
|
[0b10001101] = {sta, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10000110] = {stx, adr_zp, 3}, |
|
|
|
|
|
[0b10001110] = {stx, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10000100] = {sty, adr_zp, 3}, |
|
|
|
|
|
[0b10001100] = {sty, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10001000] = {dec, adr_reg_y, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10001010] = {txa, adr_none, 2}, |
|
|
|
|
|
|
|
|
|
|
|
// 0x90 |
|
|
|
|
|
[0b10010000] = {bcc, adr_rel, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10010001] = {sta, adr_ind_y, 6}, |
|
|
|
|
|
[0b10010101] = {sta, adr_zp_x, 4}, |
|
|
|
|
|
[0b10011001] = {sta, adr_abs_y, 5}, |
|
|
|
|
|
[0b10011101] = {sta, adr_abs_x, 5}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10010110] = {stx, adr_zp_y, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10010100] = {sty, adr_zp_x, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10011000] = {ty, adr_reg_a, 2}, |
|
|
|
|
|
[0b10011010] = {txs, adr_none, 2}, |
|
|
|
|
|
|
|
|
|
|
|
// 0xA0 |
|
|
|
|
|
[0b10100001] = {lda, adr_ind_x, 6}, |
|
|
|
|
|
[0b10100101] = {lda, adr_zp, 3}, |
|
|
|
|
|
[0b10101001] = {lda, adr_imm, 2}, |
|
|
|
|
|
[0b10101101] = {lda, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10100010] = {ldx, adr_imm, 2}, |
|
|
|
|
|
[0b10100110] = {ldx, adr_zp, 3}, |
|
|
|
|
|
[0b10101110] = {ldx, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10100000] = {ldy, adr_imm, 2}, |
|
|
|
|
|
[0b10100100] = {ldy, adr_zp, 3}, |
|
|
|
|
|
[0b10101100] = {ldy, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10101010] = {ta, adr_reg_x, 2}, |
|
|
|
|
|
[0b10101000] = {ta, adr_reg_y, 2}, |
|
|
|
|
|
|
|
|
|
|
|
// 0xB0 |
|
|
|
|
|
[0b10110000] = {bcs, adr_rel, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10110001] = {lda, adr_ind_y, 5}, |
|
|
|
|
|
[0b10110101] = {lda, adr_zp_x, 4}, |
|
|
|
|
|
[0b10111001] = {lda, adr_abs_y, 4}, |
|
|
|
|
|
[0b10111101] = {lda, adr_abs_x, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10110110] = {ldx, adr_zp_y, 4}, |
|
|
|
|
|
[0b10111110] = {ldx, adr_abs_y, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10110100] = {ldy, adr_zp_x, 4}, |
|
|
|
|
|
[0b10111100] = {ldy, adr_abs_x, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10111000] = {clv, adr_none, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b10111010] = {ts, adr_reg_x, 2}, |
|
|
|
|
|
|
|
|
|
|
|
// 0xC0 |
|
|
|
|
|
[0b11000000] = {cpy, adr_imm, 2}, |
|
|
|
|
|
[0b11000100] = {cpy, adr_zp, 3}, |
|
|
|
|
|
[0b11001100] = {cpy, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11000001] = {cpa, adr_ind_x, 6}, |
|
|
|
|
|
[0b11000101] = {cpa, adr_zp, 3}, |
|
|
|
|
|
[0b11001001] = {cpa, adr_imm, 2}, |
|
|
|
|
|
[0b11001101] = {cpa, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11001000] = {inc, adr_reg_y, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11000110] = {dec, adr_zp, 5}, |
|
|
|
|
|
[0b11001110] = {dec, adr_abs, 6}, |
|
|
|
|
|
[0b11010110] = {dec, adr_zp_x, 6}, |
|
|
|
|
|
[0b11011110] = {dec, adr_abs_x, 7}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11001010] = {dec, adr_reg_x, 2}, |
|
|
|
|
|
|
|
|
|
|
|
// 0xD0 |
|
|
|
|
|
[0b11010000] = {bne, adr_rel, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11011000] = {cld, adr_none, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11010001] = {cpa, adr_ind_y, 5}, |
|
|
|
|
|
[0b11010101] = {cpa, adr_zp_x, 4}, |
|
|
|
|
|
[0b11011001] = {cpa, adr_abs_y, 4}, |
|
|
|
|
|
[0b11011101] = {cpa, adr_abs_x, 4}, |
|
|
|
|
|
|
|
|
|
|
|
// 0xE0 |
|
|
|
|
|
[0b11100000] = {cpx, adr_imm, 2}, |
|
|
|
|
|
[0b11100100] = {cpx, adr_zp, 3}, |
|
|
|
|
|
[0b11101100] = {cpx, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11100001] = {sbc, adr_ind_x, 6}, |
|
|
|
|
|
[0b11100101] = {sbc, adr_zp, 3}, |
|
|
|
|
|
[0b11101001] = {sbc, adr_imm, 2}, |
|
|
|
|
|
[0b11101101] = {sbc, adr_abs, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11100110] = {inc, adr_zp, 5}, |
|
|
|
|
|
[0b11101110] = {inc, adr_abs, 6}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11101000] = {inc, adr_reg_x, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11101010] = {nop, adr_none, 2}, |
|
|
|
|
|
|
|
|
|
|
|
// 0xF0 |
|
|
|
|
|
[0b11110000] = {beq, adr_rel, 2}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11110001] = {sbc, adr_ind_y, 5}, |
|
|
|
|
|
[0b11110101] = {sbc, adr_zp_x, 4}, |
|
|
|
|
|
[0b11111001] = {sbc, adr_abs_y, 4}, |
|
|
|
|
|
[0b11111101] = {sbc, adr_abs_x, 4}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11110110] = {inc, adr_zp_x, 6}, |
|
|
|
|
|
[0b11111110] = {inc, adr_abs_x, 7}, |
|
|
|
|
|
|
|
|
|
|
|
[0b11111000] = {sed, adr_none, 2}, |
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
int e6502_instr_size(uint8_t opcode) { |
|
|
|
|
|
e6502_Instruction* instr = &e6502_instructions[opcode]; |
|
|
|
|
|
if ( instr->address == adr_none || |
|
|
|
|
|
instr->address == adr_reg_a || |
|
|
|
|
|
instr->address == adr_reg_x || |
|
|
|
|
|
instr->address == adr_reg_y || |
|
|
|
|
|
instr->address == adr_reg_s || |
|
|
|
|
|
instr->address == adr_reg_sp) { |
|
|
|
|
|
return 1; |
|
|
|
|
|
} else if ( instr->address == adr_abs || |
|
|
|
|
|
instr->address == adr_abs_x || |
|
|
|
|
|
instr->address == adr_abs_y) { |
|
|
|
|
|
return 3; |
|
|
|
|
|
} else { |
|
|
|
|
|
return 2; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
int e6502_dump_instr(e6502_Core* core, e6502_Mem_Addr addr, |
|
|
|
|
|
FILE* file) { |
|
|
|
|
|
uint8_t opcode = e6502_r8(core, addr); |
|
|
|
|
|
int size = e6502_instr_size(opcode); |
|
|
|
|
|
fprintf(file, "$%02x", opcode); |
|
|
|
|
|
if (size == 2) { |
|
|
|
|
|
fprintf(file, " $%02x", e6502_r8(core, addr + 1)); |
|
|
|
|
|
} else if (size == 3) { |
|
|
|
|
|
fprintf(file, " $%04x", e6502_r16(core, addr + 1)); |
|
|
|
|
|
} |
|
|
|
|
|
fputc('\n', file); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int e6502_dump_regs(e6502_Core* core, FILE* file) { |
|
|
|
|
|
fprintf(file, "S:%02x A:%02x X:%02x Y:%02x P:%02x\n", |
|
|
|
|
|
core->registers.SP, core->registers.A, |
|
|
|
|
|
core->registers.X, core->registers.Y, |
|
|
|
|
|
core->registers.S); |
|
|
|
|
|
} |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
int e6502_run(e6502_Core* core, |
|
|
|
|
|
int remaining, |
|
|
|
|
|
int* run, |
|
|
|
|
|
int instructions) { |
|
|
|
|
|
int status = 0; |
|
|
|
|
|
int start = (instructions ? core->instr : core->cycle); |
|
|
|
|
|
int end = start + remaining; |
|
|
|
|
|
int last_pc = -1; |
|
|
|
|
|
while ((instructions ? core->instr : core->cycle) < end) { |
|
|
|
|
|
if (core->registers.PC == last_pc) { |
|
|
|
|
|
// Trapped. |
|
|
|
|
|
status = -2; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
last_pc = core->registers.PC; |
|
|
|
|
|
uint8_t opcode = e6502_r8(core, core->registers.PC); |
|
|
|
|
|
e6502_Instruction* instr = &e6502_instructions[opcode]; |
|
|
|
|
|
if (!instr->operator) { |
|
|
|
|
|
/* |
|
|
|
|
|
fprintf(stdout, "$%04x: %02x\n", last_pc, opcode); |
|
|
|
|
|
*/ |
|
|
|
|
|
status = -1; |
|
|
|
|
|
break; |
|
|
|
|
|
} else { |
|
|
|
|
|
core->registers.PC++; |
|
|
|
|
|
e6502_Address adr = instr->address(core); |
|
|
|
|
|
/* |
|
|
|
|
|
uint16_t size = core->registers.PC - last_pc; |
|
|
|
|
|
*/ |
|
|
|
|
|
instr->operator(core, adr); |
|
|
|
|
|
core->cycle += instr->cycles; |
|
|
|
|
|
core->instr++; |
|
|
|
|
|
/* |
|
|
|
|
|
fprintf(stdout, "$%04x: $%02x", last_pc, opcode); |
|
|
|
|
|
if (size == 2) { |
|
|
|
|
|
fprintf(stdout, " $%02x", e6502_r8(core, last_pc + 1)); |
|
|
|
|
|
} else if (size == 3) { |
|
|
|
|
|
fprintf(stdout, " $%02x%02x", e6502_r8(core, last_pc + 2), e6502_r8(core, last_pc + 1)); |
|
|
|
|
|
} |
|
|
|
|
|
fputc('\n', stdout); |
|
|
|
|
|
e6502_dump_regs(core, stdout); |
|
|
|
|
|
*/ |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (run) { |
|
|
|
|
|
*run = (instructions ? core->instr : core->cycle) - start; |
|
|
|
|
|
} |
|
|
|
|
|
return status; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int e6502_reset(e6502_Core* core) { |
|
|
|
|
|
core->registers.PC = e6502_r16(core, e6502_Reset_Vec); |
|
|
|
|
|
core->registers.SP -= 3; |
|
|
|
|
|
core->registers.S |= (e6502_Status_B | e6502_Status_1); |
|
|
|
|
|
} |