Screen device is half ported to new device handlers

This commit is contained in:
Devine Lu Linvega 2023-01-01 13:19:40 -08:00
parent 679aec047a
commit 7afe1f39c7
13 changed files with 259 additions and 263 deletions

View File

@ -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 ..

View File

@ -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];
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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];
}
}

View File

@ -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);

View File

@ -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)
{
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, "Halted: %s#%04x, at 0x%04x\n", errors[error], u->ram[addr], addr);
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;
}
}

View File

@ -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);

View File

@ -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;

View File

@ -20,24 +20,17 @@ 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 */
#define GETVEC(d) ((d)[0] << 8 | (d)[1])
#define POKDEV(x, y) { d[(x)] = (y) >> 8; d[(x) + 1] = (y); }
#define PEKDEV(o, x) { (o) = (d[(x)] << 8) + d[(x) + 1]; }
/* clang-format on */
typedef struct {
Uint8 ptr, dat[255];
} Stack;
typedef struct Device {
struct Uxn *u;
Uint8 dat[16];
@ -45,9 +38,21 @@ typedef struct Device {
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); }
#define PEKDEV(o, x) { (o) = (d[(x)] << 8) + d[(x) + 1]; }
/* clang-format on */
typedef struct {
Uint8 dat[254], err, ptr;
} Stack;
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 */

View File

@ -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)
static int
console_input(Uxn *u, char c)
{
return 0;
Uint8 *d = &u->dev[0x10];
d[0x02] = c;
return uxn_eval(u, GETVEC(d));
}
static void
emu_deo(Uxn *u, Uint8 addr, Uint8 v)
console_deo(Uint8 *d, Uint8 port)
{
}
void
system_deo_special(Device *d, Uint8 port)
{
(void)d;
(void)port;
}
static void
console_deo(Device *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)
emu_dei(Uxn *u, Uint8 addr)
{
return d->dat[port];
}
static void
nil_deo(Device *d, Uint8 port)
{
(void)d;
(void)port;
}
static int
console_input(Uxn *u, char c)
{
Device *d = &u->devold[1];
d->dat[0x2] = c;
return uxn_eval(u, GETVECTOR(d));
}
static void
run(Uxn *u)
{
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;
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];
}
int
uxn_interrupt(void)
static void
emu_deo(Uxn *u, Uint8 addr, Uint8 v)
{
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;
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;
}
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;
}

View File

@ -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.");
@ -383,14 +384,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)
{
@ -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();
@ -479,12 +472,6 @@ run(Uxn *u)
return error("SDL_WaitEvent", SDL_GetError());
}
int
uxn_interrupt(void)
{
return !SDL_QuitRequested();
}
int
main(int argc, char **argv)
{