~rabbits/uxn11

9d889340ea73e1896043c68b8c292753d6292156 — Devine Lu Linvega a month ago 7603ddf
Simplified system loading
A oquonie.rom => oquonie.rom +0 -0
M src/devices/datetime.c => src/devices/datetime.c +1 -1
@@ 4,7 4,7 @@
#include "datetime.h"

/*
Copyright (c) 2021 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

M src/devices/file.c => src/devices/file.c +16 -20
@@ 8,6 8,11 @@
#include <sys/stat.h>
#include <unistd.h>

#ifdef _WIN32
#include <libiberty/libiberty.h>
#define realpath(s, dummy) lrealpath(s)
#endif

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif


@@ 16,7 21,7 @@
#include "file.h"

/*
Copyright (c) 2021 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


@@ 84,14 89,17 @@ file_read_dir(UxnFile *c, char *dest, Uint16 len)
			continue;
		if(strcmp(c->de->d_name, "..") == 0) {
			/* hide "sandbox/.." */
			char cwd[PATH_MAX] = {'\0'}, t[PATH_MAX] = {'\0'};
			char cwd[PATH_MAX] = {'\0'}, *t;
			/* Note there's [currently] no way of chdir()ing from uxn, so $PWD
			 * is always the sandbox top level. */
			getcwd(cwd, sizeof(cwd));
			/* We already checked that c->current_filename exists so don't need a wrapper. */
			realpath(c->current_filename, t);
			if(strcmp(cwd, t) == 0)
			t = realpath(c->current_filename, NULL);
			if(strcmp(cwd, t) == 0) {
				free(t);
				continue;
			}
			free(t);
		}
		if(strlen(c->current_filename) + 1 + strlen(c->de->d_name) < sizeof(pathname))
			sprintf(pathname, "%s/%s", c->current_filename, c->de->d_name);


@@ 108,7 116,7 @@ file_read_dir(UxnFile *c, char *dest, Uint16 len)
static char *
retry_realpath(const char *file_name)
{
	char r[PATH_MAX] = {'\0'}, p[PATH_MAX] = {'\0'}, *x;
	char *r, p[PATH_MAX] = {'\0'}, *x;
	if(file_name == NULL) {
		errno = EINVAL;
		return NULL;


@@ 123,7 131,7 @@ retry_realpath(const char *file_name)
		strcat(p, "/"); /* TODO: use a macro instead of '/' for the path delimiter */
	}
	strcat(p, file_name);
	while(realpath(p, r) == NULL) {
	while((r = realpath(p, NULL)) == NULL) {
		if(errno != ENOENT)
			return NULL;
		x = strrchr(p, '/'); /* TODO: path delimiter macro */


@@ 132,7 140,7 @@ retry_realpath(const char *file_name)
		else
			return NULL;
	}
	return strdup(r);
	return r;
}

static void


@@ 168,7 176,7 @@ file_init(UxnFile *c, char *filename, size_t max_len, int override_sandbox)
}

static Uint16
file_read(UxnFile *c, void *dest, Uint16 len)
file_read(UxnFile *c, void *dest, int len)
{
	if(c->outside_sandbox) return 0;
	if(c->state != FILE_READ && c->state != DIR_READ) {


@@ 278,15 286,3 @@ file_dei(Uint8 id, Uint8 *d, Uint8 port)
	}
	return d[port];
}

/* Boot */

int
load_rom(Uxn *u, char *filename)
{
	int ret;
	file_init(uxn_file, filename, strlen(filename) + 1, 1);
	ret = file_read(uxn_file, &u->ram[PAGE_PROGRAM], 0x10000 - PAGE_PROGRAM);
	reset(uxn_file);
	return ret;
}

M src/devices/file.h => src/devices/file.h +0 -1
@@ 14,4 14,3 @@ WITH REGARD TO THIS SOFTWARE.

void file_deo(Uint8 id, Uint8 *ram, Uint8 *d, Uint8 port);
Uint8 file_dei(Uint8 id, Uint8 *d, Uint8 port);
int load_rom(Uxn *u, char *filename);

M src/devices/system.c => src/devices/system.c +38 -30
@@ 39,37 39,10 @@ system_inspect(Uxn *u)
	system_print(u->rst, "rst");
}

int
uxn_halt(Uxn *u, Uint8 instr, Uint8 err, Uint16 addr)
{
	Uint8 *d = &u->dev[0x00];
	Uint16 handler = GETVEC(d);
	if(handler) {
		u->wst->ptr = 4;
		u->wst->dat[0] = addr >> 0x8;
		u->wst->dat[1] = addr & 0xff;
		u->wst->dat[2] = instr;
		u->wst->dat[3] = err;
		return uxn_eval(u, handler);
	} else {
		system_inspect(u);
		fprintf(stderr, "%s %s, by %02x at 0x%04x.\n", (instr & 0x40) ? "Return-stack" : "Working-stack", errors[err - 1], instr, addr);
	}
	return 0;
}

