mirror of
https://github.com/st3fan/ewm.git
synced 2025-01-03 09:29:45 +00:00
Performance improvements (#160)
This commit is contained in:
parent
58bb3d7739
commit
a4324737d5
85
src/cpu.c
85
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) {
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
100
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) {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user