Performance improvements (#160)

This commit is contained in:
Stefan Arentz 2017-09-21 22:18:53 -04:00 committed by GitHub
parent 58bb3d7739
commit a4324737d5
6 changed files with 121 additions and 113 deletions

View File

@ -42,21 +42,21 @@
// Stack management. // Stack management.
void _cpu_push_byte(struct cpu_t *cpu, uint8_t b) { 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) { void _cpu_push_word(struct cpu_t *cpu, uint16_t w) {
cpu->page1[cpu->state.sp--] = w >> 8; cpu->ram[0x0100 + cpu->state.sp--] = w >> 8;
cpu->page1[cpu->state.sp--] = w; cpu->ram[0x0100 + cpu->state.sp--] = w;
} }
uint8_t _cpu_pull_byte(struct cpu_t *cpu) { 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 _cpu_pull_word(struct cpu_t *cpu) {
uint16_t w = (uint16_t) cpu->page1[++cpu->state.sp]; uint16_t w = (uint16_t) cpu->ram[0x0100 + ++cpu->state.sp];
return w | ((uint16_t) cpu->page1[++cpu->state.sp] << 8); return w | ((uint16_t) cpu->ram[0x0100 + ++cpu->state.sp] << 8);
} }
uint8_t _cpu_stack_free(struct cpu_t *cpu) { 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) { static int cpu_execute_instruction(struct cpu_t *cpu) {
/* Trace code - Refactor into its own function or module */ // Fetch instruction
char trace_instruction[256];
char trace_state[256];
char trace_stack[256];
if (cpu->trace) {
cpu_format_instruction(cpu, trace_instruction);
}
/* Fetch instruction */
struct cpu_instruction_t *i = &cpu->instructions[mem_get_byte(cpu, cpu->state.pc)]; 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 // Remember and advance the pc
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 */
uint16_t pc = cpu->state.pc; uint16_t pc = cpu->state.pc;
cpu->state.pc += i->bytes;
/* Advance PC */
if (pc == cpu->state.pc) {
cpu->state.pc += i->bytes;
}
if (i->lua_before_handler != LUA_NOREF) { if (i->lua_before_handler != LUA_NOREF) {
lua_rawgeti(cpu->lua->state, LUA_REGISTRYINDEX, i->lua_before_handler); 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; cpu->counter += i->cycles;
return 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. // memory regions.
void cpu_optimize_memory(struct cpu_t *cpu) { void cpu_optimize_memory(struct cpu_t *cpu) {
struct mem_t *page0 = cpu_mem_for_page(cpu, 0); struct mem_t *zp= cpu_mem_for_page(cpu, 0);
if (page0 == NULL || (page0->flags != (MEM_FLAGS_READ | MEM_FLAGS_WRITE))) { if (zp == NULL || (zp->flags != (MEM_FLAGS_READ | MEM_FLAGS_WRITE)) || zp->end < 0x1ff) {
printf("[CPU] Cannot find rw memory region that handles Page 0\n"); printf("[CPU] Cannot find rw memory region that covers 0x0000 to 0x01ff\n");
exit(1); exit(1);
} }
cpu->page0 = page0->obj + (0x0000 - page0->start);
struct mem_t *page1 = cpu_mem_for_page(cpu, 1); cpu->ram = zp->obj;
if (page1 == NULL || (page1->flags != (MEM_FLAGS_READ | MEM_FLAGS_WRITE))) { cpu->ram_size = zp->end;
printf("[CPU] Cannot find rw memory region that handles Page 1\n");
exit(1);
}
cpu->page1 = page1->obj + (0x0100 - page1->start);
} }
void cpu_strict(struct cpu_t *cpu, bool strict) { void cpu_strict(struct cpu_t *cpu, bool strict) {

View File

@ -56,8 +56,8 @@ struct cpu_t {
struct cpu_instruction_t *instructions; struct cpu_instruction_t *instructions;
uint64_t counter; uint64_t counter;
uint8_t *page0; uint8_t *ram;
uint8_t *page1; size_t ram_size;
struct ewm_lua_t *lua; struct ewm_lua_t *lua;
}; };

View File

@ -22,6 +22,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include <time.h> #include <time.h>
#include "cpu.h" #include "cpu.h"
@ -29,7 +30,7 @@
#include "mem.h" #include "mem.h"
#include "utl.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) { void test(struct cpu_t *cpu, uint8_t opcode) {
uint64_t runs[3]; uint64_t runs[3];
@ -83,7 +84,17 @@ int main(int argc, char **argv) {
cpu_add_ram_data(cpu, 0, 0xffff, malloc(0xffff)); cpu_add_ram_data(cpu, 0, 0xffff, malloc(0xffff));
cpu_reset(cpu); cpu_reset(cpu);
for (int opcode = 0; opcode <= 255; opcode++) { if (argc > 1) {
test(cpu, opcode); 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);
}
} }
} }

View File

@ -32,21 +32,21 @@
#include "utl.h" #include "utl.h"
#include "lua.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); struct cpu_t *cpu = cpu_create(model);
cpu_add_ram_file(cpu, 0x0000, rom_path); cpu_add_ram_file(cpu, 0x0000, rom_path);
cpu_reset(cpu); cpu_reset(cpu);
cpu->state.pc = start_addr; cpu->state.pc = start_addr;
#if 1 if (with_lua) {
cpu->lua = ewm_lua_create(); cpu->lua = ewm_lua_create();
ewm_cpu_init_lua(cpu, cpu->lua); ewm_cpu_init_lua(cpu, cpu->lua);
if (ewm_lua_load_script(cpu->lua, "cpu_test.lua") != 0) { 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 printf("Lua script failed to load\n"); // TODO Move errors reporting into C code
exit(1); exit(1);
}
} }
#endif
uint16_t last_pc = cpu->state.pc; 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) { int main(int argc, char **argv) {
fprintf(stderr, "TEST Running 6502 tests\n"); 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"); 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);
} }

100
src/mem.c
View File

@ -33,6 +33,10 @@
// take more time but do the right thing. // take more time but do the right thing.
uint8_t mem_get_byte(struct cpu_t *cpu, uint16_t addr) { 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; struct mem_t *mem = cpu->mem;
while (mem != NULL) { while (mem != NULL) {
if (mem->enabled && addr >= mem->start && addr <= mem->end) { 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; mem = mem->next;
} }
if (cpu->strict) {
// TODO: Signal an error about reading non-existent memory?
}
return 0; return 0;
} }
void mem_set_byte(struct cpu_t *cpu, uint16_t addr, uint8_t v) { 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; struct mem_t *mem = cpu->mem;
while (mem != NULL) { while (mem != NULL) {
if (mem->enabled && addr >= mem->start && addr <= mem->end) { 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; mem = mem->next;
} }
if (cpu->strict) {
// TODO: Signal an error about writing non-existent memory?
}
} }
// Getters // Getters
uint8_t mem_get_byte_abs(struct cpu_t *cpu, uint16_t addr) { 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) { 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); return mem_get_byte(cpu, addr + cpu->state.x);
} }
uint8_t mem_get_byte_absy(struct cpu_t *cpu, uint16_t addr) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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); return ((uint16_t) mem_get_byte(cpu, addr+1) << 8) | (uint16_t) mem_get_byte(cpu, addr);
} }
// Setters // Setters
void mem_set_byte_zpg(struct cpu_t *cpu, uint8_t addr, uint8_t v) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { void mem_set_word(struct cpu_t *cpu, uint16_t addr, uint16_t v) {

View File

@ -30,6 +30,8 @@ struct cpu_t;
typedef uint8_t (*mem_mod_t)(struct cpu_t *cpu, uint8_t b); 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); 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_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_absx(struct cpu_t *cpu, uint16_t addr);
uint8_t mem_get_byte_absy(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_indy(struct cpu_t *cpu, uint8_t addr);
uint8_t mem_get_byte_ind(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_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_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); void mem_set_byte_zpgy(struct cpu_t *cpu, uint8_t addr, uint8_t v);