/* MMU */

Uint8 *
mmu_init(Mmu *m, Uint16 pages)
{
	m->length = pages;
	m->pages = (Uint8 *)calloc(0x10000 * pages, sizeof(Uint8));
	return m->pages;
}
/* RAM */

void
mmu_eval(Uint8 *ram, Uint16 addr)
system_cmd(Uint8 *ram, Uint16 addr)
{
	Uint16 a = addr, i = 0;
	Uint8 o = ram[a++];


@@ 82,6 55,20 @@ mmu_eval(Uint8 *ram, Uint16 addr)
	}
}

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], 1, 0x10000 - PAGE_PROGRAM, f);
	while(l && ++i < RAM_PAGES)
		l = fread(u->ram + 0x10000 * i, 1, 0x10000, f);
	fclose(f);
	return 1;
}

/* IO */

void


@@ 91,10 78,31 @@ system_deo(Uxn *u, Uint8 *d, Uint8 port)
	switch(port) {
	case 0x3:
		PEKDEV(a, 0x2);
		mmu_eval(u->ram, a);
		system_cmd(u->ram, a);
		break;
	case 0xe:
		if(u->wst->ptr || u->rst->ptr) system_inspect(u);
		break;
	}
}

/* Error */

int
uxn_halt(Uxn *u, Uint8 instr, Uint8 err, Uint16 addr)
{
	Uint8 *d = &u->dev[0x00];
	Uint16 handler = GETVEC(d);
	if(handler) {
		u->wst->ptr = 4;
		u->wst->dat[0] = addr >> 0x8;
		u->wst->dat[1] = addr & 0xff;
		u->wst->dat[2] = instr;
		u->wst->dat[3] = err;
		return uxn_eval(u, handler);
	} else {
		system_inspect(u);
		fprintf(stderr, "%s %s, by %02x at 0x%04x.\n", (instr & 0x40) ? "Return-stack" : "Working-stack", errors[err - 1], instr, addr);
	}
	return 0;
}

M src/devices/system.h => src/devices/system.h +4 -7
@@ 9,11 9,8 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/

void system_inspect(Uxn *u);
void system_deo(Uxn *u, Uint8 *d, Uint8 port);

typedef struct {
	Uint8 length, *pages;
} Mmu;
#define RAM_PAGES 0x10

Uint8 *mmu_init(Mmu *m, Uint16 pages);
int system_load(Uxn *u, char *filename);
void system_deo(Uxn *u, Uint8 *d, Uint8 port);
void system_inspect(Uxn *u);

M src/uxn11.c => src/uxn11.c +2 -3
@@ 108,7 108,7 @@ emu_draw(void)
static int
emu_start(Uxn *u, char *rom)
{
	if(!load_rom(u, rom))
	if(!system_load(u, rom))
		return 0;
	if(!uxn_screen.width || !uxn_screen.height)
		screen_resize(&uxn_screen, WIDTH, HEIGHT);


@@ 225,7 225,6 @@ int
main(int argc, char **argv)
{
	Uxn u;
	Mmu m;
	int i;
	char expirations[8];
	struct pollfd fds[2];


@@ 233,7 232,7 @@ main(int argc, char **argv)
	if(argc < 2)
		return emu_error("Usage", "uxn11 game.rom args");
	rom_path = argv[1];
	if(!uxn_boot(&u, mmu_init(&m, 16), emu_dei, emu_deo))
	if(!uxn_boot(&u, (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)), emu_dei, emu_deo))
		return emu_error("Boot", "Failed");
	/* start sequence */
	if(!emu_start(&u, rom_path))

M src/uxncli.c => src/uxncli.c +4 -5
@@ 37,8 37,8 @@ console_input(Uxn *u, char c)
static void
console_deo(Uint8 *d, Uint8 port)
{
	FILE *fd = port == 0x8 ? stdout : port == 0x9 ? stderr
												  : 0;
	FILE *fd = port == 0x8 ? stdout : port == 0x9 ? stderr :
													0;
	if(fd) {
		fputc(d[port], fd);
		fflush(fd);


@@ 78,12 78,11 @@ main(int argc, char **argv)
{
	Uxn u;
	int i;
	Mmu mmu;
	if(argc < 2)
		return emu_error("Usage", "uxncli game.rom args");
	if(!uxn_boot(&u, mmu_init(&mmu, 16), emu_dei, emu_deo))
	if(!uxn_boot(&u, (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)), emu_dei, emu_deo))
		return emu_error("Boot", "Failed");
	if(!load_rom(&u, argv[1]))
	if(!system_load(&u, argv[1]))
		return emu_error("Load", "Failed");
	if(!uxn_eval(&u, PAGE_PROGRAM))
		return emu_error("Init", "Failed");