Fixes #64 - Refactor Rendering Code

This commit is contained in:
Stefan Arentz 2016-12-07 16:21:23 -10:00
parent 3f939d41a9
commit b0a87bc29f
15 changed files with 638 additions and 329 deletions

View File

@ -21,11 +21,11 @@
# SOFTWARE.
CC=cc
CFLAGS=-std=c11 -O0 -Wpedantic -Wall -Wshadow -Werror -Wshadow -Wno-gnu-binary-literal -g
CFLAGS=-std=c11 -O3 -Wpedantic -Wall -Wshadow -Werror -Wshadow -Wno-gnu-binary-literal -g
LDFLAGS=-g -L/usr/local/lib
EWM_EXECUTABLE=ewm
EWM_SOURCES=cpu.c ins.c pia.c mem.c ewm.c fmt.c a2p.c scr.c dsk.c chr.c alc.c
EWM_SOURCES=cpu.c ins.c pia.c mem.c ewm.c fmt.c a2p.c scr.c dsk.c chr.c alc.c sdl.c
EWM_OBJECTS=$(EWM_SOURCES:.c=.o)
EWM_LIBS=-lcurses -lSDL2
@ -34,10 +34,15 @@ CPU_TEST_SOURCES=cpu.c ins.c mem.c fmt.c cpu_test.c
CPU_TEST_OBJECTS=$(CPU_TEST_SOURCES:.c=.o)
CPU_TEST_LIBS=
all: $(EWM_SOURCES) $(EWM_EXECUTABLE) $(CPU_TEST_SOURCES) $(CPU_TEST_EXECUTABLE)
SCR_TEST_EXECUTABLE=scr_test
SCR_TEST_SOURCES=cpu.c ins.c mem.c fmt.c a2p.c scr.c dsk.c chr.c alc.c sdl.c scr_test.c
SCR_TEST_OBJECTS=$(SCR_TEST_SOURCES:.c=.o)
SCR_TEST_LIBS=-lSDL2
all: $(EWM_SOURCES) $(EWM_EXECUTABLE) $(CPU_TEST_SOURCES) $(CPU_TEST_EXECUTABLE) $(SCR_TEST_EXECUTABLE)
clean:
rm -f $(EWM_OBJECTS) $(EWM_EXECUTABLE) $(CPU_TEST_OBJECTS) $(CPU_TEST_EXECUTABLE)
rm -f $(EWM_OBJECTS) $(EWM_EXECUTABLE) $(CPU_TEST_OBJECTS) $(CPU_TEST_EXECUTABLE) $(SCR_TEST_OBJECTS) $(SCR_TEST_EXECUTABLE)
$(EWM_EXECUTABLE): $(EWM_OBJECTS)
$(CC) $(LDFLAGS) $(EWM_OBJECTS) $(EWM_LIBS) -o $@
@ -45,5 +50,8 @@ $(EWM_EXECUTABLE): $(EWM_OBJECTS)
$(CPU_TEST_EXECUTABLE): $(CPU_TEST_OBJECTS)
$(CC) $(LDFLAGS) $(CPU_TEST_OBJECTS) $(CPU_TEST_LIBS) -o $@
$(SCR_TEST_EXECUTABLE): $(SCR_TEST_OBJECTS)
$(CC) $(LDFLAGS) $(SCR_TEST_OBJECTS) $(SCR_TEST_LIBS) -o $@
.c.o:
$(CC) $(CFLAGS) $< -c -o $@

37
a2p.c
View File

@ -142,32 +142,55 @@ void a2p_screen_hgr_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, u
a2p->screen_dirty = true;
}
void a2p_init(struct a2p_t *a2p, struct cpu_t *cpu) {
int a2p_init(struct a2p_t *a2p, struct cpu_t *cpu) {
memset(a2p, 0x00, sizeof(struct a2p_t));
a2p->cpu = cpu;
a2p->ram = cpu_add_ram(cpu, 0x0000, 48 * 1024);
a2p->rom = cpu_add_rom_file(cpu, 0xd000, "roms/341-0011.bin"); // AppleSoft BASIC D000
a2p->rom = cpu_add_rom_file(cpu, 0xd800, "roms/341-0012.bin"); // AppleSoft BASIC D800
a2p->rom = cpu_add_rom_file(cpu, 0xe000, "roms/341-0013.bin"); // AppleSoft BASIC E000
a2p->rom = cpu_add_rom_file(cpu, 0xe800, "roms/341-0014.bin"); // AppleSoft BASIC E800
a2p->rom = cpu_add_rom_file(cpu, 0xf000, "roms/341-0015.bin"); // AppleSoft BASIC E800
a2p->rom = cpu_add_rom_file(cpu, 0xf800, "roms/341-0020.bin"); // AppleSoft BASIC Autostart Monitor F8000
a2p->ram->description = "ram/a2p/$0000";
a2p->roms[0] = cpu_add_rom_file(cpu, 0xd000, "roms/341-0011.bin"); // AppleSoft BASIC D000
a2p->roms[1] = cpu_add_rom_file(cpu, 0xd800, "roms/341-0012.bin"); // AppleSoft BASIC D800
a2p->roms[2] = cpu_add_rom_file(cpu, 0xe000, "roms/341-0013.bin"); // AppleSoft BASIC E000
a2p->roms[3] = cpu_add_rom_file(cpu, 0xe800, "roms/341-0014.bin"); // AppleSoft BASIC E800
a2p->roms[4] = cpu_add_rom_file(cpu, 0xf000, "roms/341-0015.bin"); // AppleSoft BASIC E800
a2p->roms[5] = cpu_add_rom_file(cpu, 0xf800, "roms/341-0020.bin"); // AppleSoft BASIC Autostart Monitor F8000
a2p->iom = cpu_add_iom(cpu, 0xc000, 0xc07f, a2p, a2p_iom_read, a2p_iom_write);
a2p->iom->description = "iom/a2p/$C000";
a2p->dsk = ewm_dsk_create(cpu);
// TODO Move into a2p_t
struct ewm_alc_t *alc = ewm_alc_create(cpu);
if (alc == NULL) {
fprintf(stderr, "[A2P] Could not create Apple Language Card\n");
return -1;
}
// TODO Introduce ewm_scr_t that captures everything related to the apple 2 screen so that it can be re-used.
a2p->screen_txt_data = malloc(2 * 1024);
a2p->screen_txt_iom = cpu_add_iom(cpu, 0x0400, 0x0bff, a2p, a2p_screen_txt_read, a2p_screen_txt_write);
a2p->screen_txt_iom->description = "ram/a2p/$0400";
a2p->screen_hgr_data = malloc(16 * 1024);
a2p->screen_hgr_iom = cpu_add_iom(cpu, 0x2000, 0x5fff, a2p, a2p_screen_hgr_read, a2p_screen_hgr_write);
a2p->screen_hgr_iom->description = "ram/a2p/$2000";
return 0;
}
struct a2p_t *a2p_create(struct cpu_t *cpu) {
struct a2p_t *a2p = malloc(sizeof(struct a2p_t));
if (a2p_init(a2p, cpu) != 0) {
free(a2p);
a2p = NULL;
}
return a2p;
}
void a2p_destroy(struct a2p_t *a2p) {
// TODO
}
int a2p_load_disk(struct a2p_t *a2p, int drive, char *path) {

9
a2p.h
View File

@ -41,8 +41,10 @@ struct ewm_dsk_t;
#define EWM_A2P_SCREEN_PAGE2 1
struct a2p_t {
struct cpu_t *cpu;
struct mem_t *ram;
struct mem_t *rom;
struct mem_t *roms[6];
struct mem_t *iom;
struct ewm_dsk_t *dsk;
@ -62,7 +64,10 @@ struct a2p_t {
uint8_t key;
};
void a2p_init(struct a2p_t *a2p, struct cpu_t *cpu);
int a2p_init(struct a2p_t *a2p, struct cpu_t *cpu);
struct a2p_t *a2p_create(struct cpu_t *cpu);
void a2p_destroy(struct a2p_t *a2p);
int a2p_load_disk(struct a2p_t *a2p, int drive, char *path);
#endif

4
alc.c
View File

@ -170,9 +170,13 @@ int ewm_alc_init(struct ewm_alc_t *alc, struct cpu_t *cpu) {
alc->rom = cpu_add_rom_file(cpu, 0xf800, "roms/341-0020.bin");
alc->iom = cpu_add_iom(cpu, 0xc080, 0xc08f, alc, alc_iom_read, alc_iom_write);
alc->iom->description = "iom/alc/$C080";
alc->ram1 = cpu_add_ram(cpu, 0xd000, 0xd000 + 4096 - 1);
alc->ram1->description = "ram/alc/$D000 (RAM1)";
alc->ram2 = cpu_add_ram(cpu, 0xd000, 0xd000 + 4096 - 1);
alc->ram2->description = "ram/alc/$D000 (RAM2)";
alc->ram3 = cpu_add_ram(cpu, 0xe000, 0xe000 + 8192 - 1);
alc->ram3->description = "ram/alc/$E000 (RAM3)";
alc->ram1->enabled = false;
alc->ram2->enabled = false;

7
chr.c
View File

@ -140,13 +140,6 @@ int ewm_chr_init(struct ewm_chr_t *chr, char *rom_path, int rom_type, SDL_Render
return 0;
}
/* for (int i = 0; i < 8; i++) { */
/* for (int b = 0; b < 8; b++) { */
/* printf("%s", (character_data[i] & (1 << b)) ? "X" : " "); */
/* } */
/* printf("\n"); */
/* } */
#if 0
int main() {
struct ewm_chr_t *chr = ewm_chr_create("roms/3410036.bin", EWM_CHR_ROM_TYPE_2716);

31
cpu.c
View File

@ -175,7 +175,9 @@ static int cpu_execute_instruction(struct cpu_t *cpu) {
/* Public API */
void cpu_setup() {
static bool cpu_initialized = false;
static void cpu_initialize() {
for (int i = 0; i <= 255; i++) {
if (instructions_65C02[i].handler == NULL) {
instructions_65C02[i] = instructions[i];
@ -183,13 +185,29 @@ void cpu_setup() {
}
}
void cpu_init(struct cpu_t *cpu, int model) {
int cpu_init(struct cpu_t *cpu, int model) {
if (!cpu_initialized) {
cpu_initialize();
cpu_initialized = true;
}
memset(cpu, 0x00, sizeof(struct cpu_t));
cpu->model = model;
cpu->instructions = (cpu->model == EWM_CPU_MODEL_6502) ? instructions : instructions_65C02;
return 0;
}
void cpu_shutdown(struct cpu_t *cpu) {
struct cpu_t *cpu_create(int model) {
struct cpu_t *cpu = malloc(sizeof(struct cpu_t));
if (cpu_init(cpu, model) != 0) {
free(cpu);
cpu = NULL;
}
return cpu;
}
void cpu_destroy(struct cpu_t *cpu) {
if (cpu->trace != NULL) {
(void) fclose(cpu->trace);
cpu->trace = NULL;
@ -223,6 +241,7 @@ struct mem_t *cpu_add_ram(struct cpu_t *cpu, uint16_t start, uint16_t end) {
struct mem_t *cpu_add_ram_data(struct cpu_t *cpu, uint16_t start, uint16_t end, uint8_t *data) {
struct mem_t *mem = (struct mem_t*) malloc(sizeof(struct mem_t));
memset(mem, 0, sizeof(struct mem_t));
mem->enabled = true;
mem->flags = MEM_FLAGS_READ | MEM_FLAGS_WRITE;
mem->obj = data;
@ -270,6 +289,7 @@ static uint8_t _rom_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) {
struct mem_t *cpu_add_rom_data(struct cpu_t *cpu, uint16_t start, uint16_t end, uint8_t *data) {
struct mem_t *mem = (struct mem_t*) malloc(sizeof(struct mem_t));
memset(mem, 0, sizeof(struct mem_t));
mem->enabled = true;
mem->flags = MEM_FLAGS_READ;
mem->obj = data;
@ -306,13 +326,16 @@ struct mem_t *cpu_add_rom_file(struct cpu_t *cpu, uint16_t start, char *path) {
close(fd);
return cpu_add_rom_data(cpu, start, start + file_info.st_size - 1, (uint8_t*) data);
struct mem_t *result = cpu_add_rom_data(cpu, start, start + file_info.st_size - 1, (uint8_t*) data);
result->description = path;
return result;
}
// IO Memory
struct mem_t *cpu_add_iom(struct cpu_t *cpu, uint16_t start, uint16_t end, void *obj, mem_read_handler_t read_handler, mem_write_handler_t write_handler) {
struct mem_t *mem = (struct mem_t*) malloc(sizeof(struct mem_t));
memset(mem, 0, sizeof(struct mem_t));
mem->enabled = true;
mem->flags = MEM_FLAGS_READ | MEM_FLAGS_WRITE;
mem->obj = obj;

8
cpu.h
View File

@ -69,6 +69,7 @@ struct mem_t {
void *obj;
mem_read_handler_t read_handler;
mem_write_handler_t write_handler;
char *description;
struct mem_t *next;
};
@ -85,10 +86,9 @@ uint8_t _cpu_stack_used(struct cpu_t *cpu);
uint8_t _cpu_get_status(struct cpu_t *cpu);
void _cpu_set_status(struct cpu_t *cpu, uint8_t status);
void cpu_setup();
void cpu_init(struct cpu_t *cpu, int model);
void cpu_shutdown(struct cpu_t *cpu);
int cpu_init(struct cpu_t *cpu, int model);
struct cpu_t *cpu_create(int model);
void cpu_destroy(struct cpu_t *cpu);
struct mem_t *cpu_add_mem(struct cpu_t *cpu, struct mem_t *mem);
struct mem_t *cpu_add_ram(struct cpu_t *cpu, uint16_t start, uint16_t end);

View File

@ -77,7 +77,6 @@ int test(int model, uint16_t start_addr, uint16_t success_addr, char *rom_path)
}
int main(int argc, char **argv) {
cpu_setup();
fprintf(stderr, "TEST Running 6502 tests\n");
test(EWM_CPU_MODEL_6502, 0x0400, 0x3399, "roms/6502_functional_test.bin");
fprintf(stderr, "TEST Running 65C02 tests\n");

2
dsk.c
View File

@ -408,7 +408,9 @@ static struct ewm_dsk_track_t dsk_convert_track(struct ewm_dsk_t *disk, struct e
int ewm_dsk_init(struct ewm_dsk_t *dsk, struct cpu_t *cpu) {
memset(dsk, 0x00, sizeof(struct ewm_dsk_t));
dsk->rom = cpu_add_rom_data(cpu, 0xc600, 0xc6ff, dsk_rom);
dsk->rom->description = "rom/dsk/$C600";
dsk->iom = cpu_add_iom(cpu, 0xc0e0, 0xc0ef, dsk, dsk_read, dsk_write);
dsk->rom->description = "iom/dsk/$C0E0";
return 0;
}

169
ewm.c
View File

@ -34,51 +34,28 @@
#include "a2p.h"
#include "scr.h"
#include "dsk.h"
#include "scr.h"
#include "sdl.h"
// Apple 1 / 6502 / 8K RAM / WOZ Monitor
// TODO Get rid of these, use a struct ewm_t?
static int setup_apple1(struct cpu_t *cpu) {
cpu_init(cpu, EWM_CPU_MODEL_6502);
struct pia_t *pia = malloc(sizeof(struct pia_t));
pia_init(pia);
cpu_add_ram(cpu, 0x0000, 8 * 1024 - 1);
cpu_add_rom_file(cpu, 0xff00, "roms/apple1.rom");
cpu_add_iom(cpu, EWM_A1_PIA6820_ADDR, EWM_A1_PIA6820_ADDR + EWM_A1_PIA6820_LENGTH - 1, pia, pia_read, pia_write);
return 0;
}
// Replica 1 / 65C02 / 32K RAM / Krusader Assembler & Monitor
static int setup_replica1(struct cpu_t *cpu) {
cpu_init(cpu, EWM_CPU_MODEL_65C02);
struct pia_t *pia = malloc(sizeof(struct pia_t));
pia_init(pia);
cpu_add_ram(cpu, 0x0000, 32 * 1024 - 1);
cpu_add_rom_file(cpu, 0xe000, "roms/krusader.rom");
cpu_add_iom(cpu, EWM_A1_PIA6820_ADDR, EWM_A1_PIA6820_ADDR + EWM_A1_PIA6820_LENGTH - 1, pia, pia_read, pia_write);
return 0;
}
// Apple ][+ / 6502 / 48K RAM / Original ROMs
static struct a2p_t *a2p;
static int setup_apple2plus(struct cpu_t *cpu) {
cpu_init(cpu, EWM_CPU_MODEL_6502);
a2p = malloc(sizeof(struct a2p_t));
a2p_init(a2p, cpu);
return 0;
}
static struct cpu_t *cpu = NULL;
static struct a2p_t *a2p = NULL;
static struct scr_t *scr = NULL;
// Machine Setup
typedef int (*ewm_machine_setup_f)(struct cpu_t *cpu);
#define EWM_DISPLAY_TYPE_NONE 0
#define EWM_DISPLAY_TYPE_TTY 1
#define EWM_DISPLAY_TYPE_SDL 2
typedef int (*ewm_machine_create_f)();
struct ewm_machine_t {
char *name;
char *description;
int graphics;
ewm_machine_setup_f setup;
int display_type;
ewm_machine_create_f create;
};
#define EWM_MEMORY_TYPE_RAM 0
@ -91,6 +68,39 @@ struct ewm_memory_t {
struct ewm_memory_t *next;
};
// Apple 1 / 6502 / 8K RAM / WOZ Monitor
static int setup_apple1() {
cpu = cpu_create(EWM_CPU_MODEL_6502);
struct pia_t *pia = malloc(sizeof(struct pia_t));
pia_init(pia);
cpu_add_ram(cpu, 0x0000, 8 * 1024 - 1);
cpu_add_rom_file(cpu, 0xff00, "roms/apple1.rom");
cpu_add_iom(cpu, EWM_A1_PIA6820_ADDR, EWM_A1_PIA6820_ADDR + EWM_A1_PIA6820_LENGTH - 1, pia, pia_read, pia_write);
return 0;
}
// Replica 1 / 65C02 / 32K RAM / Krusader Assembler & Monitor
static int setup_replica1() {
cpu = cpu_create(EWM_CPU_MODEL_65C02);
struct pia_t *pia = malloc(sizeof(struct pia_t));
pia_init(pia);
cpu_add_ram(cpu, 0x0000, 32 * 1024 - 1);
cpu_add_rom_file(cpu, 0xe000, "roms/krusader.rom");
cpu_add_iom(cpu, EWM_A1_PIA6820_ADDR, EWM_A1_PIA6820_ADDR + EWM_A1_PIA6820_LENGTH - 1, pia, pia_read, pia_write);
return 0;
}
// Apple ][+ / 6502 / 48K RAM / Original ROMs
static int setup_apple2plus() {
cpu = cpu_create(EWM_CPU_MODEL_6502);
a2p = a2p_create(cpu);
scr = ewm_scr_create(a2p, renderer);
return 0;
}
struct ewm_memory_t *parse_memory(char *s) {
char *type = strsep(&s, ":");
if (type == NULL) { // || (strcmp(type, "ram") && strcmp(type, "rom"))) {
@ -120,10 +130,10 @@ struct ewm_memory_t *parse_memory(char *s) {
}
static struct ewm_machine_t machines[] = {
{ "apple1", "Apple 1", false, setup_apple1 },
{ "replica1", "Replica 1", false, setup_replica1 },
{ "apple2plus", "Apple ][+", true, setup_apple2plus },
{ NULL, NULL, false, NULL }
{ "apple1", "Apple 1", EWM_DISPLAY_TYPE_TTY, setup_apple1 },
{ "replica1", "Replica 1", EWM_DISPLAY_TYPE_TTY, setup_replica1 },
{ "apple2plus", "Apple ][+", EWM_DISPLAY_TYPE_SDL, setup_apple2plus },
{ NULL, NULL, EWM_DISPLAY_TYPE_NONE, NULL }
};
static struct option options[] = {
@ -149,7 +159,7 @@ int main(int argc, char **argv) {
struct ewm_machine_t *machine = &machines[0];
bool strict = false;
char *trace_path = NULL;
struct ewm_memory_t *memory;
struct ewm_memory_t *memory = NULL;
char *drive1 = NULL;
char *drive2 = NULL;
@ -194,13 +204,28 @@ int main(int argc, char **argv) {
exit(1);
}
cpu_setup();
//
// Initialize the display
//
fprintf(stderr, "[EWM] Starting up %s\n", machine->description);
switch (machine->display_type) {
case EWM_DISPLAY_TYPE_NONE:
fprintf(stderr, "[EWM] TODO EWM_DISPLAY_TYPE_NONE\n");
exit(1);
break;
case EWM_DISPLAY_TYPE_TTY:
fprintf(stderr, "[EWM] TODO EWM_DISPLAY_TYPE_TTY\n");
break;
case EWM_DISPLAY_TYPE_SDL:
sdl_initialize();
break;
}
struct cpu_t cpu;
// Create the machine and initialize it
machine->setup(&cpu);
fprintf(stderr, "[EWM] Creating %s\n", machine->description);
machine->create(cpu);
// TODO This really does not belong here. it is probably better to
// pass arguments to setup_apple2plus so that it can handle its
@ -226,12 +251,12 @@ int main(int argc, char **argv) {
while (m != NULL) {
fprintf(stderr, "[EWM] Adding %s $%.4X %s\n", m->type == EWM_MEMORY_TYPE_RAM ? "RAM" : "ROM", m->address, m->path);
if (m->type == EWM_MEMORY_TYPE_RAM) {
if (cpu_add_ram_file(&cpu, m->address, m->path) == NULL) {
if (cpu_add_ram_file(cpu, m->address, m->path) == NULL) {
fprintf(stderr, "[EWM] Failed to add RAM from %s\n", m->path);
exit(1);
}
} else {
if (cpu_add_rom_file(&cpu, m->address, m->path) == NULL) {
if (cpu_add_rom_file(cpu, m->address, m->path) == NULL) {
fprintf(stderr, "[EWM] Failed to add ROM from %s\n", m->path);
exit(1);
}
@ -239,32 +264,38 @@ int main(int argc, char **argv) {
m = m->next;
}
cpu_strict(&cpu, strict);
cpu_trace(&cpu, trace_path);
cpu_strict(cpu, strict);
cpu_trace(cpu, trace_path);
cpu_reset(&cpu);
cpu_reset(cpu);
if (machine->graphics) {
scr_init();
scr_main(&cpu, a2p);
} else {
while (true) {
switch (cpu_step(&cpu)) {
case EWM_CPU_ERR_UNIMPLEMENTED_INSTRUCTION:
fprintf(stderr, "CPU: Exited because of unimplemented instructions 0x%.2x at 0x%.4x\n",
mem_get_byte(&cpu, cpu.state.pc), cpu.state.pc);
break;
case EWM_CPU_ERR_STACK_OVERFLOW:
fprintf(stderr, "CPU: Exited because of stack overflow at 0x%.4x\n", cpu.state.pc);
break;
case EWM_CPU_ERR_STACK_UNDERFLOW:
fprintf(stderr, "CPU: Exited because of stack underflow at 0x%.4x\n", cpu.state.pc);
break;
}
}
switch (machine->display_type) {
case EWM_DISPLAY_TYPE_NONE:
fprintf(stderr, "[EWM] TODO EWM_DISPLAY_TYPE_NONE\n");
exit(1);
break;
case EWM_DISPLAY_TYPE_TTY:
fprintf(stderr, "[EWM] TODO EWM_DISPLAY_TYPE_TTY\n");
exit(1);
break;
case EWM_DISPLAY_TYPE_SDL:
sdl_main(cpu, a2p, scr);
break;
}
cpu_shutdown(&cpu);
// Clean up
if (scr != NULL) {
ewm_scr_destroy(scr);
scr = NULL;
}
if (a2p != NULL) {
a2p_destroy(a2p);
a2p = NULL;
}
cpu_destroy(cpu);
return 0;
}

316
scr.c
View File

@ -31,62 +31,36 @@
#include "chr.h"
#include "scr.h"
SDL_Window *window;
SDL_Renderer *renderer;
// Text rendering
struct ewm_chr_t *chr = NULL;
void scr_init() {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError());
exit(1);
}
//
window = SDL_CreateWindow("Test", 400, 60, 280*3, 192*3, SDL_WINDOW_SHOWN);
if (window == NULL) {
fprintf(stderr, "Failed create window: %s\n", SDL_GetError());
exit(1);
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL) {
fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError());
exit(1);
}
//
chr = ewm_chr_create("roms/3410036.bin", EWM_CHR_ROM_TYPE_2716, renderer);
if (chr == NULL) {
fprintf(stderr, "[SCR] Failed to initialize character generator\n");
exit(1);
}
}
static int screen1_offsets[24] = {
0x400, 0x480, 0x500, 0x580, 0x600, 0x680, 0x700, 0x780, 0x428, 0x4a8, 0x528, 0x5a8,
0x628, 0x6a8, 0x728, 0x7a8, 0x450, 0x4d0, 0x550, 0x5d0, 0x650, 0x6d0, 0x750, 0x7d0
static int txt_line_offsets[24] = {
0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x028, 0x0a8, 0x128, 0x1a8,
0x228, 0x2a8, 0x328, 0x3a8, 0x050, 0x0d0, 0x150, 0x1d0, 0x250, 0x2d0, 0x350, 0x3d0
};
static int screen2_offsets[24] = {
0x800, 0x880, 0x900, 0x980, 0xa00, 0xa80, 0xb00, 0xb80, 0x828, 0x8a8, 0x928, 0x9a8,
0xa28, 0xaa8, 0xb28, 0xba8, 0x850, 0x8d0, 0x950, 0x9d0, 0xa50, 0xad0, 0xb50, 0xbd0
};
static inline void _render_character(struct a2p_t *a2p, int row, int column, int *offsets) {
uint8_t c = a2p->screen_txt_data[(offsets[row] + column) - 0x0400];
if (chr->characters[c] != NULL) {
static inline void scr_render_character(struct scr_t *scr, int row, int column) {
uint16_t base = (scr->a2p->screen_page == EWM_A2P_SCREEN_PAGE1) ? 0x0400 : 0x0800;
uint8_t c = scr->a2p->screen_txt_data[((txt_line_offsets[row] + base) + column) - 0x0400];
if (scr->chr->characters[c] != NULL) {
SDL_Rect dst;
dst.x = column * 21;
dst.y = row * 24;
dst.w = 21;
dst.h = 24;
SDL_RenderCopy(renderer, chr->characters[c], NULL, &dst);
SDL_RenderCopy(scr->renderer, scr->chr->characters[c], NULL, &dst);
}
}
static inline void scr_render_txt_screen(struct scr_t *scr) {
for (int row = 0; row < 24; row++) {
for (int column = 0; column < 40; column++) {
scr_render_character(scr, row, column);
}
}
}
// Lores Rendering
static SDL_Color lores_colors[16] = {
{ 0, 0, 0, 0 }, // 0 Black
{ 255, 0, 255, 0 }, // 1 Magenta
@ -106,8 +80,9 @@ static SDL_Color lores_colors[16] = {
{ 255, 255, 255, 0 }, // 15 White
};
static inline void _render_lores_block(struct a2p_t *a2p, int row, int column, int *offsets) {
uint8_t block = a2p->screen_txt_data[(offsets[row] + column) - 0x0400];
static inline void scr_render_lores_block(struct scr_t *scr, int row, int column) {
uint16_t base = (scr->a2p->screen_page == EWM_A2P_SCREEN_PAGE1) ? 0x0400 : 0x0800;
uint8_t block = scr->a2p->screen_txt_data[((txt_line_offsets[row] + base) + column) - 0x0400];
if (block != 0) {
SDL_Rect dst;
dst.x = column * 21;
@ -117,70 +92,40 @@ static inline void _render_lores_block(struct a2p_t *a2p, int row, int column, i
uint c = block & 0x0f;
if (c != 0) {
SDL_SetRenderDrawColor(renderer, lores_colors[c].r, lores_colors[c].g, lores_colors[c].b, lores_colors[c].a);
SDL_RenderFillRect(renderer, &dst);
SDL_SetRenderDrawColor(scr->renderer, lores_colors[c].r, lores_colors[c].g, lores_colors[c].b, lores_colors[c].a);
SDL_RenderFillRect(scr->renderer, &dst);
}
c = (block & 0xf0) >> 4;
if (c != 0) {
dst.y += 12;
SDL_SetRenderDrawColor(renderer, lores_colors[c].r, lores_colors[c].g, lores_colors[c].b, lores_colors[c].a);
SDL_RenderFillRect(renderer, &dst);
SDL_SetRenderDrawColor(scr->renderer, lores_colors[c].r, lores_colors[c].g, lores_colors[c].b, lores_colors[c].a);
SDL_RenderFillRect(scr->renderer, &dst);
}
}
}
static void _render_txt_screen1(struct a2p_t *a2p) {
for (int row = 0; row < 24; row++) {
for (int column = 0; column < 40; column++) {
_render_character(a2p, row, column, screen1_offsets);
}
}
}
static inline void scr_render_lgr_screen(struct scr_t *scr) {
bool mixed = (scr->a2p->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED);
static void _render_txt_screen2(struct a2p_t *a2p) {
for (int row = 0; row < 24; row++) {
for (int column = 0; column < 40; column++) {
_render_character(a2p, row, column, screen2_offsets);
}
}
}
static void _render_lgr_screen1(struct a2p_t *a2p, bool mixed) {
// Render graphics
int rows = mixed ? 20 : 24;
for (int row = 0; row < rows; row++) {
for (int column = 0; column < 40; column++) {
_render_lores_block(a2p, row, column, screen1_offsets);
scr_render_lores_block(scr, row, column);
}
}
// Render bottom 4 lines
if (mixed) {
for (int row = 20; row < 24; row++) {
for (int column = 0; column < 40; column++) {
_render_character(a2p, row, column, screen1_offsets);
scr_render_character(scr, row, column);
}
}
}
}
static void _render_lgr_screen2(struct a2p_t *a2p, bool mixed) {
// Render graphics
int rows = mixed ? 20 : 24;
for (int row = 0; row < rows; row++) {
for (int column = 0; column < 40; column++) {
_render_lores_block(a2p, row, column, screen2_offsets);
}
}
// Render bottom 4 lines
if (mixed) {
for (int row = 20; row < 24; row++) {
for (int column = 0; column < 40; column++) {
_render_character(a2p, row, column, screen2_offsets);
}
}
}
}
// Hires rendering
static uint16_t hgr_page_offsets[2] = {
0x0000, // $0000 in our buffer, $2000 in emulator
@ -214,10 +159,10 @@ static uint16_t hgr_line_offsets[192] = {
0x03d0, 0x07d0, 0x0bd0, 0x0fd0, 0x13d0, 0x17d0, 0x1bd0, 0x1fd0
};
static void _render_hgr_line(struct a2p_t *a2p, int line, uint16_t line_base) {
static void inline scr_render_hgr_line(struct scr_t *scr, int line, uint16_t line_base) {
int x = 0;
for (int i = 0; i < 40; i++) {
uint8_t c = a2p->screen_hgr_data[line_base + i];
uint8_t c = scr->a2p->screen_hgr_data[line_base + i];
for (int j = 0; j < 7; j++) {
SDL_Rect dst;
dst.x = x * 3;
@ -225,166 +170,79 @@ static void _render_hgr_line(struct a2p_t *a2p, int line, uint16_t line_base) {
dst.w = 3;
dst.h = 3;
if (c & (1 << j)) {
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 0);
SDL_SetRenderDrawColor(scr->renderer, 0, 255, 0, 0);
} else {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_SetRenderDrawColor(scr->renderer, 0, 0, 0, 0);
}
SDL_RenderFillRect(renderer, &dst);
SDL_RenderFillRect(scr->renderer, &dst);
x++;
}
}
}
static void _render_hgr_screen(struct a2p_t *a2p) {
static void inline scr_render_hgr_screen(struct scr_t *scr) {
// Render graphics
int lines = (a2p->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED) ? 168 : 192;
uint16_t hgr_base = hgr_page_offsets[a2p->screen_page];
int lines = (scr->a2p->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED) ? 168 : 192;
uint16_t hgr_base = hgr_page_offsets[scr->a2p->screen_page];
for (int line = 0; line < lines; line++) {
uint16_t line_base = hgr_base + hgr_line_offsets[line];
_render_hgr_line(a2p, line, line_base);
scr_render_hgr_line(scr, line, line_base);
}
// Render bottom 4 lines of text
if (a2p->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED) {
if (scr->a2p->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED) {
for (int row = 20; row < 24; row++) {
for (int column = 0; column < 40; column++) {
_render_character(a2p, row, column, screen1_offsets);
scr_render_character(scr, row, column);
}
}
}
}
void scr_main(struct cpu_t *cpu, struct a2p_t *a2p) {
bool quit = false;
//bool running = true;
// TODO This is the only actual API exposed
SDL_StartTextInput();
while (quit == false)
{
// Events
SDL_Event event;
while (SDL_PollEvent(&event) != 0) {
switch (event.type) {
case SDL_QUIT:
quit = true;
break;
case SDL_KEYDOWN:
if (event.key.keysym.mod & KMOD_CTRL) {
if (event.key.keysym.sym >= SDLK_a && event.key.keysym.sym <= SDLK_z) {
a2p->key = (event.key.keysym.sym - SDLK_a) | 0x80;
} else {
// TODO Implement control codes 1b - 1f
}
} else if (event.key.keysym.mod & KMOD_GUI) {
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
cpu_reset(cpu);
break;
}
} else if (event.key.keysym.mod == KMOD_NONE) {
switch (event.key.keysym.sym) {
case SDLK_RETURN:
a2p->key = 0x0d | 0x80; // CR
break;
case SDLK_TAB:
a2p->key = 0x09 | 0x80; // HT
case SDLK_DELETE:
a2p->key = 0x7f | 0x80; // DEL
break;
case SDLK_LEFT:
a2p->key = 0x08 | 0x80; // BS
break;
case SDLK_RIGHT:
a2p->key = 0x15 | 0x80; // NAK
break;
case SDLK_UP:
a2p->key = 0x0b | 0x80; // VT
break;
case SDLK_DOWN:
a2p->key = 0x0a | 0x80; // LF
break;
case SDLK_ESCAPE:
a2p->key = 0x1b | 0x80; // ESC
break;
}
}
break;
case SDL_TEXTINPUT:
if (strlen(event.text.text) == 1) {
a2p->key = toupper(event.text.text[0]) | 0x80;
}
break;
}
}
// Logic
for (int i = 0; i < 1000; i++) {
int ret = cpu_step(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(cpu, cpu->state.pc), cpu->state.pc);
break;
case EWM_CPU_ERR_STACK_OVERFLOW:
fprintf(stderr, "CPU: Exited because of stack overflow at 0x%.4x\n", cpu->state.pc);
break;
case EWM_CPU_ERR_STACK_UNDERFLOW:
fprintf(stderr, "CPU: Exited because of stack underflow at 0x%.4x\n", cpu->state.pc);
break;
}
cpu_nmi(cpu);
//exit(1);
}
}
// Render
if (a2p->screen_dirty) {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
switch (a2p->screen_mode) {
case EWM_A2P_SCREEN_MODE_TEXT:
switch (a2p->screen_page) {
case EWM_A2P_SCREEN_PAGE1:
_render_txt_screen1(a2p);
break;
case EWM_A2P_SCREEN_PAGE2:
_render_txt_screen2(a2p);
break;
}
break;
case EWM_A2P_SCREEN_MODE_GRAPHICS:
switch (a2p->screen_graphics_mode) {
case EWM_A2P_SCREEN_GRAPHICS_MODE_LGR:
switch (a2p->screen_page) {
case EWM_A2P_SCREEN_PAGE1:
_render_lgr_screen1(a2p, a2p->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED);
break;
case EWM_A2P_SCREEN_PAGE2:
_render_lgr_screen2(a2p, a2p->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED);
break;
}
break;
case EWM_A2P_SCREEN_GRAPHICS_MODE_HGR:
_render_hgr_screen(a2p);
break;
}
break;
}
SDL_RenderPresent(renderer);
a2p->screen_dirty = false;
}
}
SDL_DestroyWindow(window);
SDL_Quit();
int ewm_scr_init(struct scr_t *scr, struct a2p_t *a2p, SDL_Renderer *renderer) {
memset(scr, 0x00, sizeof(struct scr_t));
scr->a2p = a2p;
scr->renderer = renderer;
scr->chr = ewm_chr_create("roms/3410036.bin", EWM_CHR_ROM_TYPE_2716, renderer);
if (scr->chr == NULL) {
fprintf(stderr, "[SCR] Failed to initialize character generator\n");
return -1;
}
return 0;
}
struct scr_t *ewm_scr_create(struct a2p_t *a2p, SDL_Renderer *renderer) {
struct scr_t *scr = malloc(sizeof(struct scr_t));
if (ewm_scr_init(scr, a2p, renderer) != 0) {
free(scr);
scr = NULL;
}
return scr;
}
void ewm_scr_destroy(struct scr_t *scr) {
// TODO
}
void ewm_scr_update(struct scr_t *scr) {
SDL_SetRenderDrawColor(scr->renderer, 0, 0, 0, 255);
SDL_RenderClear(scr->renderer);
switch (scr->a2p->screen_mode) {
case EWM_A2P_SCREEN_MODE_TEXT:
scr_render_txt_screen(scr);
break;
case EWM_A2P_SCREEN_MODE_GRAPHICS:
switch (scr->a2p->screen_graphics_mode) {
case EWM_A2P_SCREEN_GRAPHICS_MODE_LGR:
scr_render_lgr_screen(scr);
break;
case EWM_A2P_SCREEN_GRAPHICS_MODE_HGR:
scr_render_hgr_screen(scr);
break;
}
break;
}
}

19
scr.h
View File

@ -23,10 +23,25 @@
#ifndef EWM_SCR_H
#define EWM_SCR_H
#include <SDL2/SDL.h>
struct ewm_chr_t;
struct cpu_t;
struct a2p_t;
void scr_init();
void scr_main(struct cpu_t *cpu, struct a2p_t *a2p);
// The 'scr' object represents the screen. It renders the contents of
// the machine. It has pluggable renders.
struct scr_t {
struct a2p_t *a2p;
SDL_Renderer *renderer;
struct ewm_chr_t *chr;
};
struct scr_t *ewm_scr_create(struct a2p_t *a2p, SDL_Renderer *renderer);
int ewm_scr_init(struct scr_t *scr, struct a2p_t *a2p, SDL_Renderer *renderer);
void ewm_scr_destroy(struct scr_t *scr);
void ewm_scr_update(struct scr_t *scr);
#endif

116
scr_test.c Normal file
View File

@ -0,0 +1,116 @@
// 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 <stdlib.h>
#include <unistd.h>
#include "cpu.h"
#include "mem.h"
#include "a2p.h"
#include "scr.h"
#include "sdl.h"
typedef void (*test_setup_t)(struct scr_t *scr);
typedef void (*test_run_t)(struct scr_t *scr);
void txt_full_refresh_setup(struct scr_t *scr) {
scr->a2p->screen_mode = EWM_A2P_SCREEN_MODE_TEXT;
scr->a2p->screen_page = EWM_A2P_SCREEN_PAGE1;
for (uint16_t a = 0x0400; a <= 0x0bff; a++) {
uint8_t v = 0xa0 + (random() % 64);
mem_set_byte(scr->a2p->cpu, a, v);
}
}
void txt_full_refresh_test(struct scr_t *scr) {
ewm_scr_update(scr);
}
void lgr_full_refresh_setup(struct scr_t *scr) {
scr->a2p->screen_mode = EWM_A2P_SCREEN_MODE_GRAPHICS;
scr->a2p->screen_page = EWM_A2P_SCREEN_PAGE1;
scr->a2p->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_LGR;
scr->a2p->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->a2p->cpu, a, v);
}
}
void lgr_full_refresh_test(struct scr_t *scr) {
ewm_scr_update(scr);
}
void hgr_full_refresh_setup(struct scr_t *scr) {
scr->a2p->screen_mode = EWM_A2P_SCREEN_MODE_GRAPHICS;
scr->a2p->screen_page = EWM_A2P_SCREEN_PAGE1;
scr->a2p->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_HGR;
scr->a2p->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_FULL;
for (uint16_t a = 0x2000; a <= 0x5fff; a++) {
mem_set_byte(scr->a2p->cpu, a, random());
}
}
void hgr_full_refresh_test(struct scr_t *scr) {
ewm_scr_update(scr);
}
void test(struct scr_t *scr, char *name, test_setup_t test_setup, test_run_t test_run) {
test_setup(scr);
Uint64 start = SDL_GetPerformanceCounter();
for (int i = 0; i < 1000; i++) {
test_run(scr);
SDL_RenderPresent(scr->renderer);
}
Uint64 now = SDL_GetPerformanceCounter();
double total = (double)((now - start)*1000) / SDL_GetPerformanceFrequency();
double per_screen = total / 1000.0;
printf("%-20s %.3f/refresh\n", name, per_screen);
}
int main() {
sdl_initialize();
sleep(3); // Is this ok? Seems to be needed to get the window on the screen
// Setup the CPU, Apple ][+ and it's screen.
struct cpu_t *cpu = cpu_create(EWM_CPU_MODEL_6502);
struct a2p_t *a2p = a2p_create(cpu);
struct scr_t *scr = ewm_scr_create(a2p, renderer);
test(scr, "txt_full_refresh", txt_full_refresh_setup, txt_full_refresh_test);
test(scr, "lgr_full_refresh", lgr_full_refresh_setup, lgr_full_refresh_test);
test(scr, "hgr_full_refresh", hgr_full_refresh_setup, hgr_full_refresh_test);
// Destroy DSL things
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}

194
sdl.c Normal file
View File

@ -0,0 +1,194 @@
// 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 <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "cpu.h"
#include "a2p.h"
#include "scr.h"
#include "mem.h"
#include "sdl.h"
// TODO Remove these globals - Do we need a struct ewm_t?
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
void sdl_initialize() {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) < 0) {
fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError());
exit(1);
}
//
window = SDL_CreateWindow("Test", 400, 60, 280*3, 192*3, SDL_WINDOW_SHOWN);
if (window == NULL) {
fprintf(stderr, "Failed create window: %s\n", SDL_GetError());
exit(1);
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL) {
fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError());
exit(1);
}
}
Uint32 my_callbackfunc(Uint32 interval, void *param) {
SDL_Event event;
SDL_UserEvent userevent;
userevent.type = SDL_USEREVENT;
userevent.code = 0;
userevent.data1 = NULL;
userevent.data2 = NULL;
event.type = SDL_USEREVENT;
event.user = userevent;
SDL_PushEvent(&event);
return interval;
}
void sdl_main(struct cpu_t *cpu, struct a2p_t *a2p, struct scr_t *scr) {
bool quit = false;
int fps = 0;
Uint32 next_time = SDL_GetTicks() + (1000 / 50);
SDL_StartTextInput();
(void) SDL_AddTimer(1000, my_callbackfunc, NULL);
while (quit == false)
{
// Events
SDL_Event event;
while (SDL_PollEvent(&event) != 0) {
switch (event.type) {
case SDL_QUIT:
quit = true;
break;
case SDL_KEYDOWN:
if (event.key.keysym.mod & KMOD_CTRL) {
if (event.key.keysym.sym >= SDLK_a && event.key.keysym.sym <= SDLK_z) {
a2p->key = (event.key.keysym.sym - SDLK_a) | 0x80;
} else {
// TODO Implement control codes 1b - 1f
}
} else if (event.key.keysym.mod & KMOD_GUI) {
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
fprintf(stderr, "[SDL] Reset\n");
cpu_reset(cpu);
break;
}
} else if (event.key.keysym.mod == KMOD_NONE) {
switch (event.key.keysym.sym) {
case SDLK_RETURN:
a2p->key = 0x0d | 0x80; // CR
break;
case SDLK_TAB:
a2p->key = 0x09 | 0x80; // HT
case SDLK_DELETE:
a2p->key = 0x7f | 0x80; // DEL
break;
case SDLK_LEFT:
a2p->key = 0x08 | 0x80; // BS
break;
case SDLK_RIGHT:
a2p->key = 0x15 | 0x80; // NAK
break;
case SDLK_UP:
a2p->key = 0x0b | 0x80; // VT
break;
case SDLK_DOWN:
a2p->key = 0x0a | 0x80; // LF
break;
case SDLK_ESCAPE:
a2p->key = 0x1b | 0x80; // ESC
break;
}
}
break;
case SDL_TEXTINPUT:
if (strlen(event.text.text) == 1) {
a2p->key = toupper(event.text.text[0]) | 0x80;
}
break;
case SDL_USEREVENT:
printf("fps = %d\n", fps);
fps = 0;
break;
}
}
// Logic
for (int i = 0; i < 5000; i++) {
int ret = cpu_step(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(cpu, cpu->state.pc), cpu->state.pc);
break;
case EWM_CPU_ERR_STACK_OVERFLOW:
fprintf(stderr, "CPU: Exited because of stack overflow at 0x%.4x\n", cpu->state.pc);
break;
case EWM_CPU_ERR_STACK_UNDERFLOW:
fprintf(stderr, "CPU: Exited because of stack underflow at 0x%.4x\n", cpu->state.pc);
break;
}
cpu_nmi(cpu);
//exit(1);
}
}
SDL_Delay(10);
// Render
if (a2p->screen_dirty) {
if (SDL_GetTicks() >= next_time) {
ewm_scr_update(scr);
a2p->screen_dirty = false;
SDL_RenderPresent(scr->renderer);
fps++;
next_time = SDL_GetTicks() + (1000 / 50);
}
}
}
printf("sdl_main done\n");
SDL_DestroyWindow(window);
SDL_Quit();
}

38
sdl.h Normal file
View File

@ -0,0 +1,38 @@
// 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_SDL_H
#define EWM_SDL_H
#include <SDL2/SDL.h>
extern SDL_Window *window;
extern SDL_Renderer *renderer;
struct cpu_t;
struct a2p_t;
struct scr_t;
void sdl_initialize();
void sdl_main(struct cpu_t *cpu, struct a2p_t *a2p, struct scr_t *scr);
#endif // EWM_SDL_H