mirror of
https://git.sr.ht/~rabbits/uxn
synced 2024-11-24 23:05:12 +00:00
Updated devices
This commit is contained in:
parent
1c74aa1731
commit
215dc9db52
21 changed files with 569 additions and 590 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
172
src/uxn.c
|
@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
82
src/uxncli.c
Executable file → Normal 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();
|
||||
}
|
||||
|
|
200
src/uxnemu.c
200
src/uxnemu.c
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue