Updated devices
This commit is contained in:
parent
1c74aa1731
commit
215dc9db52
|
@ -96,10 +96,10 @@ uxnemu orca.rom | shim
|
||||||
## GUI Emulator Controls
|
## GUI Emulator Controls
|
||||||
|
|
||||||
- `F1` toggle zoom
|
- `F1` toggle zoom
|
||||||
- `F2` toggle debug
|
- `F2` toggle debugger
|
||||||
- `F3` capture screen
|
- `F3` quit
|
||||||
- `F4` reboot
|
- `F4` reboot
|
||||||
- `F5` soft reboot
|
- `F5` reboot(soft)
|
||||||
- `F11` toggle fullscreen
|
- `F11` toggle fullscreen
|
||||||
- `F12` toggle decorations
|
- `F12` toggle decorations
|
||||||
|
|
||||||
|
|
|
@ -250,10 +250,9 @@ audio_handler(void *ctx, Uint8 *out_stream, int len)
|
||||||
Uxn *u = (Uxn *)ctx;
|
Uxn *u = (Uxn *)ctx;
|
||||||
Uint8 *addr = &u->dev[device];
|
Uint8 *addr = &u->dev[device];
|
||||||
if(channel[n].duration <= 0 && PEEK2(addr)) {
|
if(channel[n].duration <= 0 && PEEK2(addr)) {
|
||||||
uxn_eval(u, PEEK2(addr));
|
uxn_eval(PEEK2(addr));
|
||||||
}
|
}
|
||||||
channel[n].duration -= SOUND_TIMER;
|
channel[n].duration -= SOUND_TIMER;
|
||||||
|
|
||||||
int x = 0;
|
int x = 0;
|
||||||
if(channel[n].xfade) {
|
if(channel[n].xfade) {
|
||||||
float delta = 1.0f / (XFADE_SAMPLES * 2);
|
float delta = 1.0f / (XFADE_SAMPLES * 2);
|
||||||
|
|
|
@ -11,8 +11,6 @@ WITH REGARD TO THIS SOFTWARE.
|
||||||
|
|
||||||
typedef signed int Sint32;
|
typedef signed int Sint32;
|
||||||
|
|
||||||
#define AUDIO_VERSION 1
|
|
||||||
|
|
||||||
#define AUDIO_BUFSIZE 256.0f
|
#define AUDIO_BUFSIZE 256.0f
|
||||||
#define SAMPLE_FREQUENCY 44100.0f
|
#define SAMPLE_FREQUENCY 44100.0f
|
||||||
#define POLYPHONY 4
|
#define POLYPHONY 4
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "console.h"
|
#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
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -16,35 +16,29 @@ WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
console_input(Uxn *u, char c, int type)
|
console_input(Uint8 c, int type)
|
||||||
{
|
{
|
||||||
Uint8 *d = &u->dev[0x10];
|
uxn.dev[0x12] = c;
|
||||||
d[0x2] = c;
|
uxn.dev[0x17] = type;
|
||||||
d[0x7] = type;
|
return uxn_eval(PEEK2(&uxn.dev[0x10]));
|
||||||
return uxn_eval(u, PEEK2(d));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
console_listen(Uxn *u, int i, int argc, char **argv)
|
console_listen(int i, int argc, char **argv)
|
||||||
{
|
{
|
||||||
for(; i < argc; i++) {
|
for(; i < argc; i++) {
|
||||||
char *p = argv[i];
|
char *p = argv[i];
|
||||||
while(*p) console_input(u, *p++, CONSOLE_ARG);
|
while(*p) console_input(*p++, CONSOLE_ARG);
|
||||||
console_input(u, '\n', i == argc - 1 ? CONSOLE_END : CONSOLE_EOA);
|
console_input('\n', i == argc - 1 ? CONSOLE_END : CONSOLE_EOA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
console_deo(Uint8 *d, Uint8 port)
|
console_deo(Uint8 addr)
|
||||||
{
|
{
|
||||||
switch(port) {
|
FILE *fd;
|
||||||
case 0x8:
|
switch(addr) {
|
||||||
fputc(d[port], stdout);
|
case 0x18: fd = stdout, fputc(uxn.dev[0x18], fd), fflush(fd); break;
|
||||||
fflush(stdout);
|
case 0x19: fd = stderr, fputc(uxn.dev[0x19], fd), fflush(fd); break;
|
||||||
return;
|
|
||||||
case 0x9:
|
|
||||||
fputc(d[port], stderr);
|
|
||||||
fflush(stderr);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,12 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
WITH REGARD TO THIS SOFTWARE.
|
WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CONSOLE_VERSION 1
|
|
||||||
|
|
||||||
#define CONSOLE_STD 0x1
|
#define CONSOLE_STD 0x1
|
||||||
#define CONSOLE_ARG 0x2
|
#define CONSOLE_ARG 0x2
|
||||||
#define CONSOLE_EOA 0x3
|
#define CONSOLE_EOA 0x3
|
||||||
#define CONSOLE_END 0x4
|
#define CONSOLE_END 0x4
|
||||||
|
|
||||||
int console_input(Uxn *u, char c, int type);
|
int console_input(Uint8 c, int type);
|
||||||
void console_listen(Uxn *u, int i, int argc, char **argv);
|
void console_listen(int i, int argc, char **argv);
|
||||||
void console_deo(Uint8 *d, Uint8 port);
|
Uint8 console_dei(Uint8 addr);
|
||||||
|
void console_deo(Uint8 addr);
|
||||||
|
|
|
@ -13,29 +13,29 @@ WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
controller_down(Uxn *u, Uint8 *d, Uint8 mask)
|
controller_down(Uint8 mask)
|
||||||
{
|
{
|
||||||
if(mask) {
|
if(mask) {
|
||||||
d[2] |= mask;
|
uxn.dev[0x82] |= mask;
|
||||||
uxn_eval(u, PEEK2(d));
|
uxn_eval(PEEK2(&uxn.dev[0x80]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
controller_up(Uxn *u, Uint8 *d, Uint8 mask)
|
controller_up(Uint8 mask)
|
||||||
{
|
{
|
||||||
if(mask) {
|
if(mask) {
|
||||||
d[2] &= (~mask);
|
uxn.dev[0x82] &= (~mask);
|
||||||
uxn_eval(u, PEEK2(d));
|
uxn_eval(PEEK2(&uxn.dev[0x80]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
controller_key(Uxn *u, Uint8 *d, Uint8 key)
|
controller_key(Uint8 key)
|
||||||
{
|
{
|
||||||
if(key) {
|
if(key) {
|
||||||
d[3] = key;
|
uxn.dev[0x83] = key;
|
||||||
uxn_eval(u, PEEK2(d));
|
uxn_eval(PEEK2(&uxn.dev[0x80]));
|
||||||
d[3] = 0x00;
|
uxn.dev[0x83] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,6 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
WITH REGARD TO THIS SOFTWARE.
|
WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CONTROL_VERSION 1
|
void controller_down(Uint8 mask);
|
||||||
|
void controller_up(Uint8 mask);
|
||||||
void controller_down(Uxn *u, Uint8 *d, Uint8 mask);
|
void controller_key(Uint8 key);
|
||||||
void controller_up(Uxn *u, Uint8 *d, Uint8 mask);
|
|
||||||
void controller_key(Uxn *u, Uint8 *d, Uint8 key);
|
|
||||||
|
|
|
@ -15,11 +15,13 @@ WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Uint8
|
Uint8
|
||||||
datetime_dei(Uxn *u, Uint8 addr)
|
datetime_dei(Uint8 addr)
|
||||||
{
|
{
|
||||||
time_t seconds = time(NULL);
|
time_t seconds = time(NULL);
|
||||||
struct tm zt = {0}, *t = localtime(&seconds);
|
struct tm zt = {0};
|
||||||
if(t == NULL) t = &zt;
|
struct tm *t = localtime(&seconds);
|
||||||
|
if(t == NULL)
|
||||||
|
t = &zt;
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
case 0xc0: return (t->tm_year + 1900) >> 8;
|
case 0xc0: return (t->tm_year + 1900) >> 8;
|
||||||
case 0xc1: return (t->tm_year + 1900);
|
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 0xc8: return t->tm_yday >> 8;
|
||||||
case 0xc9: return t->tm_yday;
|
case 0xc9: return t->tm_yday;
|
||||||
case 0xca: return t->tm_isdst;
|
case 0xca: return t->tm_isdst;
|
||||||
default: return u->dev[addr];
|
default: return uxn.dev[addr];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,4 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
WITH REGARD TO THIS SOFTWARE.
|
WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DATETIME_VERSION 1
|
Uint8 datetime_dei(Uint8 addr);
|
||||||
|
|
||||||
Uint8 datetime_dei(Uxn *u, Uint8 addr);
|
|
||||||
|
|
|
@ -54,27 +54,24 @@ typedef struct {
|
||||||
|
|
||||||
static UxnFile uxn_file[POLYFILEY];
|
static UxnFile uxn_file[POLYFILEY];
|
||||||
|
|
||||||
static char
|
|
||||||
inthex(int n)
|
|
||||||
{
|
|
||||||
n &= 0xf;
|
|
||||||
return n < 10 ? '0' + n : 'a' + (n - 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
reset(UxnFile *c)
|
reset(UxnFile *c)
|
||||||
{
|
{
|
||||||
if(c->f != NULL)
|
if(c->f != NULL) {
|
||||||
fclose(c->f), c->f = NULL;
|
fclose(c->f);
|
||||||
if(c->dir != NULL)
|
c->f = NULL;
|
||||||
closedir(c->dir), c->dir = NULL;
|
}
|
||||||
|
if(c->dir != NULL) {
|
||||||
|
closedir(c->dir);
|
||||||
|
c->dir = NULL;
|
||||||
|
}
|
||||||
c->de = NULL;
|
c->de = NULL;
|
||||||
c->state = IDLE;
|
c->state = IDLE;
|
||||||
c->outside_sandbox = 0;
|
c->outside_sandbox = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint16
|
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;
|
struct stat st;
|
||||||
if(len < strlen(basename) + 8)
|
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);
|
snprintf(pathname, sizeof(pathname), "%s/%s", c->current_filename, c->de->d_name);
|
||||||
else
|
else
|
||||||
pathname[0] = '\0';
|
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;
|
if(!n) break;
|
||||||
p += n;
|
p += n;
|
||||||
len -= n;
|
len -= n;
|
||||||
|
@ -228,25 +225,15 @@ file_write(UxnFile *c, void *src, Uint16 len, Uint8 flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint16
|
static Uint16
|
||||||
file_stat(UxnFile *c, char *p, Uint16 len)
|
file_stat(UxnFile *c, void *dest, Uint16 len)
|
||||||
{
|
{
|
||||||
unsigned int i, size;
|
char *basename = strrchr(c->current_filename, DIR_SEP_CHAR);
|
||||||
struct stat st;
|
if(c->outside_sandbox) return 0;
|
||||||
if(c->outside_sandbox || !len)
|
if(basename != NULL)
|
||||||
return 0;
|
basename++;
|
||||||
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] = '?';
|
|
||||||
else
|
else
|
||||||
for(i = 0, size = st.st_size; i < len; i++)
|
basename = c->current_filename;
|
||||||
p[i] = inthex(size >> ((len - i - 1) << 2));
|
return get_entry(dest, len, c->current_filename, basename, 0);
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint16
|
static Uint16
|
||||||
|
@ -255,48 +242,79 @@ file_delete(UxnFile *c)
|
||||||
return c->outside_sandbox ? 0 : unlink(c->current_filename);
|
return c->outside_sandbox ? 0 : unlink(c->current_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* file registers */
|
|
||||||
|
|
||||||
static Uint16 rL;
|
|
||||||
|
|
||||||
/* IO */
|
/* IO */
|
||||||
|
|
||||||
void
|
void
|
||||||
file_deo(Uint8 id, Uint8 *ram, Uint8 *d, Uint8 port)
|
file_deo(Uint8 port)
|
||||||
{
|
{
|
||||||
UxnFile *c = &uxn_file[id];
|
Uint16 addr, len, res;
|
||||||
Uint16 addr, res;
|
|
||||||
switch(port) {
|
switch(port) {
|
||||||
case 0x5:
|
case 0xa5:
|
||||||
addr = (d[0x4] << 8) | d[0x5];
|
addr = PEEK2(&uxn.dev[0xa4]);
|
||||||
if(rL > 0x10000 - addr) rL = 0x10000 - addr;
|
len = PEEK2(&uxn.dev[0xaa]);
|
||||||
res = file_stat(c, (char *)&ram[addr], rL > 0x10 ? 0x10 : rL);
|
if(len > 0x10000 - addr)
|
||||||
d[0x2] = res >> 8, d[0x3] = res;
|
len = 0x10000 - addr;
|
||||||
return;
|
res = file_stat(&uxn_file[0], &uxn.ram[addr], len);
|
||||||
case 0x6:
|
POKE2(&uxn.dev[0xa2], res);
|
||||||
res = file_delete(c);
|
break;
|
||||||
d[0x2] = res >> 8, d[0x3] = res;
|
case 0xa6:
|
||||||
return;
|
res = file_delete(&uxn_file[0]);
|
||||||
case 0x9:
|
POKE2(&uxn.dev[0xa2], res);
|
||||||
addr = (d[0x8] << 8) | d[0x9];
|
break;
|
||||||
res = file_init(c, (char *)&ram[addr], 0x10000 - addr, 0);
|
case 0xa9:
|
||||||
d[0x2] = res >> 8, d[0x3] = res;
|
addr = PEEK2(&uxn.dev[0xa8]);
|
||||||
return;
|
res = file_init(&uxn_file[0], (char *)&uxn.ram[addr], 0x10000 - addr, 0);
|
||||||
case 0xa:
|
POKE2(&uxn.dev[0xa2], res);
|
||||||
case 0xb:
|
break;
|
||||||
rL = (d[0xa] << 8) | d[0xb];
|
case 0xad:
|
||||||
return;
|
addr = PEEK2(&uxn.dev[0xac]);
|
||||||
case 0xd:
|
len = PEEK2(&uxn.dev[0xaa]);
|
||||||
addr = (d[0xc] << 8) | d[0xd];
|
if(len > 0x10000 - addr)
|
||||||
if(rL > 0x10000 - addr) rL = 0x10000 - addr;
|
len = 0x10000 - addr;
|
||||||
res = file_read(c, &ram[addr], rL);
|
res = file_read(&uxn_file[0], &uxn.ram[addr], len);
|
||||||
d[0x2] = res >> 8, d[0x3] = res;
|
POKE2(&uxn.dev[0xa2], res);
|
||||||
return;
|
break;
|
||||||
case 0xf:
|
case 0xaf:
|
||||||
addr = (d[0xe] << 8) | d[0xf];
|
addr = PEEK2(&uxn.dev[0xae]);
|
||||||
if(rL > 0x10000 - addr) rL = 0x10000 - addr;
|
len = PEEK2(&uxn.dev[0xaa]);
|
||||||
res = file_write(c, &ram[addr], rL, d[0x7]);
|
if(len > 0x10000 - addr)
|
||||||
d[0x2] = res >> 8, d[0x3] = res;
|
len = 0x10000 - addr;
|
||||||
return;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
WITH REGARD TO THIS SOFTWARE.
|
WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FILE_VERSION 1
|
|
||||||
|
|
||||||
#define POLYFILEY 2
|
#define POLYFILEY 2
|
||||||
#define DEV_FILE0 0xa
|
#define DEV_FILE0 0xa
|
||||||
|
|
||||||
void file_deo(Uint8 id, Uint8 *ram, Uint8 *d, Uint8 port);
|
void file_deo(Uint8 port);
|
||||||
|
|
|
@ -13,32 +13,33 @@ WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
mouse_down(Uxn *u, Uint8 *d, Uint8 mask)
|
mouse_down(Uint8 mask)
|
||||||
{
|
{
|
||||||
d[6] |= mask;
|
uxn.dev[0x96] |= mask;
|
||||||
uxn_eval(u, PEEK2(d));
|
uxn_eval(PEEK2(&uxn.dev[0x90]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mouse_up(Uxn *u, Uint8 *d, Uint8 mask)
|
mouse_up(Uint8 mask)
|
||||||
{
|
{
|
||||||
d[6] &= (~mask);
|
uxn.dev[0x96] &= (~mask);
|
||||||
uxn_eval(u, PEEK2(d));
|
uxn_eval(PEEK2(&uxn.dev[0x90]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mouse_pos(Uxn *u, Uint8 *d, Uint16 x, Uint16 y)
|
mouse_pos(Uint16 x, Uint16 y)
|
||||||
{
|
{
|
||||||
*(d + 2) = x >> 8, *(d + 3) = x;
|
uxn.dev[0x92] = x >> 8, uxn.dev[0x93] = x;
|
||||||
*(d + 4) = y >> 8, *(d + 5) = y;
|
uxn.dev[0x94] = y >> 8, uxn.dev[0x95] = y;
|
||||||
uxn_eval(u, PEEK2(d));
|
uxn_eval(PEEK2(&uxn.dev[0x90]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mouse_scroll(Uxn *u, Uint8 *d, Uint16 x, Uint16 y)
|
mouse_scroll(Uint16 x, Uint16 y)
|
||||||
{
|
{
|
||||||
*(d + 0xa) = x >> 8, *(d + 0xb) = x;
|
uxn.dev[0x9a] = x >> 8, uxn.dev[0x9b] = x;
|
||||||
*(d + 0xc) = -y >> 8, *(d + 0xd) = -y;
|
uxn.dev[0x9c] = -y >> 8, uxn.dev[0x9d] = -y;
|
||||||
uxn_eval(u, PEEK2(d));
|
uxn_eval(PEEK2(&uxn.dev[0x90]));
|
||||||
*(d + 0xa) = *(d + 0xb) = *(d + 0xc) = *(d + 0xd) = 0;
|
uxn.dev[0x9a] = 0, uxn.dev[0x9b] = 0;
|
||||||
|
uxn.dev[0x9c] = 0, uxn.dev[0x9d] = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
WITH REGARD TO THIS SOFTWARE.
|
WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MOUSE_VERSION 1
|
void mouse_down(Uint8 mask);
|
||||||
|
void mouse_up(Uint8 mask);
|
||||||
void mouse_down(Uxn *u, Uint8 *d, Uint8 mask);
|
void mouse_pos(Uint16 x, Uint16 y);
|
||||||
void mouse_up(Uxn *u, Uint8 *d, Uint8 mask);
|
void mouse_scroll(Uint16 x, Uint16 y);
|
||||||
void mouse_pos(Uxn *u, Uint8 *d, Uint16 x, Uint16 y);
|
|
||||||
void mouse_scroll(Uxn *u, Uint8 *d, Uint16 x, Uint16 y);
|
|
||||||
|
|
|
@ -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; */
|
/* 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, 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},
|
{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},
|
{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},
|
{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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
screen_2bpp(Uint8 *layer, Uint8 *addr, Uint16 x1, Uint16 y1, Uint16 color, int fx, int fy)
|
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 y, ymod = (fy < 0 ? 7 : 0), ymax = y1 + ymod + fy * 8;
|
||||||
Uint16 x, xmod = (fx > 0 ? 7 : 0), xmax = x1 + xmod - fx * 8;
|
Uint16 x, xmod = (fx > 0 ? 7 : 0), xmax = x1 + xmod - fx * 8;
|
||||||
for(y = y1 + ymod; y != ymax; y += fy, addr++) {
|
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)
|
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);
|
Uint8 ch = (c & 1) | ((c >> 7) & 2);
|
||||||
if(x < w && (opaque || ch))
|
if((opaque || ch) && x < w)
|
||||||
layer[x + row] = blending[ch][color];
|
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
|
static void
|
||||||
screen_1bpp(Uint8 *layer, Uint8 *addr, Uint16 x1, Uint16 y1, Uint16 color, int fx, int fy)
|
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 y, ymod = (fy < 0 ? 7 : 0), ymax = y1 + ymod + fy * 8;
|
||||||
Uint16 x, xmod = (fx > 0 ? 7 : 0), xmax = x1 + xmod - fx * 8;
|
Uint16 x, xmod = (fx > 0 ? 7 : 0), xmax = x1 + xmod - fx * 8;
|
||||||
for(y = y1 + ymod; y != ymax; y += fy) {
|
for(y = y1 + ymod; y != ymax; y += fy) {
|
||||||
int c = *addr++, row = y * w;
|
int c = *addr++;
|
||||||
if(y < h)
|
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;
|
Uint8 ch = c & 1;
|
||||||
if(x < w && (opaque || ch))
|
if((opaque || ch) && x < w)
|
||||||
layer[x + row] = blending[ch][color];
|
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 */
|
/* clang-format off */
|
||||||
|
|
||||||
static Uint8 icons[] = {
|
static Uint8 icons[] = {
|
||||||
|
@ -116,37 +116,54 @@ draw_byte(Uint8 b, Uint16 x, Uint16 y, Uint8 color)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
screen_debugger(Uxn *u)
|
screen_debugger(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < 0x08; 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
|
Uint8 color = i > 4 ? 0x01 : !pos ? 0xc
|
||||||
: i == 4 ? 0x8
|
: i == 4 ? 0x8
|
||||||
: 0x2;
|
: 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++) {
|
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
|
Uint8 color = i > 4 ? 0x01 : !pos ? 0xc
|
||||||
: i == 4 ? 0x8
|
: i == 4 ? 0x8
|
||||||
: 0x2;
|
: 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);
|
screen_1bpp(uxn_screen.fg, &arrow[0], 0x68, uxn_screen.height - 0x20, 3, 1, 1);
|
||||||
for(i = 0; i < 0x20; i++)
|
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
|
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;
|
int i, shift;
|
||||||
for(i = 0, shift = 4; i < 4; ++i, shift ^= 4) {
|
for(i = 0, shift = 4; i < 4; ++i, shift ^= 4) {
|
||||||
Uint8
|
Uint8
|
||||||
r = (addr[0 + i / 2] >> shift) & 0xf,
|
r = (uxn.dev[0x8 + i / 2] >> shift) & 0xf,
|
||||||
g = (addr[2 + i / 2] >> shift) & 0xf,
|
g = (uxn.dev[0xa + i / 2] >> shift) & 0xf,
|
||||||
b = (addr[4 + 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] = 0x0f000000 | r << 16 | g << 8 | b;
|
||||||
uxn_screen.palette[i] |= uxn_screen.palette[i] << 4;
|
uxn_screen.palette[i] |= uxn_screen.palette[i] << 4;
|
||||||
}
|
}
|
||||||
|
@ -154,56 +171,74 @@ screen_palette(Uint8 *addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_resize(Uint16 width, Uint16 height)
|
screen_resize(Uint16 width, Uint16 height, int scale)
|
||||||
{
|
{
|
||||||
Uint8 *bg, *fg;
|
Uint8 *bg, *fg;
|
||||||
Uint32 *pixels = NULL;
|
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;
|
return;
|
||||||
if(uxn_screen.width == width && uxn_screen.height == height)
|
if(uxn_screen.width == width && uxn_screen.height == height && uxn_screen.scale == scale)
|
||||||
return;
|
|
||||||
bg = malloc(width * height), fg = malloc(width * height);
|
|
||||||
if(bg && fg)
|
|
||||||
pixels = realloc(uxn_screen.pixels, width * height * sizeof(Uint32));
|
|
||||||
if(!bg || !fg || !pixels) {
|
|
||||||
free(bg), free(fg);
|
|
||||||
return;
|
return;
|
||||||
|
if(dim_change) {
|
||||||
|
bg = malloc(width * height), fg = malloc(width * height);
|
||||||
|
if(bg && fg)
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
free(uxn_screen.bg), free(uxn_screen.fg);
|
|
||||||
uxn_screen.bg = bg, uxn_screen.fg = fg;
|
uxn_screen.bg = bg, uxn_screen.fg = fg;
|
||||||
uxn_screen.pixels = pixels;
|
uxn_screen.pixels = pixels;
|
||||||
uxn_screen.width = width, uxn_screen.height = height;
|
uxn_screen.width = width, uxn_screen.height = height, uxn_screen.scale = scale;
|
||||||
screen_fill(uxn_screen.bg, 0), screen_fill(uxn_screen.fg, 0);
|
if(dim_change)
|
||||||
|
screen_fill(uxn_screen.bg, 0), screen_fill(uxn_screen.fg, 0);
|
||||||
emu_resize(width, height);
|
emu_resize(width, height);
|
||||||
screen_change(0, 0, width, height);
|
screen_change(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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;
|
Uint8 *fg = uxn_screen.fg, *bg = uxn_screen.bg;
|
||||||
Uint16 w = uxn_screen.width, h = uxn_screen.height;
|
Uint16 w = uxn_screen.width, h = uxn_screen.height;
|
||||||
Uint16 x1 = uxn_screen.x1, y1 = uxn_screen.y1;
|
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;
|
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;
|
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;
|
uxn_screen.x2 = uxn_screen.y2 = 0;
|
||||||
if(u->dev[0x0e])
|
if(uxn.dev[0x0e])
|
||||||
screen_debugger(u);
|
screen_debugger();
|
||||||
for(i = 0; i < 16; i++)
|
for(i = 0; i < 16; i++)
|
||||||
palette[i] = uxn_screen.palette[(i >> 2) ? (i >> 2) : (i & 3)];
|
palette[i] = uxn_screen.palette[(i >> 2) ? (i >> 2) : (i & 3)];
|
||||||
for(y = y1; y < y2; y++)
|
for(y = y1; y < y2; y++) {
|
||||||
for(o = y * w, i = x1 + o, j = x2 + o; i < j; i++)
|
int ys = y * s;
|
||||||
pixels[i] = palette[fg[i] << 2 | bg[i]];
|
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 */
|
/* 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
|
Uint8
|
||||||
screen_dei(Uxn *u, Uint8 addr)
|
screen_dei(Uint8 addr)
|
||||||
{
|
{
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
case 0x22: return uxn_screen.width >> 8;
|
case 0x22: return uxn_screen.width >> 8;
|
||||||
|
@ -216,25 +251,25 @@ screen_dei(Uxn *u, Uint8 addr)
|
||||||
case 0x2b: return rY;
|
case 0x2b: return rY;
|
||||||
case 0x2c: return rA >> 8;
|
case 0x2c: return rA >> 8;
|
||||||
case 0x2d: return rA;
|
case 0x2d: return rA;
|
||||||
default: return u->dev[addr];
|
default: return uxn.dev[addr];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_deo(Uint8 *ram, Uint8 *d, Uint8 port)
|
screen_deo(Uint8 addr)
|
||||||
{
|
{
|
||||||
switch(port) {
|
switch(addr) {
|
||||||
case 0x3: screen_resize(PEEK2(d + 2), uxn_screen.height); return;
|
case 0x23: screen_resize(PEEK2(&uxn.dev[0x22]), uxn_screen.height, uxn_screen.scale); return;
|
||||||
case 0x5: screen_resize(uxn_screen.width, PEEK2(d + 4)); return;
|
case 0x25: screen_resize(uxn_screen.width, PEEK2(&uxn.dev[0x24]), uxn_screen.scale); 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 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 0x8:
|
case 0x28:
|
||||||
case 0x9: rX = (d[0x8] << 8) | d[0x9]; return;
|
case 0x29: rX = (uxn.dev[0x28] << 8) | uxn.dev[0x29], rX = twos(rX); return;
|
||||||
case 0xa:
|
case 0x2a:
|
||||||
case 0xb: rY = (d[0xa] << 8) | d[0xb]; return;
|
case 0x2b: rY = (uxn.dev[0x2a] << 8) | uxn.dev[0x2b], rY = twos(rY); return;
|
||||||
case 0xc:
|
case 0x2c:
|
||||||
case 0xd: rA = (d[0xc] << 8) | d[0xd]; return;
|
case 0x2d: rA = (uxn.dev[0x2c] << 8) | uxn.dev[0x2d]; return;
|
||||||
case 0xe: {
|
case 0x2e: {
|
||||||
Uint8 ctrl = d[0xe];
|
Uint8 ctrl = uxn.dev[0x2e];
|
||||||
Uint8 color = ctrl & 0x3;
|
Uint8 color = ctrl & 0x3;
|
||||||
Uint8 *layer = ctrl & 0x40 ? uxn_screen.fg : uxn_screen.bg;
|
Uint8 *layer = ctrl & 0x40 ? uxn_screen.fg : uxn_screen.bg;
|
||||||
/* fill mode */
|
/* fill mode */
|
||||||
|
@ -254,7 +289,7 @@ screen_deo(Uint8 *ram, Uint8 *d, Uint8 port)
|
||||||
/* pixel mode */
|
/* pixel mode */
|
||||||
else {
|
else {
|
||||||
Uint16 w = uxn_screen.width;
|
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;
|
layer[rX + rY * w] = color;
|
||||||
screen_change(rX, rY, rX + 1, rY + 1);
|
screen_change(rX, rY, rX + 1, rY + 1);
|
||||||
if(rMX) rX++;
|
if(rMX) rX++;
|
||||||
|
@ -262,22 +297,30 @@ screen_deo(Uint8 *ram, Uint8 *d, Uint8 port)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 0xf: {
|
case 0x2f: {
|
||||||
Uint8 i;
|
Uint8 i;
|
||||||
Uint8 ctrl = d[0xf];
|
Uint8 ctrl = uxn.dev[0x2f];
|
||||||
Uint8 twobpp = !!(ctrl & 0x80);
|
Uint8 twobpp = !!(ctrl & 0x80);
|
||||||
Uint8 color = ctrl & 0xf;
|
Uint8 color = ctrl & 0xf;
|
||||||
Uint8 *layer = ctrl & 0x40 ? uxn_screen.fg : uxn_screen.bg;
|
Uint8 *layer = ctrl & 0x40 ? uxn_screen.fg : uxn_screen.bg;
|
||||||
int fx = ctrl & 0x10 ? -1 : 1;
|
int fx = ctrl & 0x10 ? -1 : 1, fy = ctrl & 0x20 ? -1 : 1;
|
||||||
int fy = ctrl & 0x20 ? -1 : 1;
|
int x1, x2, y1, y2, x = rX, y = rY;
|
||||||
Uint16 dxy = rDX * fy, dyx = rDY * fx, addr_incr = rMA << (1 + twobpp);
|
int dxy = rDX * fy, dyx = rDY * fx, addr_incr = rMA << (1 + twobpp);
|
||||||
if(twobpp)
|
if(twobpp)
|
||||||
for(i = 0; i <= rML; i++, rA += addr_incr)
|
for(i = 0; i <= rML; i++, x += dyx, y += dxy, rA += addr_incr)
|
||||||
screen_2bpp(layer, &ram[rA], rX + dyx * i, rY + dxy * i, color, fx, fy);
|
screen_2bpp(layer, &uxn.ram[rA], x, y, color, fx, fy);
|
||||||
else
|
else
|
||||||
for(i = 0; i <= rML; i++, rA += addr_incr)
|
for(i = 0; i <= rML; i++, x += dyx, y += dxy, rA += addr_incr)
|
||||||
screen_1bpp(layer, &ram[rA], rX + dyx * i, rY + dxy * i, color, fx, fy);
|
screen_1bpp(layer, &uxn.ram[rA], x, y, color, fx, fy);
|
||||||
screen_change(rX, rY, rX + dyx * rML + 8, rY + dxy * rML + 8);
|
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(rMX) rX += rDX * fx;
|
||||||
if(rMY) rY += rDY * fy;
|
if(rMY) rY += rDY * fy;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -9,23 +9,23 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
WITH REGARD TO THIS SOFTWARE.
|
WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SCREEN_VERSION 1
|
|
||||||
|
|
||||||
typedef struct UxnScreen {
|
typedef struct UxnScreen {
|
||||||
int width, height, x1, y1, x2, y2;
|
int width, height, x1, y1, x2, y2, scale;
|
||||||
Uint32 palette[4], *pixels;
|
Uint32 palette[4], *pixels;
|
||||||
Uint8 *fg, *bg;
|
Uint8 *fg, *bg;
|
||||||
} UxnScreen;
|
} UxnScreen;
|
||||||
|
|
||||||
extern UxnScreen uxn_screen;
|
extern UxnScreen uxn_screen;
|
||||||
extern int emu_resize(int width, int height);
|
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_fill(Uint8 *layer, int color);
|
||||||
void screen_rect(Uint8 *layer, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, int color);
|
void screen_rect(Uint8 *layer, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, int color);
|
||||||
void screen_palette(Uint8 *addr);
|
void screen_palette(void);
|
||||||
void screen_resize(Uint16 width, Uint16 height);
|
void screen_resize(Uint16 width, Uint16 height, int scale);
|
||||||
void screen_change(Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2);
|
void screen_redraw();
|
||||||
void screen_redraw(Uxn *u);
|
|
||||||
|
|
||||||
Uint8 screen_dei(Uxn *u, Uint8 addr);
|
Uint8 screen_dei(Uint8 addr);
|
||||||
void screen_deo(Uint8 *ram, Uint8 *d, Uint8 port);
|
void screen_deo(Uint8 addr);
|
||||||
|
|
||||||
|
#define twos(v) (v & 0x8000 ? (int)v - 0x10000 : (int)v)
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "system.h"
|
#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
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -16,20 +16,29 @@ WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char *boot_rom;
|
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
|
static int
|
||||||
system_load(Uxn *u, char *filename)
|
system_load(char *filename)
|
||||||
{
|
{
|
||||||
int l, i = 0;
|
|
||||||
FILE *f = fopen(filename, "rb");
|
FILE *f = fopen(filename, "rb");
|
||||||
if(!f)
|
if(f) {
|
||||||
return 0;
|
int i = 0, l = fread(&uxn.ram[PAGE_PROGRAM], 0x10000 - PAGE_PROGRAM, 1, f);
|
||||||
l = fread(&u->ram[PAGE_PROGRAM], 0x10000 - PAGE_PROGRAM, 1, f);
|
while(l && ++i < RAM_PAGES)
|
||||||
while(l && ++i < RAM_PAGES)
|
l = fread(uxn.ram + 0x10000 * i, 0x10000, 1, f);
|
||||||
l = fread(u->ram + 0x10000 * i, 0x10000, 1, f);
|
fclose(f);
|
||||||
fclose(f);
|
}
|
||||||
return 1;
|
return !!f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -41,49 +50,38 @@ system_print(Stack *s)
|
||||||
fprintf(stderr, "< \n");
|
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
|
void
|
||||||
system_inspect(Uxn *u)
|
system_inspect(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "WST "), system_print(&u->wst);
|
fprintf(stderr, "WST "), system_print(&uxn.wst);
|
||||||
fprintf(stderr, "RST "), system_print(&u->rst);
|
fprintf(stderr, "RST "), system_print(&uxn.rst);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
system_error(char *msg, const char *err)
|
system_error(char *msg, const char *err)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s %s\n", msg, err);
|
fprintf(stderr, "%s: %s\n", msg, err);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
system_reboot(Uxn *u, char *rom, int soft)
|
system_reboot(char *rom, int soft)
|
||||||
{
|
{
|
||||||
system_zero(u, soft);
|
system_zero(soft);
|
||||||
if(system_load(u, boot_rom))
|
if(system_load(boot_rom))
|
||||||
if(uxn_eval(u, PAGE_PROGRAM))
|
if(uxn_eval(PAGE_PROGRAM))
|
||||||
boot_rom = rom;
|
boot_rom = rom;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
system_init(Uxn *u, Uint8 *ram, char *rom)
|
system_boot(Uint8 *ram, char *rom)
|
||||||
{
|
{
|
||||||
u->ram = ram;
|
uxn.ram = ram;
|
||||||
system_zero(u, 0);
|
system_zero(0);
|
||||||
if(!system_load(u, rom))
|
if(!system_load(rom))
|
||||||
if(!system_load(u, "boot.rom"))
|
if(!system_load("boot.rom"))
|
||||||
return system_error("Init", "Failed to load rom.");
|
return system_error("Could not load rom", rom);
|
||||||
boot_rom = rom;
|
boot_rom = rom;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -91,56 +89,54 @@ system_init(Uxn *u, Uint8 *ram, char *rom)
|
||||||
/* IO */
|
/* IO */
|
||||||
|
|
||||||
Uint8
|
Uint8
|
||||||
system_dei(Uxn *u, Uint8 addr)
|
system_dei(Uint8 addr)
|
||||||
{
|
{
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
case 0x4: return u->wst.ptr;
|
case 0x4: return uxn.wst.ptr;
|
||||||
case 0x5: return u->rst.ptr;
|
case 0x5: return uxn.rst.ptr;
|
||||||
default: return u->dev[addr];
|
default: return uxn.dev[addr];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
system_deo(Uxn *u, Uint8 *d, Uint8 port)
|
system_deo(Uint8 port)
|
||||||
{
|
{
|
||||||
Uint8 *ram;
|
|
||||||
Uint16 addr;
|
|
||||||
switch(port) {
|
switch(port) {
|
||||||
case 0x3:
|
case 0x3: {
|
||||||
ram = u->ram;
|
Uint16 addr = PEEK2(uxn.dev + 2);
|
||||||
addr = PEEK2(d + 2);
|
if(uxn.ram[addr] == 0x0) {
|
||||||
if(ram[addr] == 0x0) {
|
Uint8 value = uxn.ram[addr + 7];
|
||||||
Uint8 value = ram[addr + 7];
|
Uint16 i, length = PEEK2(uxn.ram + addr + 1);
|
||||||
Uint16 i, length = PEEK2(ram + addr + 1);
|
Uint16 dst_page = PEEK2(uxn.ram + addr + 3), dst_addr = PEEK2(uxn.ram + addr + 5);
|
||||||
Uint16 dst_page = PEEK2(ram + addr + 3), dst_addr = PEEK2(ram + addr + 5);
|
|
||||||
int dst = (dst_page % RAM_PAGES) * 0x10000;
|
int dst = (dst_page % RAM_PAGES) * 0x10000;
|
||||||
for(i = 0; i < length; i++)
|
for(i = 0; i < length; i++)
|
||||||
ram[dst + (Uint16)(dst_addr + i)] = value;
|
uxn.ram[dst + (Uint16)(dst_addr + i)] = value;
|
||||||
} else if(ram[addr] == 0x1) {
|
} else if(uxn.ram[addr] == 0x1) {
|
||||||
Uint16 i, length = PEEK2(ram + addr + 1);
|
Uint16 i, length = PEEK2(uxn.ram + addr + 1);
|
||||||
Uint16 a_page = PEEK2(ram + addr + 3), a_addr = PEEK2(ram + addr + 5);
|
Uint16 a_page = PEEK2(uxn.ram + addr + 3), a_addr = PEEK2(uxn.ram + addr + 5);
|
||||||
Uint16 b_page = PEEK2(ram + addr + 7), b_addr = PEEK2(ram + addr + 9);
|
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;
|
int src = (a_page % RAM_PAGES) * 0x10000, dst = (b_page % RAM_PAGES) * 0x10000;
|
||||||
for(i = 0; i < length; i++)
|
for(i = 0; i < length; 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 if(ram[addr] == 0x2) {
|
} else if(uxn.ram[addr] == 0x2) {
|
||||||
Uint16 i, length = PEEK2(ram + addr + 1);
|
Uint16 i, length = PEEK2(uxn.ram + addr + 1);
|
||||||
Uint16 a_page = PEEK2(ram + addr + 3), a_addr = PEEK2(ram + addr + 5);
|
Uint16 a_page = PEEK2(uxn.ram + addr + 3), a_addr = PEEK2(uxn.ram + addr + 5);
|
||||||
Uint16 b_page = PEEK2(ram + addr + 7), b_addr = PEEK2(ram + addr + 9);
|
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;
|
int src = (a_page % RAM_PAGES) * 0x10000, dst = (b_page % RAM_PAGES) * 0x10000;
|
||||||
for(i = length - 1; i != 0xffff; i--)
|
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
|
} else
|
||||||
fprintf(stderr, "Unknown Expansion Command 0x%02x\n", ram[addr]);
|
fprintf(stderr, "Unknown Expansion Command 0x%02x\n", uxn.ram[addr]);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 0x4:
|
case 0x4:
|
||||||
u->wst.ptr = d[4];
|
uxn.wst.ptr = uxn.dev[4];
|
||||||
break;
|
break;
|
||||||
case 0x5:
|
case 0x5:
|
||||||
u->rst.ptr = d[5];
|
uxn.rst.ptr = uxn.dev[5];
|
||||||
break;
|
break;
|
||||||
case 0xe:
|
case 0xe:
|
||||||
system_inspect(u);
|
system_inspect();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
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.
|
WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SYSTEM_VERSION 2
|
|
||||||
|
|
||||||
#define RAM_PAGES 0x10
|
#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);
|
int system_error(char *msg, const char *err);
|
||||||
void system_reboot(Uxn *u, char *rom, int soft);
|
int system_boot(Uint8 *ram, char *rom);
|
||||||
void system_inspect(Uxn *u);
|
|
||||||
int system_init(Uxn *u, Uint8 *ram, char *rom);
|
|
||||||
|
|
||||||
Uint8 system_dei(Uxn *u, Uint8 addr);
|
Uint8 system_dei(Uint8 addr);
|
||||||
void system_deo(Uxn *u, Uint8 *d, Uint8 port);
|
void system_deo(Uint8 addr);
|
||||||
|
|
||||||
|
extern char *boot_rom;
|
172
src/uxn.c
172
src/uxn.c
|
@ -1,7 +1,7 @@
|
||||||
#include "uxn.h"
|
#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
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
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.
|
WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Registers
|
#define OPC(opc, body) {\
|
||||||
[ Z ][ Y ][ X ][ L ][ N ][ T ] <
|
case 0x00|opc: {int _2=0,_r=0,a,b,c; Stack *s = &uxn.wst; Uint8 *sp = &uxn.wst.ptr; body break;}\
|
||||||
[ . ][ . ][ . ][ H2 ][ . ] <
|
case 0x20|opc: {int _2=1,_r=0,a,b,c; Stack *s = &uxn.wst; Uint8 *sp = &uxn.wst.ptr; body break;}\
|
||||||
[ L2 ][ N2 ][ T2 ] <
|
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 FLP { s = _r ? &uxn.wst : &uxn.rst; }
|
||||||
#define N *(s->dat + (Uint8)(s->ptr - 1))
|
#define JMI { pc += uxn.ram[pc++] << 8 | uxn.ram[pc++]; }
|
||||||
#define L *(s->dat + (Uint8)(s->ptr - 2))
|
#define JMP(x) { if(_2) pc = (x); else pc += (Sint8)(x); }
|
||||||
#define X *(s->dat + (Uint8)(s->ptr - 3))
|
#define POx(o) { if(_2) { PO2(o) } else PO1(o) }
|
||||||
#define Y *(s->dat + (Uint8)(s->ptr - 4))
|
#define PO1(o) { o = s->dat[--*sp]; }
|
||||||
#define Z *(s->dat + (Uint8)(s->ptr - 5))
|
#define PO2(o) { o = s->dat[--*sp] | (s->dat[--*sp] << 8); }
|
||||||
#define T2 (N << 8 | T)
|
#define PUx(y) { if(_2) { PU2(y) } else PU1(y) }
|
||||||
#define H2 (L << 8 | N)
|
#define PU1(y) { s->dat[s->ptr++] = (y); }
|
||||||
#define N2 (X << 8 | L)
|
#define PU2(y) { tt = (y); s->dat[s->ptr++] = tt >> 0x8; s->dat[s->ptr++] = tt; }
|
||||||
#define L2 (Z << 8 | Y)
|
#define IMM(x, y) { uxn.x.dat[uxn.x.ptr++] = (y); }
|
||||||
#define T2_(v) { r = (v); T = r; N = r >> 8; }
|
#define DEI(o, p) { if(_2) { o = (emu_dei(p) << 8) | emu_dei(p + 1); } else o = emu_dei(p); }
|
||||||
#define N2_(v) { r = (v); L = r; X = r >> 8; }
|
#define DEO(p, y) { if(_2) { emu_deo(p, y >> 8); emu_deo(p + 1, y); } else emu_deo(p, y); }
|
||||||
#define L2_(v) { r = (v); Y = r; Z = r >> 8; }
|
#define PEK(o, x, r) { if(_2) { r = (x); o = uxn.ram[r++] << 8 | uxn.ram[r]; } else o = uxn.ram[(x)]; }
|
||||||
#define FLIP { s = ins & 0x40 ? &u->wst : &u->rst; }
|
#define POK(x, y, r) { if(_2) { r = (x); uxn.ram[r++] = y >> 8; uxn.ram[r] = y; } else uxn.ram[(x)] = (y); }
|
||||||
#define SHIFT(y) { s->ptr += (y); }
|
|
||||||
#define SET(x, y) { SHIFT((ins & 0x80) ? x + y : y) }
|
|
||||||
|
|
||||||
int
|
int
|
||||||
uxn_eval(Uxn *u, Uint16 pc)
|
uxn_eval(Uint16 pc)
|
||||||
{
|
{
|
||||||
Uint16 t, n, l, r;
|
if(!pc || uxn.dev[0x0f]) return 0;
|
||||||
Uint8 *ram = u->ram, *rr;
|
|
||||||
if(!pc || u->dev[0x0f]) return 0;
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
Uint8 ins = ram[pc++];
|
Uint8 t;
|
||||||
Stack *s = ins & 0x40 ? &u->rst : &u->wst;
|
Uint16 tt;
|
||||||
switch(ins & 0x3f) {
|
switch(uxn.ram[pc++]) {
|
||||||
/* IMM */
|
/* BRK */ case 0x00: return 1;
|
||||||
case 0x00: case 0x20:
|
/* JCI */ case 0x20: if(uxn.wst.dat[--uxn.wst.ptr]) { JMI break; } pc += 2; break;
|
||||||
switch(ins) {
|
/* JMI */ case 0x40: JMI break;
|
||||||
case 0x00: /* BRK */ return 1;
|
/* JSI */ case 0x60: tt = pc + 2; IMM(rst, tt >> 8) IMM(rst, tt) JMI break;
|
||||||
case 0x20: /* JCI */ t=T; SHIFT(-1) if(!t) { pc += 2; break; } /* fall-through */
|
/* LI2 */ case 0xa0: IMM(wst, uxn.ram[pc++])
|
||||||
case 0x40: /* JMI */ rr = ram + pc; pc += 2 + PEEK2(rr); break;
|
/* LIT */ case 0x80: IMM(wst, uxn.ram[pc++]) break;
|
||||||
case 0x60: /* JSI */ SHIFT( 2) rr = ram + pc; pc += 2; T2_(pc); pc += PEEK2(rr); break;
|
/* L2r */ case 0xe0: IMM(rst, uxn.ram[pc++])
|
||||||
case 0x80: /* LIT */ case 0xc0: SHIFT( 1) T = ram[pc++]; break;
|
/* LIr */ case 0xc0: IMM(rst, uxn.ram[pc++]) break;
|
||||||
case 0xa0: /* LIT2 */ case 0xe0: SHIFT( 2) N = ram[pc++]; T = ram[pc++]; break;
|
/* INC */ OPC(0x01, POx(a) PUx(a + 1))
|
||||||
} break;
|
/* POP */ OPC(0x02, POx(a))
|
||||||
/* ALU */
|
/* NIP */ OPC(0x03, POx(a) POx(b) PUx(a))
|
||||||
case 0x01: /* INC */ t=T; SET(1, 0) T = t + 1; break;
|
/* SWP */ OPC(0x04, POx(a) POx(b) PUx(a) PUx(b))
|
||||||
case 0x21: /* INC2 */ t=T2; SET(2, 0) T2_(t + 1) break;
|
/* ROT */ OPC(0x05, POx(a) POx(b) POx(c) PUx(b) PUx(a) PUx(c))
|
||||||
case 0x02: /* POP */ SET(1,-1) break;
|
/* DUP */ OPC(0x06, POx(a) PUx(a) PUx(a))
|
||||||
case 0x22: /* POP2 */ SET(2,-2) break;
|
/* OVR */ OPC(0x07, POx(a) POx(b) PUx(b) PUx(a) PUx(b))
|
||||||
case 0x03: /* NIP */ t=T; SET(2,-1) T = t; break;
|
/* EQU */ OPC(0x08, POx(a) POx(b) PU1(b == a))
|
||||||
case 0x23: /* NIP2 */ t=T2; SET(4,-2) T2_(t) break;
|
/* NEQ */ OPC(0x09, POx(a) POx(b) PU1(b != a))
|
||||||
case 0x04: /* SWP */ t=T;n=N; SET(2, 0) T = n; N = t; break;
|
/* GTH */ OPC(0x0a, POx(a) POx(b) PU1(b > a))
|
||||||
case 0x24: /* SWP2 */ t=T2;n=N2; SET(4, 0) T2_(n) N2_(t) break;
|
/* LTH */ OPC(0x0b, POx(a) POx(b) PU1(b < a))
|
||||||
case 0x05: /* ROT */ t=T;n=N;l=L; SET(3, 0) T = l; N = t; L = n; break;
|
/* JMP */ OPC(0x0c, POx(a) JMP(a))
|
||||||
case 0x25: /* ROT2 */ t=T2;n=N2;l=L2; SET(6, 0) T2_(l) N2_(t) L2_(n) break;
|
/* JCN */ OPC(0x0d, POx(a) PO1(b) if(b) JMP(a))
|
||||||
case 0x06: /* DUP */ t=T; SET(1, 1) T = t; N = t; break;
|
/* JSR */ OPC(0x0e, POx(a) FLP PU2(pc) JMP(a))
|
||||||
case 0x26: /* DUP2 */ t=T2; SET(2, 2) T2_(t) N2_(t) break;
|
/* STH */ OPC(0x0f, POx(a) FLP PUx(a))
|
||||||
case 0x07: /* OVR */ t=T;n=N; SET(2, 1) T = n; N = t; L = n; break;
|
/* LDZ */ OPC(0x10, PO1(a) PEK(b, a, t) PUx(b))
|
||||||
case 0x27: /* OVR2 */ t=T2;n=N2; SET(4, 2) T2_(n) N2_(t) L2_(n) break;
|
/* STZ */ OPC(0x11, PO1(a) POx(b) POK(a, b, t))
|
||||||
case 0x08: /* EQU */ t=T;n=N; SET(2,-1) T = n == t; break;
|
/* LDR */ OPC(0x12, PO1(a) PEK(b, pc + (Sint8)a, tt) PUx(b))
|
||||||
case 0x28: /* EQU2 */ t=T2;n=N2; SET(4,-3) T = n == t; break;
|
/* STR */ OPC(0x13, PO1(a) POx(b) POK(pc + (Sint8)a, b, tt))
|
||||||
case 0x09: /* NEQ */ t=T;n=N; SET(2,-1) T = n != t; break;
|
/* LDA */ OPC(0x14, PO2(a) PEK(b, a, tt) PUx(b))
|
||||||
case 0x29: /* NEQ2 */ t=T2;n=N2; SET(4,-3) T = n != t; break;
|
/* STA */ OPC(0x15, PO2(a) POx(b) POK(a, b, tt))
|
||||||
case 0x0a: /* GTH */ t=T;n=N; SET(2,-1) T = n > t; break;
|
/* DEI */ OPC(0x16, PO1(a) DEI(b, a) PUx(b))
|
||||||
case 0x2a: /* GTH2 */ t=T2;n=N2; SET(4,-3) T = n > t; break;
|
/* DEO */ OPC(0x17, PO1(a) POx(b) DEO(a, b))
|
||||||
case 0x0b: /* LTH */ t=T;n=N; SET(2,-1) T = n < t; break;
|
/* ADD */ OPC(0x18, POx(a) POx(b) PUx(b + a))
|
||||||
case 0x2b: /* LTH2 */ t=T2;n=N2; SET(4,-3) T = n < t; break;
|
/* SUB */ OPC(0x19, POx(a) POx(b) PUx(b - a))
|
||||||
case 0x0c: /* JMP */ t=T; SET(1,-1) pc += (Sint8)t; break;
|
/* MUL */ OPC(0x1a, POx(a) POx(b) PUx(b * a))
|
||||||
case 0x2c: /* JMP2 */ t=T2; SET(2,-2) pc = t; break;
|
/* DIV */ OPC(0x1b, POx(a) POx(b) PUx(a ? b / a : 0))
|
||||||
case 0x0d: /* JCN */ t=T;n=N; SET(2,-2) if(n) pc += (Sint8)t; break;
|
/* AND */ OPC(0x1c, POx(a) POx(b) PUx(b & a))
|
||||||
case 0x2d: /* JCN2 */ t=T2;n=L; SET(3,-3) if(n) pc = t; break;
|
/* ORA */ OPC(0x1d, POx(a) POx(b) PUx(b | a))
|
||||||
case 0x0e: /* JSR */ t=T; SET(1,-1) FLIP SHIFT(2) T2_(pc) pc += (Sint8)t; break;
|
/* EOR */ OPC(0x1e, POx(a) POx(b) PUx(b ^ a))
|
||||||
case 0x2e: /* JSR2 */ t=T2; SET(2,-2) FLIP SHIFT(2) T2_(pc) pc = t; break;
|
/* SFT */ OPC(0x1f, PO1(a) POx(b) PUx(b >> (a & 0xf) << (a >> 4)))
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,15 +29,16 @@ typedef struct {
|
||||||
} Stack;
|
} Stack;
|
||||||
|
|
||||||
typedef struct Uxn {
|
typedef struct Uxn {
|
||||||
Uint8 *ram, *dev;
|
Uint8 *ram, dev[0x100];
|
||||||
Stack wst, rst;
|
Stack wst, rst;
|
||||||
} Uxn;
|
} Uxn;
|
||||||
|
|
||||||
/* required functions */
|
/* required functions */
|
||||||
|
|
||||||
extern Uint8 emu_dei(Uxn *u, Uint8 addr);
|
extern Uint8 emu_dei(Uint8 addr);
|
||||||
extern void emu_deo(Uxn *u, Uint8 addr, Uint8 value);
|
extern void emu_deo(Uint8 addr, Uint8 value);
|
||||||
|
extern Uxn uxn;
|
||||||
|
|
||||||
/* built-ins */
|
/* built-ins */
|
||||||
|
|
||||||
int uxn_eval(Uxn *u, Uint16 pc);
|
int uxn_eval(Uint16 pc);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include "devices/datetime.h"
|
#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
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
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.
|
WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
Uxn uxn;
|
||||||
|
|
||||||
Uint8
|
Uint8
|
||||||
emu_dei(Uxn *u, Uint8 addr)
|
emu_dei(Uint8 addr)
|
||||||
{
|
{
|
||||||
switch(addr & 0xf0) {
|
switch(addr & 0xf0) {
|
||||||
case 0x00: return system_dei(u, addr);
|
case 0x00: return system_dei(addr);
|
||||||
case 0xc0: return datetime_dei(u, addr);
|
case 0xc0: return datetime_dei(addr);
|
||||||
}
|
}
|
||||||
return u->dev[addr];
|
return uxn.dev[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
emu_deo(Uxn *u, Uint8 addr, Uint8 value)
|
emu_deo(Uint8 addr, Uint8 value)
|
||||||
{
|
{
|
||||||
Uint8 p = addr & 0x0f, d = addr & 0xf0;
|
uxn.dev[addr] = value;
|
||||||
u->dev[addr] = value;
|
switch(addr & 0xf0) {
|
||||||
switch(d) {
|
case 0x00: system_deo(addr); break;
|
||||||
case 0x00: system_deo(u, &u->dev[d], p); break;
|
case 0x10: console_deo(addr); break;
|
||||||
case 0x10: console_deo(&u->dev[d], p); break;
|
case 0xa0: file_deo(addr); break;
|
||||||
case 0xa0: file_deo(0, u->ram, &u->dev[d], p); break;
|
case 0xb0: file_deo(addr); break;
|
||||||
case 0xb0: file_deo(1, u->ram, &u->dev[d], p); 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
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i = 1;
|
int i = 1;
|
||||||
Uxn u = {0};
|
char *rom;
|
||||||
Uint8 dev[0x100] = {0};
|
if(i != argc && argv[i][0] == '-' && argv[i][1] == 'v') {
|
||||||
u.dev = dev;
|
fprintf(stdout, "Uxncli - Console Varvara Emulator, 15 Jul 2024.\n");
|
||||||
if(i == argc)
|
i++;
|
||||||
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;
|
|
||||||
}
|
|
||||||
console_input(&u, (Uint8)c, CONSOLE_STD);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
free(u.ram);
|
rom = i == argc ? "boot.rom" : argv[i++];
|
||||||
return u.dev[0x0f] & 0x7f;
|
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();
|
||||||
}
|
}
|
||||||
|
|
200
src/uxnemu.c
200
src/uxnemu.c
|
@ -46,6 +46,8 @@ WITH REGARD TO THIS SOFTWARE.
|
||||||
#define HEIGHT 40 * 8
|
#define HEIGHT 40 * 8
|
||||||
#define TIMEOUT_MS 334
|
#define TIMEOUT_MS 334
|
||||||
|
|
||||||
|
Uxn uxn, uxn_audio;
|
||||||
|
|
||||||
static SDL_Window *emu_window;
|
static SDL_Window *emu_window;
|
||||||
static SDL_Texture *emu_texture;
|
static SDL_Texture *emu_texture;
|
||||||
static SDL_Renderer *emu_renderer;
|
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 Uint64 exec_deadline, deadline_interval, ms_interval;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
clamp(int v, int min, int max)
|
clamp(int val, int min, int max)
|
||||||
{
|
{
|
||||||
return v < min ? min : v > max ? max
|
return (val >= min) ? (val <= max) ? val : max : min;
|
||||||
: v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -79,39 +80,39 @@ audio_deo(int instance, Uint8 *d, Uint8 port, Uxn *u)
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint8
|
Uint8
|
||||||
emu_dei(Uxn *u, Uint8 addr)
|
emu_dei(Uint8 addr)
|
||||||
{
|
{
|
||||||
Uint8 p = addr & 0x0f, d = addr & 0xf0;
|
Uint8 p = addr & 0x0f, d = addr & 0xf0;
|
||||||
switch(d) {
|
switch(d) {
|
||||||
case 0x00: return system_dei(u, addr);
|
case 0x00: return system_dei(addr);
|
||||||
case 0x20: return screen_dei(u, addr);
|
case 0x20: return screen_dei(addr);
|
||||||
case 0x30: return audio_dei(0, &u->dev[d], p);
|
case 0x30: return audio_dei(0, &uxn.dev[d], p);
|
||||||
case 0x40: return audio_dei(1, &u->dev[d], p);
|
case 0x40: return audio_dei(1, &uxn.dev[d], p);
|
||||||
case 0x50: return audio_dei(2, &u->dev[d], p);
|
case 0x50: return audio_dei(2, &uxn.dev[d], p);
|
||||||
case 0x60: return audio_dei(3, &u->dev[d], p);
|
case 0x60: return audio_dei(3, &uxn.dev[d], p);
|
||||||
case 0xc0: return datetime_dei(u, addr);
|
case 0xc0: return datetime_dei(addr);
|
||||||
}
|
}
|
||||||
return u->dev[addr];
|
return uxn.dev[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
emu_deo(Uxn *u, Uint8 addr, Uint8 value)
|
emu_deo(Uint8 addr, Uint8 value)
|
||||||
{
|
{
|
||||||
Uint8 p = addr & 0x0f, d = addr & 0xf0;
|
Uint8 p = addr & 0x0f, d = addr & 0xf0;
|
||||||
u->dev[addr] = value;
|
uxn.dev[addr] = value;
|
||||||
switch(d) {
|
switch(d) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
system_deo(u, &u->dev[d], p);
|
system_deo(addr);
|
||||||
if(p > 0x7 && p < 0xe) screen_palette(&u->dev[0x8]);
|
if(p > 0x7 && p < 0xe) screen_palette();
|
||||||
break;
|
break;
|
||||||
case 0x10: console_deo(&u->dev[d], p); break;
|
case 0x10: console_deo(addr); break;
|
||||||
case 0x20: screen_deo(u->ram, &u->dev[0x20], p); break;
|
case 0x20: screen_deo(addr); break;
|
||||||
case 0x30: audio_deo(0, &u->dev[d], p, u); break;
|
case 0x30: audio_deo(0, &uxn.dev[d], p, &uxn); break;
|
||||||
case 0x40: audio_deo(1, &u->dev[d], p, u); break;
|
case 0x40: audio_deo(1, &uxn.dev[d], p, &uxn); break;
|
||||||
case 0x50: audio_deo(2, &u->dev[d], p, u); break;
|
case 0x50: audio_deo(2, &uxn.dev[d], p, &uxn); break;
|
||||||
case 0x60: audio_deo(3, &u->dev[d], p, u); break;
|
case 0x60: audio_deo(3, &uxn.dev[d], p, &uxn); break;
|
||||||
case 0xa0: file_deo(0, u->ram, &u->dev[d], p); break;
|
case 0xa0: file_deo(addr); break;
|
||||||
case 0xb0: file_deo(1, u->ram, &u->dev[d], p); break;
|
case 0xb0: file_deo(addr); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,11 +178,11 @@ set_borderless(int value)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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_fill(uxn_screen.fg, 0);
|
||||||
screen_redraw(u);
|
screen_redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* emulator primitives */
|
/* emulator primitives */
|
||||||
|
@ -208,9 +209,9 @@ emu_resize(int width, int height)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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)
|
if(SDL_UpdateTexture(emu_texture, NULL, uxn_screen.pixels, uxn_screen.width * sizeof(Uint32)) != 0)
|
||||||
system_error("SDL_UpdateTexture", SDL_GetError());
|
system_error("SDL_UpdateTexture", SDL_GetError());
|
||||||
SDL_RenderClear(emu_renderer);
|
SDL_RenderClear(emu_renderer);
|
||||||
|
@ -219,7 +220,7 @@ emu_redraw(Uxn *u)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
emu_init(Uxn *u)
|
emu_init(void)
|
||||||
{
|
{
|
||||||
SDL_AudioSpec as;
|
SDL_AudioSpec as;
|
||||||
SDL_zero(as);
|
SDL_zero(as);
|
||||||
|
@ -228,7 +229,7 @@ emu_init(Uxn *u)
|
||||||
as.channels = 2;
|
as.channels = 2;
|
||||||
as.callback = audio_handler;
|
as.callback = audio_handler;
|
||||||
as.samples = AUDIO_BUFSIZE;
|
as.samples = AUDIO_BUFSIZE;
|
||||||
as.userdata = u;
|
as.userdata = &uxn_audio;
|
||||||
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0)
|
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0)
|
||||||
return system_error("sdl", SDL_GetError());
|
return system_error("sdl", SDL_GetError());
|
||||||
audio_id = SDL_OpenAudioDevice(NULL, 0, &as, NULL, 0);
|
audio_id = SDL_OpenAudioDevice(NULL, 0, &as, NULL, 0);
|
||||||
|
@ -246,52 +247,21 @@ emu_init(Uxn *u)
|
||||||
ms_interval = SDL_GetPerformanceFrequency() / 1000;
|
ms_interval = SDL_GetPerformanceFrequency() / 1000;
|
||||||
deadline_interval = ms_interval * TIMEOUT_MS;
|
deadline_interval = ms_interval * TIMEOUT_MS;
|
||||||
exec_deadline = SDL_GetPerformanceCounter() + deadline_interval;
|
exec_deadline = SDL_GetPerformanceCounter() + deadline_interval;
|
||||||
screen_resize(WIDTH, HEIGHT);
|
screen_resize(WIDTH, HEIGHT, 1);
|
||||||
SDL_PauseAudioDevice(audio_id, 1);
|
SDL_PauseAudioDevice(audio_id, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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.bg, 0);
|
||||||
screen_fill(uxn_screen.fg, 0);
|
screen_fill(uxn_screen.fg, 0);
|
||||||
system_reboot(u, rom, soft);
|
system_reboot(rom, soft);
|
||||||
SDL_SetWindowTitle(emu_window, boot_rom);
|
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
|
static Uint8
|
||||||
get_button(SDL_Event *event)
|
get_button(SDL_Event *event)
|
||||||
{
|
{
|
||||||
|
@ -341,7 +311,7 @@ get_key(SDL_Event *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
handle_events(Uxn *u)
|
handle_events(void)
|
||||||
{
|
{
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while(SDL_PollEvent(&event)) {
|
while(SDL_PollEvent(&event)) {
|
||||||
|
@ -349,41 +319,41 @@ handle_events(Uxn *u)
|
||||||
if(event.type == SDL_QUIT)
|
if(event.type == SDL_QUIT)
|
||||||
return 0;
|
return 0;
|
||||||
else if(event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_EXPOSED)
|
else if(event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_EXPOSED)
|
||||||
emu_redraw(u);
|
emu_redraw();
|
||||||
else if(event.type == SDL_DROPFILE) {
|
else if(event.type == SDL_DROPFILE) {
|
||||||
emu_restart(u, event.drop.file, 0);
|
emu_restart(event.drop.file, 0);
|
||||||
SDL_free(event.drop.file);
|
SDL_free(event.drop.file);
|
||||||
}
|
}
|
||||||
/* Mouse */
|
/* Mouse */
|
||||||
else if(event.type == SDL_MOUSEMOTION)
|
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)
|
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)
|
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)
|
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 */
|
/* Controller */
|
||||||
else if(event.type == SDL_TEXTINPUT) {
|
else if(event.type == SDL_TEXTINPUT) {
|
||||||
char *c;
|
char *c;
|
||||||
for(c = event.text.text; *c; c++)
|
for(c = event.text.text; *c; c++)
|
||||||
controller_key(u, &u->dev[0x80], *c);
|
controller_key(*c);
|
||||||
} else if(event.type == SDL_KEYDOWN) {
|
} else if(event.type == SDL_KEYDOWN) {
|
||||||
int ksym;
|
int ksym;
|
||||||
if(get_key(&event))
|
if(get_key(&event))
|
||||||
controller_key(u, &u->dev[0x80], get_key(&event));
|
controller_key(get_key(&event));
|
||||||
else if(get_button(&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)
|
else if(event.key.keysym.sym == SDLK_F1)
|
||||||
set_zoom(zoom == 3 ? 1 : zoom + 1, 1);
|
set_zoom(zoom == 3 ? 1 : zoom + 1, 1);
|
||||||
else if(event.key.keysym.sym == SDLK_F2)
|
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)
|
else if(event.key.keysym.sym == SDLK_F3)
|
||||||
capture_screen();
|
uxn.dev[0x0f] = 0xff;
|
||||||
else if(event.key.keysym.sym == SDLK_F4)
|
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)
|
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)
|
else if(event.key.keysym.sym == SDLK_F11)
|
||||||
set_fullscreen(!fullscreen, 1);
|
set_fullscreen(!fullscreen, 1);
|
||||||
else if(event.key.keysym.sym == SDLK_F12)
|
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)
|
if(SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYUP, SDL_KEYUP) == 1 && ksym == event.key.keysym.sym)
|
||||||
return 1;
|
return 1;
|
||||||
} else if(event.type == SDL_KEYUP)
|
} 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) {
|
else if(event.type == SDL_JOYAXISMOTION) {
|
||||||
Uint8 vec = get_vector_joystick(&event);
|
Uint8 vec = get_vector_joystick(&event);
|
||||||
if(!vec)
|
if(!vec)
|
||||||
controller_up(u, &u->dev[0x80], (3 << (!event.jaxis.axis * 2)) << 4);
|
controller_up((3 << (!event.jaxis.axis * 2)) << 4);
|
||||||
else
|
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)
|
} 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)
|
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) {
|
else if(event.type == SDL_JOYHATMOTION) {
|
||||||
/* NOTE: Assuming there is only one joyhat in the controller */
|
/* NOTE: Assuming there is only one joyhat in the controller */
|
||||||
switch(event.jhat.value) {
|
switch(event.jhat.value) {
|
||||||
case SDL_HAT_UP: controller_down(u, &u->dev[0x80], 0x10); break;
|
case SDL_HAT_UP: controller_down(0x10); break;
|
||||||
case SDL_HAT_DOWN: controller_down(u, &u->dev[0x80], 0x20); break;
|
case SDL_HAT_DOWN: controller_down(0x20); break;
|
||||||
case SDL_HAT_LEFT: controller_down(u, &u->dev[0x80], 0x40); break;
|
case SDL_HAT_LEFT: controller_down(0x40); break;
|
||||||
case SDL_HAT_RIGHT: controller_down(u, &u->dev[0x80], 0x80); break;
|
case SDL_HAT_RIGHT: controller_down(0x80); break;
|
||||||
case SDL_HAT_LEFTDOWN: controller_down(u, &u->dev[0x80], 0x40 | 0x20); break;
|
case SDL_HAT_LEFTDOWN: controller_down(0x40 | 0x20); break;
|
||||||
case SDL_HAT_LEFTUP: controller_down(u, &u->dev[0x80], 0x40 | 0x10); break;
|
case SDL_HAT_LEFTUP: controller_down(0x40 | 0x10); break;
|
||||||
case SDL_HAT_RIGHTDOWN: controller_down(u, &u->dev[0x80], 0x80 | 0x20); break;
|
case SDL_HAT_RIGHTDOWN: controller_down(0x80 | 0x20); break;
|
||||||
case SDL_HAT_RIGHTUP: controller_down(u, &u->dev[0x80], 0x80 | 0x10); break;
|
case SDL_HAT_RIGHTUP: controller_down(0x80 | 0x10); break;
|
||||||
case SDL_HAT_CENTERED: controller_up(u, &u->dev[0x80], 0x10 | 0x20 | 0x40 | 0x80); break;
|
case SDL_HAT_CENTERED: controller_up(0x10 | 0x20 | 0x40 | 0x80); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Console */
|
/* Console */
|
||||||
else if(event.type == stdin_event)
|
else if(event.type == stdin_event)
|
||||||
console_input(u, event.cbutton.button, CONSOLE_STD);
|
console_input(event.cbutton.button, CONSOLE_STD);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
emu_run(Uxn *u, char *rom)
|
emu_run(char *rom)
|
||||||
{
|
{
|
||||||
Uint64 next_refresh = 0;
|
Uint64 next_refresh = 0;
|
||||||
Uint64 frame_interval = SDL_GetPerformanceFrequency() / 60;
|
Uint64 frame_interval = SDL_GetPerformanceFrequency() / 60;
|
||||||
Uint8 *vector_addr = &u->dev[0x20];
|
|
||||||
Uint32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;
|
Uint32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;
|
||||||
window_created = 1;
|
window_created = 1;
|
||||||
if(fullscreen)
|
if(fullscreen)
|
||||||
|
@ -451,18 +420,18 @@ emu_run(Uxn *u, char *rom)
|
||||||
Uint16 screen_vector;
|
Uint16 screen_vector;
|
||||||
Uint64 now = SDL_GetPerformanceCounter();
|
Uint64 now = SDL_GetPerformanceCounter();
|
||||||
/* .System/halt */
|
/* .System/halt */
|
||||||
if(u->dev[0x0f])
|
if(uxn.dev[0x0f])
|
||||||
return system_error("Run", "Ended.");
|
return system_error("Run", "Ended.");
|
||||||
exec_deadline = now + deadline_interval;
|
exec_deadline = now + deadline_interval;
|
||||||
if(!handle_events(u))
|
if(!handle_events())
|
||||||
return 0;
|
return 0;
|
||||||
screen_vector = PEEK2(vector_addr);
|
screen_vector = uxn.dev[0x20] << 8 | uxn.dev[0x21];
|
||||||
if(now >= next_refresh) {
|
if(now >= next_refresh) {
|
||||||
now = SDL_GetPerformanceCounter();
|
now = SDL_GetPerformanceCounter();
|
||||||
next_refresh = now + frame_interval;
|
next_refresh = now + frame_interval;
|
||||||
uxn_eval(u, screen_vector);
|
uxn_eval(screen_vector);
|
||||||
if(uxn_screen.x2)
|
if(uxn_screen.x2)
|
||||||
emu_redraw(u);
|
emu_redraw();
|
||||||
}
|
}
|
||||||
if(screen_vector || uxn_screen.x2) {
|
if(screen_vector || uxn_screen.x2) {
|
||||||
Uint64 delay_ms = (next_refresh - now) / ms_interval;
|
Uint64 delay_ms = (next_refresh - now) / ms_interval;
|
||||||
|
@ -473,7 +442,7 @@ emu_run(Uxn *u, char *rom)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
emu_end(Uxn *u)
|
emu_end(void)
|
||||||
{
|
{
|
||||||
SDL_CloseAudioDevice(audio_id);
|
SDL_CloseAudioDevice(audio_id);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -483,21 +452,15 @@ emu_end(Uxn *u)
|
||||||
close(0); /* make stdin thread exit */
|
close(0); /* make stdin thread exit */
|
||||||
#endif
|
#endif
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
free(u->ram);
|
free(uxn.ram);
|
||||||
return u->dev[0x0f] & 0x7f;
|
return uxn.dev[0x0f] & 0x7f;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i = 1;
|
int i = 1;
|
||||||
Uint8 *ram;
|
|
||||||
char *rom;
|
char *rom;
|
||||||
Uxn u = {0};
|
|
||||||
Uint8 dev[0x100] = {0};
|
|
||||||
Uxn u_audio = {0};
|
|
||||||
u.dev = dev;
|
|
||||||
u_audio.dev = dev;
|
|
||||||
/* flags */
|
/* flags */
|
||||||
if(argc > 1 && argv[i][0] == '-') {
|
if(argc > 1 && argv[i][0] == '-') {
|
||||||
if(!strcmp(argv[i], "-v"))
|
if(!strcmp(argv[i], "-v"))
|
||||||
|
@ -512,16 +475,15 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
/* start */
|
/* start */
|
||||||
rom = i == argc ? "boot.rom" : argv[i++];
|
rom = i == argc ? "boot.rom" : argv[i++];
|
||||||
ram = (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8));
|
if(!system_boot((Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)), rom))
|
||||||
if(!system_init(&u, ram, rom) || !system_init(&u_audio, ram, rom))
|
|
||||||
return system_error("usage:", "uxnemu [-v | -f | -2x | -3x] file.rom [args...]");
|
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.");
|
return system_error("Init", "Failed to initialize varvara.");
|
||||||
/* loop */
|
/* loop */
|
||||||
u.dev[0x17] = argc - i;
|
uxn.dev[0x17] = argc - i;
|
||||||
if(uxn_eval(&u, PAGE_PROGRAM)) {
|
if(uxn_eval(PAGE_PROGRAM)) {
|
||||||
console_listen(&u, i, argc, argv);
|
console_listen(i, argc, argv);
|
||||||
emu_run(&u, boot_rom);
|
emu_run(boot_rom);
|
||||||
}
|
}
|
||||||
return emu_end(&u);
|
return emu_end();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue