From 215dc9db5234cd32bf33babc5edfc3fa8d618024 Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Mon, 15 Jul 2024 12:12:10 -0700 Subject: [PATCH] Updated devices --- README.md | 6 +- src/devices/audio.c | 3 +- src/devices/audio.h | 2 - src/devices/console.c | 32 +++--- src/devices/console.h | 9 +- src/devices/controller.c | 20 ++-- src/devices/controller.h | 8 +- src/devices/datetime.c | 10 +- src/devices/datetime.h | 4 +- src/devices/file.c | 154 ++++++++++++++----------- src/devices/file.h | 4 +- src/devices/mouse.c | 31 ++--- src/devices/mouse.h | 10 +- src/devices/screen.c | 239 +++++++++++++++++++++++---------------- src/devices/screen.h | 20 ++-- src/devices/system.c | 126 ++++++++++----------- src/devices/system.h | 18 ++- src/uxn.c | 172 +++++++++++----------------- src/uxn.h | 9 +- src/uxncli.c | 82 ++++++++------ src/uxnemu.c | 200 +++++++++++++------------------- 21 files changed, 569 insertions(+), 590 deletions(-) mode change 100755 => 100644 src/uxncli.c diff --git a/README.md b/README.md index 0cc431f..0084082 100644 --- a/README.md +++ b/README.md @@ -96,10 +96,10 @@ uxnemu orca.rom | shim ## GUI Emulator Controls - `F1` toggle zoom -- `F2` toggle debug -- `F3` capture screen +- `F2` toggle debugger +- `F3` quit - `F4` reboot -- `F5` soft reboot +- `F5` reboot(soft) - `F11` toggle fullscreen - `F12` toggle decorations diff --git a/src/devices/audio.c b/src/devices/audio.c index e5d2660..7caabb2 100644 --- a/src/devices/audio.c +++ b/src/devices/audio.c @@ -250,10 +250,9 @@ audio_handler(void *ctx, Uint8 *out_stream, int len) Uxn *u = (Uxn *)ctx; Uint8 *addr = &u->dev[device]; if(channel[n].duration <= 0 && PEEK2(addr)) { - uxn_eval(u, PEEK2(addr)); + uxn_eval(PEEK2(addr)); } channel[n].duration -= SOUND_TIMER; - int x = 0; if(channel[n].xfade) { float delta = 1.0f / (XFADE_SAMPLES * 2); diff --git a/src/devices/audio.h b/src/devices/audio.h index 0f7c2ad..a5b2fb0 100644 --- a/src/devices/audio.h +++ b/src/devices/audio.h @@ -11,8 +11,6 @@ WITH REGARD TO THIS SOFTWARE. typedef signed int Sint32; -#define AUDIO_VERSION 1 - #define AUDIO_BUFSIZE 256.0f #define SAMPLE_FREQUENCY 44100.0f #define POLYPHONY 4 diff --git a/src/devices/console.c b/src/devices/console.c index ceb45be..000f23b 100644 --- a/src/devices/console.c +++ b/src/devices/console.c @@ -5,7 +5,7 @@ #include "console.h" /* -Copyright (c) 2022-2023 Devine Lu Linvega, Andrew Alderwick +Copyright (c) 2022-2024 Devine Lu Linvega, Andrew Alderwick Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -16,35 +16,29 @@ WITH REGARD TO THIS SOFTWARE. */ int -console_input(Uxn *u, char c, int type) +console_input(Uint8 c, int type) { - Uint8 *d = &u->dev[0x10]; - d[0x2] = c; - d[0x7] = type; - return uxn_eval(u, PEEK2(d)); + uxn.dev[0x12] = c; + uxn.dev[0x17] = type; + return uxn_eval(PEEK2(&uxn.dev[0x10])); } void -console_listen(Uxn *u, int i, int argc, char **argv) +console_listen(int i, int argc, char **argv) { for(; i < argc; i++) { char *p = argv[i]; - while(*p) console_input(u, *p++, CONSOLE_ARG); - console_input(u, '\n', i == argc - 1 ? CONSOLE_END : CONSOLE_EOA); + while(*p) console_input(*p++, CONSOLE_ARG); + console_input('\n', i == argc - 1 ? CONSOLE_END : CONSOLE_EOA); } } void -console_deo(Uint8 *d, Uint8 port) +console_deo(Uint8 addr) { - switch(port) { - case 0x8: - fputc(d[port], stdout); - fflush(stdout); - return; - case 0x9: - fputc(d[port], stderr); - fflush(stderr); - return; + FILE *fd; + switch(addr) { + case 0x18: fd = stdout, fputc(uxn.dev[0x18], fd), fflush(fd); break; + case 0x19: fd = stderr, fputc(uxn.dev[0x19], fd), fflush(fd); break; } } diff --git a/src/devices/console.h b/src/devices/console.h index 7c83708..be8abc2 100644 --- a/src/devices/console.h +++ b/src/devices/console.h @@ -9,13 +9,12 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ -#define CONSOLE_VERSION 1 - #define CONSOLE_STD 0x1 #define CONSOLE_ARG 0x2 #define CONSOLE_EOA 0x3 #define CONSOLE_END 0x4 -int console_input(Uxn *u, char c, int type); -void console_listen(Uxn *u, int i, int argc, char **argv); -void console_deo(Uint8 *d, Uint8 port); +int console_input(Uint8 c, int type); +void console_listen(int i, int argc, char **argv); +Uint8 console_dei(Uint8 addr); +void console_deo(Uint8 addr); diff --git a/src/devices/controller.c b/src/devices/controller.c index 38fd3bb..a9e9ad3 100644 --- a/src/devices/controller.c +++ b/src/devices/controller.c @@ -13,29 +13,29 @@ WITH REGARD TO THIS SOFTWARE. */ void -controller_down(Uxn *u, Uint8 *d, Uint8 mask) +controller_down(Uint8 mask) { if(mask) { - d[2] |= mask; - uxn_eval(u, PEEK2(d)); + uxn.dev[0x82] |= mask; + uxn_eval(PEEK2(&uxn.dev[0x80])); } } void -controller_up(Uxn *u, Uint8 *d, Uint8 mask) +controller_up(Uint8 mask) { if(mask) { - d[2] &= (~mask); - uxn_eval(u, PEEK2(d)); + uxn.dev[0x82] &= (~mask); + uxn_eval(PEEK2(&uxn.dev[0x80])); } } void -controller_key(Uxn *u, Uint8 *d, Uint8 key) +controller_key(Uint8 key) { if(key) { - d[3] = key; - uxn_eval(u, PEEK2(d)); - d[3] = 0x00; + uxn.dev[0x83] = key; + uxn_eval(PEEK2(&uxn.dev[0x80])); + uxn.dev[0x83] = 0; } } diff --git a/src/devices/controller.h b/src/devices/controller.h index d4d835e..376d2ff 100644 --- a/src/devices/controller.h +++ b/src/devices/controller.h @@ -9,8 +9,6 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ -#define CONTROL_VERSION 1 - -void controller_down(Uxn *u, Uint8 *d, Uint8 mask); -void controller_up(Uxn *u, Uint8 *d, Uint8 mask); -void controller_key(Uxn *u, Uint8 *d, Uint8 key); +void controller_down(Uint8 mask); +void controller_up(Uint8 mask); +void controller_key(Uint8 key); diff --git a/src/devices/datetime.c b/src/devices/datetime.c index 1968467..ec1d415 100644 --- a/src/devices/datetime.c +++ b/src/devices/datetime.c @@ -15,11 +15,13 @@ WITH REGARD TO THIS SOFTWARE. */ Uint8 -datetime_dei(Uxn *u, Uint8 addr) +datetime_dei(Uint8 addr) { time_t seconds = time(NULL); - struct tm zt = {0}, *t = localtime(&seconds); - if(t == NULL) t = &zt; + struct tm zt = {0}; + struct tm *t = localtime(&seconds); + if(t == NULL) + t = &zt; switch(addr) { case 0xc0: return (t->tm_year + 1900) >> 8; case 0xc1: return (t->tm_year + 1900); @@ -32,6 +34,6 @@ datetime_dei(Uxn *u, Uint8 addr) case 0xc8: return t->tm_yday >> 8; case 0xc9: return t->tm_yday; case 0xca: return t->tm_isdst; - default: return u->dev[addr]; + default: return uxn.dev[addr]; } } diff --git a/src/devices/datetime.h b/src/devices/datetime.h index 4ae7a6c..315389b 100644 --- a/src/devices/datetime.h +++ b/src/devices/datetime.h @@ -9,6 +9,4 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ -#define DATETIME_VERSION 1 - -Uint8 datetime_dei(Uxn *u, Uint8 addr); +Uint8 datetime_dei(Uint8 addr); diff --git a/src/devices/file.c b/src/devices/file.c index ac628fe..13dd802 100644 --- a/src/devices/file.c +++ b/src/devices/file.c @@ -54,27 +54,24 @@ typedef struct { static UxnFile uxn_file[POLYFILEY]; -static char -inthex(int n) -{ - n &= 0xf; - return n < 10 ? '0' + n : 'a' + (n - 10); -} - static void reset(UxnFile *c) { - if(c->f != NULL) - fclose(c->f), c->f = NULL; - if(c->dir != NULL) - closedir(c->dir), c->dir = NULL; + if(c->f != NULL) { + fclose(c->f); + c->f = NULL; + } + if(c->dir != NULL) { + closedir(c->dir); + c->dir = NULL; + } c->de = NULL; c->state = IDLE; c->outside_sandbox = 0; } static Uint16 -put_line(char *p, Uint16 len, const char *pathname, const char *basename, int fail_nonzero) +get_entry(char *p, Uint16 len, const char *pathname, const char *basename, int fail_nonzero) { struct stat st; if(len < strlen(basename) + 8) @@ -117,7 +114,7 @@ file_read_dir(UxnFile *c, char *dest, Uint16 len) snprintf(pathname, sizeof(pathname), "%s/%s", c->current_filename, c->de->d_name); else pathname[0] = '\0'; - n = put_line(p, len, pathname, c->de->d_name, 1); + n = get_entry(p, len, pathname, c->de->d_name, 1); if(!n) break; p += n; len -= n; @@ -228,25 +225,15 @@ file_write(UxnFile *c, void *src, Uint16 len, Uint8 flags) } static Uint16 -file_stat(UxnFile *c, char *p, Uint16 len) +file_stat(UxnFile *c, void *dest, Uint16 len) { - unsigned int i, size; - struct stat st; - if(c->outside_sandbox || !len) - return 0; - if(stat(c->current_filename, &st)) - for(i = 0; i < len; i++) - p[i] = '!'; - else if(S_ISDIR(st.st_mode)) - for(i = 0; i < len; i++) - p[i] = '-'; - else if(st.st_size >= 1 << (len << 2)) - for(i = 0; i < len; i++) - p[i] = '?'; + char *basename = strrchr(c->current_filename, DIR_SEP_CHAR); + if(c->outside_sandbox) return 0; + if(basename != NULL) + basename++; else - for(i = 0, size = st.st_size; i < len; i++) - p[i] = inthex(size >> ((len - i - 1) << 2)); - return len; + basename = c->current_filename; + return get_entry(dest, len, c->current_filename, basename, 0); } static Uint16 @@ -255,48 +242,79 @@ file_delete(UxnFile *c) return c->outside_sandbox ? 0 : unlink(c->current_filename); } -/* file registers */ - -static Uint16 rL; - /* IO */ void -file_deo(Uint8 id, Uint8 *ram, Uint8 *d, Uint8 port) +file_deo(Uint8 port) { - UxnFile *c = &uxn_file[id]; - Uint16 addr, res; + Uint16 addr, len, res; switch(port) { - case 0x5: - addr = (d[0x4] << 8) | d[0x5]; - if(rL > 0x10000 - addr) rL = 0x10000 - addr; - res = file_stat(c, (char *)&ram[addr], rL > 0x10 ? 0x10 : rL); - d[0x2] = res >> 8, d[0x3] = res; - return; - case 0x6: - res = file_delete(c); - d[0x2] = res >> 8, d[0x3] = res; - return; - case 0x9: - addr = (d[0x8] << 8) | d[0x9]; - res = file_init(c, (char *)&ram[addr], 0x10000 - addr, 0); - d[0x2] = res >> 8, d[0x3] = res; - return; - case 0xa: - case 0xb: - rL = (d[0xa] << 8) | d[0xb]; - return; - case 0xd: - addr = (d[0xc] << 8) | d[0xd]; - if(rL > 0x10000 - addr) rL = 0x10000 - addr; - res = file_read(c, &ram[addr], rL); - d[0x2] = res >> 8, d[0x3] = res; - return; - case 0xf: - addr = (d[0xe] << 8) | d[0xf]; - if(rL > 0x10000 - addr) rL = 0x10000 - addr; - res = file_write(c, &ram[addr], rL, d[0x7]); - d[0x2] = res >> 8, d[0x3] = res; - return; + case 0xa5: + addr = PEEK2(&uxn.dev[0xa4]); + len = PEEK2(&uxn.dev[0xaa]); + if(len > 0x10000 - addr) + len = 0x10000 - addr; + res = file_stat(&uxn_file[0], &uxn.ram[addr], len); + POKE2(&uxn.dev[0xa2], res); + break; + case 0xa6: + res = file_delete(&uxn_file[0]); + POKE2(&uxn.dev[0xa2], res); + break; + case 0xa9: + addr = PEEK2(&uxn.dev[0xa8]); + res = file_init(&uxn_file[0], (char *)&uxn.ram[addr], 0x10000 - addr, 0); + POKE2(&uxn.dev[0xa2], res); + break; + case 0xad: + addr = PEEK2(&uxn.dev[0xac]); + len = PEEK2(&uxn.dev[0xaa]); + if(len > 0x10000 - addr) + len = 0x10000 - addr; + res = file_read(&uxn_file[0], &uxn.ram[addr], len); + POKE2(&uxn.dev[0xa2], res); + break; + case 0xaf: + addr = PEEK2(&uxn.dev[0xae]); + len = PEEK2(&uxn.dev[0xaa]); + if(len > 0x10000 - addr) + len = 0x10000 - addr; + res = file_write(&uxn_file[0], &uxn.ram[addr], len, uxn.dev[0xa7]); + POKE2(&uxn.dev[0xa2], res); + break; + /* File 2 */ + case 0xb5: + addr = PEEK2(&uxn.dev[0xb4]); + len = PEEK2(&uxn.dev[0xba]); + if(len > 0x10000 - addr) + len = 0x10000 - addr; + res = file_stat(&uxn_file[1], &uxn.ram[addr], len); + POKE2(&uxn.dev[0xb2], res); + break; + case 0xb6: + res = file_delete(&uxn_file[1]); + POKE2(&uxn.dev[0xb2], res); + break; + case 0xb9: + addr = PEEK2(&uxn.dev[0xb8]); + res = file_init(&uxn_file[1], (char *)&uxn.ram[addr], 0x10000 - addr, 0); + POKE2(&uxn.dev[0xb2], res); + break; + case 0xbd: + addr = PEEK2(&uxn.dev[0xbc]); + len = PEEK2(&uxn.dev[0xba]); + if(len > 0x10000 - addr) + len = 0x10000 - addr; + res = file_read(&uxn_file[1], &uxn.ram[addr], len); + POKE2(&uxn.dev[0xb2], res); + break; + case 0xbf: + addr = PEEK2(&uxn.dev[0xbe]); + len = PEEK2(&uxn.dev[0xba]); + if(len > 0x10000 - addr) + len = 0x10000 - addr; + res = file_write(&uxn_file[1], &uxn.ram[addr], len, uxn.dev[0xb7]); + POKE2(&uxn.dev[0xb2], res); + break; } } diff --git a/src/devices/file.h b/src/devices/file.h index 5b06409..55b4a23 100644 --- a/src/devices/file.h +++ b/src/devices/file.h @@ -9,9 +9,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ -#define FILE_VERSION 1 - #define POLYFILEY 2 #define DEV_FILE0 0xa -void file_deo(Uint8 id, Uint8 *ram, Uint8 *d, Uint8 port); +void file_deo(Uint8 port); diff --git a/src/devices/mouse.c b/src/devices/mouse.c index ccb8aab..27f725f 100644 --- a/src/devices/mouse.c +++ b/src/devices/mouse.c @@ -13,32 +13,33 @@ WITH REGARD TO THIS SOFTWARE. */ void -mouse_down(Uxn *u, Uint8 *d, Uint8 mask) +mouse_down(Uint8 mask) { - d[6] |= mask; - uxn_eval(u, PEEK2(d)); + uxn.dev[0x96] |= mask; + uxn_eval(PEEK2(&uxn.dev[0x90])); } void -mouse_up(Uxn *u, Uint8 *d, Uint8 mask) +mouse_up(Uint8 mask) { - d[6] &= (~mask); - uxn_eval(u, PEEK2(d)); + uxn.dev[0x96] &= (~mask); + uxn_eval(PEEK2(&uxn.dev[0x90])); } void -mouse_pos(Uxn *u, Uint8 *d, Uint16 x, Uint16 y) +mouse_pos(Uint16 x, Uint16 y) { - *(d + 2) = x >> 8, *(d + 3) = x; - *(d + 4) = y >> 8, *(d + 5) = y; - uxn_eval(u, PEEK2(d)); + uxn.dev[0x92] = x >> 8, uxn.dev[0x93] = x; + uxn.dev[0x94] = y >> 8, uxn.dev[0x95] = y; + uxn_eval(PEEK2(&uxn.dev[0x90])); } void -mouse_scroll(Uxn *u, Uint8 *d, Uint16 x, Uint16 y) +mouse_scroll(Uint16 x, Uint16 y) { - *(d + 0xa) = x >> 8, *(d + 0xb) = x; - *(d + 0xc) = -y >> 8, *(d + 0xd) = -y; - uxn_eval(u, PEEK2(d)); - *(d + 0xa) = *(d + 0xb) = *(d + 0xc) = *(d + 0xd) = 0; + uxn.dev[0x9a] = x >> 8, uxn.dev[0x9b] = x; + uxn.dev[0x9c] = -y >> 8, uxn.dev[0x9d] = -y; + uxn_eval(PEEK2(&uxn.dev[0x90])); + uxn.dev[0x9a] = 0, uxn.dev[0x9b] = 0; + uxn.dev[0x9c] = 0, uxn.dev[0x9d] = 0; } diff --git a/src/devices/mouse.h b/src/devices/mouse.h index 3af21f0..7d8ece5 100644 --- a/src/devices/mouse.h +++ b/src/devices/mouse.h @@ -9,9 +9,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ -#define MOUSE_VERSION 1 - -void mouse_down(Uxn *u, Uint8 *d, Uint8 mask); -void mouse_up(Uxn *u, Uint8 *d, Uint8 mask); -void mouse_pos(Uxn *u, Uint8 *d, Uint16 x, Uint16 y); -void mouse_scroll(Uxn *u, Uint8 *d, Uint16 x, Uint16 y); +void mouse_down(Uint8 mask); +void mouse_up(Uint8 mask); +void mouse_pos(Uint16 x, Uint16 y); +void mouse_scroll(Uint16 x, Uint16 y); diff --git a/src/devices/screen.c b/src/devices/screen.c index a6ebee0..5daa081 100644 --- a/src/devices/screen.c +++ b/src/devices/screen.c @@ -19,55 +19,24 @@ UxnScreen uxn_screen; /* c = !ch ? (color % 5 ? color >> 2 : 0) : color % 4 + ch == 1 ? 0 : (ch - 2 + (color & 3)) % 3 + 1; */ -static Uint8 blending[][16] = { +static Uint8 blending[4][16] = { {0, 0, 0, 0, 1, 0, 1, 1, 2, 2, 0, 2, 3, 3, 3, 0}, {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}, {1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1}, - {2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2}, - {0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0}}; - -void -screen_change(Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2) -{ - if(x1 > uxn_screen.width && x2 > x1) return; - if(y1 > uxn_screen.height && y2 > y1) return; - if(x1 > x2) x1 = 0; - if(y1 > y2) y1 = 0; - if(x1 < uxn_screen.x1) uxn_screen.x1 = x1; - if(y1 < uxn_screen.y1) uxn_screen.y1 = y1; - if(x2 > uxn_screen.x2) uxn_screen.x2 = x2; - if(y2 > uxn_screen.y2) uxn_screen.y2 = y2; -} - -void -screen_fill(Uint8 *layer, int color) -{ - int i, length = uxn_screen.width * uxn_screen.height; - for(i = 0; i < length; i++) - layer[i] = color; -} - -void -screen_rect(Uint8 *layer, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, int color) -{ - int row, x, y, w = uxn_screen.width, h = uxn_screen.height; - for(y = y1; y < y2 && y < h; y++) - for(x = x1, row = y * w; x < x2 && x < w; x++) - layer[x + row] = color; -} + {2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2}}; static void screen_2bpp(Uint8 *layer, Uint8 *addr, Uint16 x1, Uint16 y1, Uint16 color, int fx, int fy) { - int w = uxn_screen.width, h = uxn_screen.height, opaque = blending[4][color]; + int row, w = uxn_screen.width, h = uxn_screen.height, opaque = (color % 5); Uint16 y, ymod = (fy < 0 ? 7 : 0), ymax = y1 + ymod + fy * 8; Uint16 x, xmod = (fx > 0 ? 7 : 0), xmax = x1 + xmod - fx * 8; for(y = y1 + ymod; y != ymax; y += fy, addr++) { - int c = addr[0] | (addr[8] << 8), row = y * w; + int c = (addr[8] << 8) | addr[0]; if(y < h) - for(x = x1 + xmod; x != xmax; x -= fx, c >>= 1) { + for(x = x1 + xmod, row = y * w; x != xmax; x -= fx, c >>= 1) { Uint8 ch = (c & 1) | ((c >> 7) & 2); - if(x < w && (opaque || ch)) + if((opaque || ch) && x < w) layer[x + row] = blending[ch][color]; } } @@ -76,20 +45,51 @@ screen_2bpp(Uint8 *layer, Uint8 *addr, Uint16 x1, Uint16 y1, Uint16 color, int f static void screen_1bpp(Uint8 *layer, Uint8 *addr, Uint16 x1, Uint16 y1, Uint16 color, int fx, int fy) { - int w = uxn_screen.width, h = uxn_screen.height, opaque = blending[4][color]; + int row, w = uxn_screen.width, h = uxn_screen.height, opaque = (color % 5); Uint16 y, ymod = (fy < 0 ? 7 : 0), ymax = y1 + ymod + fy * 8; Uint16 x, xmod = (fx > 0 ? 7 : 0), xmax = x1 + xmod - fx * 8; for(y = y1 + ymod; y != ymax; y += fy) { - int c = *addr++, row = y * w; + int c = *addr++; if(y < h) - for(x = x1 + xmod; x != xmax; x -= fx, c >>= 1) { + for(x = x1 + xmod, row = y * w; x != xmax; x -= fx, c >>= 1) { Uint8 ch = c & 1; - if(x < w && (opaque || ch)) + if((opaque || ch) && x < w) layer[x + row] = blending[ch][color]; } } } +int +screen_changed(void) +{ + if(uxn_screen.x1 < 0) + uxn_screen.x1 = 0; + else if(uxn_screen.x1 >= uxn_screen.width) + uxn_screen.x1 = uxn_screen.width; + if(uxn_screen.y1 < 0) + uxn_screen.y1 = 0; + else if(uxn_screen.y1 >= uxn_screen.height) + uxn_screen.y1 = uxn_screen.height; + if(uxn_screen.x2 < 0) + uxn_screen.x2 = 0; + else if(uxn_screen.x2 >= uxn_screen.width) + uxn_screen.x2 = uxn_screen.width; + if(uxn_screen.y2 < 0) + uxn_screen.y2 = 0; + else if(uxn_screen.y2 >= uxn_screen.height) + uxn_screen.y2 = uxn_screen.height; + return uxn_screen.x2 > uxn_screen.x1 && uxn_screen.y2 > uxn_screen.y1; +} + +void +screen_change(int x1, int y1, int x2, int y2) +{ + if(x1 < uxn_screen.x1) uxn_screen.x1 = x1; + if(y1 < uxn_screen.y1) uxn_screen.y1 = y1; + if(x2 > uxn_screen.x2) uxn_screen.x2 = x2; + if(y2 > uxn_screen.y2) uxn_screen.y2 = y2; +} + /* clang-format off */ static Uint8 icons[] = { @@ -116,37 +116,54 @@ draw_byte(Uint8 b, Uint16 x, Uint16 y, Uint8 color) } static void -screen_debugger(Uxn *u) +screen_debugger(void) { int i; for(i = 0; i < 0x08; i++) { - Uint8 pos = u->wst.ptr - 4 + i; + Uint8 pos = uxn.wst.ptr - 4 + i; Uint8 color = i > 4 ? 0x01 : !pos ? 0xc : i == 4 ? 0x8 : 0x2; - draw_byte(u->wst.dat[pos], i * 0x18 + 0x8, uxn_screen.height - 0x18, color); + draw_byte(uxn.wst.dat[pos], i * 0x18 + 0x8, uxn_screen.height - 0x18, color); } for(i = 0; i < 0x08; i++) { - Uint8 pos = u->rst.ptr - 4 + i; + Uint8 pos = uxn.rst.ptr - 4 + i; Uint8 color = i > 4 ? 0x01 : !pos ? 0xc : i == 4 ? 0x8 : 0x2; - draw_byte(u->rst.dat[pos], i * 0x18 + 0x8, uxn_screen.height - 0x10, color); + draw_byte(uxn.rst.dat[pos], i * 0x18 + 0x8, uxn_screen.height - 0x10, color); } screen_1bpp(uxn_screen.fg, &arrow[0], 0x68, uxn_screen.height - 0x20, 3, 1, 1); for(i = 0; i < 0x20; i++) - draw_byte(u->ram[i], (i & 0x7) * 0x18 + 0x8, ((i >> 3) << 3) + 0x8, 1 + !!u->ram[i]); + draw_byte(uxn.ram[i], (i & 0x7) * 0x18 + 0x8, ((i >> 3) << 3) + 0x8, 1 + !!uxn.ram[i]); } void -screen_palette(Uint8 *addr) +screen_fill(Uint8 *layer, int color) +{ + int i, length = uxn_screen.width * uxn_screen.height; + for(i = 0; i < length; i++) + layer[i] = color; +} + +void +screen_rect(Uint8 *layer, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, int color) +{ + int row, x, y, w = uxn_screen.width, h = uxn_screen.height; + for(y = y1; y < y2 && y < h; y++) + for(x = x1, row = y * w; x < x2 && x < w; x++) + layer[x + row] = color; +} + +void +screen_palette(void) { int i, shift; for(i = 0, shift = 4; i < 4; ++i, shift ^= 4) { Uint8 - r = (addr[0 + i / 2] >> shift) & 0xf, - g = (addr[2 + i / 2] >> shift) & 0xf, - b = (addr[4 + i / 2] >> shift) & 0xf; + r = (uxn.dev[0x8 + i / 2] >> shift) & 0xf, + g = (uxn.dev[0xa + i / 2] >> shift) & 0xf, + b = (uxn.dev[0xc + i / 2] >> shift) & 0xf; uxn_screen.palette[i] = 0x0f000000 | r << 16 | g << 8 | b; uxn_screen.palette[i] |= uxn_screen.palette[i] << 4; } @@ -154,56 +171,74 @@ screen_palette(Uint8 *addr) } void -screen_resize(Uint16 width, Uint16 height) +screen_resize(Uint16 width, Uint16 height, int scale) { Uint8 *bg, *fg; Uint32 *pixels = NULL; - if(width < 0x8 || height < 0x8 || width >= 0x800 || height >= 0x800) + int dim_change = uxn_screen.width != width || uxn_screen.height != height; + if(width < 0x8 || height < 0x8 || width >= 0x800 || height >= 0x800 || scale < 1 || scale >= 4) return; - if(uxn_screen.width == width && uxn_screen.height == height) - return; - bg = malloc(width * height), fg = malloc(width * height); - if(bg && fg) - pixels = realloc(uxn_screen.pixels, width * height * sizeof(Uint32)); - if(!bg || !fg || !pixels) { - free(bg), free(fg); + if(uxn_screen.width == width && uxn_screen.height == height && uxn_screen.scale == scale) return; + if(dim_change) { + bg = malloc(width * height), fg = malloc(width * height); + if(bg && fg) + pixels = realloc(uxn_screen.pixels, width * height * sizeof(Uint32) * scale * scale); + if(!bg || !fg || !pixels) { + free(bg), free(fg); + return; + } + free(uxn_screen.bg), free(uxn_screen.fg); + } else { + bg = uxn_screen.bg, fg = uxn_screen.fg; + pixels = realloc(uxn_screen.pixels, width * height * sizeof(Uint32) * scale * scale); + if(!pixels) + return; } - free(uxn_screen.bg), free(uxn_screen.fg); uxn_screen.bg = bg, uxn_screen.fg = fg; uxn_screen.pixels = pixels; - uxn_screen.width = width, uxn_screen.height = height; - screen_fill(uxn_screen.bg, 0), screen_fill(uxn_screen.fg, 0); + uxn_screen.width = width, uxn_screen.height = height, uxn_screen.scale = scale; + if(dim_change) + screen_fill(uxn_screen.bg, 0), screen_fill(uxn_screen.fg, 0); emu_resize(width, height); screen_change(0, 0, width, height); } void -screen_redraw(Uxn *u) +screen_redraw(void) { - int i, j, o, y; + int i, x, y, k, l, s = uxn_screen.scale; Uint8 *fg = uxn_screen.fg, *bg = uxn_screen.bg; Uint16 w = uxn_screen.width, h = uxn_screen.height; Uint16 x1 = uxn_screen.x1, y1 = uxn_screen.y1; Uint16 x2 = uxn_screen.x2 > w ? w : uxn_screen.x2, y2 = uxn_screen.y2 > h ? h : uxn_screen.y2; Uint32 palette[16], *pixels = uxn_screen.pixels; - uxn_screen.x1 = uxn_screen.y1 = 0xffff; + uxn_screen.x1 = uxn_screen.y1 = 9000; uxn_screen.x2 = uxn_screen.y2 = 0; - if(u->dev[0x0e]) - screen_debugger(u); + if(uxn.dev[0x0e]) + screen_debugger(); for(i = 0; i < 16; i++) palette[i] = uxn_screen.palette[(i >> 2) ? (i >> 2) : (i & 3)]; - for(y = y1; y < y2; y++) - for(o = y * w, i = x1 + o, j = x2 + o; i < j; i++) - pixels[i] = palette[fg[i] << 2 | bg[i]]; + for(y = y1; y < y2; y++) { + int ys = y * s; + int o = y * w; + for(x = x1, i = x1 + o; x < x2; x++, i++) { + int c = palette[fg[i] << 2 | bg[i]]; + for(k = 0; k < s; k++) { + int oo = ((ys + k) * w + x) * s; + for(l = 0; l < s; l++) + pixels[oo + l] = c; + } + } + } } /* screen registers */ -static Uint16 rX, rY, rA, rMX, rMY, rMA, rML, rDX, rDY; +static int rX, rY, rA, rMX, rMY, rMA, rML, rDX, rDY; Uint8 -screen_dei(Uxn *u, Uint8 addr) +screen_dei(Uint8 addr) { switch(addr) { case 0x22: return uxn_screen.width >> 8; @@ -216,25 +251,25 @@ screen_dei(Uxn *u, Uint8 addr) case 0x2b: return rY; case 0x2c: return rA >> 8; case 0x2d: return rA; - default: return u->dev[addr]; + default: return uxn.dev[addr]; } } void -screen_deo(Uint8 *ram, Uint8 *d, Uint8 port) +screen_deo(Uint8 addr) { - switch(port) { - case 0x3: screen_resize(PEEK2(d + 2), uxn_screen.height); return; - case 0x5: screen_resize(uxn_screen.width, PEEK2(d + 4)); return; - case 0x6: rMX = d[0x6] & 0x1, rMY = d[0x6] & 0x2, rMA = d[0x6] & 0x4, rML = d[0x6] >> 4, rDX = rMX << 3, rDY = rMY << 2; return; - case 0x8: - case 0x9: rX = (d[0x8] << 8) | d[0x9]; return; - case 0xa: - case 0xb: rY = (d[0xa] << 8) | d[0xb]; return; - case 0xc: - case 0xd: rA = (d[0xc] << 8) | d[0xd]; return; - case 0xe: { - Uint8 ctrl = d[0xe]; + switch(addr) { + case 0x23: screen_resize(PEEK2(&uxn.dev[0x22]), uxn_screen.height, uxn_screen.scale); return; + case 0x25: screen_resize(uxn_screen.width, PEEK2(&uxn.dev[0x24]), uxn_screen.scale); return; + case 0x26: rMX = uxn.dev[0x26] & 0x1, rMY = uxn.dev[0x26] & 0x2, rMA = uxn.dev[0x26] & 0x4, rML = uxn.dev[0x26] >> 4, rDX = rMX << 3, rDY = rMY << 2; return; + case 0x28: + case 0x29: rX = (uxn.dev[0x28] << 8) | uxn.dev[0x29], rX = twos(rX); return; + case 0x2a: + case 0x2b: rY = (uxn.dev[0x2a] << 8) | uxn.dev[0x2b], rY = twos(rY); return; + case 0x2c: + case 0x2d: rA = (uxn.dev[0x2c] << 8) | uxn.dev[0x2d]; return; + case 0x2e: { + Uint8 ctrl = uxn.dev[0x2e]; Uint8 color = ctrl & 0x3; Uint8 *layer = ctrl & 0x40 ? uxn_screen.fg : uxn_screen.bg; /* fill mode */ @@ -254,7 +289,7 @@ screen_deo(Uint8 *ram, Uint8 *d, Uint8 port) /* pixel mode */ else { Uint16 w = uxn_screen.width; - if(rX < w && rY < uxn_screen.height) + if(rX >= 0 && rY >= 0 && rX < w && rY < uxn_screen.height) layer[rX + rY * w] = color; screen_change(rX, rY, rX + 1, rY + 1); if(rMX) rX++; @@ -262,22 +297,30 @@ screen_deo(Uint8 *ram, Uint8 *d, Uint8 port) } return; } - case 0xf: { + case 0x2f: { Uint8 i; - Uint8 ctrl = d[0xf]; + Uint8 ctrl = uxn.dev[0x2f]; Uint8 twobpp = !!(ctrl & 0x80); Uint8 color = ctrl & 0xf; Uint8 *layer = ctrl & 0x40 ? uxn_screen.fg : uxn_screen.bg; - int fx = ctrl & 0x10 ? -1 : 1; - int fy = ctrl & 0x20 ? -1 : 1; - Uint16 dxy = rDX * fy, dyx = rDY * fx, addr_incr = rMA << (1 + twobpp); + int fx = ctrl & 0x10 ? -1 : 1, fy = ctrl & 0x20 ? -1 : 1; + int x1, x2, y1, y2, x = rX, y = rY; + int dxy = rDX * fy, dyx = rDY * fx, addr_incr = rMA << (1 + twobpp); if(twobpp) - for(i = 0; i <= rML; i++, rA += addr_incr) - screen_2bpp(layer, &ram[rA], rX + dyx * i, rY + dxy * i, color, fx, fy); + for(i = 0; i <= rML; i++, x += dyx, y += dxy, rA += addr_incr) + screen_2bpp(layer, &uxn.ram[rA], x, y, color, fx, fy); else - for(i = 0; i <= rML; i++, rA += addr_incr) - screen_1bpp(layer, &ram[rA], rX + dyx * i, rY + dxy * i, color, fx, fy); - screen_change(rX, rY, rX + dyx * rML + 8, rY + dxy * rML + 8); + for(i = 0; i <= rML; i++, x += dyx, y += dxy, rA += addr_incr) + screen_1bpp(layer, &uxn.ram[rA], x, y, color, fx, fy); + if(fx < 0) + x1 = x, x2 = rX; + else + x1 = rX, x2 = x; + if(fy < 0) + y1 = y, y2 = rY; + else + y1 = rY, y2 = y; + screen_change(x1, y1, x2 + 8, y2 + 8); if(rMX) rX += rDX * fx; if(rMY) rY += rDY * fy; return; diff --git a/src/devices/screen.h b/src/devices/screen.h index 8fd449f..2ad82d5 100644 --- a/src/devices/screen.h +++ b/src/devices/screen.h @@ -9,23 +9,23 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ -#define SCREEN_VERSION 1 - typedef struct UxnScreen { - int width, height, x1, y1, x2, y2; + int width, height, x1, y1, x2, y2, scale; Uint32 palette[4], *pixels; Uint8 *fg, *bg; } UxnScreen; extern UxnScreen uxn_screen; extern int emu_resize(int width, int height); - +int screen_changed(void); +void screen_change(int x1, int y1, int x2, int y2); void screen_fill(Uint8 *layer, int color); void screen_rect(Uint8 *layer, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, int color); -void screen_palette(Uint8 *addr); -void screen_resize(Uint16 width, Uint16 height); -void screen_change(Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2); -void screen_redraw(Uxn *u); +void screen_palette(void); +void screen_resize(Uint16 width, Uint16 height, int scale); +void screen_redraw(); -Uint8 screen_dei(Uxn *u, Uint8 addr); -void screen_deo(Uint8 *ram, Uint8 *d, Uint8 port); +Uint8 screen_dei(Uint8 addr); +void screen_deo(Uint8 addr); + +#define twos(v) (v & 0x8000 ? (int)v - 0x10000 : (int)v) diff --git a/src/devices/system.c b/src/devices/system.c index edd281e..d8e421d 100644 --- a/src/devices/system.c +++ b/src/devices/system.c @@ -5,7 +5,7 @@ #include "system.h" /* -Copyright (c) 2022-2023 Devine Lu Linvega, Andrew Alderwick +Copyright (c) 2022-2024 Devine Lu Linvega, Andrew Alderwick Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -16,20 +16,29 @@ WITH REGARD TO THIS SOFTWARE. */ char *boot_rom; -Uint16 dev_vers[0x10]; + +static void +system_zero(int soft) +{ + int i; + for(i = soft ? 0x100 : 0; i < 0x10000; i++) + uxn.ram[i] = 0; + for(i = 0x0; i < 0x100; i++) + uxn.dev[i] = 0; + uxn.wst.ptr = uxn.rst.ptr = 0; +} static int -system_load(Uxn *u, char *filename) +system_load(char *filename) { - int l, i = 0; FILE *f = fopen(filename, "rb"); - if(!f) - return 0; - l = fread(&u->ram[PAGE_PROGRAM], 0x10000 - PAGE_PROGRAM, 1, f); - while(l && ++i < RAM_PAGES) - l = fread(u->ram + 0x10000 * i, 0x10000, 1, f); - fclose(f); - return 1; + if(f) { + int i = 0, l = fread(&uxn.ram[PAGE_PROGRAM], 0x10000 - PAGE_PROGRAM, 1, f); + while(l && ++i < RAM_PAGES) + l = fread(uxn.ram + 0x10000 * i, 0x10000, 1, f); + fclose(f); + } + return !!f; } static void @@ -41,49 +50,38 @@ system_print(Stack *s) fprintf(stderr, "< \n"); } -static void -system_zero(Uxn *u, int soft) -{ - int i; - for(i = PAGE_PROGRAM * soft; i < 0x10000; i++) - u->ram[i] = 0; - for(i = 0x0; i < 0x100; i++) - u->dev[i] = 0; - u->wst.ptr = u->rst.ptr = 0; -} - void -system_inspect(Uxn *u) +system_inspect(void) { - fprintf(stderr, "WST "), system_print(&u->wst); - fprintf(stderr, "RST "), system_print(&u->rst); + fprintf(stderr, "WST "), system_print(&uxn.wst); + fprintf(stderr, "RST "), system_print(&uxn.rst); } int system_error(char *msg, const char *err) { - fprintf(stderr, "%s %s\n", msg, err); + fprintf(stderr, "%s: %s\n", msg, err); fflush(stderr); return 0; } void -system_reboot(Uxn *u, char *rom, int soft) +system_reboot(char *rom, int soft) { - system_zero(u, soft); - if(system_load(u, boot_rom)) - if(uxn_eval(u, PAGE_PROGRAM)) + system_zero(soft); + if(system_load(boot_rom)) + if(uxn_eval(PAGE_PROGRAM)) boot_rom = rom; } int -system_init(Uxn *u, Uint8 *ram, char *rom) +system_boot(Uint8 *ram, char *rom) { - u->ram = ram; - system_zero(u, 0); - if(!system_load(u, rom)) - if(!system_load(u, "boot.rom")) - return system_error("Init", "Failed to load rom."); + uxn.ram = ram; + system_zero(0); + if(!system_load(rom)) + if(!system_load("boot.rom")) + return system_error("Could not load rom", rom); boot_rom = rom; return 1; } @@ -91,56 +89,54 @@ system_init(Uxn *u, Uint8 *ram, char *rom) /* IO */ Uint8 -system_dei(Uxn *u, Uint8 addr) +system_dei(Uint8 addr) { switch(addr) { - case 0x4: return u->wst.ptr; - case 0x5: return u->rst.ptr; - default: return u->dev[addr]; + case 0x4: return uxn.wst.ptr; + case 0x5: return uxn.rst.ptr; + default: return uxn.dev[addr]; } } void -system_deo(Uxn *u, Uint8 *d, Uint8 port) +system_deo(Uint8 port) { - Uint8 *ram; - Uint16 addr; switch(port) { - case 0x3: - ram = u->ram; - addr = PEEK2(d + 2); - if(ram[addr] == 0x0) { - Uint8 value = ram[addr + 7]; - Uint16 i, length = PEEK2(ram + addr + 1); - Uint16 dst_page = PEEK2(ram + addr + 3), dst_addr = PEEK2(ram + addr + 5); + case 0x3: { + Uint16 addr = PEEK2(uxn.dev + 2); + if(uxn.ram[addr] == 0x0) { + Uint8 value = uxn.ram[addr + 7]; + Uint16 i, length = PEEK2(uxn.ram + addr + 1); + Uint16 dst_page = PEEK2(uxn.ram + addr + 3), dst_addr = PEEK2(uxn.ram + addr + 5); int dst = (dst_page % RAM_PAGES) * 0x10000; for(i = 0; i < length; i++) - ram[dst + (Uint16)(dst_addr + i)] = value; - } else if(ram[addr] == 0x1) { - Uint16 i, length = PEEK2(ram + addr + 1); - Uint16 a_page = PEEK2(ram + addr + 3), a_addr = PEEK2(ram + addr + 5); - Uint16 b_page = PEEK2(ram + addr + 7), b_addr = PEEK2(ram + addr + 9); + uxn.ram[dst + (Uint16)(dst_addr + i)] = value; + } else if(uxn.ram[addr] == 0x1) { + Uint16 i, length = PEEK2(uxn.ram + addr + 1); + Uint16 a_page = PEEK2(uxn.ram + addr + 3), a_addr = PEEK2(uxn.ram + addr + 5); + Uint16 b_page = PEEK2(uxn.ram + addr + 7), b_addr = PEEK2(uxn.ram + addr + 9); int src = (a_page % RAM_PAGES) * 0x10000, dst = (b_page % RAM_PAGES) * 0x10000; for(i = 0; i < length; i++) - ram[dst + (Uint16)(b_addr + i)] = ram[src + (Uint16)(a_addr + i)]; - } else if(ram[addr] == 0x2) { - Uint16 i, length = PEEK2(ram + addr + 1); - Uint16 a_page = PEEK2(ram + addr + 3), a_addr = PEEK2(ram + addr + 5); - Uint16 b_page = PEEK2(ram + addr + 7), b_addr = PEEK2(ram + addr + 9); + uxn.ram[dst + (Uint16)(b_addr + i)] = uxn.ram[src + (Uint16)(a_addr + i)]; + } else if(uxn.ram[addr] == 0x2) { + Uint16 i, length = PEEK2(uxn.ram + addr + 1); + Uint16 a_page = PEEK2(uxn.ram + addr + 3), a_addr = PEEK2(uxn.ram + addr + 5); + Uint16 b_page = PEEK2(uxn.ram + addr + 7), b_addr = PEEK2(uxn.ram + addr + 9); int src = (a_page % RAM_PAGES) * 0x10000, dst = (b_page % RAM_PAGES) * 0x10000; for(i = length - 1; i != 0xffff; i--) - ram[dst + (Uint16)(b_addr + i)] = ram[src + (Uint16)(a_addr + i)]; + uxn.ram[dst + (Uint16)(b_addr + i)] = uxn.ram[src + (Uint16)(a_addr + i)]; } else - fprintf(stderr, "Unknown Expansion Command 0x%02x\n", ram[addr]); + fprintf(stderr, "Unknown Expansion Command 0x%02x\n", uxn.ram[addr]); break; + } case 0x4: - u->wst.ptr = d[4]; + uxn.wst.ptr = uxn.dev[4]; break; case 0x5: - u->rst.ptr = d[5]; + uxn.rst.ptr = uxn.dev[5]; break; case 0xe: - system_inspect(u); + system_inspect(); break; } } diff --git a/src/devices/system.h b/src/devices/system.h index bea865e..f9f0704 100644 --- a/src/devices/system.h +++ b/src/devices/system.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2022 Devine Lu Linvega, Andrew Alderwick +Copyright (c) 2024 Devine Lu Linvega, Andrew Alderwick Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -9,16 +9,14 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ -#define SYSTEM_VERSION 2 - #define RAM_PAGES 0x10 -extern char *boot_rom; - +void system_reboot(char *rom, int soft); +void system_inspect(void); int system_error(char *msg, const char *err); -void system_reboot(Uxn *u, char *rom, int soft); -void system_inspect(Uxn *u); -int system_init(Uxn *u, Uint8 *ram, char *rom); +int system_boot(Uint8 *ram, char *rom); -Uint8 system_dei(Uxn *u, Uint8 addr); -void system_deo(Uxn *u, Uint8 *d, Uint8 port); +Uint8 system_dei(Uint8 addr); +void system_deo(Uint8 addr); + +extern char *boot_rom; \ No newline at end of file diff --git a/src/uxn.c b/src/uxn.c index ae7463c..b8a3ac1 100644 --- a/src/uxn.c +++ b/src/uxn.c @@ -1,7 +1,7 @@ #include "uxn.h" /* -Copyright (u) 2022-2023 Devine Lu Linvega, Andrew Alderwick, Andrew Richards +Copyright (u) 2022-2024 Devine Lu Linvega, Andrew Alderwick, Andrew Richards Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -11,113 +11,79 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ -/* Registers -[ Z ][ Y ][ X ][ L ][ N ][ T ] < -[ . ][ . ][ . ][ H2 ][ . ] < -[ L2 ][ N2 ][ T2 ] < -*/ +#define OPC(opc, body) {\ + case 0x00|opc: {int _2=0,_r=0,a,b,c; Stack *s = &uxn.wst; Uint8 *sp = &uxn.wst.ptr; body break;}\ + case 0x20|opc: {int _2=1,_r=0,a,b,c; Stack *s = &uxn.wst; Uint8 *sp = &uxn.wst.ptr; body break;}\ + case 0x40|opc: {int _2=0,_r=1,a,b,c; Stack *s = &uxn.rst; Uint8 *sp = &uxn.rst.ptr; body break;}\ + case 0x60|opc: {int _2=1,_r=1,a,b,c; Stack *s = &uxn.rst; Uint8 *sp = &uxn.rst.ptr; body break;}\ + case 0x80|opc: {int _2=0,_r=0,a,b,c; Stack *s = &uxn.wst; Uint8 kp = uxn.wst.ptr, *sp = &kp; body break;}\ + case 0xa0|opc: {int _2=1,_r=0,a,b,c; Stack *s = &uxn.wst; Uint8 kp = uxn.wst.ptr, *sp = &kp; body break;}\ + case 0xc0|opc: {int _2=0,_r=1,a,b,c; Stack *s = &uxn.rst; Uint8 kp = uxn.rst.ptr, *sp = &kp; body break;}\ + case 0xe0|opc: {int _2=1,_r=1,a,b,c; Stack *s = &uxn.rst; Uint8 kp = uxn.rst.ptr, *sp = &kp; body break;}\ +} -#define T *(s->dat + s->ptr) -#define N *(s->dat + (Uint8)(s->ptr - 1)) -#define L *(s->dat + (Uint8)(s->ptr - 2)) -#define X *(s->dat + (Uint8)(s->ptr - 3)) -#define Y *(s->dat + (Uint8)(s->ptr - 4)) -#define Z *(s->dat + (Uint8)(s->ptr - 5)) -#define T2 (N << 8 | T) -#define H2 (L << 8 | N) -#define N2 (X << 8 | L) -#define L2 (Z << 8 | Y) -#define T2_(v) { r = (v); T = r; N = r >> 8; } -#define N2_(v) { r = (v); L = r; X = r >> 8; } -#define L2_(v) { r = (v); Y = r; Z = r >> 8; } -#define FLIP { s = ins & 0x40 ? &u->wst : &u->rst; } -#define SHIFT(y) { s->ptr += (y); } -#define SET(x, y) { SHIFT((ins & 0x80) ? x + y : y) } +#define FLP { s = _r ? &uxn.wst : &uxn.rst; } +#define JMI { pc += uxn.ram[pc++] << 8 | uxn.ram[pc++]; } +#define JMP(x) { if(_2) pc = (x); else pc += (Sint8)(x); } +#define POx(o) { if(_2) { PO2(o) } else PO1(o) } +#define PO1(o) { o = s->dat[--*sp]; } +#define PO2(o) { o = s->dat[--*sp] | (s->dat[--*sp] << 8); } +#define PUx(y) { if(_2) { PU2(y) } else PU1(y) } +#define PU1(y) { s->dat[s->ptr++] = (y); } +#define PU2(y) { tt = (y); s->dat[s->ptr++] = tt >> 0x8; s->dat[s->ptr++] = tt; } +#define IMM(x, y) { uxn.x.dat[uxn.x.ptr++] = (y); } +#define DEI(o, p) { if(_2) { o = (emu_dei(p) << 8) | emu_dei(p + 1); } else o = emu_dei(p); } +#define DEO(p, y) { if(_2) { emu_deo(p, y >> 8); emu_deo(p + 1, y); } else emu_deo(p, y); } +#define PEK(o, x, r) { if(_2) { r = (x); o = uxn.ram[r++] << 8 | uxn.ram[r]; } else o = uxn.ram[(x)]; } +#define POK(x, y, r) { if(_2) { r = (x); uxn.ram[r++] = y >> 8; uxn.ram[r] = y; } else uxn.ram[(x)] = (y); } int -uxn_eval(Uxn *u, Uint16 pc) +uxn_eval(Uint16 pc) { - Uint16 t, n, l, r; - Uint8 *ram = u->ram, *rr; - if(!pc || u->dev[0x0f]) return 0; + if(!pc || uxn.dev[0x0f]) return 0; for(;;) { - Uint8 ins = ram[pc++]; - Stack *s = ins & 0x40 ? &u->rst : &u->wst; - switch(ins & 0x3f) { - /* IMM */ - case 0x00: case 0x20: - switch(ins) { - case 0x00: /* BRK */ return 1; - case 0x20: /* JCI */ t=T; SHIFT(-1) if(!t) { pc += 2; break; } /* fall-through */ - case 0x40: /* JMI */ rr = ram + pc; pc += 2 + PEEK2(rr); break; - case 0x60: /* JSI */ SHIFT( 2) rr = ram + pc; pc += 2; T2_(pc); pc += PEEK2(rr); break; - case 0x80: /* LIT */ case 0xc0: SHIFT( 1) T = ram[pc++]; break; - case 0xa0: /* LIT2 */ case 0xe0: SHIFT( 2) N = ram[pc++]; T = ram[pc++]; break; - } break; - /* ALU */ - case 0x01: /* INC */ t=T; SET(1, 0) T = t + 1; break; - case 0x21: /* INC2 */ t=T2; SET(2, 0) T2_(t + 1) break; - case 0x02: /* POP */ SET(1,-1) break; - case 0x22: /* POP2 */ SET(2,-2) break; - case 0x03: /* NIP */ t=T; SET(2,-1) T = t; break; - case 0x23: /* NIP2 */ t=T2; SET(4,-2) T2_(t) break; - case 0x04: /* SWP */ t=T;n=N; SET(2, 0) T = n; N = t; break; - case 0x24: /* SWP2 */ t=T2;n=N2; SET(4, 0) T2_(n) N2_(t) break; - case 0x05: /* ROT */ t=T;n=N;l=L; SET(3, 0) T = l; N = t; L = n; break; - case 0x25: /* ROT2 */ t=T2;n=N2;l=L2; SET(6, 0) T2_(l) N2_(t) L2_(n) break; - case 0x06: /* DUP */ t=T; SET(1, 1) T = t; N = t; break; - case 0x26: /* DUP2 */ t=T2; SET(2, 2) T2_(t) N2_(t) break; - case 0x07: /* OVR */ t=T;n=N; SET(2, 1) T = n; N = t; L = n; break; - case 0x27: /* OVR2 */ t=T2;n=N2; SET(4, 2) T2_(n) N2_(t) L2_(n) break; - case 0x08: /* EQU */ t=T;n=N; SET(2,-1) T = n == t; break; - case 0x28: /* EQU2 */ t=T2;n=N2; SET(4,-3) T = n == t; break; - case 0x09: /* NEQ */ t=T;n=N; SET(2,-1) T = n != t; break; - case 0x29: /* NEQ2 */ t=T2;n=N2; SET(4,-3) T = n != t; break; - case 0x0a: /* GTH */ t=T;n=N; SET(2,-1) T = n > t; break; - case 0x2a: /* GTH2 */ t=T2;n=N2; SET(4,-3) T = n > t; break; - case 0x0b: /* LTH */ t=T;n=N; SET(2,-1) T = n < t; break; - case 0x2b: /* LTH2 */ t=T2;n=N2; SET(4,-3) T = n < t; break; - case 0x0c: /* JMP */ t=T; SET(1,-1) pc += (Sint8)t; break; - case 0x2c: /* JMP2 */ t=T2; SET(2,-2) pc = t; break; - case 0x0d: /* JCN */ t=T;n=N; SET(2,-2) if(n) pc += (Sint8)t; break; - case 0x2d: /* JCN2 */ t=T2;n=L; SET(3,-3) if(n) pc = t; break; - case 0x0e: /* JSR */ t=T; SET(1,-1) FLIP SHIFT(2) T2_(pc) pc += (Sint8)t; break; - case 0x2e: /* JSR2 */ t=T2; SET(2,-2) FLIP SHIFT(2) T2_(pc) pc = t; break; - case 0x0f: /* STH */ t=T; SET(1,-1) FLIP SHIFT(1) T = t; break; - case 0x2f: /* STH2 */ t=T2; SET(2,-2) FLIP SHIFT(2) T2_(t) break; - case 0x10: /* LDZ */ t=T; SET(1, 0) T = ram[t]; break; - case 0x30: /* LDZ2 */ t=T; SET(1, 1) N = ram[t++]; T = ram[(Uint8)t]; break; - case 0x11: /* STZ */ t=T;n=N; SET(2,-2) ram[t] = n; break; - case 0x31: /* STZ2 */ t=T;n=H2; SET(3,-3) ram[t++] = n >> 8; ram[(Uint8)t] = n; break; - case 0x12: /* LDR */ t=T; SET(1, 0) r = pc + (Sint8)t; T = ram[r]; break; - case 0x32: /* LDR2 */ t=T; SET(1, 1) r = pc + (Sint8)t; N = ram[r++]; T = ram[r]; break; - case 0x13: /* STR */ t=T;n=N; SET(2,-2) r = pc + (Sint8)t; ram[r] = n; break; - case 0x33: /* STR2 */ t=T;n=H2; SET(3,-3) r = pc + (Sint8)t; ram[r++] = n >> 8; ram[r] = n; break; - case 0x14: /* LDA */ t=T2; SET(2,-1) T = ram[t]; break; - case 0x34: /* LDA2 */ t=T2; SET(2, 0) N = ram[t++]; T = ram[t]; break; - case 0x15: /* STA */ t=T2;n=L; SET(3,-3) ram[t] = n; break; - case 0x35: /* STA2 */ t=T2;n=N2; SET(4,-4) ram[t++] = n >> 8; ram[t] = n; break; - case 0x16: /* DEI */ t=T; SET(1, 0) T = emu_dei(u, t); break; - case 0x36: /* DEI2 */ t=T; SET(1, 1) N = emu_dei(u, t++); T = emu_dei(u, t); break; - case 0x17: /* DEO */ t=T;n=N; SET(2,-2) emu_deo(u, t, n); break; - case 0x37: /* DEO2 */ t=T;n=N;l=L; SET(3,-3) emu_deo(u, t++, l); emu_deo(u, t, n); break; - case 0x18: /* ADD */ t=T;n=N; SET(2,-1) T = n + t; break; - case 0x38: /* ADD2 */ t=T2;n=N2; SET(4,-2) T2_(n + t) break; - case 0x19: /* SUB */ t=T;n=N; SET(2,-1) T = n - t; break; - case 0x39: /* SUB2 */ t=T2;n=N2; SET(4,-2) T2_(n - t) break; - case 0x1a: /* MUL */ t=T;n=N; SET(2,-1) T = n * t; break; - case 0x3a: /* MUL2 */ t=T2;n=N2; SET(4,-2) T2_(n * t) break; - case 0x1b: /* DIV */ t=T;n=N; SET(2,-1) T = t ? n / t : 0; break; - case 0x3b: /* DIV2 */ t=T2;n=N2; SET(4,-2) T2_(t ? n / t : 0) break; - case 0x1c: /* AND */ t=T;n=N; SET(2,-1) T = n & t; break; - case 0x3c: /* AND2 */ t=T2;n=N2; SET(4,-2) T2_(n & t) break; - case 0x1d: /* ORA */ t=T;n=N; SET(2,-1) T = n | t; break; - case 0x3d: /* ORA2 */ t=T2;n=N2; SET(4,-2) T2_(n | t) break; - case 0x1e: /* EOR */ t=T;n=N; SET(2,-1) T = n ^ t; break; - case 0x3e: /* EOR2 */ t=T2;n=N2; SET(4,-2) T2_(n ^ t) break; - case 0x1f: /* SFT */ t=T;n=N; SET(2,-1) T = n >> (t & 0xf) << (t >> 4); break; - case 0x3f: /* SFT2 */ t=T;n=H2; SET(3,-1) T2_(n >> (t & 0xf) << (t >> 4)) break; + Uint8 t; + Uint16 tt; + switch(uxn.ram[pc++]) { + /* BRK */ case 0x00: return 1; + /* JCI */ case 0x20: if(uxn.wst.dat[--uxn.wst.ptr]) { JMI break; } pc += 2; break; + /* JMI */ case 0x40: JMI break; + /* JSI */ case 0x60: tt = pc + 2; IMM(rst, tt >> 8) IMM(rst, tt) JMI break; + /* LI2 */ case 0xa0: IMM(wst, uxn.ram[pc++]) + /* LIT */ case 0x80: IMM(wst, uxn.ram[pc++]) break; + /* L2r */ case 0xe0: IMM(rst, uxn.ram[pc++]) + /* LIr */ case 0xc0: IMM(rst, uxn.ram[pc++]) break; + /* INC */ OPC(0x01, POx(a) PUx(a + 1)) + /* POP */ OPC(0x02, POx(a)) + /* NIP */ OPC(0x03, POx(a) POx(b) PUx(a)) + /* SWP */ OPC(0x04, POx(a) POx(b) PUx(a) PUx(b)) + /* ROT */ OPC(0x05, POx(a) POx(b) POx(c) PUx(b) PUx(a) PUx(c)) + /* DUP */ OPC(0x06, POx(a) PUx(a) PUx(a)) + /* OVR */ OPC(0x07, POx(a) POx(b) PUx(b) PUx(a) PUx(b)) + /* EQU */ OPC(0x08, POx(a) POx(b) PU1(b == a)) + /* NEQ */ OPC(0x09, POx(a) POx(b) PU1(b != a)) + /* GTH */ OPC(0x0a, POx(a) POx(b) PU1(b > a)) + /* LTH */ OPC(0x0b, POx(a) POx(b) PU1(b < a)) + /* JMP */ OPC(0x0c, POx(a) JMP(a)) + /* JCN */ OPC(0x0d, POx(a) PO1(b) if(b) JMP(a)) + /* JSR */ OPC(0x0e, POx(a) FLP PU2(pc) JMP(a)) + /* STH */ OPC(0x0f, POx(a) FLP PUx(a)) + /* LDZ */ OPC(0x10, PO1(a) PEK(b, a, t) PUx(b)) + /* STZ */ OPC(0x11, PO1(a) POx(b) POK(a, b, t)) + /* LDR */ OPC(0x12, PO1(a) PEK(b, pc + (Sint8)a, tt) PUx(b)) + /* STR */ OPC(0x13, PO1(a) POx(b) POK(pc + (Sint8)a, b, tt)) + /* LDA */ OPC(0x14, PO2(a) PEK(b, a, tt) PUx(b)) + /* STA */ OPC(0x15, PO2(a) POx(b) POK(a, b, tt)) + /* DEI */ OPC(0x16, PO1(a) DEI(b, a) PUx(b)) + /* DEO */ OPC(0x17, PO1(a) POx(b) DEO(a, b)) + /* ADD */ OPC(0x18, POx(a) POx(b) PUx(b + a)) + /* SUB */ OPC(0x19, POx(a) POx(b) PUx(b - a)) + /* MUL */ OPC(0x1a, POx(a) POx(b) PUx(b * a)) + /* DIV */ OPC(0x1b, POx(a) POx(b) PUx(a ? b / a : 0)) + /* AND */ OPC(0x1c, POx(a) POx(b) PUx(b & a)) + /* ORA */ OPC(0x1d, POx(a) POx(b) PUx(b | a)) + /* EOR */ OPC(0x1e, POx(a) POx(b) PUx(b ^ a)) + /* SFT */ OPC(0x1f, PO1(a) POx(b) PUx(b >> (a & 0xf) << (a >> 4))) } } } - diff --git a/src/uxn.h b/src/uxn.h index 6a0dc97..c63e6bf 100644 --- a/src/uxn.h +++ b/src/uxn.h @@ -29,15 +29,16 @@ typedef struct { } Stack; typedef struct Uxn { - Uint8 *ram, *dev; + Uint8 *ram, dev[0x100]; Stack wst, rst; } Uxn; /* required functions */ -extern Uint8 emu_dei(Uxn *u, Uint8 addr); -extern void emu_deo(Uxn *u, Uint8 addr, Uint8 value); +extern Uint8 emu_dei(Uint8 addr); +extern void emu_deo(Uint8 addr, Uint8 value); +extern Uxn uxn; /* built-ins */ -int uxn_eval(Uxn *u, Uint16 pc); +int uxn_eval(Uint16 pc); diff --git a/src/uxncli.c b/src/uxncli.c old mode 100755 new mode 100644 index 4e8e908..c1a337d --- a/src/uxncli.c +++ b/src/uxncli.c @@ -8,7 +8,7 @@ #include "devices/datetime.h" /* -Copyright (c) 2021-2024 Devine Lu Linvega, Andrew Alderwick +Copyright (c) 2021-2023 Devine Lu Linvega, Andrew Alderwick Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -18,55 +18,65 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ +Uxn uxn; + Uint8 -emu_dei(Uxn *u, Uint8 addr) +emu_dei(Uint8 addr) { switch(addr & 0xf0) { - case 0x00: return system_dei(u, addr); - case 0xc0: return datetime_dei(u, addr); + case 0x00: return system_dei(addr); + case 0xc0: return datetime_dei(addr); } - return u->dev[addr]; + return uxn.dev[addr]; } void -emu_deo(Uxn *u, Uint8 addr, Uint8 value) +emu_deo(Uint8 addr, Uint8 value) { - Uint8 p = addr & 0x0f, d = addr & 0xf0; - u->dev[addr] = value; - switch(d) { - case 0x00: system_deo(u, &u->dev[d], p); break; - case 0x10: console_deo(&u->dev[d], p); break; - case 0xa0: file_deo(0, u->ram, &u->dev[d], p); break; - case 0xb0: file_deo(1, u->ram, &u->dev[d], p); break; + uxn.dev[addr] = value; + switch(addr & 0xf0) { + case 0x00: system_deo(addr); break; + case 0x10: console_deo(addr); break; + case 0xa0: file_deo(addr); break; + case 0xb0: file_deo(addr); break; } } +static void +emu_run(void) +{ + while(!uxn.dev[0x0f]) { + int c = fgetc(stdin); + if(c == EOF) { + console_input(0x00, CONSOLE_END); + break; + } + console_input(c, CONSOLE_STD); + } +} + +static int +emu_end(void) +{ + free(uxn.ram); + return uxn.dev[0x0f] & 0x7f; +} + int main(int argc, char **argv) { int i = 1; - Uxn u = {0}; - Uint8 dev[0x100] = {0}; - u.dev = dev; - if(i == argc) - return system_error("usage:", "uxncli [-v] file.rom [args..]"); - if(argv[i][0] == '-' && argv[i][1] == 'v') - return system_error("Uxncli - Varvara Emulator(CLI)", "18 Mar 2024."); - if(!system_init(&u, (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)), argv[i++])) - return system_error("Init", "Failed to initialize uxn."); - /* eval */ - u.dev[0x17] = argc - i; - if(uxn_eval(&u, PAGE_PROGRAM) && PEEK2(u.dev + 0x10)) { - console_listen(&u, i, argc, argv); - while(!u.dev[0x0f]) { - int c = fgetc(stdin); - if(c == EOF) { - console_input(&u, 0x00, CONSOLE_END); - break; - } - console_input(&u, (Uint8)c, CONSOLE_STD); - } + char *rom; + if(i != argc && argv[i][0] == '-' && argv[i][1] == 'v') { + fprintf(stdout, "Uxncli - Console Varvara Emulator, 15 Jul 2024.\n"); + i++; } - free(u.ram); - return u.dev[0x0f] & 0x7f; + rom = i == argc ? "boot.rom" : argv[i++]; + if(!system_boot((Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)), rom)) + return !fprintf(stdout, "usage: %s [-v] file.rom [args..]\n", argv[0]); + /* Event Loop */ + uxn.dev[0x17] = argc - i; + if(uxn_eval(PAGE_PROGRAM) && PEEK2(uxn.dev + 0x10)) + console_listen(i, argc, argv), emu_run(); + return emu_end(); } diff --git a/src/uxnemu.c b/src/uxnemu.c index a91a5c4..29147ab 100644 --- a/src/uxnemu.c +++ b/src/uxnemu.c @@ -46,6 +46,8 @@ WITH REGARD TO THIS SOFTWARE. #define HEIGHT 40 * 8 #define TIMEOUT_MS 334 +Uxn uxn, uxn_audio; + static SDL_Window *emu_window; static SDL_Texture *emu_texture; static SDL_Renderer *emu_renderer; @@ -60,10 +62,9 @@ static Uint32 stdin_event, audio0_event, zoom = 1; static Uint64 exec_deadline, deadline_interval, ms_interval; static int -clamp(int v, int min, int max) +clamp(int val, int min, int max) { - return v < min ? min : v > max ? max - : v; + return (val >= min) ? (val <= max) ? val : max : min; } static void @@ -79,39 +80,39 @@ audio_deo(int instance, Uint8 *d, Uint8 port, Uxn *u) } Uint8 -emu_dei(Uxn *u, Uint8 addr) +emu_dei(Uint8 addr) { Uint8 p = addr & 0x0f, d = addr & 0xf0; switch(d) { - case 0x00: return system_dei(u, addr); - case 0x20: return screen_dei(u, addr); - case 0x30: return audio_dei(0, &u->dev[d], p); - case 0x40: return audio_dei(1, &u->dev[d], p); - case 0x50: return audio_dei(2, &u->dev[d], p); - case 0x60: return audio_dei(3, &u->dev[d], p); - case 0xc0: return datetime_dei(u, addr); + case 0x00: return system_dei(addr); + case 0x20: return screen_dei(addr); + case 0x30: return audio_dei(0, &uxn.dev[d], p); + case 0x40: return audio_dei(1, &uxn.dev[d], p); + case 0x50: return audio_dei(2, &uxn.dev[d], p); + case 0x60: return audio_dei(3, &uxn.dev[d], p); + case 0xc0: return datetime_dei(addr); } - return u->dev[addr]; + return uxn.dev[addr]; } void -emu_deo(Uxn *u, Uint8 addr, Uint8 value) +emu_deo(Uint8 addr, Uint8 value) { Uint8 p = addr & 0x0f, d = addr & 0xf0; - u->dev[addr] = value; + uxn.dev[addr] = value; switch(d) { case 0x00: - system_deo(u, &u->dev[d], p); - if(p > 0x7 && p < 0xe) screen_palette(&u->dev[0x8]); + system_deo(addr); + if(p > 0x7 && p < 0xe) screen_palette(); break; - case 0x10: console_deo(&u->dev[d], p); break; - case 0x20: screen_deo(u->ram, &u->dev[0x20], p); break; - case 0x30: audio_deo(0, &u->dev[d], p, u); break; - case 0x40: audio_deo(1, &u->dev[d], p, u); break; - case 0x50: audio_deo(2, &u->dev[d], p, u); break; - case 0x60: audio_deo(3, &u->dev[d], p, u); break; - case 0xa0: file_deo(0, u->ram, &u->dev[d], p); break; - case 0xb0: file_deo(1, u->ram, &u->dev[d], p); break; + case 0x10: console_deo(addr); break; + case 0x20: screen_deo(addr); break; + case 0x30: audio_deo(0, &uxn.dev[d], p, &uxn); break; + case 0x40: audio_deo(1, &uxn.dev[d], p, &uxn); break; + case 0x50: audio_deo(2, &uxn.dev[d], p, &uxn); break; + case 0x60: audio_deo(3, &uxn.dev[d], p, &uxn); break; + case 0xa0: file_deo(addr); break; + case 0xb0: file_deo(addr); break; } } @@ -177,11 +178,11 @@ set_borderless(int value) } static void -set_debugger(Uxn *u, int value) +set_debugger(int value) { - u->dev[0x0e] = value; + uxn.dev[0x0e] = value; screen_fill(uxn_screen.fg, 0); - screen_redraw(u); + screen_redraw(); } /* emulator primitives */ @@ -208,9 +209,9 @@ emu_resize(int width, int height) } static void -emu_redraw(Uxn *u) +emu_redraw(void) { - screen_redraw(u); + screen_redraw(); if(SDL_UpdateTexture(emu_texture, NULL, uxn_screen.pixels, uxn_screen.width * sizeof(Uint32)) != 0) system_error("SDL_UpdateTexture", SDL_GetError()); SDL_RenderClear(emu_renderer); @@ -219,7 +220,7 @@ emu_redraw(Uxn *u) } static int -emu_init(Uxn *u) +emu_init(void) { SDL_AudioSpec as; SDL_zero(as); @@ -228,7 +229,7 @@ emu_init(Uxn *u) as.channels = 2; as.callback = audio_handler; as.samples = AUDIO_BUFSIZE; - as.userdata = u; + as.userdata = &uxn_audio; if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) return system_error("sdl", SDL_GetError()); audio_id = SDL_OpenAudioDevice(NULL, 0, &as, NULL, 0); @@ -246,52 +247,21 @@ emu_init(Uxn *u) ms_interval = SDL_GetPerformanceFrequency() / 1000; deadline_interval = ms_interval * TIMEOUT_MS; exec_deadline = SDL_GetPerformanceCounter() + deadline_interval; - screen_resize(WIDTH, HEIGHT); + screen_resize(WIDTH, HEIGHT, 1); SDL_PauseAudioDevice(audio_id, 1); return 1; } static void -emu_restart(Uxn *u, char *rom, int soft) +emu_restart(char *rom, int soft) { - screen_resize(WIDTH, HEIGHT); + screen_resize(WIDTH, HEIGHT, 1); screen_fill(uxn_screen.bg, 0); screen_fill(uxn_screen.fg, 0); - system_reboot(u, rom, soft); + system_reboot(rom, soft); SDL_SetWindowTitle(emu_window, boot_rom); } -static void -capture_screen(void) -{ - const Uint32 format = SDL_PIXELFORMAT_RGB24; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - /* SDL_PIXELFORMAT_RGB24 */ - Uint32 Rmask = 0x000000FF; - Uint32 Gmask = 0x0000FF00; - Uint32 Bmask = 0x00FF0000; -#else - /* SDL_PIXELFORMAT_BGR24 */ - Uint32 Rmask = 0x00FF0000; - Uint32 Gmask = 0x0000FF00; - Uint32 Bmask = 0x000000FF; -#endif - time_t t = time(NULL); - char fname[64]; - int w, h; - SDL_Surface *surface; - SDL_GetRendererOutputSize(emu_renderer, &w, &h); - if((surface = SDL_CreateRGBSurface(0, w, h, 24, Rmask, Gmask, Bmask, 0)) == NULL) - return; - SDL_RenderReadPixels(emu_renderer, NULL, format, surface->pixels, surface->pitch); - strftime(fname, sizeof(fname), "screenshot-%Y%m%d-%H%M%S.bmp", localtime(&t)); - if(SDL_SaveBMP(surface, fname) == 0) { - fprintf(stderr, "Saved %s\n", fname); - fflush(stderr); - } - SDL_FreeSurface(surface); -} - static Uint8 get_button(SDL_Event *event) { @@ -341,7 +311,7 @@ get_key(SDL_Event *event) } static int -handle_events(Uxn *u) +handle_events(void) { SDL_Event event; while(SDL_PollEvent(&event)) { @@ -349,41 +319,41 @@ handle_events(Uxn *u) if(event.type == SDL_QUIT) return 0; else if(event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_EXPOSED) - emu_redraw(u); + emu_redraw(); else if(event.type == SDL_DROPFILE) { - emu_restart(u, event.drop.file, 0); + emu_restart(event.drop.file, 0); SDL_free(event.drop.file); } /* Mouse */ else if(event.type == SDL_MOUSEMOTION) - mouse_pos(u, &u->dev[0x90], clamp(event.motion.x - PAD, 0, uxn_screen.width - 1), clamp(event.motion.y - PAD, 0, uxn_screen.height - 1)); + mouse_pos(clamp(event.motion.x - PAD, 0, uxn_screen.width - 1), clamp(event.motion.y - PAD, 0, uxn_screen.height - 1)); else if(event.type == SDL_MOUSEBUTTONUP) - mouse_up(u, &u->dev[0x90], SDL_BUTTON(event.button.button)); + mouse_up(SDL_BUTTON(event.button.button)); else if(event.type == SDL_MOUSEBUTTONDOWN) - mouse_down(u, &u->dev[0x90], SDL_BUTTON(event.button.button)); + mouse_down(SDL_BUTTON(event.button.button)); else if(event.type == SDL_MOUSEWHEEL) - mouse_scroll(u, &u->dev[0x90], event.wheel.x, event.wheel.y); + mouse_scroll(event.wheel.x, event.wheel.y); /* Controller */ else if(event.type == SDL_TEXTINPUT) { char *c; for(c = event.text.text; *c; c++) - controller_key(u, &u->dev[0x80], *c); + controller_key(*c); } else if(event.type == SDL_KEYDOWN) { int ksym; if(get_key(&event)) - controller_key(u, &u->dev[0x80], get_key(&event)); + controller_key(get_key(&event)); else if(get_button(&event)) - controller_down(u, &u->dev[0x80], get_button(&event)); + controller_down(get_button(&event)); else if(event.key.keysym.sym == SDLK_F1) set_zoom(zoom == 3 ? 1 : zoom + 1, 1); else if(event.key.keysym.sym == SDLK_F2) - set_debugger(u, !u->dev[0x0e]); + set_debugger(!uxn.dev[0x0e]); else if(event.key.keysym.sym == SDLK_F3) - capture_screen(); + uxn.dev[0x0f] = 0xff; else if(event.key.keysym.sym == SDLK_F4) - emu_restart(u, boot_rom, 0); + emu_restart(boot_rom, 0); else if(event.key.keysym.sym == SDLK_F5) - emu_restart(u, boot_rom, 1); + emu_restart(boot_rom, 1); else if(event.key.keysym.sym == SDLK_F11) set_fullscreen(!fullscreen, 1); else if(event.key.keysym.sym == SDLK_F12) @@ -392,44 +362,43 @@ handle_events(Uxn *u) if(SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYUP, SDL_KEYUP) == 1 && ksym == event.key.keysym.sym) return 1; } else if(event.type == SDL_KEYUP) - controller_up(u, &u->dev[0x80], get_button(&event)); + controller_up(get_button(&event)); else if(event.type == SDL_JOYAXISMOTION) { Uint8 vec = get_vector_joystick(&event); if(!vec) - controller_up(u, &u->dev[0x80], (3 << (!event.jaxis.axis * 2)) << 4); + controller_up((3 << (!event.jaxis.axis * 2)) << 4); else - controller_down(u, &u->dev[0x80], (1 << ((vec + !event.jaxis.axis * 2) - 1)) << 4); + controller_down((1 << ((vec + !event.jaxis.axis * 2) - 1)) << 4); } else if(event.type == SDL_JOYBUTTONDOWN) - controller_down(u, &u->dev[0x80], get_button_joystick(&event)); + controller_down(get_button_joystick(&event)); else if(event.type == SDL_JOYBUTTONUP) - controller_up(u, &u->dev[0x80], get_button_joystick(&event)); + controller_up(get_button_joystick(&event)); else if(event.type == SDL_JOYHATMOTION) { /* NOTE: Assuming there is only one joyhat in the controller */ switch(event.jhat.value) { - case SDL_HAT_UP: controller_down(u, &u->dev[0x80], 0x10); break; - case SDL_HAT_DOWN: controller_down(u, &u->dev[0x80], 0x20); break; - case SDL_HAT_LEFT: controller_down(u, &u->dev[0x80], 0x40); break; - case SDL_HAT_RIGHT: controller_down(u, &u->dev[0x80], 0x80); break; - case SDL_HAT_LEFTDOWN: controller_down(u, &u->dev[0x80], 0x40 | 0x20); break; - case SDL_HAT_LEFTUP: controller_down(u, &u->dev[0x80], 0x40 | 0x10); break; - case SDL_HAT_RIGHTDOWN: controller_down(u, &u->dev[0x80], 0x80 | 0x20); break; - case SDL_HAT_RIGHTUP: controller_down(u, &u->dev[0x80], 0x80 | 0x10); break; - case SDL_HAT_CENTERED: controller_up(u, &u->dev[0x80], 0x10 | 0x20 | 0x40 | 0x80); break; + case SDL_HAT_UP: controller_down(0x10); break; + case SDL_HAT_DOWN: controller_down(0x20); break; + case SDL_HAT_LEFT: controller_down(0x40); break; + case SDL_HAT_RIGHT: controller_down(0x80); break; + case SDL_HAT_LEFTDOWN: controller_down(0x40 | 0x20); break; + case SDL_HAT_LEFTUP: controller_down(0x40 | 0x10); break; + case SDL_HAT_RIGHTDOWN: controller_down(0x80 | 0x20); break; + case SDL_HAT_RIGHTUP: controller_down(0x80 | 0x10); break; + case SDL_HAT_CENTERED: controller_up(0x10 | 0x20 | 0x40 | 0x80); break; } } /* Console */ else if(event.type == stdin_event) - console_input(u, event.cbutton.button, CONSOLE_STD); + console_input(event.cbutton.button, CONSOLE_STD); } return 1; } static int -emu_run(Uxn *u, char *rom) +emu_run(char *rom) { Uint64 next_refresh = 0; Uint64 frame_interval = SDL_GetPerformanceFrequency() / 60; - Uint8 *vector_addr = &u->dev[0x20]; Uint32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI; window_created = 1; if(fullscreen) @@ -451,18 +420,18 @@ emu_run(Uxn *u, char *rom) Uint16 screen_vector; Uint64 now = SDL_GetPerformanceCounter(); /* .System/halt */ - if(u->dev[0x0f]) + if(uxn.dev[0x0f]) return system_error("Run", "Ended."); exec_deadline = now + deadline_interval; - if(!handle_events(u)) + if(!handle_events()) return 0; - screen_vector = PEEK2(vector_addr); + screen_vector = uxn.dev[0x20] << 8 | uxn.dev[0x21]; if(now >= next_refresh) { now = SDL_GetPerformanceCounter(); next_refresh = now + frame_interval; - uxn_eval(u, screen_vector); + uxn_eval(screen_vector); if(uxn_screen.x2) - emu_redraw(u); + emu_redraw(); } if(screen_vector || uxn_screen.x2) { Uint64 delay_ms = (next_refresh - now) / ms_interval; @@ -473,7 +442,7 @@ emu_run(Uxn *u, char *rom) } static int -emu_end(Uxn *u) +emu_end(void) { SDL_CloseAudioDevice(audio_id); #ifdef _WIN32 @@ -483,21 +452,15 @@ emu_end(Uxn *u) close(0); /* make stdin thread exit */ #endif SDL_Quit(); - free(u->ram); - return u->dev[0x0f] & 0x7f; + free(uxn.ram); + return uxn.dev[0x0f] & 0x7f; } int main(int argc, char **argv) { int i = 1; - Uint8 *ram; char *rom; - Uxn u = {0}; - Uint8 dev[0x100] = {0}; - Uxn u_audio = {0}; - u.dev = dev; - u_audio.dev = dev; /* flags */ if(argc > 1 && argv[i][0] == '-') { if(!strcmp(argv[i], "-v")) @@ -512,16 +475,15 @@ main(int argc, char **argv) } /* start */ rom = i == argc ? "boot.rom" : argv[i++]; - ram = (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)); - if(!system_init(&u, ram, rom) || !system_init(&u_audio, ram, rom)) + if(!system_boot((Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)), rom)) return system_error("usage:", "uxnemu [-v | -f | -2x | -3x] file.rom [args...]"); - if(!emu_init(&u_audio)) + if(!emu_init()) return system_error("Init", "Failed to initialize varvara."); /* loop */ - u.dev[0x17] = argc - i; - if(uxn_eval(&u, PAGE_PROGRAM)) { - console_listen(&u, i, argc, argv); - emu_run(&u, boot_rom); + uxn.dev[0x17] = argc - i; + if(uxn_eval(PAGE_PROGRAM)) { + console_listen(i, argc, argv); + emu_run(boot_rom); } - return emu_end(&u); + return emu_end(); }