0
0
Fork 0
mirror of https://git.sr.ht/~rabbits/uxn synced 2024-11-24 23:05:12 +00:00

Updated devices

This commit is contained in:
Devine Lu Linvega 2024-07-15 12:12:10 -07:00
parent 1c74aa1731
commit 215dc9db52
21 changed files with 569 additions and 590 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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)
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));
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;
}
uxn_screen.bg = bg, uxn_screen.fg = fg;
uxn_screen.pixels = pixels;
uxn_screen.width = width, uxn_screen.height = height;
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;

View file

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

View file

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

View file

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

172
src/uxn.c
View file

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

View file

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

82
src/uxncli.c Executable file → Normal file
View file

@ -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;
char *rom;
if(i != argc && argv[i][0] == '-' && argv[i][1] == 'v') {
fprintf(stdout, "Uxncli - Console Varvara Emulator, 15 Jul 2024.\n");
i++;
}
console_input(&u, (Uint8)c, CONSOLE_STD);
}
}
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();
}

View file

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