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.
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) {

View File

@ -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;
};

View File

@ -22,6 +22,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#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);
}
}
}

View File

@ -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);
}

100
src/mem.c
View File

@ -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) {

View File

@ -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);