From a4324737d5e2c51c92add6a1f47c32f0548568e7 Mon Sep 17 00:00:00 2001 From: Stefan Arentz Date: Thu, 21 Sep 2017 22:18:53 -0400 Subject: [PATCH] Performance improvements (#160) --- src/cpu.c | 85 +++++++--------------------------------- src/cpu.h | 4 +- src/cpu_bench.c | 17 ++++++-- src/cpu_test.c | 25 +++++++----- src/mem.c | 100 +++++++++++++++++++++++++++++++++++------------- src/mem.h | 3 +- 6 files changed, 121 insertions(+), 113 deletions(-) diff --git a/src/cpu.c b/src/cpu.c index 548bca2..c926b91 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -42,21 +42,21 @@ // Stack management. void _cpu_push_byte(struct cpu_t *cpu, uint8_t b) { - cpu->page1[cpu->state.sp--] = b; + cpu->ram[0x0100 + cpu->state.sp--] = b; } void _cpu_push_word(struct cpu_t *cpu, uint16_t w) { - cpu->page1[cpu->state.sp--] = w >> 8; - cpu->page1[cpu->state.sp--] = w; + cpu->ram[0x0100 + cpu->state.sp--] = w >> 8; + cpu->ram[0x0100 + cpu->state.sp--] = w; } uint8_t _cpu_pull_byte(struct cpu_t *cpu) { - return cpu->page1[++cpu->state.sp]; + return cpu->ram[0x0100 + ++cpu->state.sp]; } uint16_t _cpu_pull_word(struct cpu_t *cpu) { - uint16_t w = (uint16_t) cpu->page1[++cpu->state.sp]; - return w | ((uint16_t) cpu->page1[++cpu->state.sp] << 8); + uint16_t w = (uint16_t) cpu->ram[0x0100 + ++cpu->state.sp]; + return w | ((uint16_t) cpu->ram[0x0100 + ++cpu->state.sp] << 8); } uint8_t _cpu_stack_free(struct cpu_t *cpu) { @@ -95,43 +95,12 @@ void _cpu_set_status(struct cpu_t *cpu, uint8_t status) { } static int cpu_execute_instruction(struct cpu_t *cpu) { - /* Trace code - Refactor into its own function or module */ - char trace_instruction[256]; - char trace_state[256]; - char trace_stack[256]; - - if (cpu->trace) { - cpu_format_instruction(cpu, trace_instruction); - } - - /* Fetch instruction */ + // Fetch instruction struct cpu_instruction_t *i = &cpu->instructions[mem_get_byte(cpu, cpu->state.pc)]; - if (i->name[0] == '?') { - if (cpu->strict) { - return EWM_CPU_ERR_UNIMPLEMENTED_INSTRUCTION; - } - } - // If strict mode and if we need the stack, check if that works out - if (cpu->strict && i->stack != 0) { - if (i->stack > 0) { - if (_cpu_stack_free(cpu) < i->stack) { - return EWM_CPU_ERR_STACK_OVERFLOW; - } - } else { - if (_cpu_stack_used(cpu) < -(i->stack)) { - return EWM_CPU_ERR_STACK_UNDERFLOW; - } - } - } - - /* Remember the PC since some instructions modify it */ + // Remember and advance the pc uint16_t pc = cpu->state.pc; - - /* Advance PC */ - if (pc == cpu->state.pc) { - cpu->state.pc += i->bytes; - } + cpu->state.pc += i->bytes; if (i->lua_before_handler != LUA_NOREF) { lua_rawgeti(cpu->lua->state, LUA_REGISTRYINDEX, i->lua_before_handler); @@ -186,27 +155,6 @@ static int cpu_execute_instruction(struct cpu_t *cpu) { } } - if (cpu->trace) { - cpu_format_state(cpu, trace_state); - cpu_format_stack(cpu, trace_stack); - - char bytes[10]; - switch (i->bytes) { - case 1: - snprintf(bytes, sizeof bytes, "%.2X", mem_get_byte(cpu, pc)); - break; - case 2: - snprintf(bytes, sizeof bytes, "%.2X %.2X", mem_get_byte(cpu, pc), mem_get_byte(cpu, pc+1)); - break; - case 3: - 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 %-14s %-20s %s\n", - pc, bytes, trace_instruction, trace_state, trace_stack); - } - cpu->counter += i->cycles; return i->cycles; @@ -408,19 +356,14 @@ struct mem_t *cpu_add_iom(struct cpu_t *cpu, uint16_t start, uint16_t end, void // memory regions. void cpu_optimize_memory(struct cpu_t *cpu) { - struct mem_t *page0 = cpu_mem_for_page(cpu, 0); - if (page0 == NULL || (page0->flags != (MEM_FLAGS_READ | MEM_FLAGS_WRITE))) { - printf("[CPU] Cannot find rw memory region that handles Page 0\n"); + struct mem_t *zp= cpu_mem_for_page(cpu, 0); + if (zp == NULL || (zp->flags != (MEM_FLAGS_READ | MEM_FLAGS_WRITE)) || zp->end < 0x1ff) { + printf("[CPU] Cannot find rw memory region that covers 0x0000 to 0x01ff\n"); exit(1); } - cpu->page0 = page0->obj + (0x0000 - page0->start); - struct mem_t *page1 = cpu_mem_for_page(cpu, 1); - if (page1 == NULL || (page1->flags != (MEM_FLAGS_READ | MEM_FLAGS_WRITE))) { - printf("[CPU] Cannot find rw memory region that handles Page 1\n"); - exit(1); - } - cpu->page1 = page1->obj + (0x0100 - page1->start); + cpu->ram = zp->obj; + cpu->ram_size = zp->end; } void cpu_strict(struct cpu_t *cpu, bool strict) { diff --git a/src/cpu.h b/src/cpu.h index 21a1124..e252300 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -56,8 +56,8 @@ struct cpu_t { struct cpu_instruction_t *instructions; uint64_t counter; - uint8_t *page0; - uint8_t *page1; + uint8_t *ram; + size_t ram_size; struct ewm_lua_t *lua; }; diff --git a/src/cpu_bench.c b/src/cpu_bench.c index 216512f..08db3fc 100644 --- a/src/cpu_bench.c +++ b/src/cpu_bench.c @@ -22,6 +22,7 @@ #include #include +#include #include #include "cpu.h" @@ -29,7 +30,7 @@ #include "mem.h" #include "utl.h" -#define CPU_BENCH_ITERATIONS (100 * 1000 * 1000) +#define CPU_BENCH_ITERATIONS (10 * 1000 * 1000) void test(struct cpu_t *cpu, uint8_t opcode) { uint64_t runs[3]; @@ -83,7 +84,17 @@ int main(int argc, char **argv) { cpu_add_ram_data(cpu, 0, 0xffff, malloc(0xffff)); cpu_reset(cpu); - for (int opcode = 0; opcode <= 255; opcode++) { - test(cpu, opcode); + if (argc > 1) { + for (int i = 1; i < argc; i++) { + for (int opcode = 0; opcode <= 255; opcode++) { + if (strcmp(cpu->instructions[opcode].name, argv[i]) == 0) { + test(cpu, opcode); + } + } + } + } else { + for (int opcode = 0; opcode <= 255; opcode++) { + test(cpu, opcode); + } } } diff --git a/src/cpu_test.c b/src/cpu_test.c index b86b168..3611306 100644 --- a/src/cpu_test.c +++ b/src/cpu_test.c @@ -32,21 +32,21 @@ #include "utl.h" #include "lua.h" -int test(int model, uint16_t start_addr, uint16_t success_addr, char *rom_path) { +int test(int model, uint16_t start_addr, uint16_t success_addr, char *rom_path, int with_lua) { struct cpu_t *cpu = cpu_create(model); cpu_add_ram_file(cpu, 0x0000, rom_path); cpu_reset(cpu); cpu->state.pc = start_addr; -#if 1 - cpu->lua = ewm_lua_create(); - ewm_cpu_init_lua(cpu, cpu->lua); + if (with_lua) { + cpu->lua = ewm_lua_create(); + ewm_cpu_init_lua(cpu, cpu->lua); - if (ewm_lua_load_script(cpu->lua, "cpu_test.lua") != 0) { - printf("Lua script failed to load\n"); // TODO Move errors reporting into C code - exit(1); + if (ewm_lua_load_script(cpu->lua, "cpu_test.lua") != 0) { + printf("Lua script failed to load\n"); // TODO Move errors reporting into C code + exit(1); + } } -#endif uint16_t last_pc = cpu->state.pc; @@ -114,7 +114,12 @@ int test(int model, uint16_t start_addr, uint16_t success_addr, char *rom_path) int main(int argc, char **argv) { fprintf(stderr, "TEST Running 6502 tests\n"); - test(EWM_CPU_MODEL_6502, 0x0400, 0x3399, "rom/6502_functional_test.bin"); + test(EWM_CPU_MODEL_6502, 0x0400, 0x3399, "rom/6502_functional_test.bin", 0); fprintf(stderr, "TEST Running 65C02 tests\n"); - test(EWM_CPU_MODEL_65C02, 0x0400, 0x24a8, "rom/65C02_extended_opcodes_test.bin"); + test(EWM_CPU_MODEL_65C02, 0x0400, 0x24a8, "rom/65C02_extended_opcodes_test.bin", 0); + + fprintf(stderr, "TEST Running 6502 tests - With Lua\n"); + test(EWM_CPU_MODEL_6502, 0x0400, 0x3399, "rom/6502_functional_test.bin", 1); + fprintf(stderr, "TEST Running 65C02 tests - With Lua\n"); + test(EWM_CPU_MODEL_65C02, 0x0400, 0x24a8, "rom/65C02_extended_opcodes_test.bin", 1); } diff --git a/src/mem.c b/src/mem.c index 15b9be0..618a621 100644 --- a/src/mem.c +++ b/src/mem.c @@ -33,6 +33,10 @@ // take more time but do the right thing. uint8_t mem_get_byte(struct cpu_t *cpu, uint16_t addr) { + if (addr < cpu->ram_size) { + return cpu->ram[addr]; + } + struct mem_t *mem = cpu->mem; while (mem != NULL) { if (mem->enabled && addr >= mem->start && addr <= mem->end) { @@ -42,15 +46,15 @@ uint8_t mem_get_byte(struct cpu_t *cpu, uint16_t addr) { } mem = mem->next; } - - if (cpu->strict) { - // TODO: Signal an error about reading non-existent memory? - } - return 0; } void mem_set_byte(struct cpu_t *cpu, uint16_t addr, uint8_t v) { + if (addr < cpu->ram_size) { + cpu->ram[addr] = v; + return; + } + struct mem_t *mem = cpu->mem; while (mem != NULL) { if (mem->enabled && addr >= mem->start && addr <= mem->end) { @@ -61,90 +65,134 @@ void mem_set_byte(struct cpu_t *cpu, uint16_t addr, uint8_t v) { } mem = mem->next; } - - if (cpu->strict) { - // TODO: Signal an error about writing non-existent memory? - } } // Getters uint8_t mem_get_byte_abs(struct cpu_t *cpu, uint16_t addr) { - return mem_get_byte(cpu, addr); + if (addr < cpu->ram_size) { + return cpu->ram[addr]; + } + return mem_get_byte(cpu, addr); } uint8_t mem_get_byte_absx(struct cpu_t *cpu, uint16_t addr) { + if (addr < cpu->ram_size) { + return cpu->ram[addr + cpu->state.x]; + } return mem_get_byte(cpu, addr + cpu->state.x); } uint8_t mem_get_byte_absy(struct cpu_t *cpu, uint16_t addr) { - return mem_get_byte(cpu, addr + cpu->state.y); + return cpu->ram[addr + cpu->state.y]; } uint8_t mem_get_byte_zpg(struct cpu_t *cpu, uint8_t addr) { - return cpu->page0[addr]; + return cpu->ram[addr]; } uint8_t mem_get_byte_zpgx(struct cpu_t *cpu, uint8_t addr) { - return cpu->page0[((uint16_t) addr + cpu->state.x) & 0x00ff]; + return cpu->ram[((uint16_t) addr + cpu->state.x) & 0x00ff]; } uint8_t mem_get_byte_zpgy(struct cpu_t *cpu, uint8_t addr) { - return cpu->page0[((uint16_t) addr + cpu->state.y) & 0x00ff]; + return cpu->ram[((uint16_t) addr + cpu->state.y) & 0x00ff]; } uint8_t mem_get_byte_indx(struct cpu_t *cpu, uint8_t addr) { - return mem_get_byte(cpu, (((uint16_t) cpu->page0[((uint16_t)addr+1+cpu->state.x)&0x00ff] << 8) | (uint16_t) cpu->page0[((uint16_t) addr+cpu->state.x) & 0x00ff])); + uint16_t a = *((uint16_t*) &cpu->ram[(addr + cpu->state.x) & 0x0ff]); + if (a < cpu->ram_size) { + return cpu->ram[a]; + } + return mem_get_byte(cpu, a); } uint8_t mem_get_byte_indy(struct cpu_t *cpu, uint8_t addr) { - return mem_get_byte(cpu, (((uint16_t) cpu->page0[addr+1] << 8) | (uint16_t) cpu->page0[addr]) + cpu->state.y); + uint16_t a = *((uint16_t*) &cpu->ram[addr]) + cpu->state.y; + if (a < cpu->ram_size) { + return cpu->ram[a]; + } + return mem_get_byte(cpu, a); } uint8_t mem_get_byte_ind(struct cpu_t *cpu, uint8_t addr) { - return mem_get_byte(cpu, ((uint16_t) cpu->page0[addr+1] << 8) | (uint16_t) cpu->page0[addr]); + uint16_t a = *((uint16_t*) &cpu->ram[addr]); + if (a < cpu->ram_size) { + return cpu->ram[a]; + } + return mem_get_byte(cpu, a); } uint16_t mem_get_word(struct cpu_t *cpu, uint16_t addr) { + if (addr < cpu->ram_size) { + return *((uint16_t*) &cpu->ram[addr]); + } return ((uint16_t) mem_get_byte(cpu, addr+1) << 8) | (uint16_t) mem_get_byte(cpu, addr); } // Setters void mem_set_byte_zpg(struct cpu_t *cpu, uint8_t addr, uint8_t v) { - cpu->page0[addr] = v; + cpu->ram[addr] = v; } void mem_set_byte_zpgx(struct cpu_t *cpu, uint8_t addr, uint8_t v) { - cpu->page0[((uint16_t) addr + cpu->state.x) & 0x00ff] = v; + cpu->ram[((uint16_t) addr + cpu->state.x) & 0x00ff] = v; } void mem_set_byte_zpgy(struct cpu_t *cpu, uint8_t addr, uint8_t v) { - cpu->page0[((uint16_t) addr + cpu->state.y) & 0x00ff] = v; + cpu->ram[((uint16_t) addr + cpu->state.y) & 0x00ff] = v; } void mem_set_byte_abs(struct cpu_t *cpu, uint16_t addr, uint8_t v) { - mem_set_byte(cpu, addr, v); + if (addr < cpu->ram_size) { + cpu->ram[addr] = v; + return; + } + mem_set_byte(cpu, addr, v); } void mem_set_byte_absx(struct cpu_t *cpu, uint16_t addr, uint8_t v) { - mem_set_byte(cpu, addr+cpu->state.x, v); + if (addr < cpu->ram_size) { + cpu->ram[addr + cpu->state.x] = v; + return; + } + mem_set_byte(cpu, addr + cpu->state.x, v); } void mem_set_byte_absy(struct cpu_t *cpu, uint16_t addr, uint8_t v) { - mem_set_byte(cpu, addr+cpu->state.y, v); + if (addr < cpu->ram_size) { + cpu->ram[addr + cpu->state.y] = v; + return; + } + mem_set_byte(cpu, addr + cpu->state.y, v); } void mem_set_byte_indx(struct cpu_t *cpu, uint8_t addr, uint8_t v) { - mem_set_byte(cpu, (((uint16_t) cpu->page0[((uint16_t)addr+1+cpu->state.x)&0x00ff] << 8) | (uint16_t) cpu->page0[((uint16_t) addr+cpu->state.x) & 0x00ff]), v); + uint16_t a = *((uint16_t*) &cpu->ram[(addr + cpu->state.x) & 0x0ff]); + if (a < cpu->ram_size) { + cpu->ram[a] = v; + return; + } + mem_set_byte(cpu, a, v); } void mem_set_byte_indy(struct cpu_t *cpu, uint8_t addr, uint8_t v) { - mem_set_byte(cpu, (((uint16_t) cpu->page0[addr+1] << 8) | (uint16_t) cpu->page0[addr]) + cpu->state.y, v); + uint16_t a = *((uint16_t*) &cpu->ram[addr]) + cpu->state.y; + if (a < cpu->ram_size) { + cpu->ram[a] = v; + return; + } + mem_set_byte(cpu, a, v); } void mem_set_byte_ind(struct cpu_t *cpu, uint8_t addr, uint8_t v) { - mem_set_byte(cpu, (((uint16_t) cpu->page0[addr+1] << 8) | (uint16_t) cpu->page0[addr]), v); + uint16_t a = *((uint16_t*) &cpu->ram[addr]); + if (a < cpu->ram_size) { + cpu->ram[a] = v; + return; + } + mem_set_byte(cpu, a, v); } void mem_set_word(struct cpu_t *cpu, uint16_t addr, uint16_t v) { diff --git a/src/mem.h b/src/mem.h index b3b7417..4470834 100644 --- a/src/mem.h +++ b/src/mem.h @@ -30,6 +30,8 @@ struct cpu_t; typedef uint8_t (*mem_mod_t)(struct cpu_t *cpu, uint8_t b); uint8_t mem_get_byte(struct cpu_t *cpu, uint16_t addr); +void mem_set_byte(struct cpu_t *cpu, uint16_t addr, uint8_t v); + uint8_t mem_get_byte_abs(struct cpu_t *cpu, uint16_t addr); uint8_t mem_get_byte_absx(struct cpu_t *cpu, uint16_t addr); uint8_t mem_get_byte_absy(struct cpu_t *cpu, uint16_t addr); @@ -40,7 +42,6 @@ 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); void mem_set_byte_zpgx(struct cpu_t *cpu, uint8_t addr, uint8_t v); void mem_set_byte_zpgy(struct cpu_t *cpu, uint8_t addr, uint8_t v);