Performance Improvements Part II (#161)

This commit is contained in:
Stefan Arentz 2017-09-23 07:45:36 -04:00 committed by GitHub
parent ab4c8e025e
commit fd6818e2ab
6 changed files with 51 additions and 129 deletions

View File

@ -23,8 +23,8 @@
UNAME := $(shell uname)
CC?=cc
CFLAGS=-std=gnu11 -O3 -Wall -Wextra -Werror -Wno-unused-parameter -I/usr/include
LDFLAGS=-L/usr/local/lib
CFLAGS=-std=gnu11 -O3 -flto -Wall -Wextra -Werror -Wno-unused-parameter -I/usr/include
LDFLAGS=-L/usr/local/lib -flto
LUA_LIBS=-llua
ifeq ($(UNAME), Linux)

View File

@ -350,20 +350,19 @@ struct mem_t *cpu_add_iom(struct cpu_t *cpu, uint16_t start, uint16_t end, void
return cpu_add_mem(cpu, mem);
}
// Call this when the memory layout changes for page 0 and 1. For
// example when those pages are bankswitched. I don't think anything
// does that right now. The Apple Language Card works in different
// memory regions.
// For now, as a good optimization, this emulator is going to assume
// that there is a memory region covering at least the first two pages
// of memory. This will probably break on the IIe where $0200 to $BFFF
// is also bank switched. But that is a problem for later.
void cpu_optimize_memory(struct cpu_t *cpu) {
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");
struct mem_t *zp = cpu_mem_for_page(cpu, 0);
if (zp == NULL || (zp->flags != (MEM_FLAGS_READ | MEM_FLAGS_WRITE)) || zp->end < 0x01ff) {
printf("[CPU] Cannot find a rw memory region that covers at least the first two pages\n");
exit(1);
}
cpu->ram = zp->obj;
cpu->ram_size = zp->end;
cpu->ram_size = zp->end + 1;
}
void cpu_strict(struct cpu_t *cpu, bool strict) {

101
src/mem.c
View File

@ -46,9 +46,12 @@ uint8_t mem_get_byte(struct cpu_t *cpu, uint16_t addr) {
}
mem = mem->next;
}
return 0;
}
extern struct ewm_two_t *two;
void mem_set_byte(struct cpu_t *cpu, uint16_t addr, uint8_t v) {
if (addr < cpu->ram_size) {
cpu->ram[addr] = v;
@ -70,129 +73,81 @@ void mem_set_byte(struct cpu_t *cpu, uint16_t addr, uint8_t v) {
// Getters
uint8_t mem_get_byte_abs(struct cpu_t *cpu, uint16_t addr) {
if (addr < cpu->ram_size) {
return cpu->ram[addr];
}
return mem_get_byte(cpu, 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 cpu->ram[addr + cpu->state.y];
return mem_get_byte(cpu, addr + cpu->state.y);
}
uint8_t mem_get_byte_zpg(struct cpu_t *cpu, uint8_t addr) {
return cpu->ram[addr];
return mem_get_byte(cpu, addr);
}
uint8_t mem_get_byte_zpgx(struct cpu_t *cpu, uint8_t addr) {
return cpu->ram[((uint16_t) addr + cpu->state.x) & 0x00ff];
return mem_get_byte(cpu, ((uint16_t) addr + cpu->state.x) & 0x00ff);
}
uint8_t mem_get_byte_zpgy(struct cpu_t *cpu, uint8_t addr) {
return cpu->ram[((uint16_t) addr + cpu->state.y) & 0x00ff];
return mem_get_byte(cpu, ((uint16_t) addr + cpu->state.y) & 0x00ff);
}
uint8_t mem_get_byte_indx(struct cpu_t *cpu, uint8_t addr) {
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);
return mem_get_byte(cpu, (((uint16_t) cpu->ram[((uint16_t)addr+1+cpu->state.x)&0x00ff] << 8) | (uint16_t) cpu->ram[((uint16_t) addr+cpu->state.x) & 0x00ff]));
}
uint8_t mem_get_byte_indy(struct cpu_t *cpu, uint8_t addr) {
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);
return mem_get_byte(cpu, (((uint16_t) cpu->ram[addr+1] << 8) | (uint16_t) cpu->ram[addr]) + cpu->state.y);
}
uint8_t mem_get_byte_ind(struct cpu_t *cpu, uint8_t addr) {
uint16_t a = *((uint16_t*) &cpu->ram[addr]);
if (a < cpu->ram_size) {
return cpu->ram[a];
}
return mem_get_byte(cpu, a);
return mem_get_byte(cpu, ((uint16_t) cpu->ram[addr+1] << 8) | (uint16_t) cpu->ram[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);
}
// Setters
void mem_set_byte_zpg(struct cpu_t *cpu, uint8_t addr, uint8_t v) {
cpu->ram[addr] = v;
}
void mem_set_byte_zpgx(struct cpu_t *cpu, uint8_t addr, uint8_t 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->ram[((uint16_t) addr + cpu->state.y) & 0x00ff] = v;
}
void mem_set_byte_abs(struct cpu_t *cpu, uint16_t addr, uint8_t v) {
if (addr < cpu->ram_size) {
cpu->ram[addr] = v;
return;
}
mem_set_byte(cpu, addr, v);
}
void mem_set_byte_zpgx(struct cpu_t *cpu, uint8_t addr, uint8_t v) {
mem_set_byte(cpu, ((uint16_t) addr + cpu->state.x) & 0x00ff, v);
}
void mem_set_byte_zpgy(struct cpu_t *cpu, uint8_t addr, uint8_t v) {
mem_set_byte(cpu, ((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);
}
void mem_set_byte_absx(struct cpu_t *cpu, uint16_t addr, uint8_t v) {
if (addr < cpu->ram_size) {
cpu->ram[addr + cpu->state.x] = v;
return;
}
mem_set_byte(cpu, addr + cpu->state.x, v);
mem_set_byte(cpu, addr+cpu->state.x, v);
}
void mem_set_byte_absy(struct cpu_t *cpu, uint16_t addr, uint8_t v) {
if (addr < cpu->ram_size) {
cpu->ram[addr + cpu->state.y] = v;
return;
}
mem_set_byte(cpu, addr + cpu->state.y, v);
mem_set_byte(cpu, addr+cpu->state.y, v);
}
void mem_set_byte_indx(struct cpu_t *cpu, uint8_t addr, uint8_t 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);
mem_set_byte(cpu, (((uint16_t) cpu->ram[((uint16_t)addr+1+cpu->state.x)&0x00ff] << 8) | (uint16_t) cpu->ram[((uint16_t) addr+cpu->state.x) & 0x00ff]), v);
}
void mem_set_byte_indy(struct cpu_t *cpu, uint8_t addr, uint8_t 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);
mem_set_byte(cpu, (((uint16_t) cpu->ram[addr+1] << 8) | (uint16_t) cpu->ram[addr]) + cpu->state.y, v);
}
void mem_set_byte_ind(struct cpu_t *cpu, uint8_t addr, uint8_t 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);
mem_set_byte(cpu, (((uint16_t) cpu->ram[addr+1] << 8) | (uint16_t) cpu->ram[addr]), v);
}
void mem_set_word(struct cpu_t *cpu, uint16_t addr, uint16_t v) {

View File

@ -40,7 +40,7 @@ static int txt_line_offsets[24] = {
static inline void scr_render_character(struct scr_t *scr, int row, int column, bool flash) {
uint16_t base = (scr->two->screen_page == EWM_A2P_SCREEN_PAGE1) ? 0x0400 : 0x0800;
uint8_t c = scr->two->screen_txt_data[((txt_line_offsets[row] + base) + column) - 0x0400];
uint8_t c = scr->two->cpu->ram[((txt_line_offsets[row] + base) + column)];
if (scr->chr->characters[c] != NULL) {
SDL_Rect dst;
dst.x = column * 21;
@ -101,7 +101,7 @@ static SDL_Color lores_colors[16] = {
static inline void scr_render_lores_block(struct scr_t *scr, int row, int column) {
uint16_t base = (scr->two->screen_page == EWM_A2P_SCREEN_PAGE1) ? 0x0400 : 0x0800;
uint8_t block = scr->two->screen_txt_data[((txt_line_offsets[row] + base) + column) - 0x0400];
uint8_t block = scr->two->cpu->ram[((txt_line_offsets[row] + base) + column)];
if (block != 0) {
SDL_Rect dst;
dst.x = column * 21;
@ -147,8 +147,8 @@ static inline void scr_render_lgr_screen(struct scr_t *scr, bool flash) {
// Hires rendering
static uint16_t hgr_page_offsets[2] = {
0x0000, // $0000 in our buffer, $2000 in emulator
0x2000 // $2000 in our buffer, $4000 in emulator
0x2000, // $0000 in our buffer, $2000 in emulator
0x4000 // $2000 in our buffer, $4000 in emulator
};
static uint16_t hgr_line_offsets[192] = {
@ -192,7 +192,7 @@ static SDL_Color hgr_colors[16] = {
inline static void scr_render_hgr_line_green(struct scr_t *scr, int line, uint16_t line_base) {
int x = 0;
for (int i = 0; i < 40; i++) {
uint8_t c = scr->two->screen_hgr_data[line_base + i];
uint8_t c = scr->two->cpu->ram[line_base + i];
for (int j = 0; j < 7; j++) {
SDL_Rect dst;
dst.x = x * 3;
@ -216,7 +216,7 @@ inline static void scr_render_hgr_line_color(struct scr_t *scr, int line, uint16
int pixels[280], x = 0;
for (int i = 0; i < 40; i++) {
uint8_t c = scr->two->screen_hgr_data[line_base + i];
uint8_t c = scr->two->cpu->ram[line_base + i];
for (int j = 0; j < 7; j++) {
if (c & (1 << j)) {
if (x % 2 == 0) {

View File

@ -73,6 +73,7 @@
static uint8_t ewm_two_iom_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) {
struct ewm_two_t *two = (struct ewm_two_t*) mem->obj;
//printf("ewm_two_iom_read(%x)\n", addr);
switch (addr) {
case EWM_A2P_SS_KBD:
return two->key;
@ -181,6 +182,7 @@ static uint8_t ewm_two_iom_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t a
static void ewm_two_iom_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, uint8_t b) {
struct ewm_two_t *two = (struct ewm_two_t*) mem->obj;
//printf("ewm_two_iom_write(%x)\n", addr);
switch (addr) {
case EWM_A2P_SS_KBDSTRB:
@ -251,33 +253,14 @@ static void ewm_two_iom_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t add
}
}
static uint8_t ewm_two_screen_txt_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) {
struct ewm_two_t *two = (struct ewm_two_t*) mem->obj;
return two->screen_txt_data[addr - mem->start];
}
static void ewm_two_screen_txt_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, uint8_t b) {
struct ewm_two_t *two = (struct ewm_two_t*) mem->obj;
two->screen_txt_data[addr - mem->start] = b;
two->screen_dirty = true;
}
static uint8_t ewm_two_screen_hgr_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) {
struct ewm_two_t *two = (struct ewm_two_t*) mem->obj;
return two->screen_hgr_data[addr - mem->start];
}
static void ewm_two_screen_hgr_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, uint8_t b) {
struct ewm_two_t *two = (struct ewm_two_t*) mem->obj;
two->screen_hgr_data[addr - mem->start] = b;
two->screen_dirty = true;
}
static int ewm_two_init(struct ewm_two_t *two, int type, SDL_Renderer *renderer, SDL_Joystick *joystick) {
memset(two, 0, sizeof(struct ewm_two_t));
two->type = type;
two->lua_key_down_fn = LUA_NOREF;
two->lua_key_up_fn = LUA_NOREF;
switch (type) {
case EWM_TWO_TYPE_APPLE2: {
return -1; // TODO
@ -288,7 +271,7 @@ static int ewm_two_init(struct ewm_two_t *two, int type, SDL_Renderer *renderer,
case EWM_TWO_TYPE_APPLE2PLUS: {
two->cpu = cpu_create(EWM_CPU_MODEL_6502);
two->ram = cpu_add_ram(two->cpu, 0x0000, 48 * 1024);
two->ram = cpu_add_ram(two->cpu, 0x0000, 0xbfff);
two->roms[0] = cpu_add_rom_file(two->cpu, 0xd000, "rom/341-0011.bin"); // AppleSoft BASIC D000
two->roms[1] = cpu_add_rom_file(two->cpu, 0xd800, "rom/341-0012.bin"); // AppleSoft BASIC D800
two->roms[2] = cpu_add_rom_file(two->cpu, 0xe000, "rom/341-0013.bin"); // AppleSoft BASIC E000
@ -324,14 +307,6 @@ static int ewm_two_init(struct ewm_two_t *two, int type, SDL_Renderer *renderer,
}
}
// TODO Introduce ewm_scr_t that captures everything related to the apple 2 screen so that it can be re-used?
two->screen_txt_data = malloc(2 * 1024);
two->screen_txt_iom = cpu_add_iom(two->cpu, 0x0400, 0x0bff, two, ewm_two_screen_txt_read, ewm_two_screen_txt_write);
two->screen_hgr_data = malloc(16 * 1024);
two->screen_hgr_iom = cpu_add_iom(two->cpu, 0x2000, 0x5fff, two, ewm_two_screen_hgr_read, ewm_two_screen_hgr_write);
two->joystick = joystick;
return 0;
@ -916,6 +891,7 @@ int ewm_two_main(int argc, char **argv) {
// the second half of the frames we draw each second. The
// latter because that is when we update flashing text.
two->screen_dirty = 1;
if (two->screen_dirty || (phase == 0) || (phase == (fps / 2))) {
ewm_scr_update(two->scr, phase, fps);
two->screen_dirty = false;

View File

@ -70,14 +70,6 @@ struct ewm_two_t {
struct mem_t *roms[6];
struct mem_t *iom;
// TODO Should all this move into scr_t
uint8_t *screen_txt_data;
struct mem_t *screen_txt_iom;
uint8_t *screen_hgr_data;
struct mem_t *screen_hgr_iom;
int screen_hgr_page;
int screen_mode;
int screen_graphics_mode;
int screen_graphics_style;