From 7dac87dcba56d6d6063160bcbf55b6432819983d Mon Sep 17 00:00:00 2001
From: neauoire <aliceffekt@gmail.com>
Date: Wed, 16 Aug 2023 13:10:42 -0700
Subject: [PATCH] Standardized varvara boot

---
 src/devices/console.c | 10 +++++
 src/devices/console.h |  1 +
 src/devices/screen.c  |  2 +-
 src/devices/screen.h  |  2 +
 src/devices/system.c  | 85 ++++++++++++++++++++++++++-----------------
 src/devices/system.h  |  8 +++-
 src/uxn.c             | 11 ------
 src/uxn.h             |  1 -
 src/uxn11.c           | 41 ++++++++++-----------
 src/uxncli.c          | 42 +++++++++++----------
 10 files changed, 113 insertions(+), 90 deletions(-)

diff --git a/src/devices/console.c b/src/devices/console.c
index db0dd20..a699f2d 100644
--- a/src/devices/console.c
+++ b/src/devices/console.c
@@ -24,6 +24,16 @@ console_input(Uxn *u, char c, int type)
 	return uxn_eval(u, PEEK2(d));
 }
 
+void
+console_listen(Uxn *u, 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);
+	}
+}
+
 void
 console_deo(Uint8 *d, Uint8 port)
 {
diff --git a/src/devices/console.h b/src/devices/console.h
index aaaef23..eaa64f5 100644
--- a/src/devices/console.h
+++ b/src/devices/console.h
@@ -19,4 +19,5 @@ WITH REGARD TO THIS SOFTWARE.
 #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);
diff --git a/src/devices/screen.c b/src/devices/screen.c
index f28bf82..01b2b68 100644
--- a/src/devices/screen.c
+++ b/src/devices/screen.c
@@ -38,7 +38,7 @@ screen_change(Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2)
 	if(y2 > uxn_screen.y2) uxn_screen.y2 = y2;
 }
 
