From be41dcfe9128aad942e77049b67efc1f94e1bd66 Mon Sep 17 00:00:00 2001 From: Nathaniel Walizer Date: Thu, 28 Nov 2024 11:01:15 -0800 Subject: [PATCH] Fix interrupt support - Passes Klaus Dormann's interrupt tests --- e6502.c | 132 ++++++++++++++++++++++++++++++++++++++++++++------------ e6502.h | 45 ++++++++++++++++--- 2 files changed, 142 insertions(+), 35 deletions(-) diff --git a/e6502.c b/e6502.c index c94c6f7..e189a9e 100644 --- a/e6502.c +++ b/e6502.c @@ -6,48 +6,81 @@ // Instruction Addressing -typedef uint16_t e6502_Address; +#ifdef E6502_POLL_MEM + +typedef uint8_t* e6502_Address; static inline e6502_Address e6502_mem_adr(e6502_Core* core, e6502_Mem_Addr adr) { -// return &core->memory[adr]; - return adr; + return &core->memory[adr]; } static inline e6502_Mem_Addr e6502_adr_mem(e6502_Core* core, e6502_Address adr) { -// return (adr - core->memory); - return adr; + return (adr - core->memory); } +static inline uint8_t e6502_adr_r8(e6502_Core* core, + e6502_Address adr) { + return &adr[0]; +} +static inline uint8_t e6502_adr_r16(e6502_Core* core, + e6502_Address adr) { + return (&adr[0] | ((uint16_t)&adr[1] << 8)); +} + +static inline void e6502_adr_w8(e6502_Core* core, + e6502_Address adr, + uint8_t val) { + &adr[0] = val; +} + +static inline void e6502_adr_w16(e6502_Core* core, + e6502_Address adr, + uint16_t val) { + &adr[0] = val; + &adr[1] = val >> 8; +} + +#else // !E6502_POLL_MEM + +typedef uint16_t e6502_Address; + +static inline e6502_Address e6502_mem_adr(e6502_Core*, + e6502_Mem_Addr adr) { + return adr; +} + +static inline e6502_Mem_Addr e6502_adr_mem(e6502_Core*, + e6502_Address adr) { + return adr; +} static inline uint8_t e6502_adr_r8(e6502_Core* core, e6502_Address adr) { -// return *adr; return e6502_r8(core, adr); } static inline uint8_t e6502_adr_r16(e6502_Core* core, e6502_Address adr) { -// return *(uint16_t*)adr; return e6502_r16(core, adr); } static inline void e6502_adr_w8(e6502_Core* core, e6502_Address adr, uint8_t val) { -// *adr = val; e6502_w8(core, adr, val); } static inline void e6502_adr_w16(e6502_Core* core, e6502_Address adr, uint16_t val) { -// *(uint16_t*)adr = val; e6502_w16(core, adr,val); } +#endif // !E6502_POLL_MEM + // Read values after opcodes @@ -153,7 +186,9 @@ static inline void brk(e6502_Core *core, e6502_Address) { } static inline void rti(e6502_Core *core, e6502_Address) { - core->registers.P = e6502_pop8(core) & ~(e6502_Status_B); + core->registers.P = e6502_pop8(core) | + e6502_Status_1 | + e6502_Status_B; core->registers.PC = e6502_pop16(core); } @@ -387,14 +422,14 @@ static inline void jsr(e6502_Core *core, e6502_Address adr) { 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 rts(e6502_Core *core, e6502_Address) { + core->registers.PC = e6502_pop16(core) + 1; +} + static inline void bit(e6502_Core *core, e6502_Address adr) { uint8_t val = e6502_adr_r8(core, adr); core->registers.P &= ~(e6502_Status_Z | @@ -865,6 +900,26 @@ int e6502_dump_regs(e6502_Core* core, FILE* file) { } #endif + +static void e6502_irq(e6502_Core* core) { + if (!(core->registers.P & e6502_Status_I)) { + e6502_push16(core, core->registers.PC); + e6502_push8(core, (core->registers.P & ~e6502_Status_B) | + e6502_Status_1); + core->registers.P |= e6502_Status_I; + core->registers.PC = e6502_r16(core, e6502_IRQ_Vec); + } +} + +static void e6502_nmi(e6502_Core* core) { + e6502_push16(core, core->registers.PC); + e6502_push8(core, (core->registers.P & ~e6502_Status_B) | + e6502_Status_1); + core->registers.P |= e6502_Status_I; + core->registers.PC = e6502_r16(core, e6502_NMI_Vec); +} + + int e6502_run(e6502_Core* core, int remaining, int* run, @@ -895,20 +950,31 @@ int e6502_run(e6502_Core* core, e6502_Address adr = instr->address(core); #ifdef E6502_DEBUG uint16_t size = core->registers.PC - last_pc; + uint16_t val = 0; + if (size > 1) { + if (size == 2) val = e6502_r8(core, last_pc + 1); + else val = e6502_r16(core, last_pc + 1); + } + e6502_dump_regs(core, stdout); + fprintf(stdout, "$%04x: $%02x", last_pc, opcode); + if (size > 1) { + fprintf(stdout, size == 2 ? " $%02x" : " $%04x", + val); + } + fputc('\n', stdout); #endif instr->operator(core, adr); core->cycle += instr->cycles; i_count++; -#ifdef E6502_DEBUG - 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)); + + if ( (core->pins & e6502_Pin_NMI) && + !(core->pins & e6502_NMI_Serviced)) { + core->pins |= e6502_NMI_Serviced; + e6502_nmi(core); + } else if ( (core->pins & e6502_Pin_IRQ) && + !(core->registers.P & e6502_Status_I)) { + e6502_irq(core); } - fputc('\n', stdout); - e6502_dump_regs(core, stdout); -#endif } } if (run) { @@ -917,15 +983,25 @@ int e6502_run(e6502_Core* core, return status; } +void e6502_init(e6502_Core* core, e6502_Read read, + e6502_Write write, void* context) { + core->bus_read = read; + core->bus_write = write; + core->bus_context = context; +} + void e6502_reset(e6502_Core* core) { core->registers.PC = e6502_r16(core, e6502_Reset_Vec); core->registers.S -= 3; core->registers.P |= (e6502_Status_B | e6502_Status_1); } -void e6502_init(e6502_Core* core, e6502_Read read, - e6502_Write write, void* context) { - core->bus_read = read; - core->bus_write = write; - core->bus_context = context; +void e6502_set_nmi(e6502_Core* core, int active) { + if (active) core->pins |= e6502_Pin_NMI; + else core->pins &= ~(e6502_Pin_NMI | e6502_NMI_Serviced); +} + +void e6502_set_irq(e6502_Core* core, int active) { + if (active) core->pins |= e6502_Pin_IRQ; + else core->pins &= ~e6502_Pin_IRQ; } diff --git a/e6502.h b/e6502.h index df1befb..99787a8 100644 --- a/e6502.h +++ b/e6502.h @@ -12,6 +12,13 @@ typedef enum { e6502_Status_N = 0b10000000, } e6502_Status_Flag; +typedef enum { + e6502_Pin_NMI = 0b01, + e6502_Pin_IRQ = 0b10, + + e6502_NMI_Serviced = 0b10000000 +} e6502_Pin; + typedef struct { uint16_t PC; uint8_t S; @@ -23,14 +30,21 @@ typedef struct { typedef uint16_t e6502_Mem_Addr; +#ifndef E6502_POLL_MEM typedef uint8_t(e6502_Read)(void*, e6502_Mem_Addr); typedef void(e6502_Write)(void*, e6502_Mem_Addr, uint8_t); +#endif typedef struct { e6502_Registers registers; + e6502_Pin pins; +#ifdef E6502_POLL_MEM + uint8_t memory[65536]; +#else e6502_Read* bus_read; e6502_Write* bus_write; void* bus_context; +#endif int cycle; } e6502_Core; @@ -40,27 +54,34 @@ typedef struct { #define e6502_Reset_Vec (0xFFFCU) #define e6502_NMI_Vec (0xFFFAU) -void e6502_init(e6502_Core*, e6502_Read, e6502_Write, void*); +#ifdef E6502_POLL_MEM -/* -uint8_t e6502_r8(e6502_Core* core, e6502_Mem_Addr adr); +static inline uint8_t e6502_r8(e6502_Core* core, + e6502_Mem_Addr adr) { + return core->memory[adr]; +} -void e6502_w8(e6502_Core* core, e6502_Mem_Addr adr, uint8_t val); -*/ +static inline void e6502_w8(e6502_Core* core, + e6502_Mem_Addr adr, + uint8_t val) { + core->memory[adr] = val; +} + +#else static inline uint8_t e6502_r8(e6502_Core* core, e6502_Mem_Addr adr) { -// return core->memory[adr]; return core->bus_read(core->bus_context, adr); } static inline void e6502_w8(e6502_Core* core, e6502_Mem_Addr adr, uint8_t val) { -// core->memory[adr] = val; return core->bus_write(core->bus_context, adr, val); } +#endif + static inline uint16_t e6502_r16(e6502_Core* core, e6502_Mem_Addr adr) { return e6502_r8(core, adr) | @@ -93,9 +114,19 @@ static inline uint16_t e6502_pop16(e6502_Core* core) { } +#ifdef E6502_POLL_MEM +void e6502_init(e6502_Core*); +#else +void e6502_init(e6502_Core*, e6502_Read, e6502_Write, void*); +#endif + int e6502_run(e6502_Core* core, int remaining, int* run, int instructions); void e6502_reset(e6502_Core* core); + +void e6502_set_irq(e6502_Core* core, int active); + +void e6502_set_nmi(e6502_Core* core, int active);