commit 7afe1f39c70b279ae47e2ea8995c494eb0c56680
parent 679aec047a5ef0e30c05b07402043c50fcee3852
Author: Devine Lu Linvega <aliceffekt@gmail.com>
Date: Sun, 1 Jan 2023 13:19:40 -0800
Screen device is half ported to new device handlers
Diffstat:
13 files changed, 255 insertions(+), 259 deletions(-)
diff --git a/build.sh b/build.sh
@@ -117,11 +117,9 @@ echo "Assembling(asma).."
if [ $norun = 1 ]; then exit; fi
echo "Assembling(piano).."
-bin/uxncli bin/asma.rom projects/software/piano.tal bin/piano.rom 2> bin/piano.log
+./bin/uxnasm projects/software/piano.tal bin/piano.rom 2> bin/piano.log
echo "Running.."
-cd bin
-./uxnemu piano.rom
+./bin/uxnemu bin/piano.rom
echo "Done."
-cd ..
diff --git a/src/devices/datetime.c b/src/devices/datetime.c
@@ -4,8 +4,7 @@
#include "datetime.h"
/*
-Copyright (c) 2021 Devine Lu Linvega
-Copyright (c) 2021 Andrew Alderwick
+Copyright (c) 2021 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,7 +15,7 @@ WITH REGARD TO THIS SOFTWARE.
*/
Uint8
-datetime_dei(Device *d, Uint8 port)
+datetime_dei(Uint8 *d, Uint8 port)
{
time_t seconds = time(NULL);
struct tm zt = {0};
@@ -35,6 +34,6 @@ datetime_dei(Device *d, Uint8 port)
case 0x8: return t->tm_yday >> 8;
case 0x9: return t->tm_yday;
case 0xa: return t->tm_isdst;
- default: return d->dat[port];
+ default: return d[port];
}
}
diff --git a/src/devices/datetime.h b/src/devices/datetime.h
@@ -1,6 +1,5 @@
/*
-Copyright (c) 2021 Devine Lu Linvega
-Copyright (c) 2021 Andrew Alderwick
+Copyright (c) 2021 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
@@ -10,4 +9,4 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/
-Uint8 datetime_dei(Device *d, Uint8 port);
+Uint8 datetime_dei(Uint8 *d, Uint8 port);
diff --git a/src/devices/file.c b/src/devices/file.c
@@ -1,15 +1,22 @@
+#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
#include <string.h>
+#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
#include "../uxn.h"
#include "file.h"
/*
-Copyright (c) 2021 Devine Lu Linvega
-Copyright (c) 2021 Andrew Alderwick
+Copyright (c) 2021 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
@@ -28,6 +35,7 @@ typedef struct {
FILE_READ,
FILE_WRITE,
DIR_READ } state;
+ int outside_sandbox;
} UxnFile;
static UxnFile uxn_file[POLYFILEY];
@@ -45,6 +53,7 @@ reset(UxnFile *c)
}
c->de = NULL;
c->state = IDLE;
+ c->outside_sandbox = 0;
}
static Uint16
@@ -66,13 +75,24 @@ get_entry(char *p, Uint16 len, const char *pathname, const char *basename, int f
static Uint16
file_read_dir(UxnFile *c, char *dest, Uint16 len)
{
- static char pathname[4356];
+ static char pathname[4352];
char *p = dest;
if(c->de == NULL) c->de = readdir(c->dir);
for(; c->de != NULL; c->de = readdir(c->dir)) {
Uint16 n;
if(c->de->d_name[0] == '.' && c->de->d_name[1] == '\0')
continue;
+ if(strcmp(c->de->d_name, "..") == 0) {
+ /* hide "sandbox/.." */
+ char cwd[PATH_MAX] = {'\0'}, t[PATH_MAX] = {'\0'};
+ /* 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)
+ continue;
+ }
if(strlen(c->current_filename) + 1 + strlen(c->de->d_name) < sizeof(pathname))
sprintf(pathname, "%s/%s", c->current_filename, c->de->d_name);
else
@@ -85,16 +105,62 @@ file_read_dir(UxnFile *c, char *dest, Uint16 len)
return p - dest;
}
+static char *
+retry_realpath(const char *file_name)
+{
+ char r[PATH_MAX] = {'\0'}, p[PATH_MAX] = {'\0'}, *x;
+ if(file_name == NULL) {
+ errno = EINVAL;
+ return NULL;
+ } else if(strlen(file_name) >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+ if(file_name[0] != '/') {
+ /* TODO: use a macro instead of '/' for absolute path first character so that other systems can work */
+ /* if a relative path, prepend cwd */
+ getcwd(p, sizeof(p));
+ strcat(p, "/"); /* TODO: use a macro instead of '/' for the path delimiter */
+ }
+ strcat(p, file_name);
+ while(realpath(p, r) == NULL) {
+ if(errno != ENOENT)
+ return NULL;
+ x = strrchr(p, '/'); /* TODO: path delimiter macro */
+ if(x)
+ *x = '\0';
+ else
+ return NULL;
+ }
+ return strdup(r);
+}
+
+static void
+file_check_sandbox(UxnFile *c)
+{
+ char *x, *rp, cwd[PATH_MAX] = {'\0'};
+ x = getcwd(cwd, sizeof(cwd));
+ rp = retry_realpath(c->current_filename);
+ if(rp == NULL || (x && strncmp(cwd, rp, strlen(cwd)) != 0)) {
+ c->outside_sandbox = 1;
+ fprintf(stderr, "file warning: blocked attempt to access %s outside of sandbox\n", c->current_filename);
+ }
+ free(rp);
+}
+
static Uint16
-file_init(UxnFile *c, char *filename, size_t max_len)
+file_init(UxnFile *c, char *filename, size_t max_len, int override_sandbox)
{
char *p = c->current_filename;
size_t len = sizeof(c->current_filename);
reset(c);
if(len > max_len) len = max_len;
while(len) {
- if((*p++ = *filename++) == '\0')
+ if((*p++ = *filename++) == '\0') {
+ if(!override_sandbox) /* override sandbox for loading roms */
+ file_check_sandbox(c);
return 0;
+ }
len--;
}
c->current_filename[0] = '\0';
@@ -104,6 +170,7 @@ file_init(UxnFile *c, char *filename, size_t max_len)
static Uint16
file_read(UxnFile *c, void *dest, Uint16 len)
{
+ if(c->outside_sandbox) return 0;
if(c->state != FILE_READ && c->state != DIR_READ) {
reset(c);
if((c->dir = opendir(c->current_filename)) != NULL)
@@ -122,6 +189,7 @@ static Uint16
file_write(UxnFile *c, void *src, Uint16 len, Uint8 flags)
{
Uint16 ret = 0;
+ if(c->outside_sandbox) return 0;
if(c->state != FILE_WRITE) {
reset(c);
if((c->f = fopen(c->current_filename, (flags & 0x01) ? "ab" : "wb")) != NULL)
@@ -138,6 +206,7 @@ static Uint16
file_stat(UxnFile *c, void *dest, Uint16 len)
{
char *basename = strrchr(c->current_filename, '/');
+ if(c->outside_sandbox) return 0;
if(basename != NULL)
basename++;
else
@@ -148,72 +217,66 @@ file_stat(UxnFile *c, void *dest, Uint16 len)
static Uint16
file_delete(UxnFile *c)
{
- return unlink(c->current_filename);
-}
-
-static UxnFile *
-file_instance(Device *d)
-{
- return &uxn_file[d - &d->u->devold[DEV_FILE0]];
+ return c->outside_sandbox ? 0 : unlink(c->current_filename);
}
/* IO */
void
-file_deo(Device *d, Uint8 port)
+file_deo(Uint8 id, Uint8 *ram, Uint8 *d, Uint8 port)
{
- UxnFile *c = file_instance(d);
+ UxnFile *c = &uxn_file[id];
Uint16 addr, len, res;
switch(port) {
case 0x5:
- DEVPEEK16(addr, 0x4);
- DEVPEEK16(len, 0xa);
+ PEKDEV(addr, 0x4);
+ PEKDEV(len, 0xa);
if(len > 0x10000 - addr)
len = 0x10000 - addr;
- res = file_stat(c, &d->u->ram[addr], len);
- DEVPOKE16(0x2, res);
+ res = file_stat(c, &ram[addr], len);
+ POKDEV(0x2, res);
break;
case 0x6:
res = file_delete(c);
- DEVPOKE16(0x2, res);
+ POKDEV(0x2, res);
break;
case 0x9:
- DEVPEEK16(addr, 0x8);
- res = file_init(c, (char *)&d->u->ram[addr], 0x10000 - addr);
- DEVPOKE16(0x2, res);
+ PEKDEV(addr, 0x8);
+ res = file_init(c, (char *)&ram[addr], 0x10000 - addr, 0);
+ POKDEV(0x2, res);
break;
case 0xd:
- DEVPEEK16(addr, 0xc);
- DEVPEEK16(len, 0xa);
+ PEKDEV(addr, 0xc);
+ PEKDEV(len, 0xa);
if(len > 0x10000 - addr)
len = 0x10000 - addr;
- res = file_read(c, &d->u->ram[addr], len);
- DEVPOKE16(0x2, res);
+ res = file_read(c, &ram[addr], len);
+ POKDEV(0x2, res);
break;
case 0xf:
- DEVPEEK16(addr, 0xe);
- DEVPEEK16(len, 0xa);
+ PEKDEV(addr, 0xe);
+ PEKDEV(len, 0xa);
if(len > 0x10000 - addr)
len = 0x10000 - addr;
- res = file_write(c, &d->u->ram[addr], len, d->dat[0x7]);
- DEVPOKE16(0x2, res);
+ res = file_write(c, &ram[addr], len, d[0x7]);
+ POKDEV(0x2, res);
break;
}
}
Uint8
-file_dei(Device *d, Uint8 port)
+file_dei(Uint8 id, Uint8 *d, Uint8 port)
{
- UxnFile *c = file_instance(d);
+ UxnFile *c = &uxn_file[id];
Uint16 res;
switch(port) {
case 0xc:
case 0xd:
- res = file_read(c, &d->dat[port], 1);
- DEVPOKE16(0x2, res);
+ res = file_read(c, &d[port], 1);
+ POKDEV(0x2, res);
break;
}
- return d->dat[port];
+ return d[port];
}
/* Boot */
@@ -222,7 +285,7 @@ int
load_rom(Uxn *u, char *filename)
{
int ret;
- file_init(uxn_file, filename, strlen(filename) + 1);
+ 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;
diff --git a/src/devices/file.h b/src/devices/file.h
@@ -1,6 +1,5 @@
/*
-Copyright (c) 2021 Devine Lu Linvega
-Copyright (c) 2021 Andrew Alderwick
+Copyright (c) 2021 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
@@ -13,6 +12,6 @@ WITH REGARD TO THIS SOFTWARE.
#define POLYFILEY 2
#define DEV_FILE0 0xa
-void file_deo(Device *d, Uint8 port);
-Uint8 file_dei(Device *d, Uint8 port);
+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);
diff --git a/src/devices/screen.c b/src/devices/screen.c
@@ -132,14 +132,14 @@ screen_mono(UxnScreen *p, Uint32 *pixels)
/* IO */
Uint8
-screen_dei(Device *d, Uint8 port)
+screen_dei(Uint8 *d, Uint8 port)
{
switch(port) {
case 0x2: return uxn_screen.width >> 8;
case 0x3: return uxn_screen.width;
case 0x4: return uxn_screen.height >> 8;
case 0x5: return uxn_screen.height;
- default: return d->dat[port];
+ default: return d[port];
}
}
diff --git a/src/devices/screen.h b/src/devices/screen.h
@@ -31,6 +31,6 @@ void screen_clear(UxnScreen *p, Layer *layer);
void screen_redraw(UxnScreen *p, Uint32 *pixels);
void screen_mono(UxnScreen *p, Uint32 *pixels);
-Uint8 screen_dei(Device *d, Uint8 port);
+Uint8 screen_dei(Uint8 *d, Uint8 port);
void screen_deo(Device *d, Uint8 port);
int clamp(int val, int min, int max);
diff --git a/src/devices/system.c b/src/devices/system.c
@@ -15,13 +15,9 @@ WITH REGARD TO THIS SOFTWARE.
*/
static const char *errors[] = {
- "Working-stack underflow",
- "Return-stack underflow",
- "Working-stack overflow",
- "Return-stack overflow",
- "Working-stack division by zero",
- "Return-stack division by zero",
- "Execution timeout"};
+ "underflow",
+ "overflow",
+ "division by zero"};
static void
system_print(Stack *s, char *name)
@@ -38,37 +34,37 @@ system_print(Stack *s, char *name)
void
system_inspect(Uxn *u)
{
- system_print(&u->wst, "wst");
- system_print(&u->rst, "rst");
+ system_print(u->wst, "wst");
+ system_print(u->rst, "rst");
}
int
-uxn_halt(Uxn *u, Uint8 error, Uint16 addr)
+uxn_halt(Uxn *u, Uint8 instr, Uint8 err, Uint16 addr)
{
- system_inspect(u);
- fprintf(stderr, "Halted: %s#%04x, at 0x%04x\n", errors[error], u->ram[addr], addr);
+ Uint8 *d = &u->dev[0x00];
+ if(instr & 0x40)
+ u->rst->err = err;
+ else
+ u->wst->err = err;
+ if(GETVEC(d))
+ uxn_eval(u, GETVEC(d));
+ 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;
}
/* IO */
-Uint8
-system_dei(Device *d, Uint8 port)
-{
- switch(port) {
- case 0x2: return d->u->wst.ptr;
- case 0x3: return d->u->rst.ptr;
- default: return d->dat[port];
- }
-}
-
void
-system_deo(Device *d, Uint8 port)
+system_deo(Uxn *u, Uint8 *d, Uint8 port)
{
switch(port) {
- case 0x2: d->u->wst.ptr = d->dat[port]; break;
- case 0x3: d->u->rst.ptr = d->dat[port]; break;
- case 0xe: system_inspect(d->u); break;
- default: system_deo_special(d, port);
+ case 0x2: u->wst = (Stack *)(u->ram + (d[port] ? (d[port] * 0x100) : 0x10000)); break;
+ case 0x3: u->rst = (Stack *)(u->ram + (d[port] ? (d[port] * 0x100) : 0x10100)); break;
+ case 0xe:
+ if(u->wst->ptr || u->rst->ptr) system_inspect(u);
+ break;
}
}
diff --git a/src/devices/system.h b/src/devices/system.h
@@ -9,13 +9,5 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/
-typedef struct SystemDevice {
- Device device;
- struct UxnScreen *screen;
-} SystemDevice;
-
void system_inspect(Uxn *u);
-
-Uint8 system_dei(Device *d, Uint8 port);
-void system_deo(Device *d, Uint8 port);
-void system_deo_special(Device *d, Uint8 port);
+void system_deo(Uxn *u, Uint8 *d, Uint8 port);
diff --git a/src/uxn.c b/src/uxn.c
@@ -31,6 +31,9 @@ WITH REGARD TO THIS SOFTWARE.
#define DEVW8OLD(x, y) { dev->dat[(x) & 0xf] = y; dev->deo(dev, (x) & 0x0f); }
#define DEVWOLD(d, x, y) { dev = (d); if(bs) { DEVW8OLD((x), (y) >> 8); DEVW8OLD((x) + 1, (y)); } else { DEVW8OLD((x), (y)) } }
+#define DEVR(o, x) { o = u->dei(u, x); if (bs) o = (o << 8) + u->dei(u, ((x) + 1) & 0xFF); }
+#define DEVW(x, y) { if (bs) { u->deo(u, (x), (y) >> 8); u->deo(u, ((x) + 1) & 0xFF, (y)); } else { u->deo(u, x, (y)); } }
+
#define WARP(x) { if(bs) pc = (x); else pc += (Sint8)(x); }
#define LIMIT 0x40000 /* around 3 ms */
@@ -41,21 +44,16 @@ uxn_eval(Uxn *u, Uint16 pc)
unsigned int limit = LIMIT;
Uint8 kptr, *sp;
Stack *src, *dst;
- Device *dev;
if(!pc || u->devold[0].dat[0xf]) return 0;
while((instr = u->ram[pc++])) {
if(!limit--) {
- if(!uxn_interrupt()) {
- errcode = 6;
- goto timeout;
- }
limit = LIMIT;
}
/* Return Mode */
if(instr & 0x40) {
- src = &u->rst; dst = &u->wst;
+ src = u->rst; dst = u->wst;
} else {
- src = &u->wst; dst = &u->rst;
+ src = u->wst; dst = u->rst;
}
/* Keep Mode */
if(instr & 0x80) {
@@ -92,8 +90,8 @@ uxn_eval(Uxn *u, Uint16 pc)
case 0x13: /* STR */ POP8(a) POP(b) c = pc + (Sint8)a; POKE(c, b) break;
case 0x14: /* LDA */ POP16(a) PEEK(b, a) PUSH(src, b) break;
case 0x15: /* STA */ POP16(a) POP(b) POKE(a, b) break;
- case 0x16: /* DEI */ POP8(a) DEVROLD(b, &u->devold[a >> 4], a) PUSH(src, b) break;
- case 0x17: /* DEO */ POP8(a) POP(b) DEVWOLD(&u->devold[a >> 4], a, b) break;
+ case 0x16: /* DEI */ POP8(a) DEVR(b, a) PUSH(src, b) break;
+ case 0x17: /* DEO */ POP8(a) POP(b) DEVW(a, b) break;
/* Arithmetic */
case 0x18: /* ADD */ POP(a) POP(b) PUSH(src, b + a) break;
case 0x19: /* SUB */ POP(a) POP(b) PUSH(src, b - a) break;
@@ -106,13 +104,8 @@ uxn_eval(Uxn *u, Uint16 pc)
}
}
return 1;
-
err:
- /* set 1 in errcode if it involved the return stack instead of the working stack */
- /* (stack overflow & ( opcode was STH / JSR )) ^ Return Mode */
- errcode |= ((errcode >> 1 & ((instr & 0x1e) == 0x0e)) ^ instr >> 6) & 1;
-timeout:
- return uxn_halt(u, errcode, pc - 1);
+ return uxn_halt(u, instr, errcode, pc - 1);
}
/* clang-format on */
@@ -125,6 +118,8 @@ uxn_boot(Uxn *u, Uint8 *ram, Dei *dei, Deo *deo)
for(i = 0; i < sizeof(*u); i++)
cptr[i] = 0x00;
u->ram = ram;
+ u->wst = (Stack *)(ram + 0x10000);
+ u->rst = (Stack *)(ram + 0x10100);
u->dev = (Uint8 *)(ram + 0x10200);
u->dei = dei;
u->deo = deo;
diff --git a/src/uxn.h b/src/uxn.h
@@ -20,13 +20,25 @@ typedef unsigned int Uint32;
#define PAGE_PROGRAM 0x0100
-/* clang-format off */
-
-#define DEVPEEK16(o, x) { (o) = (d->dat[(x)] << 8) + d->dat[(x) + 1]; }
-#define DEVPOKE16(x, y) { d->dat[(x)] = (y) >> 8; d->dat[(x) + 1] = (y); }
+#define DEVPEEK16(o, x) \
+ { \
+ (o) = (d->dat[(x)] << 8) + d->dat[(x) + 1]; \
+ }
+#define DEVPOKE16(x, y) \
+ { \
+ d->dat[(x)] = (y) >> 8; \
+ d->dat[(x) + 1] = (y); \
+ }
#define GETVECTOR(d) ((d)->dat[0] << 8 | (d)->dat[1])
-/* new macros */
+typedef struct Device {
+ struct Uxn *u;
+ Uint8 dat[16];
+ Uint8 (*dei)(struct Device *d, Uint8);
+ void (*deo)(struct Device *d, Uint8);
+} Device;
+
+/* clang-format off */
#define GETVEC(d) ((d)[0] << 8 | (d)[1])
#define POKDEV(x, y) { d[(x)] = (y) >> 8; d[(x) + 1] = (y); }
@@ -35,19 +47,12 @@ typedef unsigned int Uint32;
/* clang-format on */
typedef struct {
- Uint8 ptr, dat[255];
+ Uint8 dat[254], err, ptr;
} Stack;
-typedef struct Device {
- struct Uxn *u;
- Uint8 dat[16];
- Uint8 (*dei)(struct Device *d, Uint8);
- void (*deo)(struct Device *d, Uint8);
-} Device;
-
typedef struct Uxn {
Uint8 *ram, *dev;
- Stack wst, rst;
+ Stack *wst, *rst;
Device devold[16];
Uint8 (*dei)(struct Uxn *u, Uint8 addr);
void (*deo)(struct Uxn *u, Uint8 addr, Uint8 value);
@@ -58,7 +63,9 @@ typedef void Deo(Uxn *u, Uint8 addr, Uint8 value);
int uxn_boot(Uxn *u, Uint8 *ram, Dei *dei, Deo *deo);
int uxn_eval(Uxn *u, Uint16 pc);
-int uxn_interrupt(void);
-int uxn_halt(Uxn *u, Uint8 error, Uint16 addr);
+int uxn_halt(Uxn *u, Uint8 instr, Uint8 err, Uint16 addr);
+
+/* TODO: remove */
+
Device *uxn_port(Uxn *u, Uint8 id, Uint8 (*deifn)(Device *, Uint8), void (*deofn)(Device *, Uint8));
#endif /* UXN_UXN_H */
diff --git a/src/uxncli.c b/src/uxncli.c
@@ -17,102 +17,60 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/
+#define SUPPORT 0x1c03 /* devices mask */
+
static int
-error(char *msg, const char *err)
+emu_error(char *msg, const char *err)
{
fprintf(stderr, "Error %s: %s\n", msg, err);
return 0;
}
-static Uint8
-emu_dei(Uxn *u, Uint8 addr)
-{
- return 0;
-}
-
-static void
-emu_deo(Uxn *u, Uint8 addr, Uint8 v)
-{
-}
-
-void
-system_deo_special(Device *d, Uint8 port)
+static int
+console_input(Uxn *u, char c)
{
- (void)d;
- (void)port;
+ Uint8 *d = &u->dev[0x10];
+ d[0x02] = c;
+ return uxn_eval(u, GETVEC(d));
}
static void
-console_deo(Device *d, Uint8 port)
+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->dat[port], fd);
+ fputc(d[port], fd);
fflush(fd);
}
}
static Uint8
-nil_dei(Device *d, Uint8 port)
-{
- return d->dat[port];
-}
-
-static void
-nil_deo(Device *d, Uint8 port)
-{
- (void)d;
- (void)port;
-}
-
-static int
-console_input(Uxn *u, char c)
+emu_dei(Uxn *u, Uint8 addr)
{
- Device *d = &u->devold[1];
- d->dat[0x2] = c;
- return uxn_eval(u, GETVECTOR(d));
+ Uint8 p = addr & 0x0f, d = addr & 0xf0;
+ switch(d) {
+ case 0xa0: return file_dei(0, &u->dev[d], p);
+ case 0xb0: return file_dei(1, &u->dev[d], p);
+ case 0xc0: return datetime_dei(&u->dev[d], p);
+ }
+ return u->dev[addr];
}
static void
-run(Uxn *u)
+emu_deo(Uxn *u, Uint8 addr, Uint8 v)
{
- Device *d = &u->devold[0];
- while(!d->dat[0xf]) {
- int c = fgetc(stdin);
- if(c != EOF)
- console_input(u, (Uint8)c);
+ Uint8 p = addr & 0x0f, d = addr & 0xf0;
+ Uint16 mask = 0x1 << (d >> 4);
+ u->dev[addr] = v;
+ 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;
}
-}
-
-int
-uxn_interrupt(void)
-{
- return 1;
-}
-
-static int
-start(Uxn *u)
-{
- if(!uxn_boot(u, (Uint8 *)calloc(0x10300, sizeof(Uint8)), emu_dei, emu_deo))
- return error("Boot", "Failed");
- /* system */ uxn_port(u, 0x0, system_dei, system_deo);
- /* console */ uxn_port(u, 0x1, nil_dei, console_deo);
- /* empty */ uxn_port(u, 0x2, nil_dei, nil_deo);
- /* empty */ uxn_port(u, 0x3, nil_dei, nil_deo);
- /* empty */ uxn_port(u, 0x4, nil_dei, nil_deo);
- /* empty */ uxn_port(u, 0x5, nil_dei, nil_deo);
- /* empty */ uxn_port(u, 0x6, nil_dei, nil_deo);
- /* empty */ uxn_port(u, 0x7, nil_dei, nil_deo);
- /* empty */ uxn_port(u, 0x8, nil_dei, nil_deo);
- /* empty */ uxn_port(u, 0x9, nil_dei, nil_deo);
- /* file0 */ uxn_port(u, 0xa, file_dei, file_deo);
- /* file1 */ uxn_port(u, 0xb, file_dei, file_deo);
- /* datetime */ uxn_port(u, 0xc, datetime_dei, nil_deo);
- /* empty */ uxn_port(u, 0xd, nil_dei, nil_deo);
- /* empty */ uxn_port(u, 0xe, nil_dei, nil_deo);
- /* empty */ uxn_port(u, 0xf, nil_dei, nil_deo);
- return 1;
+ if(p == 0x01 && !(SUPPORT & mask))
+ fprintf(stderr, "Warning: Incompatible emulation, device: %02x.\n", d);
}
int
@@ -121,19 +79,22 @@ main(int argc, char **argv)
Uxn u;
int i;
if(argc < 2)
- return error("Usage", "uxncli game.rom args");
- if(!start(&u))
- return error("Start", "Failed");
+ return emu_error("Usage", "uxncli game.rom args");
+ if(!uxn_boot(&u, (Uint8 *)calloc(0x10300, sizeof(Uint8)), emu_dei, emu_deo))
+ return emu_error("Boot", "Failed");
if(!load_rom(&u, argv[1]))
- return error("Load", "Failed");
- fprintf(stderr, "Loaded %s\n", argv[1]);
+ return emu_error("Load", "Failed");
if(!uxn_eval(&u, PAGE_PROGRAM))
- return error("Init", "Failed");
+ return emu_error("Init", "Failed");
for(i = 2; i < argc; i++) {
char *p = argv[i];
while(*p) console_input(&u, *p++);
console_input(&u, '\n');
}
- run(&u);
+ while(!u.dev[0x0f]) {
+ int c = fgetc(stdin);
+ if(c != EOF)
+ console_input(&u, (Uint8)c);
+ }
return 0;
}
diff --git a/src/uxnemu.c b/src/uxnemu.c
@@ -63,6 +63,25 @@ error(char *msg, const char *err)
return 0;
}
+static int
+console_input(Uxn *u, char c)
+{
+ Uint8 *d = &u->dev[0x10];
+ d[0x02] = c;
+ return uxn_eval(u, GETVEC(d));
+}
+
+static void
+console_deo(Uint8 *d, Uint8 port)
+{
+ FILE *fd = port == 0x8 ? stdout : port == 0x9 ? stderr
+ : 0;
+ if(fd) {
+ fputc(d[port], fd);
+ fflush(fd);
+ }
+}
+
#pragma mark - Generics
static void
@@ -179,12 +198,34 @@ init(void)
static Uint8
emu_dei(Uxn *u, Uint8 addr)
{
+ Uint8 p = addr & 0x0f, d = addr & 0xf0;
+ switch(d) {
+ case 0x20: return screen_dei(&u->dev[d], p);
+ case 0xa0: return file_dei(0, &u->dev[d], p);
+ case 0xb0: return file_dei(1, &u->dev[d], p);
+ case 0xc0: return datetime_dei(&u->dev[d], p);
+ }
+ return u->dev[addr];
return 0;
}
static void
emu_deo(Uxn *u, Uint8 addr, Uint8 v)
{
+Uint8 p = addr & 0x0f, d = addr & 0xf0;
+ Uint16 mask = 0x1 << (d >> 4);
+ u->dev[addr] = v;
+ switch(d) {
+ case 0x00:
+ system_deo(u, &u->dev[d], p);
+ if(p > 0x7 && p < 0xe)
+ screen_palette(&uxn_screen, &u->dev[0x8]);
+ break;
+ case 0x10: console_deo(&u->dev[d], p); break;
+ /* case 0x20: screen_deo(u->ram, &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;
+ }
}
void
@@ -194,17 +235,6 @@ system_deo_special(Device *d, Uint8 port)
screen_palette(&uxn_screen, &d->dat[0x8]);
}
-static void
-console_deo(Device *d, Uint8 port)
-{
- FILE *fd = port == 0x8 ? stdout : port == 0x9 ? stderr
- : 0;
- if(fd) {
- fputc(d->dat[port], fd);
- fflush(fd);
- }
-}
-
static Uint8
audio_dei(Device *d, Uint8 port)
{
@@ -230,19 +260,6 @@ audio_deo(Device *d, Uint8 port)
}
}
-static Uint8
-nil_dei(Device *d, Uint8 port)
-{
- return d->dat[port];
-}
-
-static void
-nil_deo(Device *d, Uint8 port)
-{
- (void)d;
- (void)port;
-}
-
/* Boot */
static int
@@ -264,26 +281,10 @@ static int
start(Uxn *u, char *rom)
{
free(u->ram);
- if(!uxn_boot(u, calloc(0x10300, 1), emu_dei, emu_deo))
+ if(!uxn_boot(u, (Uint8 *)calloc(0x10300, sizeof(Uint8)), emu_dei, emu_deo))
return error("Boot", "Failed to start uxn.");
if(!load(u, rom))
return error("Boot", "Failed to load rom.");
- /* system */ uxn_port(u, 0x0, system_dei, system_deo);
- /* console */ uxn_port(u, 0x1, nil_dei, console_deo);
- /* screen */ devscreen = uxn_port(u, 0x2, screen_dei, screen_deo);
- /* audio0 */ devaudio0 = uxn_port(u, 0x3, audio_dei, audio_deo);
- /* audio1 */ uxn_port(u, 0x4, audio_dei, audio_deo);
- /* audio2 */ uxn_port(u, 0x5, audio_dei, audio_deo);
- /* audio3 */ uxn_port(u, 0x6, audio_dei, audio_deo);
- /* unused */ uxn_port(u, 0x7, nil_dei, nil_deo);
- /* control */ uxn_port(u, 0x8, nil_dei, nil_deo);
- /* mouse */ uxn_port(u, 0x9, nil_dei, nil_deo);
- /* file0 */ uxn_port(u, 0xa, file_dei, file_deo);
- /* file1 */ uxn_port(u, 0xb, file_dei, file_deo);
- /* datetime */ uxn_port(u, 0xc, datetime_dei, nil_deo);
- /* unused */ uxn_port(u, 0xd, nil_dei, nil_deo);
- /* unused */ uxn_port(u, 0xe, nil_dei, nil_deo);
- /* unused */ uxn_port(u, 0xf, nil_dei, nil_deo);
exec_deadline = SDL_GetPerformanceCounter() + deadline_interval;
if(!uxn_eval(u, PAGE_PROGRAM))
return error("Boot", "Failed to start rom.");
@@ -384,14 +385,6 @@ do_shortcut(Uxn *u, SDL_Event *event)
}
static int
-console_input(Uxn *u, char c)
-{
- Device *d = &u->devold[1];
- d->dat[0x2] = c;
- return uxn_eval(u, GETVECTOR(d));
-}
-
-static int
handle_events(Uxn *u)
{
SDL_Event event;
@@ -408,8 +401,8 @@ handle_events(Uxn *u)
}
/* Audio */
else if(event.type >= audio0_event && event.type < audio0_event + POLYPHONY) {
- Device *d = devaudio0 + (event.type - audio0_event);
- uxn_eval(u, GETVECTOR(d));
+ /* Device *d = devaudio0 + (event.type - audio0_event);
+ uxn_eval(u, GETVECTOR(d)); */
}
/* Mouse */
else if(event.type == SDL_MOUSEMOTION)
@@ -467,7 +460,7 @@ run(Uxn *u)
exec_deadline = now + deadline_interval;
if(!handle_events(u))
return 0;
- uxn_eval(u, GETVECTOR(devscreen));
+ uxn_eval(u, GETVEC(&u->dev[0x20]));
if(uxn_screen.fg.changed || uxn_screen.bg.changed)
redraw();
now = SDL_GetPerformanceCounter();
@@ -480,12 +473,6 @@ run(Uxn *u)
}
int
-uxn_interrupt(void)
-{
- return !SDL_QuitRequested();
-}
-
-int
main(int argc, char **argv)
{
SDL_DisplayMode DM;