-static void
+void
 screen_fill(Uint8 *layer, int x1, int y1, int x2, int y2, int color)
 {
 	int x, y, width = uxn_screen.width, height = uxn_screen.height;
diff --git a/src/devices/screen.h b/src/devices/screen.h
index 320cc33..2989faf 100644
--- a/src/devices/screen.h
+++ b/src/devices/screen.h
@@ -22,10 +22,12 @@ typedef struct UxnScreen {
 extern UxnScreen uxn_screen;
 extern int emu_resize(int width, int height);
 
+void screen_fill(Uint8 *layer, int x1, int y1, int x2, int 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(void);
 void screen_debugger(Uxn *u);
+
 Uint8 screen_dei(Uxn *u, Uint8 addr);
 void screen_deo(Uint8 *ram, Uint8 *d, Uint8 port);
diff --git a/src/devices/system.c b/src/devices/system.c
index 5a44c5e..389ee0c 100644
--- a/src/devices/system.c
+++ b/src/devices/system.c
@@ -15,11 +15,27 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 WITH REGARD TO THIS SOFTWARE.
 */
 
+char *boot_rom;
+
 static const char *errors[] = {
 	"underflow",
 	"overflow",
 	"division by zero"};
 
+static int
+system_load(Uxn *u, 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;
+}
+
 static void
 system_print(Stack *s, char *name)
 {
@@ -32,19 +48,6 @@ system_print(Stack *s, char *name)
 	fprintf(stderr, "\n");
 }
 
-static void
-system_cmd(Uint8 *ram, Uint16 addr)
-{
-	if(ram[addr] == 0x1) {
-		Uint16 i, length = PEEK2(ram + addr + 1);
-		Uint16 a_page = PEEK2(ram + addr + 1 + 2), a_addr = PEEK2(ram + addr + 1 + 4);
-		Uint16 b_page = PEEK2(ram + addr + 1 + 6), b_addr = PEEK2(ram + addr + 1 + 8);
-		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)];
-	}
-}
-
 int
 system_error(char *msg, const char *err)
 {
@@ -53,20 +56,6 @@ system_error(char *msg, const char *err)
 	return 0;
 }
 
-int
-system_load(Uxn *u, 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;
-}
-
 void
 system_inspect(Uxn *u)
 {
@@ -94,6 +83,32 @@ system_version(char *name, char *date)
 	return 0;
 }
 
+void
+system_reboot(Uxn *u, char *rom, int soft)
+{
+	int i;
+	for(i = 0x100 * soft; i < 0x10000; i++)
+		u->ram[i] = 0;
+	for(i = 0x0; i < 0x100; i++)
+		u->dev[i] = 0;
+	u->wst.ptr = 0;
+	u->rst.ptr = 0;
+	if(system_load(u, boot_rom))
+		if(uxn_eval(u, PAGE_PROGRAM))
+			boot_rom = rom;
+}
+
+int
+system_init(Uxn *u, Uint8 *ram, char *rom)
+{
+	u->ram = ram;
+	if(!system_load(u, rom))
+		if(!system_load(u, "boot.rom"))
+			return system_error("Init", "Failed to load rom.");
+	boot_rom = rom;
+	return 1;
+}
+
 /* IO */
 
 void
@@ -101,13 +116,15 @@ system_deo(Uxn *u, Uint8 *d, Uint8 port)
 {
 	switch(port) {
 	case 0x3:
-		system_cmd(u->ram, PEEK2(d + 2));
-		break;
-	case 0x5:
-		if(PEEK2(d + 4)) {
-			Uxn friend;
-			uxn_boot(&friend, u->ram);
-			uxn_eval(&friend, PEEK2(d + 4));
+		Uint8 *ram = u->ram;
+		Uint16 addr = PEEK2(d + 2);
+		if(ram[addr] == 0x1) {
+			Uint16 i, length = PEEK2(ram + addr + 1);
+			Uint16 a_page = PEEK2(ram + addr + 1 + 2), a_addr = PEEK2(ram + addr + 1 + 4);
+			Uint16 b_page = PEEK2(ram + addr + 1 + 6), b_addr = PEEK2(ram + addr + 1 + 8);
+			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)];
 		}
 		break;
 	case 0xe:
diff --git a/src/devices/system.h b/src/devices/system.h
index 0ec1e33..36c2cb3 100644
--- a/src/devices/system.h
+++ b/src/devices/system.h
@@ -15,9 +15,13 @@ WITH REGARD TO THIS SOFTWARE.
 
 #define RAM_PAGES 0x10
 
+extern char *boot_rom;
+
 void system_connect(Uint8 device, Uint8 ver, Uint16 dei, Uint16 deo);
-int system_version(char *emulator, char *date);
-int system_load(Uxn *u, char *filename);
+void system_reboot(Uxn *u, char *rom, int soft);
 void system_inspect(Uxn *u);
+int system_version(char *emulator, char *date);
 int system_error(char *msg, const char *err);
+int system_init(Uxn *u, Uint8 *ram, char *rom);
+
 void system_deo(Uxn *u, Uint8 *d, Uint8 port);
diff --git a/src/uxn.c b/src/uxn.c
index 068cc78..d367181 100644
--- a/src/uxn.c
+++ b/src/uxn.c
@@ -117,14 +117,3 @@ uxn_eval(Uxn *u, Uint16 pc)
 		}
 	}
 }
-
-int
-uxn_boot(Uxn *u, Uint8 *ram)
-{
-	Uint32 i;
-	char *cptr = (char *)u;
-	for(i = 0; i < sizeof(*u); i++)
-		cptr[i] = 0;
-	u->ram = ram;
-	return 1;
-}
diff --git a/src/uxn.h b/src/uxn.h
index 8cab5f1..896bb53 100644
--- a/src/uxn.h
+++ b/src/uxn.h
@@ -46,5 +46,4 @@ extern Uint16 dev_vers[0x10], dei_mask[0x10], deo_mask[0x10];
 
 /* built-ins */
 
-int uxn_boot(Uxn *u, Uint8 *ram);
 int uxn_eval(Uxn *u, Uint16 pc);
diff --git a/src/uxn11.c b/src/uxn11.c
index f16c13a..3bae085 100644
--- a/src/uxn11.c
+++ b/src/uxn11.c
@@ -32,8 +32,6 @@ static Display *display;
 static Visual *visual;
 static Window window;
 
-char *rom_path;
-
 #define WIDTH (64 * 8)
 #define HEIGHT (40 * 8)
 #define PAD 2
@@ -86,7 +84,8 @@ emu_resize(int width, int height)
 static int
 emu_start(Uxn *u, char *rom)
 {
-
+	(void)u;
+	(void)rom;
 	return 1;
 }
 
