From e56ccfa009af9697bb16a6da61b02a1bf65f92b7 Mon Sep 17 00:00:00 2001 From: Nathaniel Walizer Date: Wed, 27 Nov 2024 01:56:49 -0800 Subject: [PATCH] Implement memory interface with callbacks --- e6502.c | 277 +++++++++++++++++++++++++++++++++++++------------------- e6502.h | 21 +++-- 2 files changed, 197 insertions(+), 101 deletions(-) diff --git a/e6502.c b/e6502.c index d73caa7..0ee68ba 100644 --- a/e6502.c +++ b/e6502.c @@ -1,42 +1,51 @@ #include "e6502.h" +#ifdef E6502_DEBUG +#include +#endif // Instruction Addressing -typedef uint8_t* e6502_Address; +typedef uint16_t e6502_Address; static inline e6502_Address e6502_mem_adr(e6502_Core* core, e6502_Mem_Addr adr) { - return &core->memory[adr]; +// return &core->memory[adr]; + return adr; } static inline e6502_Mem_Addr e6502_adr_mem(e6502_Core* core, e6502_Address adr) { - return (adr - core->memory); +// return (adr - core->memory); + return adr; } -static inline uint8_t e6502_adr_r8(e6502_Core*, +static inline uint8_t e6502_adr_r8(e6502_Core* core, e6502_Address adr) { - return *adr; +// return *adr; + return e6502_r8(core, adr); } -static inline uint8_t e6502_adr_r16(e6502_Core*, +static inline uint8_t e6502_adr_r16(e6502_Core* core, e6502_Address adr) { - return *(uint16_t*)adr; +// return *(uint16_t*)adr; + return e6502_r16(core, adr); } -static inline void e6502_adr_w8(e6502_Core*, +static inline void e6502_adr_w8(e6502_Core* core, e6502_Address adr, uint8_t val) { - *adr = val; +// *adr = val; + e6502_w8(core, adr, val); } -static inline void e6502_adr_w16(e6502_Core*, +static inline void e6502_adr_w16(e6502_Core* core, e6502_Address adr, uint16_t val) { - *(uint16_t*)adr = val; +// *(uint16_t*)adr = val; + e6502_w16(core, adr,val); } @@ -53,7 +62,11 @@ static inline uint16_t arg16(e6502_Core* core) { // Interpret opcode values -static inline e6502_Address adr_none(e6502_Core*) { +static inline e6502_Address adr_imp(e6502_Core*) { + return 0; +} + +static inline e6502_Address adr_acc(e6502_Core* core) { return 0; } @@ -123,25 +136,6 @@ static inline e6502_Address adr_rel(e6502_Core* core) { ); } -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.P; -} - -static inline e6502_Address adr_reg_sp (e6502_Core* core) { - return &core->registers.S; -} // Instructions @@ -189,6 +183,18 @@ static inline void asl(e6502_Core *core, e6502_Address adr) { e6502_adr_w8(core, adr, val); } +static inline void asl_a(e6502_Core *core, e6502_Address adr) { + uint8_t val = core->registers.A; + core->registers.P &= ~(e6502_Status_C | + e6502_Status_Z | + e6502_Status_N); + if (val & 0x80) core->registers.P |= e6502_Status_C; + val <<= 1; + core->registers.P |= (val & e6502_Status_N); + if (!val) core->registers.P |= e6502_Status_Z; + core->registers.A = val; +} + static inline void lsr(e6502_Core *core, e6502_Address adr) { uint8_t val = e6502_adr_r8(core, adr); core->registers.P &= ~(e6502_Status_C | @@ -201,6 +207,18 @@ static inline void lsr(e6502_Core *core, e6502_Address adr) { e6502_adr_w8(core, adr, val); } +static inline void lsr_a(e6502_Core *core, e6502_Address adr) { + uint8_t val = core->registers.A; + core->registers.P &= ~(e6502_Status_C | + e6502_Status_Z | + e6502_Status_N); + core->registers.P |= (val & e6502_Status_C); + val >>= 1; + core->registers.P |= (val & e6502_Status_N); + if (!val) core->registers.P |= e6502_Status_Z; + core->registers.A = 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; @@ -215,6 +233,20 @@ static inline void rol(e6502_Core *core, e6502_Address adr) { e6502_adr_w8(core, adr, val); } +static inline void rol_a(e6502_Core *core, e6502_Address adr) { + uint8_t val = core->registers.A; + uint8_t new_c = (val & 0x80) ? e6502_Status_C : 0; + val <<= 1; + val |= (core->registers.P & e6502_Status_C); + core->registers.P &= ~(e6502_Status_C | + e6502_Status_Z | + e6502_Status_N); + core->registers.P |= new_c; + if (!val) core->registers.P |= e6502_Status_Z; + core->registers.P |= (val & e6502_Status_N); + core->registers.A = 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); @@ -229,6 +261,20 @@ static inline void ror(e6502_Core *core, e6502_Address adr) { e6502_adr_w8(core, adr, val); } +static inline void ror_a(e6502_Core *core, e6502_Address adr) { + uint8_t val = core->registers.A; + uint8_t new_c = (val & e6502_Status_C); + val >>= 1; + if (core->registers.P & e6502_Status_C) val |= e6502_Status_N; + core->registers.P &= ~(e6502_Status_C | + e6502_Status_Z | + e6502_Status_N); + core->registers.P |= new_c; + if (!val) core->registers.P |= e6502_Status_Z; + core->registers.P |= (val & e6502_Status_N); + core->registers.A = val; +} + static inline void pha(e6502_Core *core, e6502_Address adr) { e6502_push8(core, core->registers.A); } @@ -435,6 +481,22 @@ static inline void inc(e6502_Core *core, e6502_Address adr) { e6502_adr_w8(core, adr, val); } +static inline void ini(e6502_Core *core, uint8_t* reg) { + uint8_t val = *reg + 1; + core->registers.P &= ~(e6502_Status_Z | e6502_Status_N); + core->registers.P |= (val & e6502_Status_N); + if (!val) core->registers.P |= e6502_Status_Z; + *reg = val; +} + +static inline void inx(e6502_Core *core, e6502_Address) { + ini(core, &core->registers.X); +} + +static inline void iny(e6502_Core *core, e6502_Address) { + ini(core, &core->registers.Y); +} + static inline void dec(e6502_Core *core, e6502_Address adr) { uint8_t val = e6502_adr_r8(core, adr) - 1; core->registers.P &= ~(e6502_Status_Z | e6502_Status_N); @@ -443,6 +505,22 @@ static inline void dec(e6502_Core *core, e6502_Address adr) { e6502_adr_w8(core, adr, val); } +static inline void dei(e6502_Core *core, uint8_t* reg) { + uint8_t val = *reg - 1; + core->registers.P &= ~(e6502_Status_Z | e6502_Status_N); + core->registers.P |= (val & e6502_Status_N); + if (!val) core->registers.P |= e6502_Status_Z; + *reg = val; +} + +static inline void dex(e6502_Core *core, e6502_Address) { + return dei(core, &core->registers.X); +} + +static inline void dey(e6502_Core *core, e6502_Address) { + return dei(core, &core->registers.Y); +} + static inline void sta(e6502_Core *core, e6502_Address adr) { e6502_adr_w8(core, adr, core->registers.A); } @@ -456,32 +534,36 @@ static inline void sty(e6502_Core *core, e6502_Address adr) { } static inline void t(e6502_Core *core, - e6502_Address adr, - uint8_t reg) { + uint8_t* reg, + uint8_t val) { core->registers.P &= ~(e6502_Status_Z | e6502_Status_N); - core->registers.P |= (reg & e6502_Status_N); - if (!reg) core->registers.P |= e6502_Status_Z; - e6502_adr_w8(core, adr, reg); + core->registers.P |= (val & e6502_Status_N); + if (!val) core->registers.P |= e6502_Status_Z; + *reg = val; +} + +static inline void tax(e6502_Core *core, e6502_Address) { + t(core, &core->registers.X, core->registers.A); } -static inline void ta(e6502_Core *core, e6502_Address adr) { - t(core, adr, core->registers.A); +static inline void tay(e6502_Core *core, e6502_Address) { + t(core, &core->registers.Y, core->registers.A); } -static inline void txs(e6502_Core *core, e6502_Address adr) { +static inline void txs(e6502_Core *core, e6502_Address) { core->registers.S = core->registers.X; } -static inline void txa(e6502_Core *core, e6502_Address adr) { +static inline void txa(e6502_Core *core, e6502_Address) { 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 tya(e6502_Core *core, e6502_Address) { + t(core, &core->registers.A, core->registers.Y); } -static inline void ts(e6502_Core *core, e6502_Address adr) { - t(core, adr, core->registers.S); +static inline void tsx(e6502_Core *core, e6502_Address) { + t(core, &core->registers.X, core->registers.S); } static inline void lda(e6502_Core *core, e6502_Address adr) { @@ -503,9 +585,9 @@ typedef struct { uint16_t cycles; } e6502_Instruction; -static e6502_Instruction e6502_instructions[256] = { +static const e6502_Instruction e6502_instructions[256] = { // 0x00 - [0b00000000] = {brk, adr_none, 7}, + [0b00000000] = {brk, adr_imp, 7}, [0b00000001] = {ora, adr_ind_x, 6}, [0b00000101] = {ora, adr_zp, 3}, @@ -513,10 +595,10 @@ static e6502_Instruction e6502_instructions[256] = { [0b00001101] = {ora, adr_abs, 4}, [0b00000110] = {asl, adr_zp, 5}, - [0b00001010] = {asl, adr_reg_a, 2}, + [0b00001010] = {asl_a, adr_acc, 2}, [0b00001110] = {asl, adr_abs, 6}, - [0b00001000] = {php, adr_none, 3}, + [0b00001000] = {php, adr_imp, 3}, // 0x10 [0b00010000] = {bpl, adr_rel, 2}, @@ -526,7 +608,7 @@ static e6502_Instruction e6502_instructions[256] = { [0b00011001] = {ora, adr_abs_y, 4}, [0b00011101] = {ora, adr_abs_x, 4}, - [0b00011000] = {clc, adr_none, 2}, + [0b00011000] = {clc, adr_imp, 2}, [0b00010110] = {asl, adr_zp_x, 6}, [0b00011110] = {asl, adr_abs_x, 7}, @@ -543,10 +625,10 @@ static e6502_Instruction e6502_instructions[256] = { [0b00101101] = {and, adr_abs, 4}, [0b00100110] = {rol, adr_zp, 5}, - [0b00101010] = {rol, adr_reg_a, 2}, + [0b00101010] = {rol_a, adr_acc, 2}, [0b00101110] = {rol, adr_abs, 6}, - [0b00101000] = {plp, adr_none, 4}, + [0b00101000] = {plp, adr_imp, 4}, // 0x30 [0b00110000] = {bmi, adr_rel, 2}, @@ -559,10 +641,10 @@ static e6502_Instruction e6502_instructions[256] = { [0b00110110] = {rol, adr_zp_x, 6}, [0b00111110] = {rol, adr_abs_x, 7}, - [0b00111000] = {sec, adr_none, 2}, + [0b00111000] = {sec, adr_imp, 2}, // 0x40 - [0b01000000] = {rti, adr_none, 6}, + [0b01000000] = {rti, adr_imp, 6}, [0b01000001] = {eor, adr_ind_x, 6}, [0b01000101] = {eor, adr_zp, 3}, @@ -570,10 +652,10 @@ static e6502_Instruction e6502_instructions[256] = { [0b01001101] = {eor, adr_abs, 4}, [0b01000110] = {lsr, adr_zp, 5}, - [0b01001010] = {lsr, adr_reg_a, 2}, + [0b01001010] = {lsr_a, adr_acc, 2}, [0b01001110] = {lsr, adr_abs, 6}, - [0b01001000] = {pha, adr_none, 3}, + [0b01001000] = {pha, adr_imp, 3}, [0b01001100] = {jmp, adr_abs, 3}, @@ -588,10 +670,10 @@ static e6502_Instruction e6502_instructions[256] = { [0b01010110] = {lsr, adr_zp_x, 6}, [0b01011110] = {lsr, adr_abs_x, 7}, - [0b01011000] = {cli, adr_none, 2}, + [0b01011000] = {cli, adr_imp, 2}, // 0x60 - [0b01100000] = {rts, adr_none, 6}, + [0b01100000] = {rts, adr_imp, 6}, [0b01100001] = {adc, adr_ind_x, 6}, [0b01100101] = {adc, adr_zp, 3}, @@ -599,10 +681,10 @@ static e6502_Instruction e6502_instructions[256] = { [0b01101101] = {adc, adr_abs, 4}, [0b01100110] = {ror, adr_zp, 5}, - [0b01101010] = {ror, adr_reg_a, 2}, + [0b01101010] = {ror_a, adr_acc, 2}, [0b01101110] = {ror, adr_abs, 6}, - [0b01101000] = {pla, adr_none, 4}, + [0b01101000] = {pla, adr_imp, 4}, [0b01101100] = {jmp, adr_ind, 5}, @@ -617,7 +699,7 @@ static e6502_Instruction e6502_instructions[256] = { [0b01110110] = {ror, adr_zp_x, 6}, [0b01111110] = {ror, adr_abs_x, 7}, - [0b01111000] = {sei, adr_none, 2}, + [0b01111000] = {sei, adr_imp, 2}, // 0x80 [0b10000001] = {sta, adr_ind_x, 6}, @@ -630,9 +712,9 @@ static e6502_Instruction e6502_instructions[256] = { [0b10000100] = {sty, adr_zp, 3}, [0b10001100] = {sty, adr_abs, 4}, - [0b10001000] = {dec, adr_reg_y, 2}, + [0b10001000] = {dey, adr_imp, 2}, - [0b10001010] = {txa, adr_none, 2}, + [0b10001010] = {txa, adr_imp, 2}, // 0x90 [0b10010000] = {bcc, adr_rel, 2}, @@ -646,8 +728,8 @@ static e6502_Instruction e6502_instructions[256] = { [0b10010100] = {sty, adr_zp_x, 4}, - [0b10011000] = {ty, adr_reg_a, 2}, - [0b10011010] = {txs, adr_none, 2}, + [0b10011000] = {tya, adr_imp, 2}, + [0b10011010] = {txs, adr_imp, 2}, // 0xA0 [0b10100001] = {lda, adr_ind_x, 6}, @@ -663,8 +745,8 @@ static e6502_Instruction e6502_instructions[256] = { [0b10100100] = {ldy, adr_zp, 3}, [0b10101100] = {ldy, adr_abs, 4}, - [0b10101010] = {ta, adr_reg_x, 2}, - [0b10101000] = {ta, adr_reg_y, 2}, + [0b10101010] = {tax, adr_imp, 2}, + [0b10101000] = {tay, adr_imp, 2}, // 0xB0 [0b10110000] = {bcs, adr_rel, 2}, @@ -680,9 +762,9 @@ static e6502_Instruction e6502_instructions[256] = { [0b10110100] = {ldy, adr_zp_x, 4}, [0b10111100] = {ldy, adr_abs_x, 4}, - [0b10111000] = {clv, adr_none, 2}, + [0b10111000] = {clv, adr_imp, 2}, - [0b10111010] = {ts, adr_reg_x, 2}, + [0b10111010] = {tsx, adr_imp, 2}, // 0xC0 [0b11000000] = {cpy, adr_imm, 2}, @@ -694,19 +776,19 @@ static e6502_Instruction e6502_instructions[256] = { [0b11001001] = {cpa, adr_imm, 2}, [0b11001101] = {cpa, adr_abs, 4}, - [0b11001000] = {inc, adr_reg_y, 2}, + [0b11001000] = {iny, adr_imp, 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}, + [0b11001010] = {dex, adr_imp, 2}, // 0xD0 [0b11010000] = {bne, adr_rel, 2}, - [0b11011000] = {cld, adr_none, 2}, + [0b11011000] = {cld, adr_imp, 2}, [0b11010001] = {cpa, adr_ind_y, 5}, [0b11010101] = {cpa, adr_zp_x, 4}, @@ -726,9 +808,9 @@ static e6502_Instruction e6502_instructions[256] = { [0b11100110] = {inc, adr_zp, 5}, [0b11101110] = {inc, adr_abs, 6}, - [0b11101000] = {inc, adr_reg_x, 2}, + [0b11101000] = {inx, adr_imp, 2}, - [0b11101010] = {nop, adr_none, 2}, + [0b11101010] = {nop, adr_imp, 2}, // 0xF0 [0b11110000] = {beq, adr_rel, 2}, @@ -741,18 +823,15 @@ static e6502_Instruction e6502_instructions[256] = { [0b11110110] = {inc, adr_zp_x, 6}, [0b11111110] = {inc, adr_abs_x, 7}, - [0b11111000] = {sed, adr_none, 2}, + [0b11111000] = {sed, adr_imp, 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) { + const e6502_Instruction* instr = &e6502_instructions[opcode]; + if ( instr->address == adr_imp || + instr->address == adr_acc) { return 1; } else if ( instr->address == adr_abs || instr->address == adr_abs_x || @@ -763,7 +842,6 @@ int e6502_instr_size(uint8_t opcode) { } } -/* int e6502_dump_instr(e6502_Core* core, e6502_Mem_Addr addr, FILE* file) { uint8_t opcode = e6502_r8(core, addr); @@ -776,24 +854,27 @@ int e6502_dump_instr(e6502_Core* core, e6502_Mem_Addr addr, } fputc('\n', file); } +*/ +#ifdef E6502_DEBUG int e6502_dump_regs(e6502_Core* core, FILE* file) { fprintf(file, "S:%02x A:%02x X:%02x Y:%02x P:%02x\n", core->registers.S, core->registers.A, core->registers.X, core->registers.Y, core->registers.P); } -*/ +#endif int e6502_run(e6502_Core* core, int remaining, int* run, int instructions) { int status = 0; - int start = (instructions ? core->instr : core->cycle); + int i_count = 0; + int start = (instructions ? i_count : core->cycle); int end = start + remaining; int last_pc = -1; - while ((instructions ? core->instr : core->cycle) < end) { + while ((instructions ? i_count : core->cycle) < end) { if (core->registers.PC == last_pc) { // Trapped. status = -2; @@ -801,23 +882,24 @@ int e6502_run(e6502_Core* core, } last_pc = core->registers.PC; uint8_t opcode = e6502_r8(core, core->registers.PC); - e6502_Instruction* instr = &e6502_instructions[opcode]; + const e6502_Instruction* instr = + &e6502_instructions[opcode]; if (!instr->operator) { -/* +#ifdef E6502_DEBUG fprintf(stdout, "$%04x: %02x\n", last_pc, opcode); -*/ +#endif status = -1; break; } else { core->registers.PC++; e6502_Address adr = instr->address(core); -/* +#ifdef E6502_DEBUG uint16_t size = core->registers.PC - last_pc; -*/ +#endif instr->operator(core, adr); core->cycle += instr->cycles; - core->instr++; -/* + i_count++; +#ifdef E6502_DEBUG fprintf(stdout, "$%04x: $%02x", last_pc, opcode); if (size == 2) { fprintf(stdout, " $%02x", e6502_r8(core, last_pc + 1)); @@ -826,11 +908,11 @@ int e6502_run(e6502_Core* core, } fputc('\n', stdout); e6502_dump_regs(core, stdout); -*/ +#endif } } if (run) { - *run = (instructions ? core->instr : core->cycle) - start; + *run = (instructions ? i_count : core->cycle) - start; } return status; } @@ -840,3 +922,10 @@ int e6502_reset(e6502_Core* core) { 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; +} diff --git a/e6502.h b/e6502.h index 6e388ea..dffaa1e 100644 --- a/e6502.h +++ b/e6502.h @@ -10,7 +10,7 @@ typedef enum { e6502_Status_1 = 0b00100000, e6502_Status_V = 0b01000000, e6502_Status_N = 0b10000000, -} e6502_Status_Flag_Bit; +} e6502_Status_Flag; typedef struct { uint16_t PC; @@ -21,11 +21,17 @@ typedef struct { uint8_t P; } e6502_Registers; +typedef uint16_t e6502_Mem_Addr; + +typedef uint8_t(e6502_Read)(void*, e6502_Mem_Addr); +typedef void(e6502_Write)(void*, e6502_Mem_Addr, uint8_t); + typedef struct { e6502_Registers registers; + e6502_Read* bus_read; + e6502_Write* bus_write; + void* bus_context; int cycle; - int instr; - uint8_t memory[65536]; } e6502_Core; #define e6502_Memory_Stack (0x0100U) @@ -34,8 +40,7 @@ typedef struct { #define e6502_Reset_Vec (0xFFFCU) #define e6502_NMI_Vec (0xFFFAU) - -typedef uint16_t e6502_Mem_Addr; +void e6502_init(e6502_Core*, e6502_Read, e6502_Write, void*); /* uint8_t e6502_r8(e6502_Core* core, e6502_Mem_Addr adr); @@ -45,13 +50,15 @@ void e6502_w8(e6502_Core* core, e6502_Mem_Addr adr, uint8_t val); static inline uint8_t e6502_r8(e6502_Core* core, e6502_Mem_Addr adr) { - return core->memory[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; +// core->memory[adr] = val; + return core->bus_write(core->bus_context, adr, val); } static inline uint16_t e6502_r16(e6502_Core* core,