From eab16a1d3b8571496543127d2fad6bcdbad78eb4 Mon Sep 17 00:00:00 2001 From: Stefan Arentz Date: Wed, 23 Nov 2016 22:17:24 -0500 Subject: [PATCH] Fixes #3 - Implement 65C02 Instructions (#42) --- Makefile | 2 +- cpu.c | 18 +- cpu.h | 11 +- cpu_test.c | 38 ++-- ewm.c | 16 +- fmt.c | 109 ++++++++--- ins.c | 561 ++++++++++++++++++++++++++++++++++++++++++++++++++++- ins.h | 7 +- mem.c | 8 + mem.h | 2 + 10 files changed, 718 insertions(+), 54 deletions(-) diff --git a/Makefile b/Makefile index fd35d1b..90bcd00 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ CFLAGS=-std=c11 -O2 -Wpedantic -Wall -Wshadow -Werror -Wshadow -Wno-gnu-binary- LDFLAGS=-g EWM_EXECUTABLE=ewm -EWM_SOURCES=cpu.c ins.c pia.c mem.c ewm.c fmt.c mmu.c dsk.c +EWM_SOURCES=cpu.c ins.c pia.c mem.c ewm.c fmt.c EWM_OBJECTS=$(EWM_SOURCES:.c=.o) EWM_LIBS=-lcurses diff --git a/cpu.c b/cpu.c index d0099e7..69c3cf2 100644 --- a/cpu.c +++ b/cpu.c @@ -110,7 +110,7 @@ static int cpu_execute_instruction(struct cpu_t *cpu) { } /* Fetch instruction */ - cpu_instruction_t *i = &instructions[mem_get_byte(cpu, cpu->state.pc)]; + struct cpu_instruction_t *i = &cpu->instructions[mem_get_byte(cpu, cpu->state.pc)]; if (i->handler == NULL) { return EWM_CPU_ERR_UNIMPLEMENTED_INSTRUCTION; } @@ -165,8 +165,8 @@ static int cpu_execute_instruction(struct cpu_t *cpu) { snprintf(bytes, sizeof bytes, "%.2X %.2X %.2X", mem_get_byte(cpu, pc), mem_get_byte(cpu, pc+1), mem_get_byte(cpu, pc+2)); break; } - - fprintf(cpu->trace, "%.4X: %-8s %-11s %-20s %s\n", + + fprintf(cpu->trace, "%.4X: %-8s %-14s %-20s %s\n", pc, bytes, trace_instruction, trace_state, trace_stack); } @@ -175,8 +175,18 @@ static int cpu_execute_instruction(struct cpu_t *cpu) { /* Public API */ -void cpu_init(struct cpu_t *cpu) { +void cpu_setup() { + for (int i = 0; i <= 255; i++) { + if (instructions_65C02[i].handler == NULL) { + instructions_65C02[i] = instructions[i]; + } + } +} + +void cpu_init(struct cpu_t *cpu, int model) { memset(cpu, 0x00, sizeof(struct cpu_t)); + cpu->model = model; + cpu->instructions = (cpu->model == EWM_CPU_MODEL_6502) ? instructions : instructions_65C02; } void cpu_shutdown(struct cpu_t *cpu) { diff --git a/cpu.h b/cpu.h index 4467504..910e6e8 100644 --- a/cpu.h +++ b/cpu.h @@ -27,6 +27,9 @@ #include #include +#define EWM_CPU_MODEL_6502 0 +#define EWM_CPU_MODEL_65C02 1 + #define EWM_CPU_ERR_UNIMPLEMENTED_INSTRUCTION (-1) #define EWM_CPU_ERR_STACK_OVERFLOW (-2) #define EWM_CPU_ERR_STACK_UNDERFLOW (-3) @@ -35,6 +38,8 @@ #define EWM_VECTOR_RES 0xfffc #define EWM_VECTOR_IRQ 0xfffe +struct cpu_instruction_t; + struct cpu_state_t { uint8_t a, x, y, s, sp; uint16_t pc; @@ -42,11 +47,13 @@ struct cpu_state_t { }; struct cpu_t { + int model; struct cpu_state_t state; FILE *trace; bool strict; struct mem_t *mem; uint8_t *memory; // This is pointing to the first 2 pages of memory, zero page and stack. + struct cpu_instruction_t *instructions; }; #define MEM_TYPE_RAM 0 @@ -79,7 +86,9 @@ uint8_t _cpu_stack_used(struct cpu_t *cpu); uint8_t _cpu_get_status(struct cpu_t *cpu); void _cpu_set_status(struct cpu_t *cpu, uint8_t status); -void cpu_init(struct cpu_t *cpu); +void cpu_setup(); + +void cpu_init(struct cpu_t *cpu, int model); void cpu_shutdown(struct cpu_t *cpu); void cpu_add_mem(struct cpu_t *cpu, struct mem_t *mem); diff --git a/cpu_test.c b/cpu_test.c index f481ec1..f237850 100644 --- a/cpu_test.c +++ b/cpu_test.c @@ -27,29 +27,35 @@ #include "cpu.h" #include "mem.h" -int main(int argc, char **argv) { +int test(int model, uint16_t start_addr, uint16_t success_addr, char *rom_path) { struct cpu_t cpu; - cpu_init(&cpu); - cpu_add_ram_file(&cpu, 0x0000, "roms/6502_functional_test.bin"); - + cpu_init(&cpu, model); + cpu_add_ram_file(&cpu, 0x0000, rom_path); cpu_reset(&cpu); - cpu.state.pc = 0x0400; + cpu.state.pc = start_addr; uint16_t last_pc = cpu.state.pc; while (true) { int ret = cpu_step(&cpu); if (ret != 0) { - fprintf(stderr, "TEST Unexpected error %d\n", ret); - exit(1); + switch (ret) { + case EWM_CPU_ERR_UNIMPLEMENTED_INSTRUCTION: + fprintf(stderr, "TEST Unimplemented instruction 0x%.2x at 0x%.4x\n", + mem_get_byte(&cpu, cpu.state.pc), cpu.state.pc); + return -1; + default: + fprintf(stderr, "TEST Unexpected error %d\n", ret); + return -1; + } } // End of the tests is at 0x3399. This is hard coded and not // ideal. Is there a better way to detect this? - if (cpu.state.pc == 0x3399) { - fprintf(stderr, "TEST Success\n"); - exit(1); + if (cpu.state.pc == success_addr) { + fprintf(stderr, "TEST Success\n"); + return 0; } // We detect a test failure because we are in a branch deadlock, @@ -60,8 +66,8 @@ int main(int argc, char **argv) { uint8_t i = mem_get_byte(&cpu, cpu.state.pc); if (i == 0x10 || i == 0x30 || i == 0x50 || i == 0x70 || i == 0x90 || i == 0xb0 || i == 0xd0 || i == 0xf0) { if (mem_get_byte(&cpu, cpu.state.pc + 1) == 0xfe) { - fprintf(stderr, "TEST Failure at 0x%.4x \n", cpu.state.pc); - exit(1); + fprintf(stderr, "TEST Failure at 0x%.4x \n", cpu.state.pc); + return -1; } } } @@ -69,3 +75,11 @@ int main(int argc, char **argv) { last_pc = cpu.state.pc; } } + +int main(int argc, char **argv) { + cpu_setup(); + fprintf(stderr, "TEST Running 6502 tests\n"); + test(EWM_CPU_MODEL_6502, 0x0400, 0x3399, "roms/6502_functional_test.bin"); + fprintf(stderr, "TEST Running 65C02 tests\n"); + test(EWM_CPU_MODEL_65C02, 0x0400, 0x24a8, "roms/65C02_extended_opcodes_test.bin"); +} diff --git a/ewm.c b/ewm.c index 3fa7f1b..b869a53 100644 --- a/ewm.c +++ b/ewm.c @@ -31,9 +31,10 @@ #include "mem.h" #include "pia.h" -// Apple 1 / 8K RAM / WOZ Monitor +// Apple 1 / 6502 / 8K RAM / WOZ Monitor static int setup_apple1(struct cpu_t *cpu) { + cpu_init(cpu, EWM_CPU_MODEL_6502); struct pia_t *pia = malloc(sizeof(struct pia_t)); pia_init(pia); cpu_add_ram(cpu, 0x0000, 8 * 1024 - 1); @@ -42,9 +43,10 @@ static int setup_apple1(struct cpu_t *cpu) { return 0; } -// Replica 1 / 32K RAM / Krusader Assembler & Monitor +// Replica 1 / 65C02 / 32K RAM / Krusader Assembler & Monitor static int setup_replica1(struct cpu_t *cpu) { + cpu_init(cpu, EWM_CPU_MODEL_65C02); struct pia_t *pia = malloc(sizeof(struct pia_t)); pia_init(pia); cpu_add_ram(cpu, 0x0000, 32 * 1024 - 1); @@ -53,9 +55,10 @@ static int setup_replica1(struct cpu_t *cpu) { return 0; } -// Apple ][+ / 48K RAM / Original ROMs +// Apple ][+ / 6502 / 48K RAM / Original ROMs static int setup_apple2plus(struct cpu_t *cpu) { + cpu_init(cpu, EWM_CPU_MODEL_6502); cpu_add_ram(cpu, 0x0000, 48 * 1024); cpu_add_rom_file(cpu, 0xd000, "roms/a2p.rom"); return 0; @@ -122,12 +125,13 @@ int main(int argc, char **argv) { exit(1); } + cpu_setup(); + struct cpu_t cpu; - cpu_init(&cpu); - cpu_strict(&cpu, strict); - cpu_trace(&cpu, trace_path); machine->setup(&cpu); + cpu_strict(&cpu, strict); + cpu_trace(&cpu, trace_path); cpu_reset(&cpu); diff --git a/fmt.c b/fmt.c index 65815fb..09c89e9 100644 --- a/fmt.c +++ b/fmt.c @@ -63,51 +63,113 @@ void cpu_format_stack(struct cpu_t *cpu, char buffer[764]) { void cpu_format_instruction(struct cpu_t *cpu, char *buffer) { *buffer = 0x00; - cpu_instruction_t *i = &instructions[mem_get_byte(cpu, cpu->state.pc)]; uint8_t opcode = mem_get_byte(cpu, cpu->state.pc); + struct cpu_instruction_t *i = &cpu->instructions[opcode]; + + if (i->handler == NULL) { + sprintf(buffer, "???"); + return; + } /* Single byte instructions */ if (i->bytes == 1) { - sprintf(buffer, "%s", i->name); + sprintf(buffer, "%-4s", i->name); } + /* 65C02 ADC, AND, CMP, EOR, LDA, ORA, SBC, STA */ + else if ((opcode & 0b00011111) == 0b00010010) { + sprintf(buffer, "%-4s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + } + + /* 65C02 RMB / SMB */ + else if ((opcode & 0b00001111) == 0b00000111) { + sprintf(buffer, "%s%d $%.2X", + (opcode & 0b10000000) == 0b00000000 ? "RMB" : "SMB", + (opcode & 0b01110000) >> 4, + mem_get_byte(cpu, cpu->state.pc+1)); + } + + /* 65C02 BBR / BBS */ + else if ((opcode & 0b00001111) == 0b00001111) { + sprintf(buffer, "%s%d $%.2X,$%.4X", + (opcode & 0b10000000) == 0b00000000 ? "BBR" : "BBS", + (opcode & 0b01110000) >> 4, + mem_get_byte(cpu, cpu->state.pc+1), + cpu->state.pc + 2 + (int8_t) mem_get_byte(cpu, cpu->state.pc+2)); + } + + /* 65C02 JMP (ABS,X) */ + else if (opcode == 0x7c) { + sprintf(buffer, "JMP ($%.4X,X)", mem_get_word(cpu, cpu->state.pc+1)); + } + + /* 65C02 BRA */ + else if (opcode == 0x80) { + sprintf(buffer, "BRA $%.4X", cpu->state.pc + 2 + (int8_t) mem_get_byte(cpu, cpu->state.pc+1)); + } + + /* 65C02 STZ ABS */ + else if (opcode == 0x9c) { + sprintf(buffer, "JMP $%.4X", mem_get_word(cpu, cpu->state.pc+1)); + } + + /* 65C02 TRB ZP */ + else if (opcode == 0x14) { + sprintf(buffer, "TRB $%.2X", mem_get_byte(cpu, cpu->state.pc+1)); + } + + /* 65C02 TRB ABS */ + else if (opcode == 0x1c) { + sprintf(buffer, "TRB $%.4X", mem_get_word(cpu, cpu->state.pc+1)); + } + + /* 65C02 TSB ZP */ + else if (opcode == 0x04) { + sprintf(buffer, "TSB $%.2X", mem_get_byte(cpu, cpu->state.pc+1)); + } + + /* 65C02 TSB ABS */ + else if (opcode == 0x0c) { + sprintf(buffer, "TSB $%.4X", mem_get_word(cpu, cpu->state.pc+1)); + } + /* JSR is the only exception */ else if (opcode == 0x20) { - sprintf(buffer, "%s $%.4X", i->name, mem_get_word(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.4X", i->name, mem_get_word(cpu, cpu->state.pc+1)); } /* Branches */ else if ((opcode & 0b00011111) == 0b00010000) { int8_t offset = (int8_t) mem_get_byte(cpu, cpu->state.pc+1); uint16_t addr = cpu->state.pc + 2 + offset; - sprintf(buffer, "%s $%.4X", i->name, addr); + sprintf(buffer, "%-4s $%.4X", i->name, addr); } else if ((opcode & 0b00000011) == 0b00000001) { switch ((opcode & 0b00011100) >> 2) { case 0b000: - sprintf(buffer, "%s ($%.2X,X)", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s ($%.2X,X)", i->name, mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b001: - sprintf(buffer, "%s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b010: - sprintf(buffer, "%s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b011: - sprintf(buffer, "%s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b100: - sprintf(buffer, "%s ($%.2X),Y", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s ($%.2X),Y", i->name, mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b101: - sprintf(buffer, "%s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b110: - sprintf(buffer, "%s $%.2X%.2X,Y", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.2X%.2X,Y", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b111: - sprintf(buffer, "%s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); break; } } @@ -115,22 +177,22 @@ void cpu_format_instruction(struct cpu_t *cpu, char *buffer) { else if ((opcode & 0b00000011) == 0b00000010) { switch ((opcode & 0b00011100) >> 2) { case 0b000: - sprintf(buffer, "%s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b001: - sprintf(buffer, "%s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b010: - sprintf(buffer, "%s", i->name); + sprintf(buffer, "%-4s", i->name); break; case 0b011: - sprintf(buffer, "%s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b101: - sprintf(buffer, "%s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b111: - sprintf(buffer, "%s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); break; } } @@ -138,19 +200,20 @@ void cpu_format_instruction(struct cpu_t *cpu, char *buffer) { else if ((opcode & 0b00000011) == 0b00000000) { switch ((opcode & 0b00011100) >> 2) { case 0b000: - sprintf(buffer, "%s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b001: - sprintf(buffer, "%s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b011: - sprintf(buffer, "%s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b101: - sprintf(buffer, "%s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + sprintf(buffer, "%-4s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); break; case 0b111: - sprintf(buffer, "%s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + + sprintf(buffer, "%-4s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); break; } } diff --git a/ins.c b/ins.c index 968e2d9..db19737 100644 --- a/ins.c +++ b/ins.c @@ -32,6 +32,8 @@ static void update_zn(struct cpu_t *cpu, uint8_t v) { cpu->state.n = (v & 0x80); } +// EWM_CPU_MODEL_6502 + /* ADC */ static void adc(struct cpu_t *cpu, uint8_t m) { @@ -55,7 +57,7 @@ static void adc(struct cpu_t *cpu, uint8_t m) { cpu->state.c = (high > 15); cpu->state.z = (r == 0); - cpu->state.n = 0; + cpu->state.n = (r & 0b10000000); // TODO Only on 6502? Does the 6502 test still pass? cpu->state.v = 0; cpu->state.a = r; @@ -241,6 +243,9 @@ static void bvs(struct cpu_t *cpu, uint8_t oper) { static void brk(struct cpu_t *cpu) { cpu->state.b = 1; + if (cpu->model == EWM_CPU_MODEL_65C02) { + cpu->state.d = 0; + } cpu_irq(cpu); } @@ -734,7 +739,7 @@ static void sbc(struct cpu_t *cpu, uint8_t m) { uint8_t c = cpu->state.c ? 1 : 0; if (cpu->state.d) { uint8_t cb = 0; - + if (c == 0) { c = 1; } else { @@ -758,7 +763,7 @@ static void sbc(struct cpu_t *cpu, uint8_t m) { cpu->state.c = (high & 0xff) < 15; cpu->state.z = (result == 0); - cpu->state.n = 0; + cpu->state.n = (result & 0b10000000); // TODO Only on 6502? Does the 6502 test still pass? cpu->state.v = 0; cpu->state.a = result; @@ -904,7 +909,7 @@ static void tya(struct cpu_t *cpu) { /* Instruction dispatch table */ -cpu_instruction_t instructions[256] = { +struct cpu_instruction_t instructions[256] = { /* 0x00 */ { "BRK", 0x00, 1, 2, 3, (void*) brk }, /* 0x01 */ { "ORA", 0x01, 2, 6, 0, (void*) ora_indx }, /* 0x02 */ { "???", 0x02, 1, 2, 0, (void*) NULL }, @@ -1169,3 +1174,551 @@ cpu_instruction_t instructions[256] = { /* 0xfe */ { "INC", 0xfe, 3, 7, 0, (void*) inc_absx }, /* 0xff */ { "???", 0xff, 1, 2, 0, (void*) NULL } }; + +// EWM_CPU_MODEL_65C02 + +static void ora_ind(struct cpu_t *cpu, uint8_t oper) { + ora(cpu, mem_get_byte_ind(cpu, oper)); +} + +static void and_ind(struct cpu_t *cpu, uint8_t oper) { + and(cpu, mem_get_byte_ind(cpu, oper)); +} + +static void eor_ind(struct cpu_t *cpu, uint8_t oper) { + eor(cpu, mem_get_byte_ind(cpu, oper)); +} + +static void adc_ind(struct cpu_t *cpu, uint8_t oper) { + adc(cpu, mem_get_byte_ind(cpu, oper)); +} + +static void sta_ind(struct cpu_t *cpu, uint8_t oper) { + mem_set_byte_ind(cpu, oper, cpu->state.a); +} + +static void lda_ind(struct cpu_t *cpu, uint8_t oper) { + cpu->state.a = mem_get_byte_ind(cpu, oper); + update_zn(cpu, cpu->state.a); +} + +static void cmp_ind(struct cpu_t *cpu, uint8_t oper) { + cmp(cpu, mem_get_byte_ind(cpu, oper)); +} + +static void sbc_ind(struct cpu_t *cpu, uint8_t oper) { + sbc(cpu, mem_get_byte_ind(cpu, oper)); +} + +static void bit_imm(struct cpu_t *cpu, uint8_t oper) { + uint8_t t = cpu->state.a & oper; + cpu->state.z = (t == 0); +} + +static void bit_zpgx(struct cpu_t *cpu, uint8_t oper) { + bit(cpu, mem_get_byte_zpgx(cpu, oper)); +} + +static void bit_absx(struct cpu_t *cpu, uint16_t oper) { + bit(cpu, mem_get_byte_absx(cpu, oper)); +} + +static void dec_acc(struct cpu_t *cpu) { + cpu->state.a--; + update_zn(cpu, cpu->state.a); +} + +static void inc_acc(struct cpu_t *cpu) { + cpu->state.a++; + update_zn(cpu, cpu->state.a); +} + +static void jmp_absx(struct cpu_t *cpu, uint16_t oper) { + cpu->state.pc = mem_get_word(cpu, oper + cpu->state.x); +} + +static void bra(struct cpu_t *cpu, uint8_t oper) { + cpu->state.pc += (int8_t) oper; +} + +static void phx(struct cpu_t *cpu) { + _cpu_push_byte(cpu, cpu->state.x); +} + +static void phy(struct cpu_t *cpu) { + _cpu_push_byte(cpu, cpu->state.y); +} + +static void plx(struct cpu_t *cpu) { + cpu->state.x = _cpu_pull_byte(cpu); + update_zn(cpu, cpu->state.x); +} + +static void ply(struct cpu_t *cpu) { + cpu->state.y = _cpu_pull_byte(cpu); + update_zn(cpu, cpu->state.y); +} + +static void stz_zpg(struct cpu_t *cpu, uint8_t oper) { + mem_set_byte_zpg(cpu, oper, 0x00); +} + +static void stz_zpgx(struct cpu_t *cpu, uint8_t oper) { + mem_set_byte_zpgx(cpu, oper, 0x00); +} + +static void stz_abs(struct cpu_t *cpu, uint16_t oper) { + mem_set_byte_abs(cpu, oper, 0x00); +} + +static void stz_absx(struct cpu_t *cpu, uint16_t oper) { + mem_set_byte_absx(cpu, oper, 0x00); +} + +static void trb_zpg(struct cpu_t *cpu, uint8_t oper) { + cpu->state.z = (mem_get_byte(cpu, oper) & cpu->state.a) == 0; + uint8_t r = mem_get_byte(cpu, oper) & ~cpu->state.a; + mem_set_byte_zpg(cpu, oper, r); +} + +static void trb_abs(struct cpu_t *cpu, uint16_t oper) { + cpu->state.z = (mem_get_byte(cpu, oper) & cpu->state.a) == 0; + uint8_t r = mem_get_byte(cpu, oper) & (cpu->state.a ^ 0xff); + mem_set_byte_abs(cpu, oper, r); +} + +static void tsb_zpg(struct cpu_t *cpu, uint8_t oper) { + cpu->state.z = (mem_get_byte(cpu, oper) & cpu->state.a) == 0; + uint8_t r = mem_get_byte(cpu, oper) | cpu->state.a; + mem_set_byte_zpg(cpu, oper, r); +} + +static void tsb_abs(struct cpu_t *cpu, uint16_t oper) { + cpu->state.z = (mem_get_byte(cpu, oper) & cpu->state.a) == 0; + uint8_t r = mem_get_byte(cpu, oper) | cpu->state.a; + mem_set_byte_abs(cpu, oper, r); +} + +static void bbr(struct cpu_t *cpu, uint8_t bit, uint8_t zp, int8_t label) { + if ((mem_get_byte_zpg(cpu, zp) & bit) == 0) { + cpu->state.pc += label; + } +} + +static void bbr0(struct cpu_t *cpu, uint16_t oper) { + bbr(cpu, 0b00000001, oper & 0x00ff, oper >> 8); +} + +static void bbr1(struct cpu_t *cpu, uint16_t oper) { + bbr(cpu, 0b00000010, oper & 0x00ff, oper >> 8); +} + +static void bbr2(struct cpu_t *cpu, uint16_t oper) { + bbr(cpu, 0b00000100, oper & 0x00ff, oper >> 8); +} + +static void bbr3(struct cpu_t *cpu, uint16_t oper) { + bbr(cpu, 0b00001000, oper & 0x00ff, oper >> 8); +} + +static void bbr4(struct cpu_t *cpu, uint16_t oper) { + bbr(cpu, 0b00010000, oper & 0x00ff, oper >> 8); +} + +static void bbr5(struct cpu_t *cpu, uint16_t oper) { + bbr(cpu, 0b00100000, oper & 0x00ff, oper >> 8); +} + +static void bbr6(struct cpu_t *cpu, uint16_t oper) { + bbr(cpu, 0b01000000, oper & 0x00ff, oper >> 8); +} + +static void bbr7(struct cpu_t *cpu, uint16_t oper) { + bbr(cpu, 0b10000000, oper & 0x00ff, oper >> 8); +} + +static void bbs(struct cpu_t *cpu, uint8_t bit, uint8_t zp, int8_t label) { + if ((mem_get_byte_zpg(cpu, zp) & bit) != 0) { + cpu->state.pc += label; + } +} + +static void bbs0(struct cpu_t *cpu, uint16_t oper) { + bbs(cpu, 0b00000001, oper & 0x00ff, oper >> 8); +} + +static void bbs1(struct cpu_t *cpu, uint16_t oper) { + bbs(cpu, 0b00000010, oper & 0x00ff, oper >> 8); +} + +static void bbs2(struct cpu_t *cpu, uint16_t oper) { + bbs(cpu, 0b00000100, oper & 0x00ff, oper >> 8); +} + +static void bbs3(struct cpu_t *cpu, uint16_t oper) { + bbs(cpu, 0b00001000, oper & 0x00ff, oper >> 8); +} + +static void bbs4(struct cpu_t *cpu, uint16_t oper) { + bbs(cpu, 0b00010000, oper & 0x00ff, oper >> 8); +} + +static void bbs5(struct cpu_t *cpu, uint16_t oper) { + bbs(cpu, 0b00100000, oper & 0x00ff, oper >> 8); +} + +static void bbs6(struct cpu_t *cpu, uint16_t oper) { + bbs(cpu, 0b01000000, oper & 0x00ff, oper >> 8); +} + +static void bbs7(struct cpu_t *cpu, uint16_t oper) { + bbs(cpu, 0b10000000, oper & 0x00ff, oper >> 8); +} + +static void rmb(struct cpu_t *cpu, uint8_t bit, uint8_t zp) { + mem_set_byte_zpg(cpu, zp, mem_get_byte(cpu, zp) & ~bit); +} + +static void rmb0(struct cpu_t *cpu, uint8_t oper) { + rmb(cpu, 0b00000001, oper); +} + +static void rmb1(struct cpu_t *cpu, uint8_t oper) { + rmb(cpu, 0b00000010, oper); +} + +static void rmb2(struct cpu_t *cpu, uint8_t oper) { + rmb(cpu, 0b00000100, oper); +} + +static void rmb3(struct cpu_t *cpu, uint8_t oper) { + rmb(cpu, 0b00001000, oper); +} + +static void rmb4(struct cpu_t *cpu, uint8_t oper) { + rmb(cpu, 0b00010000, oper); +} + +static void rmb5(struct cpu_t *cpu, uint8_t oper) { + rmb(cpu, 0b00100000, oper); +} + +static void rmb6(struct cpu_t *cpu, uint8_t oper) { + rmb(cpu, 0b01000000, oper); +} + +static void rmb7(struct cpu_t *cpu, uint8_t oper) { + rmb(cpu, 0b10000000, oper); +} + +static void smb(struct cpu_t *cpu, uint8_t bit, uint8_t zp) { + mem_set_byte_zpg(cpu, zp, mem_get_byte(cpu, zp) | bit); +} + +static void smb0(struct cpu_t *cpu, uint8_t oper) { + smb(cpu, 0b00000001, oper); +} + +static void smb1(struct cpu_t *cpu, uint8_t oper) { + smb(cpu, 0b00000010, oper); +} + +static void smb2(struct cpu_t *cpu, uint8_t oper) { + smb(cpu, 0b00000100, oper); +} + +static void smb3(struct cpu_t *cpu, uint8_t oper) { + smb(cpu, 0b00001000, oper); +} + +static void smb4(struct cpu_t *cpu, uint8_t oper) { + smb(cpu, 0b00010000, oper); +} + +static void smb5(struct cpu_t *cpu, uint8_t oper) { + smb(cpu, 0b00100000, oper); +} + +static void smb6(struct cpu_t *cpu, uint8_t oper) { + smb(cpu, 0b01000000, oper); +} + +static void smb7(struct cpu_t *cpu, uint8_t oper) { + smb(cpu, 0b10000000, oper); +} + +/* Instruction dispatch table */ + +struct cpu_instruction_t instructions_65C02[256] = { + /* 0x00 */ { "???", 0x00, 0, 0, 0, NULL }, + /* 0x01 */ { "???", 0x01, 0, 0, 0, NULL }, + /* 0x02 */ { "NOP", 0x02, 2, 2, 0, (void*) nop }, + /* 0x03 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0x04 */ { "TSB", 0x04, 2, 5, 0, (void*) tsb_zpg }, + /* 0x05 */ { "???", 0x05, 0, 0, 0, NULL }, + /* 0x06 */ { "???", 0x06, 0, 0, 0, NULL }, + /* 0x07 */ { "RMB", 0x07, 2, 5, 0, (void*) rmb0 }, + /* 0x08 */ { "???", 0x08, 0, 0, 0, NULL }, + /* 0x09 */ { "???", 0x09, 0, 0, 0, NULL }, + /* 0x0a */ { "???", 0x0a, 0, 0, 0, NULL }, + /* 0x0b */ { "NOP", 0x0b, 1, 1, 0, (void*) nop }, + /* 0x0c */ { "TSB", 0x0c, 3, 6, 0, (void*) tsb_abs }, + /* 0x0d */ { "???", 0x0d, 0, 0, 0, NULL }, + /* 0x0e */ { "???", 0x0e, 0, 0, 0, NULL }, + /* 0x0f */ { "BBR", 0x0f, 3, 5, 0, (void*) bbr0 }, + + /* 0x10 */ { "???", 0x10, 0, 0, 0, NULL }, + /* 0x11 */ { "???", 0x12, 0, 0, 0, NULL }, + /* 0x12 */ { "ORA", 0x12, 2, 5, 0, (void*) ora_ind }, + /* 0x13 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0x14 */ { "TRB", 0x14, 2, 5, 0, (void*) trb_zpg }, + /* 0x15 */ { "???", 0x15, 0, 0, 0, NULL }, + /* 0x16 */ { "???", 0x16, 0, 0, 0, NULL }, + /* 0x17 */ { "RMB", 0x17, 2, 5, 0, (void*) rmb1 }, + /* 0x18 */ { "???", 0x18, 0, 0, 0, NULL }, + /* 0x19 */ { "???", 0x19, 0, 0, 0, NULL }, + /* 0x1a */ { "INC", 0x1a, 1, 2, 0, (void*) inc_acc }, + /* 0x1b */ { "NOP", 0x1b, 1, 1, 0, (void*) nop }, + /* 0x1c */ { "TRB", 0x1c, 3, 6, 0, (void*) trb_abs }, + /* 0x1d */ { "???", 0x1d, 0, 0, 0, NULL }, + /* 0x1e */ { "???", 0x1e, 0, 0, 0, NULL }, + /* 0x1f */ { "BBR", 0x1f, 3, 5, 0, (void*) bbr1 }, + + /* 0x20 */ { "???", 0x20, 0, 0, 0, NULL }, + /* 0x21 */ { "???", 0x21, 0, 0, 0, NULL }, + /* 0x22 */ { "NOP", 0x22, 2, 2, 0, (void*) nop }, + /* 0x23 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0x24 */ { "???", 0x24, 0, 0, 0, NULL }, + /* 0x25 */ { "???", 0x25, 0, 0, 0, NULL }, + /* 0x26 */ { "???", 0x26, 0, 0, 0, NULL }, + /* 0x27 */ { "RMB", 0x27, 2, 5, 0, (void*) rmb2 }, + /* 0x28 */ { "???", 0x28, 0, 0, 0, NULL }, + /* 0x29 */ { "???", 0x29, 0, 0, 0, NULL }, + /* 0x2a */ { "???", 0x2a, 0, 0, 0, NULL }, + /* 0x2b */ { "NOP", 0x2b, 1, 1, 0, (void*) nop }, + /* 0x2c */ { "???", 0x2c, 0, 0, 0, NULL }, + /* 0x2d */ { "???", 0x2d, 0, 0, 0, NULL }, + /* 0x2e */ { "???", 0x2e, 0, 0, 0, NULL }, + /* 0x2f */ { "BBR", 0x2f, 3, 5, 0, (void*) bbr2 }, + + /* 0x30 */ { "???", 0x30, 0, 0, 0, NULL }, + /* 0x31 */ { "???", 0x31, 0, 0, 0, NULL }, + /* 0x32 */ { "AND", 0x32, 2, 5, 0, (void*) and_ind }, + /* 0x33 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0x34 */ { "BIT", 0x34, 2, 4, 0, (void*) bit_zpgx }, + /* 0x35 */ { "???", 0x35, 0, 0, 0, NULL }, + /* 0x36 */ { "???", 0x36, 0, 0, 0, NULL }, + /* 0x37 */ { "RMB", 0x37, 2, 5, 0, (void*) rmb3 }, + /* 0x38 */ { "???", 0x38, 0, 0, 0, NULL }, + /* 0x39 */ { "???", 0x39, 0, 0, 0, NULL }, + /* 0x3a */ { "DEC", 0x3a, 1, 2, 0, (void*) dec_acc }, + /* 0x3b */ { "NOP", 0x3b, 1, 1, 0, (void*) nop }, + /* 0x3c */ { "BIT", 0x3c, 3, 4, 0, (void*) bit_absx }, + /* 0x3d */ { "???", 0x3d, 0, 0, 0, NULL }, + /* 0x3e */ { "???", 0x3e, 0, 0, 0, NULL }, + /* 0x3f */ { "BBR", 0x3f, 3, 5, 0, (void*) bbr3 }, + + /* 0x40 */ { "???", 0x40, 0, 0, 0, NULL }, + /* 0x41 */ { "???", 0x41, 0, 0, 0, NULL }, + /* 0x42 */ { "NOP", 0x42, 2, 2, 0, (void*) nop }, + /* 0x43 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0x44 */ { "NOP", 0x44, 2, 3, 0, (void*) nop }, + /* 0x45 */ { "???", 0x45, 0, 0, 0, NULL }, + /* 0x46 */ { "???", 0x46, 0, 0, 0, NULL }, + /* 0x47 */ { "RMB", 0x47, 2, 5, 0, (void*) rmb4 }, + /* 0x48 */ { "???", 0x48, 0, 0, 0, NULL }, + /* 0x49 */ { "???", 0x49, 0, 0, 0, NULL }, + /* 0x4a */ { "???", 0x4a, 0, 0, 0, NULL }, + /* 0x4b */ { "NOP", 0x4b, 1, 1, 0, (void*) nop }, + /* 0x4c */ { "???", 0x4c, 0, 0, 0, NULL }, + /* 0x4d */ { "???", 0x4d, 0, 0, 0, NULL }, + /* 0x4e */ { "???", 0x4e, 0, 0, 0, NULL }, + /* 0x4f */ { "BBR", 0x4f, 3, 5, 0, (void*) bbr4 }, + + /* 0x50 */ { "???", 0x50, 0, 0, 0, NULL }, + /* 0x51 */ { "???", 0x51, 0, 0, 0, NULL }, + /* 0x52 */ { "EOR", 0x52, 2, 5, 0, (void*) eor_ind }, + /* 0x53 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0x54 */ { "NOP", 0x54, 2, 4, 0, (void*) nop }, + /* 0x55 */ { "???", 0x55, 0, 0, 0, NULL }, + /* 0x56 */ { "???", 0x56, 0, 0, 0, NULL }, + /* 0x57 */ { "RMB", 0x57, 2, 5, 0, (void*) rmb5 }, + /* 0x58 */ { "???", 0x58, 0, 0, 0, NULL }, + /* 0x59 */ { "???", 0x59, 0, 0, 0, NULL }, + /* 0x5a */ { "PHY", 0x5a, 1, 3, 0, (void*) phy }, + /* 0x5b */ { "NOP", 0x5b, 1, 1, 0, (void*) nop }, + /* 0x5c */ { "NOP", 0x5c, 3, 8, 0, (void*) nop }, + /* 0x5d */ { "???", 0x5d, 0, 0, 0, NULL }, + /* 0x5e */ { "???", 0x5e, 0, 0, 0, NULL }, + /* 0x5f */ { "BBR", 0x5f, 3, 5, 0, (void*) bbr5 }, + + /* 0x60 */ { "???", 0x60, 0, 0, 0, NULL }, + /* 0x61 */ { "???", 0x61, 0, 0, 0, NULL }, + /* 0x62 */ { "NOP", 0x62, 2, 2, 0, (void*) nop }, + /* 0x63 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0x64 */ { "STZ", 0x64, 2, 3, 0, (void*) stz_zpg }, + /* 0x65 */ { "???", 0x65, 0, 0, 0, NULL }, + /* 0x66 */ { "???", 0x66, 0, 0, 0, NULL }, + /* 0x67 */ { "RMB", 0x67, 2, 5, 0, (void*) rmb6 }, + /* 0x68 */ { "???", 0x68, 0, 0, 0, NULL }, + /* 0x69 */ { "???", 0x69, 0, 0, 0, NULL }, + /* 0x6a */ { "???", 0x6a, 0, 0, 0, NULL }, + /* 0x6b */ { "NOP", 0x6b, 1, 1, 0, (void*) nop }, + /* 0x6c */ { "???", 0x6c, 0, 0, 0, NULL }, + /* 0x6d */ { "???", 0x6d, 0, 0, 0, NULL }, + /* 0x6e */ { "???", 0x6e, 0, 0, 0, NULL }, + /* 0x6f */ { "BBR", 0x6f, 3, 5, 0, (void*) bbr6 }, + + /* 0x70 */ { "???", 0x70, 0, 0, 0, NULL }, + /* 0x71 */ { "???", 0x71, 0, 0, 0, NULL }, + /* 0x72 */ { "ADC", 0x72, 2, 5, 0, (void*) adc_ind }, + /* 0x73 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0x74 */ { "STZ", 0x74, 2, 4, 0, (void*) stz_zpgx }, + /* 0x75 */ { "???", 0x75, 0, 0, 0, NULL }, + /* 0x76 */ { "???", 0x76, 0, 0, 0, NULL }, + /* 0x77 */ { "RMB", 0x77, 2, 5, 0, (void*) rmb7 }, + /* 0x78 */ { "???", 0x78, 0, 0, 0, NULL }, + /* 0x79 */ { "???", 0x79, 0, 0, 0, NULL }, + /* 0x7a */ { "PLY", 0x7a, 1, 4, 0, (void*) ply }, + /* 0x7b */ { "NOP", 0x7b, 1, 1, 0, (void*) nop }, + /* 0x7c */ { "JMP", 0x7c, 3, 6, 0, (void*) jmp_absx }, + /* 0x7d */ { "???", 0x7d, 0, 0, 0, NULL }, + /* 0x7e */ { "???", 0x7e, 0, 0, 0, NULL }, + /* 0x7f */ { "BBR", 0x7f, 3, 5, 0, (void*) bbr7 }, + + /* 0x80 */ { "BRA", 0x80, 2, 3, 0, (void*) bra }, + /* 0x81 */ { "???", 0x81, 0, 0, 0, NULL }, + /* 0x82 */ { "NOP", 0x82, 2, 2, 0, (void*) nop }, + /* 0x83 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0x84 */ { "???", 0x84, 0, 0, 0, NULL }, + /* 0x85 */ { "???", 0x85, 0, 0, 0, NULL }, + /* 0x86 */ { "???", 0x86, 0, 0, 0, NULL }, + /* 0x87 */ { "SMB", 0x87, 2, 5, 0, (void*) smb0 }, + /* 0x88 */ { "???", 0x88, 0, 0, 0, NULL }, + /* 0x89 */ { "BIT", 0x89, 2, 2, 0, (void*) bit_imm }, + /* 0x8a */ { "???", 0x8a, 0, 0, 0, NULL }, + /* 0x8b */ { "NOP", 0x8b, 1, 1, 0, (void*) nop }, + /* 0x8c */ { "???", 0x8c, 0, 0, 0, NULL }, + /* 0x8d */ { "???", 0x8d, 0, 0, 0, NULL }, + /* 0x8e */ { "???", 0x8e, 0, 0, 0, NULL }, + /* 0x8f */ { "BBS", 0x8f, 3, 5, 0, (void*) bbs0 }, + + /* 0x90 */ { "???", 0x90, 0, 0, 0, NULL }, + /* 0x91 */ { "???", 0x91, 0, 0, 0, NULL }, + /* 0x92 */ { "STA", 0x92, 2, 5, 0, (void*) sta_ind }, + /* 0x93 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0x94 */ { "???", 0x94, 0, 0, 0, NULL }, + /* 0x95 */ { "???", 0x95, 0, 0, 0, NULL }, + /* 0x96 */ { "???", 0x96, 0, 0, 0, NULL }, + /* 0x97 */ { "SMB", 0x97, 2, 5, 0, (void*) smb1 }, + /* 0x98 */ { "???", 0x98, 0, 0, 0, NULL }, + /* 0x99 */ { "???", 0x99, 0, 0, 0, NULL }, + /* 0x9a */ { "???", 0x9a, 0, 0, 0, NULL }, + /* 0x9b */ { "NOP", 0x9b, 1, 1, 0, (void*) nop }, + /* 0x9c */ { "STZ", 0x9c, 3, 4, 0, (void*) stz_abs }, + /* 0x9d */ { "???", 0x9d, 0, 0, 0, NULL }, + /* 0x9e */ { "STZ", 0x9e, 3, 5, 0, (void*) stz_absx }, + /* 0x9f */ { "BBS", 0x9f, 3, 5, 0, (void*) bbs1 }, + + /* 0xa0 */ { "???", 0xa0, 0, 0, 0, NULL }, + /* 0xa1 */ { "???", 0xa1, 0, 0, 0, NULL }, + /* 0xa2 */ { "???", 0xa2, 0, 0, 0, NULL }, + /* 0xa3 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0xa4 */ { "???", 0xa4, 0, 0, 0, NULL }, + /* 0xa5 */ { "???", 0xa5, 0, 0, 0, NULL }, + /* 0xa6 */ { "???", 0xa6, 0, 0, 0, NULL }, + /* 0xa7 */ { "SMB", 0xa7, 2, 5, 0, (void*) smb2 }, + /* 0xa8 */ { "???", 0xa8, 0, 0, 0, NULL }, + /* 0xa9 */ { "???", 0xa9, 0, 0, 0, NULL }, + /* 0xaa */ { "???", 0xaa, 0, 0, 0, NULL }, + /* 0xab */ { "NOP", 0xab, 1, 1, 0, (void*) nop }, + /* 0xac */ { "???", 0xac, 0, 0, 0, NULL }, + /* 0xad */ { "???", 0xad, 0, 0, 0, NULL }, + /* 0xae */ { "???", 0xae, 0, 0, 0, NULL }, + /* 0xaf */ { "BBS", 0xaf, 3, 5, 0, (void*) bbs2 }, + + /* 0xb0 */ { "???", 0xb0, 0, 0, 0, NULL }, + /* 0xb1 */ { "???", 0xb1, 0, 0, 0, NULL }, + /* 0xb2 */ { "LDA", 0xb2, 2, 5, 0, (void*) lda_ind }, + /* 0xb3 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0xb4 */ { "???", 0xb4, 0, 0, 0, NULL }, + /* 0xb5 */ { "???", 0xb5, 0, 0, 0, NULL }, + /* 0xb6 */ { "???", 0xb6, 0, 0, 0, NULL }, + /* 0xb7 */ { "SMB", 0xb7, 2, 5, 0, (void*) smb3 }, + /* 0xb8 */ { "???", 0xb8, 0, 0, 0, NULL }, + /* 0xb9 */ { "???", 0xb9, 0, 0, 0, NULL }, + /* 0xba */ { "???", 0xba, 0, 0, 0, NULL }, + /* 0xbb */ { "NOP", 0xbb, 1, 1, 0, (void*) nop }, + /* 0xbc */ { "???", 0xbc, 0, 0, 0, NULL }, + /* 0xbd */ { "???", 0xbd, 0, 0, 0, NULL }, + /* 0xbe */ { "???", 0xbe, 0, 0, 0, NULL }, + /* 0xbf */ { "BBS", 0xbf, 3, 5, 0, (void*) bbs3 }, + + /* 0xc0 */ { "???", 0xc0, 0, 0, 0, NULL }, + /* 0xc1 */ { "???", 0xc1, 0, 0, 0, NULL }, + /* 0xc2 */ { "NOP", 0xc2, 2, 2, 0, (void*) nop }, + /* 0xc3 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0xc4 */ { "???", 0xc4, 0, 0, 0, NULL }, + /* 0xc5 */ { "???", 0xc5, 0, 0, 0, NULL }, + /* 0xc6 */ { "???", 0xc6, 0, 0, 0, NULL }, + /* 0xc7 */ { "SMB", 0xc7, 2, 5, 0, (void*) smb4 }, + /* 0xc8 */ { "???", 0xc8, 0, 0, 0, NULL }, + /* 0xc9 */ { "???", 0xc9, 0, 0, 0, NULL }, + /* 0xca */ { "???", 0xca, 0, 0, 0, NULL }, + /* 0xcb */ { "NOP", 0xcb, 1, 1, 0, (void*) nop }, + /* 0xcc */ { "???", 0xcc, 0, 0, 0, NULL }, + /* 0xcd */ { "???", 0xcd, 0, 0, 0, NULL }, + /* 0xce */ { "???", 0xce, 0, 0, 0, NULL }, + /* 0xcf */ { "BBS", 0xcf, 3, 5, 0, (void*) bbs4 }, + + /* 0xd0 */ { "???", 0xd0, 0, 0, 0, NULL }, + /* 0xd1 */ { "???", 0xd1, 0, 0, 0, NULL }, + /* 0xd2 */ { "CMP", 0xd2, 2, 5, 0, (void*) cmp_ind }, + /* 0xd3 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0xd4 */ { "NOP", 0xd4, 2, 4, 0, (void*) nop }, + /* 0xd5 */ { "???", 0xd5, 0, 0, 0, NULL }, + /* 0xd6 */ { "???", 0xd6, 0, 0, 0, NULL }, + /* 0xd7 */ { "SMB", 0xd7, 2, 5, 0, (void*) smb5 }, + /* 0xd8 */ { "???", 0xd8, 0, 0, 0, NULL }, + /* 0xd9 */ { "???", 0xd9, 0, 0, 0, NULL }, + /* 0xda */ { "PHX", 0xda, 1, 3, 0, (void*) phx }, + /* 0xdb */ { "NOP", 0xdb, 1, 1, 0, (void*) nop }, + /* 0xdc */ { "NOP", 0xdc, 3, 4, 0, (void*) nop }, + /* 0xdd */ { "???", 0xdd, 0, 0, 0, NULL }, + /* 0xde */ { "???", 0xde, 0, 0, 0, NULL }, + /* 0xdf */ { "BBS", 0xdf, 3, 5, 0, (void*) bbs5 }, + + /* 0xe0 */ { "???", 0xe0, 0, 0, 0, NULL }, + /* 0xe1 */ { "???", 0xe1, 0, 0, 0, NULL }, + /* 0xe2 */ { "NOP", 0xe2, 2, 2, 0, (void*) nop }, + /* 0xe3 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0xe4 */ { "???", 0xe4, 0, 0, 0, NULL }, + /* 0xe5 */ { "???", 0xe5, 0, 0, 0, NULL }, + /* 0xe6 */ { "???", 0xe6, 0, 0, 0, NULL }, + /* 0xe7 */ { "SMB", 0xe7, 2, 5, 0, (void*) smb6 }, + /* 0xe8 */ { "???", 0xe8, 0, 0, 0, NULL }, + /* 0xe9 */ { "???", 0xe9, 0, 0, 0, NULL }, + /* 0xea */ { "???", 0xea, 0, 0, 0, NULL }, + /* 0xeb */ { "NOP", 0xeb, 1, 1, 0, (void*) nop }, + /* 0xec */ { "???", 0xec, 0, 0, 0, NULL }, + /* 0xed */ { "???", 0xed, 0, 0, 0, NULL }, + /* 0xee */ { "???", 0xee, 0, 0, 0, NULL }, + /* 0xef */ { "BBS", 0xef, 3, 5, 0, (void*) bbs6 }, + + /* 0xf0 */ { "???", 0xf0, 0, 0, 0, NULL }, + /* 0xf1 */ { "???", 0xf1, 0, 0, 0, NULL }, + /* 0xf2 */ { "SBC", 0xf2, 2, 5, 0, (void*) sbc_ind }, + /* 0xf3 */ { "NOP", 0x03, 1, 1, 0, (void*) nop }, + /* 0xf4 */ { "NOP", 0xf4, 2, 4, 0, (void*) nop }, + /* 0xf5 */ { "???", 0xf5, 0, 0, 0, NULL }, + /* 0xf6 */ { "???", 0xf6, 0, 0, 0, NULL }, + /* 0xf7 */ { "SMB", 0xf7, 2, 5, 0, (void*) smb7 }, + /* 0xf8 */ { "???", 0xf8, 0, 0, 0, NULL }, + /* 0xf9 */ { "???", 0xf9, 0, 0, 0, NULL }, + /* 0xfa */ { "PLX", 0xfa, 1, 4, 0, (void*) plx }, + /* 0xfb */ { "NOP", 0xfb, 1, 1, 0, (void*) nop }, + /* 0xfc */ { "NOP", 0xfc, 3, 4, 0, (void*) nop }, + /* 0xfd */ { "???", 0xfd, 0, 0, 0, NULL }, + /* 0xfe */ { "???", 0xfe, 0, 0, 0, NULL }, + /* 0xff */ { "BBS", 0xff, 3, 5, 0, (void*) bbs7 } +}; diff --git a/ins.h b/ins.h index d685a94..f8fcd7b 100644 --- a/ins.h +++ b/ins.h @@ -25,15 +25,16 @@ #include -typedef struct { +struct cpu_instruction_t { char *name; uint8_t opcode; uint8_t bytes; uint8_t cycles; int8_t stack; // How much stack does this instruction need. Negative means pull, positive push void *handler; -} cpu_instruction_t; +}; -extern cpu_instruction_t instructions[256]; +extern struct cpu_instruction_t instructions[256]; +extern struct cpu_instruction_t instructions_65C02[256]; #endif diff --git a/mem.c b/mem.c index 0b98fb1..7c83008 100644 --- a/mem.c +++ b/mem.c @@ -109,6 +109,10 @@ uint8_t mem_get_byte_indy(struct cpu_t *cpu, uint8_t addr) { return mem_get_byte(cpu, mem_get_word(cpu, addr) + cpu->state.y); } +uint8_t mem_get_byte_ind(struct cpu_t *cpu, uint8_t addr) { + return mem_get_byte(cpu, mem_get_word(cpu, addr)); +} + uint16_t mem_get_word(struct cpu_t *cpu, uint16_t addr) { // TODO Did I do this right? return ((uint16_t) mem_get_byte(cpu, addr+1) << 8) | (uint16_t) mem_get_byte(cpu, addr); @@ -149,6 +153,10 @@ void mem_set_byte_indy(struct cpu_t *cpu, uint8_t addr, uint8_t v) { mem_set_byte(cpu, mem_get_word(cpu, addr)+cpu->state.y, v); } +void mem_set_byte_ind(struct cpu_t *cpu, uint8_t addr, uint8_t v) { + mem_set_byte(cpu, mem_get_word(cpu, addr), v); +} + void mem_set_word(struct cpu_t *cpu, uint16_t addr, uint16_t v) { mem_set_byte(cpu, addr+0, (uint8_t) v); // TODO Did I do this right? mem_set_byte(cpu, addr+1, (uint8_t) (v >> 8)); diff --git a/mem.h b/mem.h index b193d8c..878ab3d 100644 --- a/mem.h +++ b/mem.h @@ -36,6 +36,7 @@ uint8_t mem_get_byte_zpgx(struct cpu_t *cpu, uint8_t addr); uint8_t mem_get_byte_zpgy(struct cpu_t *cpu, uint8_t addr); uint8_t mem_get_byte_indx(struct cpu_t *cpu, uint8_t addr); uint8_t mem_get_byte_indy(struct cpu_t *cpu, uint8_t addr); +uint8_t mem_get_byte_ind(struct cpu_t *cpu, uint8_t addr); void mem_set_byte(struct cpu_t *cpu, uint16_t addr, uint8_t v); void mem_set_byte_zpg(struct cpu_t *cpu, uint8_t addr, uint8_t v); @@ -46,6 +47,7 @@ void mem_set_byte_absx(struct cpu_t *cpu, uint16_t addr, uint8_t v); void mem_set_byte_absy(struct cpu_t *cpu, uint16_t addr, uint8_t v); void mem_set_byte_indx(struct cpu_t *cpu, uint8_t addr, uint8_t v); void mem_set_byte_indy(struct cpu_t *cpu, uint8_t addr, uint8_t v); +void mem_set_byte_ind(struct cpu_t *cpu, uint8_t addr, uint8_t v); void mem_mod_byte_zpg(struct cpu_t *cpu, uint8_t addr, mem_mod_t op); void mem_mod_byte_zpgx(struct cpu_t *cpu, uint8_t addr, mem_mod_t op);