@@ -144,7 +143,7 @@ emu_event(Uxn *u)
 			u->dev[0x0e] = !u->dev[0x0e];
 		if(sym == XK_F4)
 			if(!emu_start(u, "boot.rom"))
-				emu_start(u, rom_path);
+				emu_start(u, boot_rom);
 		controller_down(u, &u->dev[0x80], get_button(sym));
 		controller_key(u, &u->dev[0x80], sym < 0x80 ? sym : (Uint8)buf[0]);
 	} break;
@@ -176,6 +175,13 @@ emu_event(Uxn *u)
 	}
 }
 
+static int
+emu_init(void)
+{
+	screen_resize(WIDTH, HEIGHT);
+	return 1;
+}
+
 static int
 emu_run(Uxn *u, char *rom)
 {
@@ -259,24 +265,15 @@ main(int argc, char **argv)
 	/* Read flags */
 	if(argv[i][0] == '-' && argv[i][1] == 'v')
 		return system_version("Uxn11 - Graphical Varvara Emulator", "16 Aug 2023");
-
-	rom_path = argv[1];
-	if(!uxn_boot(&u, (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8))))
-		return system_error("boot", "Failed");
-	/* start sequence */
-	screen_resize(WIDTH, HEIGHT);
-
-	if(!system_load(&u, rom_path))
-		return 0;
-	if(!uxn_eval(&u, PAGE_PROGRAM))
-		return system_error("boot", "Failed to start rom.");
-
-	/* console vector */
-	for(i = 2; i < argc; i++) {
-		char *p = argv[i];
-		while(*p) console_input(&u, *p++, CONSOLE_ARG);
-		console_input(&u, '\n', i == argc ? CONSOLE_END : CONSOLE_EOA);
+	if(!emu_init())
+		return system_error("Init", "Failed to initialize varvara.");
+	if(!system_init(&u, (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)), argv[i++]))
+		return system_error("Init", "Failed to initialize uxn.");
+	/* Game Loop */
+	u.dev[0x17] = argc - i;
+	if(uxn_eval(&u, PAGE_PROGRAM)) {
+		console_listen(&u, i, argc, argv);
+		emu_run(&u, boot_rom);
 	}
-	emu_run(&u, rom_path);
 	return emu_end(&u);
 }
diff --git a/src/uxncli.c b/src/uxncli.c
index d792062..93a50ac 100644
--- a/src/uxncli.c
+++ b/src/uxncli.c
@@ -41,6 +41,23 @@ emu_deo(Uxn *u, Uint8 addr)
 	}
 }
 
+static void
+emu_run(Uxn *u)
+{
+	while(!u->dev[0x0f]) {
+		int c = fgetc(stdin);
+		if(c == EOF) break;
+		console_input(u, (Uint8)c, CONSOLE_STD);
+	}
+}
+
+static int
+emu_end(Uxn *u)
+{
+	free(u->ram);
+	return u->dev[0x0f] & 0x7f;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -56,27 +73,14 @@ main(int argc, char **argv)
 	system_connect(0xc, DATETIME_VERSION, DATETIME_DEIMASK, DATETIME_DEOMASK);
 	/* Read flags */
 	if(argv[i][0] == '-' && argv[i][1] == 'v')
-		return system_version("Uxncli - Console Varvara Emulator", "9 Aug 2023");
-	/* Continue.. */
-	if(!uxn_boot(&u, (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8))))
-		return system_error("Boot", "Failed");
-	/* Load rom */
-	if(!system_load(&u, argv[i++]))
-		return system_error("Load", "Failed");
+		return system_version("Uxncli - Console Varvara Emulator", "15 Aug 2023");
+	if(!system_init(&u, (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)), argv[i++]))
+		return system_error("Init", "Failed to initialize uxn.");
 	/* Game Loop */
 	u.dev[0x17] = argc - i;
 	if(uxn_eval(&u, PAGE_PROGRAM)) {
-		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(!u.dev[0x0f]) {
-			int c = fgetc(stdin);
-			if(c == EOF) break;
-			console_input(&u, (Uint8)c, CONSOLE_STD);
-		}
+		console_listen(&u, i, argc, argv);
+		emu_run(&u);
 	}
-	free(u.ram);
-	return u.dev[0x0f] & 0x7f;
+	return emu_end(&u);
 }