diff --git a/src/f6502.c b/src/f6502.c index 4265143..f1609cb 100644 --- a/src/f6502.c +++ b/src/f6502.c @@ -1,3 +1,5 @@ +#include + #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)); } diff --git a/src/f6502.h b/src/f6502.h index b6cbfdf..dc5c387 100644 --- a/src/f6502.h +++ b/src/f6502.h @@ -1,8 +1,10 @@ #ifndef F6502_H_ #define F6502_H_ +#include #include + #define F6502_RAM_SIZE (0x2000U) @@ -34,8 +36,9 @@ typedef struct __attribute__ ((__packed__)) { } f6502_Registers; typedef enum { - f6502_Int_NMI = 0b01, - f6502_Int_IRQ = 0b10, + f6502_Int_NMI = 0b00000001, + f6502_Int_IRQ = 0b00000010, + f6502_Int_NMI_Serviced = 0b10000000, } f6502_Interrupt; typedef struct __attribute__ ((__packed__)) { @@ -51,15 +54,15 @@ typedef struct __attribute__ ((__packed__)) { typedef struct __attribute__ ((__packed__)) { f6502_Registers registers; - f6502_Interrupt int_state:2; - f6502_Interrupt int_wiring:2; + f6502_Interrupt interrupts; f6502_Memory memory; } f6502_Core; void f6502_init(f6502_Core*); void f6502_reset(f6502_Core*); int f6502_step(f6502_Core*, int clocks); -void f6502_wire_interrupts(f6502_Core*, f6502_Interrupt ints); +void f6502_set_NMI(f6502_Core*, bool active); +void f6502_set_IRQ(f6502_Core*, bool active); #endif // F6502_H_