diff --git a/src/Makefile b/src/Makefile index fa6e991..097087b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -25,7 +25,7 @@ CFLAGS=-std=c11 -O0 -Wpedantic -Wall -Wshadow -Werror -Wshadow -Wno-gnu-binary- LDFLAGS=-g -L/usr/local/lib EWM_EXECUTABLE=ewm -EWM_SOURCES=cpu.c ins.c pia.c mem.c ewm.c fmt.c two.c scr.c dsk.c chr.c alc.c one.c tty.c +EWM_SOURCES=cpu.c ins.c pia.c mem.c ewm.c fmt.c two.c scr.c dsk.c chr.c alc.c one.c tty.c sma.c EWM_OBJECTS=$(EWM_SOURCES:.c=.o) EWM_LIBS=-lSDL2 diff --git a/src/cpu.h b/src/cpu.h index 6b93dc5..c69f6ec 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -56,6 +56,15 @@ struct cpu_t { uint64_t counter; }; +#define EWM_CPU_VECTORS_BASE (0xfffa) +#define EWM_CPU_VECTORS_SIZE (6) + +struct cpu_vectors_t { + uint16_t rst; + uint16_t nmi; + uint16_t irq; +}; + #define MEM_FLAGS_READ 0x01 #define MEM_FLAGS_WRITE 0x02 diff --git a/src/ewm.c b/src/ewm.c index 79b02d7..0c989ed 100644 --- a/src/ewm.c +++ b/src/ewm.c @@ -22,13 +22,17 @@ #include "one.h" #include "two.h" +#include "sma.h" int main(int argc, char **argv) { - if (strcmp(argv[1], "one") == 0) { - return ewm_one_main(argc-1, &argv[1]); + if (argc > 1) { + if (strcmp(argv[1], "one") == 0) { + return ewm_one_main(argc-1, &argv[1]); + } + if (strcmp(argv[1], "two") == 0) { + return ewm_two_main(argc-1, &argv[1]); + } + } else { + return ewm_sma_main(argc-1, &argv[1]); } - if (strcmp(argv[1], "two") == 0) { - return ewm_two_main(argc-1, &argv[1]); - } - return 1; } diff --git a/src/scr.c b/src/scr.c index 7a60bc0..c2c5685 100644 --- a/src/scr.c +++ b/src/scr.c @@ -39,8 +39,8 @@ static int txt_line_offsets[24] = { }; static inline void scr_render_character(struct scr_t *scr, int row, int column) { - 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]; + uint16_t base = (scr->screen_page == EWM_A2P_SCREEN_PAGE1) ? 0x0400 : 0x0800; + uint8_t c = scr->screen_txt_data[((txt_line_offsets[row] + base) + column) - 0x0400]; if (scr->chr->characters[c] != NULL) { SDL_Rect dst; dst.x = column * 21; @@ -86,8 +86,8 @@ 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]; + uint16_t base = (scr->screen_page == EWM_A2P_SCREEN_PAGE1) ? 0x0400 : 0x0800; + uint8_t block = scr->screen_txt_data[((txt_line_offsets[row] + base) + column) - 0x0400]; if (block != 0) { SDL_Rect dst; dst.x = column * 21; @@ -111,7 +111,7 @@ static inline void scr_render_lores_block(struct scr_t *scr, int row, int column } static inline void scr_render_lgr_screen(struct scr_t *scr) { - bool mixed = (scr->two->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED); + bool mixed = (scr->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED); // Render graphics int rows = mixed ? 20 : 24; @@ -178,7 +178,7 @@ static SDL_Color hgr_colors[16] = { static void inline 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->screen_hgr_data[line_base + i]; for (int j = 0; j < 7; j++) { SDL_Rect dst; dst.x = x * 3; @@ -202,7 +202,7 @@ static void inline 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->screen_hgr_data[line_base + i]; for (int j = 0; j < 7; j++) { if (c & (1 << j)) { if (x % 2 == 0) { @@ -250,8 +250,8 @@ static void inline scr_render_hgr_line_color(struct scr_t *scr, int line, uint16 static void inline scr_render_hgr_screen(struct scr_t *scr) { // Render graphics - int lines = (scr->two->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED) ? 160 : 192; - uint16_t hgr_base = hgr_page_offsets[scr->two->screen_page]; + int lines = (scr->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED) ? 160 : 192; + uint16_t hgr_base = hgr_page_offsets[scr->screen_page]; for (int line = 0; line < lines; line++) { uint16_t line_base = hgr_base + hgr_line_offsets[line]; if (scr->color_scheme == EWM_SCR_COLOR_SCHEME_COLOR) { @@ -262,7 +262,7 @@ static void inline scr_render_hgr_screen(struct scr_t *scr) { } // Render bottom 4 lines of text - if (scr->two->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED) { + if (scr->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED) { for (int row = 20; row < 24; row++) { for (int column = 0; column < 40; column++) { scr_render_character(scr, row, column); @@ -271,23 +271,53 @@ static void inline scr_render_hgr_screen(struct scr_t *scr) { } } +static uint8_t ewm_scr_screen_txt_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) { + struct scr_t *scr = (struct scr_t*) mem->obj; + return scr->screen_txt_data[addr - mem->start]; +} + +static void ewm_scr_screen_txt_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, uint8_t b) { + struct scr_t *scr = (struct scr_t*) mem->obj; + scr->screen_txt_data[addr - mem->start] = b; + scr->screen_dirty = true; +} + +static uint8_t ewm_scr_screen_hgr_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) { + struct scr_t *scr = (struct scr_t*) mem->obj; + return scr->screen_hgr_data[addr - mem->start]; +} + +static void ewm_scr_screen_hgr_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, uint8_t b) { + struct scr_t *scr = (struct scr_t*) mem->obj; + scr->screen_hgr_data[addr - mem->start] = b; + scr->screen_dirty = true; +} + // TODO This is the only actual API exposed -int ewm_scr_init(struct scr_t *scr, struct ewm_two_t *two, SDL_Renderer *renderer) { +static int ewm_scr_init(struct scr_t *scr, struct cpu_t *cpu, SDL_Renderer *renderer) { memset(scr, 0x00, sizeof(struct scr_t)); - scr->two = two; + scr->renderer = renderer; + scr->chr = ewm_chr_create("rom/3410036.bin", EWM_CHR_ROM_TYPE_2716, renderer); if (scr->chr == NULL) { fprintf(stderr, "[SCR] Failed to initialize character generator\n"); return -1; } + + scr->screen_txt_data = malloc(2 * 1024); + scr->screen_txt_iom = cpu_add_iom(cpu, 0x0400, 0x0bff, scr, ewm_scr_screen_txt_read, ewm_scr_screen_txt_write); + + scr->screen_hgr_data = malloc(16 * 1024); + scr->screen_hgr_iom = cpu_add_iom(cpu, 0x2000, 0x5fff, scr, ewm_scr_screen_hgr_read, ewm_scr_screen_hgr_write); + return 0; } -struct scr_t *ewm_scr_create(struct ewm_two_t *two, SDL_Renderer *renderer) { +struct scr_t *ewm_scr_create(struct cpu_t *cpu, SDL_Renderer *renderer) { struct scr_t *scr = malloc(sizeof(struct scr_t)); - if (ewm_scr_init(scr, two, renderer) != 0) { + if (ewm_scr_init(scr, cpu, renderer) != 0) { free(scr); scr = NULL; } @@ -302,12 +332,12 @@ void ewm_scr_update(struct scr_t *scr) { SDL_SetRenderDrawColor(scr->renderer, 0, 0, 0, 255); SDL_RenderClear(scr->renderer); - switch (scr->two->screen_mode) { + switch (scr->screen_mode) { case EWM_A2P_SCREEN_MODE_TEXT: scr_render_txt_screen(scr); break; case EWM_A2P_SCREEN_MODE_GRAPHICS: - switch (scr->two->screen_graphics_mode) { + switch (scr->screen_graphics_mode) { case EWM_A2P_SCREEN_GRAPHICS_MODE_LGR: scr_render_lgr_screen(scr); break; diff --git a/src/scr.h b/src/scr.h index 31ee3ea..065c4b7 100644 --- a/src/scr.h +++ b/src/scr.h @@ -32,18 +32,28 @@ struct ewm_two_t; struct ewm_chr_t; -// The 'scr' object represents the screen. It renders the contents of -// the machine. It has pluggable renders. +// The 'scr' object represents the Apple ][ screen. It renders the +// contents of the machine. struct scr_t { - struct ewm_two_t *two; SDL_Renderer *renderer; struct ewm_chr_t *chr; int color_scheme; + + uint8_t *screen_txt_data; + struct mem_t *screen_txt_iom; + + uint8_t *screen_hgr_data; + struct mem_t *screen_hgr_iom; + + int screen_mode; + int screen_graphics_mode; + int screen_graphics_style; + int screen_page; + int screen_dirty; }; -struct scr_t *ewm_scr_create(struct ewm_two_t *two, SDL_Renderer *renderer); -int ewm_scr_init(struct scr_t *scr, struct ewm_two_t *two, SDL_Renderer *renderer); +struct scr_t *ewm_scr_create(struct cpu_t *cpu, SDL_Renderer *renderer); void ewm_scr_destroy(struct scr_t *scr); void ewm_scr_update(struct scr_t *scr); void ewm_scr_set_color_scheme(struct scr_t *scr, int color_scheme); diff --git a/src/scr_test.c b/src/scr_test.c index a410fce..dd79ed7 100644 --- a/src/scr_test.c +++ b/src/scr_test.c @@ -28,62 +28,62 @@ #include "two.h" #include "scr.h" -typedef void (*test_setup_t)(struct scr_t *scr); -typedef void (*test_run_t)(struct scr_t *scr); +typedef void (*test_setup_t)(struct ewm_two_t *two); +typedef void (*test_run_t)(struct ewm_two_t *two); -void txt_full_refresh_setup(struct scr_t *scr) { - scr->two->screen_mode = EWM_A2P_SCREEN_MODE_TEXT; - scr->two->screen_page = EWM_A2P_SCREEN_PAGE1; +void txt_full_refresh_setup(struct ewm_two_t *two) { + two->scr->screen_mode = EWM_A2P_SCREEN_MODE_TEXT; + two->scr->screen_page = EWM_A2P_SCREEN_PAGE1; for (uint16_t a = 0x0400; a <= 0x0bff; a++) { uint8_t v = 0xa0 + (random() % 64); - mem_set_byte(scr->two->cpu, a, v); + mem_set_byte(two->cpu, a, v); } } -void txt_full_refresh_test(struct scr_t *scr) { - ewm_scr_update(scr); +void txt_full_refresh_test(struct ewm_two_t *two) { + ewm_scr_update(two->scr); } -void lgr_full_refresh_setup(struct scr_t *scr) { - scr->two->screen_mode = EWM_A2P_SCREEN_MODE_GRAPHICS; - scr->two->screen_page = EWM_A2P_SCREEN_PAGE1; - scr->two->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_LGR; - scr->two->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_FULL; +void lgr_full_refresh_setup(struct ewm_two_t *two) { + two->scr->screen_mode = EWM_A2P_SCREEN_MODE_GRAPHICS; + two->scr->screen_page = EWM_A2P_SCREEN_PAGE1; + two->scr->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_LGR; + two->scr->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_FULL; for (uint16_t a = 0x0400; a <= 0x0bff; a++) { uint8_t v = ((random() % 16) << 4) | (random() % 16); - mem_set_byte(scr->two->cpu, a, v); + mem_set_byte(two->cpu, a, v); } } -void lgr_full_refresh_test(struct scr_t *scr) { - ewm_scr_update(scr); +void lgr_full_refresh_test(struct ewm_two_t *two) { + ewm_scr_update(two->scr); } -void hgr_full_refresh_setup(struct scr_t *scr) { - scr->two->screen_mode = EWM_A2P_SCREEN_MODE_GRAPHICS; - scr->two->screen_page = EWM_A2P_SCREEN_PAGE1; - scr->two->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_HGR; - scr->two->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_FULL; +void hgr_full_refresh_setup(struct ewm_two_t *two) { + two->scr->screen_mode = EWM_A2P_SCREEN_MODE_GRAPHICS; + two->scr->screen_page = EWM_A2P_SCREEN_PAGE1; + two->scr->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_HGR; + two->scr->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_FULL; for (uint16_t a = 0x2000; a <= 0x5fff; a++) { - mem_set_byte(scr->two->cpu, a, random()); + mem_set_byte(two->cpu, a, random()); } } -void hgr_full_refresh_test(struct scr_t *scr) { - ewm_scr_update(scr); +void hgr_full_refresh_test(struct ewm_two_t *two) { + ewm_scr_update(two->scr); } -void test(struct scr_t *scr, char *name, test_setup_t test_setup, test_run_t test_run) { - test_setup(scr); +void test(struct ewm_two_t *two, char *name, test_setup_t test_setup, test_run_t test_run) { + test_setup(two); Uint64 start = SDL_GetPerformanceCounter(); for (int i = 0; i < 1000; i++) { - test_run(scr); - SDL_RenderPresent(scr->renderer); + test_run(two); + SDL_RenderPresent(two->scr->renderer); } Uint64 now = SDL_GetPerformanceCounter(); double total = (double)((now - start)*1000) / SDL_GetPerformanceFrequency(); @@ -118,9 +118,9 @@ int main() { struct ewm_two_t *two = ewm_two_create(EWM_TWO_TYPE_APPLE2PLUS, renderer, NULL); - test(two->scr, "txt_full_refresh", txt_full_refresh_setup, txt_full_refresh_test); - test(two->scr, "lgr_full_refresh", lgr_full_refresh_setup, lgr_full_refresh_test); - test(two->scr, "hgr_full_refresh", hgr_full_refresh_setup, hgr_full_refresh_test); + test(two, "txt_full_refresh", txt_full_refresh_setup, txt_full_refresh_test); + test(two, "lgr_full_refresh", lgr_full_refresh_setup, lgr_full_refresh_test); + test(two, "hgr_full_refresh", hgr_full_refresh_setup, hgr_full_refresh_test); // Destroy DSL things diff --git a/src/sma.c b/src/sma.c new file mode 100644 index 0000000..d8871c8 --- /dev/null +++ b/src/sma.c @@ -0,0 +1,207 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Stefan Arentz - http://github.com/st3fan/ewm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +#include + +#include "cpu.h" +#include "mem.h" +#include "tty.h" +#include "sma.h" + +#define EWM_SMA_RAM_BASE (0) +#define EWM_SMA_RAM_SIZE (16 * 1024) +#define EWM_SMA_ROM_BASE (EWM_SMA_RAM_BASE + EWM_SMA_RAM_SIZE - 1) +#define EWM_SMA_ROM_SIZE (4 * 1024) +#define EWM_SMA_TTY_BASE (EWM_SMA_ROM_BASE + EWM_SMA_ROM_SIZE - 1) +#define EWM_SMA_TTY_SIZE (1 * 1024) + +static bool ewm_sma_poll_event(struct ewm_sma_t *sma, SDL_Window *window) { + SDL_Event event; + while (SDL_PollEvent(&event) != 0) { + switch (event.type) { + case SDL_QUIT: + return false; + + case SDL_WINDOWEVENT: + sma->tty->screen_dirty = true; + break; + + case SDL_KEYDOWN: + if (event.key.keysym.mod & KMOD_GUI) { + switch (event.key.keysym.sym) { + case SDLK_ESCAPE: + fprintf(stderr, "[SDL] Reset\n"); + cpu_reset(sma->cpu); + break; + case SDLK_RETURN: + if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) { + SDL_SetWindowFullscreen(window, 0); + } else { + SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN); + } + break; + } + } + break; + + case SDL_TEXTINPUT: + if (strlen(event.text.text) == 1) { + sma->key = toupper(event.text.text[0]) | 0x80; + } + break; + } + } + return true; +} + +static bool ewm_sma_step_cpu(struct ewm_sma_t *sma, int cycles) { + while (true) { + int ret = cpu_step(sma->cpu); + if (ret < 0) { + switch (ret) { + case EWM_CPU_ERR_UNIMPLEMENTED_INSTRUCTION: + fprintf(stderr, "CPU: Exited because of unimplemented instructions 0x%.2x at 0x%.4x\n", + mem_get_byte(sma->cpu, sma->cpu->state.pc), sma->cpu->state.pc); + break; + case EWM_CPU_ERR_STACK_OVERFLOW: + fprintf(stderr, "CPU: Exited because of stack overflow at 0x%.4x\n", sma->cpu->state.pc); + break; + case EWM_CPU_ERR_STACK_UNDERFLOW: + fprintf(stderr, "CPU: Exited because of stack underflow at 0x%.4x\n", sma->cpu->state.pc); + break; + } + cpu_nmi(sma->cpu); + } + cycles -= ret; + if (cycles <= 0) { + break; + } + } + return true; +} + +static uint8_t ewm_sma_tty_buffer_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) { + struct ewm_sma_t *sma = (struct ewm_sma_t*) mem->obj; + return sma->tty->screen_buffer[addr - mem->start]; +} + +static void ewm_sma_tty_buffer_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, uint8_t b) { + struct ewm_sma_t *sma = (struct ewm_sma_t*) mem->obj; + sma->tty->screen_buffer[addr - mem->start] = b; + sma->tty->screen_dirty = true; +} + +static struct cpu_vectors_t ewm_sma_cpu_vectors = { 0, 0, 0 }; + +static int ewm_sma_init(struct ewm_sma_t *sma, SDL_Renderer *renderer) { + memset(sma, 0, sizeof(struct ewm_sma_t)); + + sma->cpu = cpu_create(EWM_CPU_MODEL_6502); + + sma->ram = cpu_add_ram(sma->cpu, EWM_SMA_RAM_BASE, EWM_SMA_RAM_BASE + EWM_SMA_RAM_SIZE - 1); + sma->rom = cpu_add_rom_file(sma->cpu, EWM_SMA_ROM_BASE, "rom/sma.bin"); + sma->rom = cpu_add_rom_data(sma->cpu, EWM_CPU_VECTORS_BASE, EWM_CPU_VECTORS_BASE + EWM_CPU_VECTORS_SIZE - 1, + (uint8_t*) &ewm_sma_cpu_vectors); + sma->tty = ewm_tty_create(renderer); + if (sma->tty == NULL) { + fprintf(stderr, "[SMA] Could not create TTY\n"); + return -1; + } + sma->tty_iom = cpu_add_iom(sma->cpu, EWM_SMA_TTY_BASE, EWM_SMA_TTY_BASE + EWM_SMA_TTY_SIZE - 1, + sma->tty, ewm_sma_tty_buffer_read, ewm_sma_tty_buffer_write); + + + return 0; +} + +static struct ewm_sma_t *ewm_sma_create(SDL_Renderer *renderer) { + struct ewm_sma_t *sma = malloc(sizeof(struct ewm_sma_t)); + if (ewm_sma_init(sma, renderer) != 0) { + free(sma); + sma = NULL; + } + return sma; +} + +int ewm_sma_main(int argc, char **argv) { + // Initialize SDL + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER) < 0) { + fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + + SDL_Window *window = SDL_CreateWindow("EWM v0.1 / System Management Agent", 400, 60, 280*3, 192*3, SDL_WINDOW_SHOWN); + if (window == NULL) { + fprintf(stderr, "Failed create window: %s\n", SDL_GetError()); + exit(1); + } + + SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + if (renderer == NULL) { + fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); + exit(1); + } + + SDL_RenderSetLogicalSize(renderer, 280*3, 192*3); + + // Create the System Management Agent + + struct ewm_sma_t *sma = ewm_sma_create(renderer); + cpu_reset(sma->cpu); + + // + + SDL_StartTextInput(); + + Uint32 ticks = SDL_GetTicks(); + + while (true) { + if (!ewm_sma_poll_event(sma, window)) { + break; + } + + if ((SDL_GetTicks() - ticks) >= (1000 / 50)) { + if (!ewm_sma_step_cpu(sma, 1000000 / 50)) { + break; + } + + if (sma->tty->screen_dirty) { + ewm_tty_refresh(sma->tty); + sma->tty->screen_dirty = false; + SDL_RenderPresent(sma->tty->renderer); + } + + ticks = SDL_GetTicks(); + } + } + + // Destroy SDL + + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); + + return 0; +} diff --git a/src/sma.h b/src/sma.h new file mode 100644 index 0000000..4770da0 --- /dev/null +++ b/src/sma.h @@ -0,0 +1,44 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Stefan Arentz - http://github.com/st3fan/ewm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef EWM_SMA_H +#define EWM_SMA_H + +#include +#include + +struct cpu_t; +struct scr_t; +struct mem_t; + +struct ewm_sma_t { + struct cpu_t *cpu; + struct mem_t *ram; + struct mem_t *rom; + struct ewm_tty_t *tty; + struct mem_t *tty_iom; + uint8_t key; +}; + +int ewm_sma_main(int argc, char **argv); + +#endif // EWM_SMA_H diff --git a/src/two.c b/src/two.c index f4480c1..30a93db 100644 --- a/src/two.c +++ b/src/two.c @@ -79,39 +79,39 @@ static uint8_t ewm_two_iom_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t a return 0x00; case EWM_A2P_SS_SCREEN_MODE_GRAPHICS: - two->screen_mode = EWM_A2P_SCREEN_MODE_GRAPHICS; - two->screen_dirty = true; + two->scr->screen_mode = EWM_A2P_SCREEN_MODE_GRAPHICS; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_SCREEN_MODE_TEXT: - two->screen_mode = EWM_A2P_SCREEN_MODE_TEXT; - two->screen_dirty = true; + two->scr->screen_mode = EWM_A2P_SCREEN_MODE_TEXT; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_GRAPHICS_MODE_LGR: - two->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_LGR; - two->screen_dirty = true; + two->scr->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_LGR; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_GRAPHICS_MODE_HGR: - two->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_HGR; - two->screen_dirty = true; + two->scr->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_HGR; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_GRAPHICS_STYLE_FULL: - two->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_FULL; - two->screen_dirty = true; + two->scr->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_FULL; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_GRAPHICS_STYLE_MIXED: - two->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED; - two->screen_dirty = true; + two->scr->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_SCREEN_PAGE1: - two->screen_page = EWM_A2P_SCREEN_PAGE1; - two->screen_dirty = true; + two->scr->screen_page = EWM_A2P_SCREEN_PAGE1; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_SCREEN_PAGE2: - two->screen_page = EWM_A2P_SCREEN_PAGE2; - two->screen_dirty = true; + two->scr->screen_page = EWM_A2P_SCREEN_PAGE2; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_SPKR: @@ -190,39 +190,39 @@ static void ewm_two_iom_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t add break; case EWM_A2P_SS_SCREEN_MODE_GRAPHICS: - two->screen_mode = EWM_A2P_SCREEN_MODE_GRAPHICS; - two->screen_dirty = true; + two->scr->screen_mode = EWM_A2P_SCREEN_MODE_GRAPHICS; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_SCREEN_MODE_TEXT: - two->screen_mode = EWM_A2P_SCREEN_MODE_TEXT; - two->screen_dirty = true; + two->scr->screen_mode = EWM_A2P_SCREEN_MODE_TEXT; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_GRAPHICS_MODE_LGR: - two->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_LGR; - two->screen_dirty = true; + two->scr->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_LGR; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_GRAPHICS_MODE_HGR: - two->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_HGR; - two->screen_dirty = true; + two->scr->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_HGR; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_GRAPHICS_STYLE_FULL: - two->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_FULL; - two->screen_dirty = true; + two->scr->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_FULL; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_GRAPHICS_STYLE_MIXED: - two->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED; - two->screen_dirty = true; + two->scr->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_SCREEN_PAGE1: - two->screen_page = EWM_A2P_SCREEN_PAGE1; - two->screen_dirty = true; + two->scr->screen_page = EWM_A2P_SCREEN_PAGE1; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_SCREEN_PAGE2: - two->screen_page = EWM_A2P_SCREEN_PAGE2; - two->screen_dirty = true; + two->scr->screen_page = EWM_A2P_SCREEN_PAGE2; + two->scr->screen_dirty = true; break; case EWM_A2P_SS_SETAN0: @@ -249,28 +249,6 @@ 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)); @@ -306,7 +284,7 @@ static int ewm_two_init(struct ewm_two_t *two, int type, SDL_Renderer *renderer, return -1; } - two->scr = ewm_scr_create(two, renderer); + two->scr = ewm_scr_create(two->cpu, renderer); if (two->scr == NULL) { fprintf(stderr, "[TWO] Could not create Screen\n"); return -1; @@ -323,12 +301,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; @@ -361,7 +333,7 @@ static bool ewm_two_poll_event(struct ewm_two_t *two, SDL_Window *window) { // T return false; case SDL_WINDOWEVENT: - two->screen_dirty = true; + two->scr->screen_dirty = true; break; case SDL_CONTROLLERBUTTONDOWN: @@ -595,9 +567,9 @@ int ewm_two_main(int argc, char **argv) { break; } - if (two->screen_dirty) { + if (two->scr->screen_dirty) { ewm_scr_update(two->scr); - two->screen_dirty = false; + two->scr->screen_dirty = false; SDL_RenderPresent(two->scr->renderer); } diff --git a/src/two.h b/src/two.h index b5e5545..ff0a110 100644 --- a/src/two.h +++ b/src/two.h @@ -64,20 +64,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; - int screen_page; - int screen_dirty; - uint8_t key; uint8_t buttons[EWM_A2P_BUTTON_COUNT];