|
|
|
@@ -1,3 +1,5 @@ |
|
|
|
#include <stdbool.h> |
|
|
|
|
|
|
|
#include "f6502.h" |
|
|
|
#include "f6502_consts.h" |
|
|
|
|
|
|
|
@@ -67,8 +69,9 @@ static inline uint16_t f6502_read16(f6502_Memory* mem, |
|
|
|
((uint16_t)f6502_read(mem, addr + 1) << 8)); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void f6502_write(f6502_Memory* mem, |
|
|
|
uint16_t addr, uint8_t val) { |
|
|
|
static inline int f6502_write(f6502_Memory* mem, |
|
|
|
uint16_t addr, uint8_t val) { |
|
|
|
int ret = 0; |
|
|
|
#ifdef F6502_TRACE |
|
|
|
printf("W $%04X <- %02X\n", addr, val); |
|
|
|
#endif |
|
|
|
@@ -80,10 +83,19 @@ static inline void f6502_write(f6502_Memory* mem, |
|
|
|
int irq = val & 0b01; |
|
|
|
int nmi = val & 0b10; |
|
|
|
|
|
|
|
f6502_wire_interrupts(core, |
|
|
|
(irq ? f6502_Int_IRQ : 0) | |
|
|
|
(nmi ? f6502_Int_NMI : 0) |
|
|
|
); |
|
|
|
#ifdef F6502_TRACE |
|
|
|
if (!irq ^ !(core->interrupts & f6502_Int_IRQ)) { |
|
|
|
fprintf(stdout, "%s IRQ\n", irq ? "Set" : "Clear"); |
|
|
|
} |
|
|
|
if (!nmi ^ !(core->interrupts & f6502_Int_NMI)) { |
|
|
|
fprintf(stdout, "%s NMI\n", nmi ? "Set" : "Clear"); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
f6502_set_NMI(core, nmi); |
|
|
|
f6502_set_IRQ(core, irq); |
|
|
|
|
|
|
|
ret = 1; // Interrupt [may have been] triggered |
|
|
|
} |
|
|
|
#endif |
|
|
|
mem->ram[addr] = val; |
|
|
|
@@ -91,12 +103,12 @@ static inline void f6502_write(f6502_Memory* mem, |
|
|
|
// TODO |
|
|
|
memval = val; |
|
|
|
#endif |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void f6502_init(f6502_Core* core) { |
|
|
|
core->int_state = f6502_Int_NMI | f6502_Int_IRQ; |
|
|
|
core->int_wiring = f6502_Int_NMI | f6502_Int_IRQ; |
|
|
|
// TODO: ??? |
|
|
|
} |
|
|
|
|
|
|
|
void f6502_reset(f6502_Core* core) { |
|
|
|
@@ -106,9 +118,14 @@ void f6502_reset(f6502_Core* core) { |
|
|
|
core->registers.P |= (f6502_Status_B | f6502_Status_1); |
|
|
|
} |
|
|
|
|
|
|
|
void f6502_wire_interrupts(f6502_Core* core, |
|
|
|
f6502_Interrupt ints) { |
|
|
|
core->int_wiring = ints; |
|
|
|
void f6502_set_NMI(f6502_Core* core, bool active) { |
|
|
|
if (active) core->interrupts |= f6502_Int_NMI; |
|
|
|
else core->interrupts &= ~(f6502_Int_NMI | f6502_Int_NMI_Serviced); |
|
|
|
} |
|
|
|
|
|
|
|
void f6502_set_IRQ(f6502_Core* core, bool active) { |
|
|
|
if (active) core->interrupts |= f6502_Int_IRQ; |
|
|
|
else core->interrupts &= ~f6502_Int_IRQ; |
|
|
|
} |
|
|
|
|
|
|
|
#define PUSH(core, S, val) \ |
|
|
|
@@ -128,32 +145,31 @@ void f6502_wire_interrupts(f6502_Core* core, |
|
|
|
#define SET(R, flags) R |= (flags) |
|
|
|
|
|
|
|
static inline int f6502_interrupt(f6502_Core* core, |
|
|
|
f6502_Interrupt interrupt, |
|
|
|
uint16_t addr) { |
|
|
|
core->int_state &= ~interrupt; |
|
|
|
core->int_state |= (core->int_wiring & interrupt); |
|
|
|
PUSH16(core, core->registers.S, core->registers.PC); |
|
|
|
PUSH(core, core->registers.S, |
|
|
|
core->registers.P & ~f6502_Status_B); |
|
|
|
CLR(core->registers.P, f6502_Status_D); |
|
|
|
SET(core->registers.P, f6502_Status_I); |
|
|
|
core->registers.PC = f6502_read16(&core->memory, addr); |
|
|
|
return 7; |
|
|
|
} |
|
|
|
|
|
|
|
static inline int f6502_int_ready(const f6502_Core* core, |
|
|
|
f6502_Interrupt interrupt) { |
|
|
|
return ((core->int_state ^ core->int_wiring) & interrupt); |
|
|
|
static inline bool f6502_nmi_ready(const f6502_Core* core) { |
|
|
|
return ( (core->interrupts & f6502_Int_NMI) && |
|
|
|
!(core->interrupts & f6502_Int_NMI_Serviced)); |
|
|
|
} |
|
|
|
|
|
|
|
static inline bool f6502_irq_ready(const f6502_Core* core) { |
|
|
|
return ( (core->interrupts & f6502_Int_IRQ) && |
|
|
|
!(core->registers.P & f6502_Status_I)); |
|
|
|
} |
|
|
|
|
|
|
|
static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
|
if (f6502_int_ready(core, f6502_Int_NMI)) { |
|
|
|
return f6502_interrupt(core, f6502_Int_NMI, |
|
|
|
f6502_Vector_NMI); |
|
|
|
} else if ( f6502_int_ready(core, f6502_Int_IRQ) && |
|
|
|
!(core->registers.P & f6502_Status_I)) { |
|
|
|
return f6502_interrupt(core, f6502_Int_IRQ, |
|
|
|
f6502_Vector_IRQ); |
|
|
|
if (f6502_nmi_ready(core)) { |
|
|
|
core->interrupts |= f6502_Int_NMI_Serviced; |
|
|
|
return f6502_interrupt(core, f6502_Vector_NMI); |
|
|
|
} else if (f6502_irq_ready(core)) { |
|
|
|
return f6502_interrupt(core, f6502_Vector_IRQ); |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
@@ -223,19 +239,18 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
|
A = res; \ |
|
|
|
} |
|
|
|
#define AND(v) A &= (v); TEST(A) |
|
|
|
#define ASL(a) { \ |
|
|
|
#define ASL(a) ({ \ |
|
|
|
CLR(P, f6502_Status_N | f6502_Status_Z | f6502_Status_C); \ |
|
|
|
register uint16_t addr = a; \ |
|
|
|
register uint8_t val = f6502_read(&core->memory, addr); \ |
|
|
|
SET(P, table_asl[val]); \ |
|
|
|
val <<= 1; \ |
|
|
|
f6502_write(&core->memory, addr, val); \ |
|
|
|
} |
|
|
|
int_trig = f6502_write(&core->memory, addr, val); \ |
|
|
|
}) |
|
|
|
#define ASL_A() \ |
|
|
|
CLR(P, f6502_Status_N | f6502_Status_Z | f6502_Status_C); \ |
|
|
|
SET(P, table_asl[A]); \ |
|
|
|
A <<= 1 |
|
|
|
|
|
|
|
#ifdef F6502_HCF |
|
|
|
#define BIF_HCF() \ |
|
|
|
if (pc_prev == PC + 2) { \ |
|
|
|
@@ -268,22 +283,24 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
|
SET(P, table_test[diff & 0xFFU]); \ |
|
|
|
if (diff < 0x100) SET(P, f6502_Status_C); \ |
|
|
|
} |
|
|
|
#define DEC(a) { \ |
|
|
|
#define DEC(a) ({ \ |
|
|
|
register uint16_t addr = a; \ |
|
|
|
register uint8_t val = f6502_read(&core->memory, addr); \ |
|
|
|
f6502_write(&core->memory, addr, --val); \ |
|
|
|
--val; \ |
|
|
|
TEST(val); \ |
|
|
|
} |
|
|
|
int_trig = f6502_write(&core->memory, addr, val); \ |
|
|
|
}) |
|
|
|
#define EOR(v) A ^= (v); TEST(A) |
|
|
|
#define INC(a) { \ |
|
|
|
#define INC(a) ({ \ |
|
|
|
register uint16_t addr = a; \ |
|
|
|
register uint8_t val = f6502_read(&core->memory, addr); \ |
|
|
|
f6502_write(&core->memory, addr, ++val); \ |
|
|
|
++val; \ |
|
|
|
TEST(val); \ |
|
|
|
} |
|
|
|
int_trig = f6502_write(&core->memory, addr, val); \ |
|
|
|
}) |
|
|
|
#define JMP(a) PC = (a) |
|
|
|
#define LD(reg, v) reg = (v); TEST(reg) |
|
|
|
#define LSR(a) { \ |
|
|
|
#define LSR(a) ({ \ |
|
|
|
register uint16_t addr = a; \ |
|
|
|
register uint8_t val = f6502_read(&core->memory, addr); \ |
|
|
|
CLR(P, f6502_Status_N | f6502_Status_Z | f6502_Status_C); \ |
|
|
|
@@ -291,8 +308,8 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
|
val >>= 1; \ |
|
|
|
SET(P, val & f6502_Status_N); \ |
|
|
|
if (!val) SET(P, f6502_Status_Z); \ |
|
|
|
f6502_write(&core->memory, addr, val); \ |
|
|
|
} |
|
|
|
int_trig = f6502_write(&core->memory, addr, val); \ |
|
|
|
}) |
|
|
|
#define LSR_A() \ |
|
|
|
CLR(P, f6502_Status_N | f6502_Status_Z | f6502_Status_C); \ |
|
|
|
SET(P, A & f6502_Status_C); \ |
|
|
|
@@ -300,7 +317,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
|
SET(P, A & f6502_Status_N); \ |
|
|
|
if (!A) SET(P, f6502_Status_Z) |
|
|
|
#define ORA(v) A |= (v); TEST(A) |
|
|
|
#define ROL(a) { \ |
|
|
|
#define ROL(a) ({ \ |
|
|
|
register uint16_t addr = a; \ |
|
|
|
register uint8_t val = f6502_read(&core->memory, addr); \ |
|
|
|
register uint8_t new_c = (A & 0x80) ? f6502_Status_C : 0; \ |
|
|
|
@@ -309,8 +326,8 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
|
P |= new_c; \ |
|
|
|
if (!val) SET(P, f6502_Status_Z); \ |
|
|
|
SET(P, val & f6502_Status_N); \ |
|
|
|
f6502_write(&core->memory, addr, val); \ |
|
|
|
} |
|
|
|
int_trig = f6502_write(&core->memory, addr, val); \ |
|
|
|
}) |
|
|
|
#define ROL_A() { \ |
|
|
|
register uint8_t new_c = (A & 0x80) ? f6502_Status_C : 0; \ |
|
|
|
A = (A << 1) | (P & f6502_Status_C); \ |
|
|
|
@@ -319,7 +336,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
|
if (!A) SET(P, f6502_Status_Z); \ |
|
|
|
SET(P, A & f6502_Status_N); \ |
|
|
|
} |
|
|
|
#define ROR(a) { \ |
|
|
|
#define ROR(a) ({ \ |
|
|
|
register uint16_t addr = a; \ |
|
|
|
register uint8_t val = f6502_read(&core->memory, addr); \ |
|
|
|
register uint8_t new_c = (val & f6502_Status_C); \ |
|
|
|
@@ -329,10 +346,10 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
|
P |= new_c; \ |
|
|
|
if (!val) SET(P, f6502_Status_Z); \ |
|
|
|
SET(P, (val & f6502_Status_N)); \ |
|
|
|
f6502_write(&core->memory, addr, val); \ |
|
|
|
} |
|
|
|
int_trig = f6502_write(&core->memory, addr, val); \ |
|
|
|
}) |
|
|
|
#define ROR_A() { \ |
|
|
|
register uint8_t new_c = (A & f6502_Status_C); \ |
|
|
|
register uint8_t new_c = (A & f6502_Status_C); \ |
|
|
|
A >>= 1; \ |
|
|
|
if (P & f6502_Status_C) A |= f6502_Status_N; \ |
|
|
|
CLR(P, f6502_Status_C | f6502_Status_Z | f6502_Status_N); \ |
|
|
|
@@ -352,7 +369,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
|
} \ |
|
|
|
A = res; \ |
|
|
|
} |
|
|
|
#define ST(reg, a) f6502_write(&core->memory, (a), reg) |
|
|
|
#define ST(reg, a) int_trig = f6502_write(&core->memory, (a), reg) |
|
|
|
|
|
|
|
|
|
|
|
static int f6502_do_step(f6502_Core* core, int clocks) { |
|
|
|
@@ -365,11 +382,21 @@ static int f6502_do_step(f6502_Core* core, int clocks) { |
|
|
|
register uint8_t Y = core->registers.Y; |
|
|
|
register uint8_t P = core->registers.P; |
|
|
|
|
|
|
|
while (clocks_elapsed < clocks) { |
|
|
|
register bool int_trig = 0; |
|
|
|
|
|
|
|
while (clocks_elapsed < clocks && !int_trig) { |
|
|
|
uint8_t opcode = f6502_read(&core->memory, PC++); |
|
|
|
#ifdef F6502_TRACE |
|
|
|
printf("S:%02x A:%02x X:%02x Y:%02x P:%02x\n", |
|
|
|
S, A, X, Y, P); |
|
|
|
|
|
|
|
printf("$%04x:", (int)S + f6502_Base_Stack); |
|
|
|
for (int i = S; i < 256; ++i) |
|
|
|
printf(" %02x", (int)f6502_read(&core->memory, i + f6502_Base_Stack)); |
|
|
|
putc('\n', stdout); |
|
|
|
|
|
|
|
printf("INT %02x\n", core->interrupts); |
|
|
|
|
|
|
|
printf("$%04x: ", PC - 1); |
|
|
|
f6502_dump_instr(core, PC - 1); |
|
|
|
printf(" -> "); |
|
|
|
@@ -605,9 +632,10 @@ static int f6502_do_step(f6502_Core* core, int clocks) { |
|
|
|
|
|
|
|
case 0x40: // RTI |
|
|
|
POP(core, S, P); |
|
|
|
SET(P, f6502_Status_1); |
|
|
|
SET(P, f6502_Status_1 | f6502_Status_B); |
|
|
|
POP16(core, S, PC); |
|
|
|
CLK(6); |
|
|
|
int_trig = 1; |
|
|
|
break; |
|
|
|
|
|
|
|
case 0x41: // EOR (zp, X) |
|
|
|
@@ -705,14 +733,10 @@ static int f6502_do_step(f6502_Core* core, int clocks) { |
|
|
|
CLR(P, f6502_Status_I); |
|
|
|
CLK(2); |
|
|
|
if ( (p_old & f6502_Status_I) && |
|
|
|
f6502_int_ready(core, f6502_Int_IRQ)) { |
|
|
|
core->int_state &= ~f6502_Int_IRQ; |
|
|
|
core->int_state |= ( core->int_wiring & |
|
|
|
f6502_Int_IRQ); |
|
|
|
(core->interrupts & f6502_Int_IRQ)) { |
|
|
|
CLK(7); |
|
|
|
PUSH16(core, S, PC); |
|
|
|
PUSH(core, S, P & ~f6502_Status_B); |
|
|
|
CLR(P, f6502_Status_D); |
|
|
|
SET(P, f6502_Status_I); |
|
|
|
PC = f6502_read16(&core->memory, |
|
|
|
f6502_Vector_IRQ); |
|
|
|
@@ -1380,6 +1404,10 @@ static int f6502_do_step(f6502_Core* core, int clocks) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef F6502_TRACE |
|
|
|
if (int_trig) printf("Possible interrupt trigger\n"); |
|
|
|
#endif |
|
|
|
|
|
|
|
step_done: |
|
|
|
core->registers = (f6502_Registers){ |
|
|
|
.PC = PC, |
|
|
|
@@ -1396,10 +1424,12 @@ step_done: |
|
|
|
int f6502_step(f6502_Core* core, int clocks) { |
|
|
|
int clocks_elapsed = 0; |
|
|
|
// TODO: Why are we processing seven clocks prior to NMI? |
|
|
|
if (f6502_int_ready(core, f6502_Int_NMI)) { |
|
|
|
/* |
|
|
|
if (f6502_nmi_ready(core)) { |
|
|
|
clocks_elapsed += f6502_do_step(core, 7); |
|
|
|
clocks -= clocks_elapsed; |
|
|
|
} |
|
|
|
*/ |
|
|
|
clocks_elapsed += f6502_check_interrupts(core); |
|
|
|
return (clocks_elapsed + f6502_do_step(core, clocks)); |
|
|
|
} |