mirror of
https://github.com/st3fan/ewm.git
synced 2025-01-03 09:29:45 +00:00
Performance Improvements Part II (#161)
This commit is contained in:
parent
ab4c8e025e
commit
fd6818e2ab
@ -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)
|
||||
|
17
src/cpu.c
17
src/cpu.c
@ -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
101
src/mem.c
@ -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) {
|
||||
|
12
src/scr.c
12
src/scr.c
@ -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) {
|
||||
|
38
src/two.c
38
src/two.c
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user