diff --git a/src/Makefile b/src/Makefile index d26e205..5251191 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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) diff --git a/src/cpu.c b/src/cpu.c index c926b91..c011b0a 100644 --- a/src/cpu.c +++ b/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) { diff --git a/src/mem.c b/src/mem.c index 618a621..2f1b80a 100644 --- a/src/mem.c +++ b/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) { diff --git a/src/scr.c b/src/scr.c index 8cb3fdf..1a77009 100644 --- a/src/scr.c +++ b/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) { diff --git a/src/two.c b/src/two.c index dcf8655..d5b3164 100644 --- a/src/two.c +++ b/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; diff --git a/src/two.h b/src/two.h index 892c320..311588b 100644 --- a/src/two.h +++ b/src/two.h @@ -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;