diff --git a/build.sh b/build.sh index 0757d62..afa4748 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ RELEASE_FLAGS="-DNDEBUG -O2 -g0 -s" DEBUG_FLAGS="-std=c89 -D_POSIX_C_SOURCE=199309L -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined" -CORE_DEVICES="src/uxn.c src/devices/system.c src/devices/file.c src/devices/datetime.c -lpthread" +CORE_DEVICES="src/uxn.c src/devices/system.c src/devices/console.c src/devices/file.c src/devices/datetime.c -lpthread" EMU_INC="${CORE_DEVICES} src/devices/screen.c src/devices/controller.c src/devices/mouse.c src/uxn11.c -o bin/uxn11 -lX11" CLI_INC="${CORE_DEVICES} src/uxncli.c -o bin/uxncli" @@ -36,7 +36,7 @@ fi if [ "${1}" = '--install' ]; then - cp bin/uxn11 bin/uxnemu + cp bin/uxn11 bin/uxn11 cp bin/uxnemu bin/uxnasm bin/uxncli $HOME/bin/ fi @@ -46,6 +46,16 @@ fi if [ "${1}" = '--norun' ]; then exit; fi +# Test usage + +./bin/uxncli +./bin/uxn11 + +# Test version + +./bin/uxncli -v +./bin/uxn11 -v + # bin/uxnasm etc/mouse.tal bin/res.rom bin/uxnasm etc/pict.tal bin/res.rom bin/uxn11 bin/res.rom diff --git a/src/devices/console.c b/src/devices/console.c new file mode 100644 index 0000000..db0dd20 --- /dev/null +++ b/src/devices/console.c @@ -0,0 +1,40 @@ +#include +#include + +#include "../uxn.h" +#include "console.h" + +/* +Copyright (c) 2022-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 +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE. +*/ + +int +console_input(Uxn *u, char c, int type) +{ + Uint8 *d = &u->dev[0x10]; + d[0x2] = c; + d[0x7] = type; + return uxn_eval(u, PEEK2(d)); +} + +void +console_deo(Uint8 *d, Uint8 port) +{ + switch(port) { + case 0x8: + fputc(d[port], stdout); + fflush(stdout); + return; + case 0x9: + fputc(d[port], stderr); + fflush(stderr); + return; + } +} \ No newline at end of file diff --git a/src/devices/console.h b/src/devices/console.h new file mode 100644 index 0000000..aaaef23 --- /dev/null +++ b/src/devices/console.h @@ -0,0 +1,22 @@ +/* +Copyright (c) 2021 Devine Lu Linvega, Andrew Alderwick + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE. +*/ + +#define CONSOLE_VERSION 1 +#define CONSOLE_DEIMASK 0x0000 +#define CONSOLE_DEOMASK 0x0300 + +#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_deo(Uint8 *d, Uint8 port); diff --git a/src/devices/controller.c b/src/devices/controller.c index 1bd9ce4..38fd3bb 100644 --- a/src/devices/controller.c +++ b/src/devices/controller.c @@ -2,7 +2,7 @@ #include "controller.h" /* -Copyright (c) 2021 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 diff --git a/src/devices/controller.h b/src/devices/controller.h index 487cb86..bbc68e1 100644 --- a/src/devices/controller.h +++ b/src/devices/controller.h @@ -9,6 +9,10 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ +#define CONTROL_VERSION 1 +#define CONTROL_DEIMASK 0x0000 +#define CONTROL_DEOMASK 0x0000 + 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); diff --git a/src/devices/datetime.h b/src/devices/datetime.h index d007531..f74c0a0 100644 --- a/src/devices/datetime.h +++ b/src/devices/datetime.h @@ -9,4 +9,8 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ +#define DATETIME_VERSION 1 +#define DATETIME_DEIMASK 0x07ff +#define DATETIME_DEOMASK 0x0000 + Uint8 datetime_dei(Uxn *u, Uint8 addr); diff --git a/src/devices/file.c b/src/devices/file.c index a208b8f..1fe3747 100644 --- a/src/devices/file.c +++ b/src/devices/file.c @@ -126,10 +126,11 @@ static char * retry_realpath(const char *file_name) { char *r, p[PATH_MAX] = {'\0'}, *x; + int fnlen; if(file_name == NULL) { errno = EINVAL; return NULL; - } else if(strlen(file_name) >= PATH_MAX) { + } else if((fnlen = strlen(file_name)) >= PATH_MAX) { errno = ENAMETOOLONG; return NULL; } @@ -137,6 +138,10 @@ retry_realpath(const char *file_name) /* TODO: use a macro instead of '/' for absolute path first character so that other systems can work */ /* if a relative path, prepend cwd */ getcwd(p, sizeof(p)); + if(strlen(p) + strlen(DIR_SEP_STR) + fnlen >= PATH_MAX) { + errno = ENAMETOOLONG; + return NULL; + } strcat(p, DIR_SEP_STR); /* TODO: use a macro instead of '/' for the path delimiter */ } strcat(p, file_name); diff --git a/src/devices/file.h b/src/devices/file.h index c839cfc..b29b482 100644 --- a/src/devices/file.h +++ b/src/devices/file.h @@ -9,6 +9,10 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ +#define FILE_VERSION 1 +#define FILE_DEIMASK 0x0000 +#define FILE_DEOMASK 0xa260 + #define POLYFILEY 2 #define DEV_FILE0 0xa diff --git a/src/devices/mouse.h b/src/devices/mouse.h index d63ded8..e848e7b 100644 --- a/src/devices/mouse.h +++ b/src/devices/mouse.h @@ -9,6 +9,10 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ +#define MOUSE_VERSION 1 +#define MOUSE_DEIMASK 0x0000 +#define MOUSE_DEOMASK 0x0000 + 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); diff --git a/src/devices/screen.h b/src/devices/screen.h index 6620909..320cc33 100644 --- a/src/devices/screen.h +++ b/src/devices/screen.h @@ -1,6 +1,5 @@ /* -Copyright (c) 2021 Devine Lu Linvega -Copyright (c) 2021 Andrew Alderwick +Copyright (c) 2021 Devine Lu Linvega, Andrew Alderwick Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -10,6 +9,10 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ +#define SCREEN_VERSION 1 +#define SCREEN_DEIMASK 0x003c +#define SCREEN_DEOMASK 0xc028 + typedef struct UxnScreen { int width, height, x1, y1, x2, y2; Uint32 palette[4], *pixels; diff --git a/src/devices/system.c b/src/devices/system.c index 5c2a842..5a44c5e 100644 --- a/src/devices/system.c +++ b/src/devices/system.c @@ -1,6 +1,5 @@ #include #include -#include #include "../uxn.h" #include "system.h" @@ -75,33 +74,24 @@ system_inspect(Uxn *u) system_print(&u->rst, "rst"); } -static Uint8 *global_ram, friends_count = 0; -static Uint16 friends_tasks[MAX_FRIENDS]; -static pthread_t friends[MAX_FRIENDS]; - -static void * -friend_task(void *vector) +void +system_connect(Uint8 device, Uint8 ver, Uint16 dei, Uint16 deo) { - Uxn friend; - uxn_boot(&friend, global_ram); - uxn_eval(&friend, *((Uint16 *)vector)); - return NULL; + dev_vers[device] = ver; + dei_mask[device] = dei; + deo_mask[device] = deo; } -static void -system_friend(Uint8 *ram, Uint16 task) +int +system_version(char *name, char *date) { - if(!task) { - while(friends_count) - pthread_join(friends[--friends_count], NULL); - } else if(friends_count >= MAX_FRIENDS) { - system_error("friends", "Too many threads"); - } else { - global_ram = ram; - friends_tasks[friends_count] = task; - pthread_create(&friends[friends_count], NULL, friend_task, (void *)&friends_tasks[friends_count]); - friends_count++; - } + int i; + printf("%s, %s.\n", name, date); + printf("Device Version Dei Deo\n"); + for(i = 0; i < 0x10; i++) + if(dev_vers[i]) + printf("%6x %7d %04x %04x\n", i, dev_vers[i], dei_mask[i], deo_mask[i]); + return 0; } /* IO */ @@ -114,7 +104,11 @@ system_deo(Uxn *u, Uint8 *d, Uint8 port) system_cmd(u->ram, PEEK2(d + 2)); break; case 0x5: - system_friend(u->ram, PEEK2(d + 4)); + if(PEEK2(d + 4)) { + Uxn friend; + uxn_boot(&friend, u->ram); + uxn_eval(&friend, PEEK2(d + 4)); + } break; case 0xe: system_inspect(u); @@ -142,29 +136,3 @@ emu_halt(Uxn *u, Uint8 instr, Uint8 err, Uint16 addr) } return 0; } - -/* Console */ - -int -console_input(Uxn *u, char c, int type) -{ - Uint8 *d = &u->dev[0x10]; - d[0x2] = c; - d[0x7] = type; - return uxn_eval(u, PEEK2(d)); -} - -void -console_deo(Uint8 *d, Uint8 port) -{ - switch(port) { - case 0x8: - fputc(d[port], stdout); - fflush(stdout); - return; - case 0x9: - fputc(d[port], stderr); - fflush(stderr); - return; - } -} diff --git a/src/devices/system.h b/src/devices/system.h index 8d521c0..0ec1e33 100644 --- a/src/devices/system.h +++ b/src/devices/system.h @@ -9,17 +9,15 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ +#define SYSTEM_VERSION 1 +#define SYSTEM_DEIMASK 0x0000 +#define SYSTEM_DEOMASK 0xff28 + #define RAM_PAGES 0x10 -#define MAX_FRIENDS 0x10 - -#define CONSOLE_STD 0x1 -#define CONSOLE_ARG 0x2 -#define CONSOLE_EOA 0x3 -#define CONSOLE_END 0x4 +void system_connect(Uint8 device, Uint8 ver, Uint16 dei, Uint16 deo); +int system_version(char *emulator, char *date); int system_load(Uxn *u, char *filename); void system_inspect(Uxn *u); int system_error(char *msg, const char *err); void system_deo(Uxn *u, Uint8 *d, Uint8 port); -int console_input(Uxn *u, char c, int type); -void console_deo(Uint8 *d, Uint8 port); diff --git a/src/uxn.c b/src/uxn.c index 18e4ba3..e7f8bf8 100644 --- a/src/uxn.c +++ b/src/uxn.c @@ -95,4 +95,5 @@ uxn_boot(Uxn *u, Uint8 *ram) cptr[i] = 0; u->ram = ram; return 1; + } diff --git a/src/uxn.h b/src/uxn.h index 8bb5831..8cab5f1 100644 --- a/src/uxn.h +++ b/src/uxn.h @@ -9,8 +9,6 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ -#define PAGE_PROGRAM 0x0100 - /* clang-format off */ #define POKE2(d, v) { (d)[0] = (v) >> 8; (d)[1] = (v); } @@ -20,6 +18,8 @@ WITH REGARD TO THIS SOFTWARE. /* clang-format on */ +#define PAGE_PROGRAM 0x0100 + typedef unsigned char Uint8; typedef signed char Sint8; typedef unsigned short Uint16; @@ -42,8 +42,7 @@ typedef struct Uxn { extern Uint8 emu_dei(Uxn *u, Uint8 addr); extern void emu_deo(Uxn *u, Uint8 addr); extern int emu_halt(Uxn *u, Uint8 instr, Uint8 err, Uint16 addr); -extern Uint16 dei_mask[]; -extern Uint16 deo_mask[]; +extern Uint16 dev_vers[0x10], dei_mask[0x10], deo_mask[0x10]; /* built-ins */ diff --git a/src/uxn11.c b/src/uxn11.c index 7af02c7..beca53e 100644 --- a/src/uxn11.c +++ b/src/uxn11.c @@ -9,6 +9,7 @@ #include "uxn.h" #include "devices/system.h" +#include "devices/console.h" #include "devices/screen.h" #include "devices/controller.h" #include "devices/mouse.h" @@ -39,8 +40,7 @@ char *rom_path; #define SCALE 1 #define CONINBUFSIZE 256 -Uint16 deo_mask[] = {0xff28, 0x0300, 0xc028, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0x0000, 0x0000, 0xa260, 0xa260, 0x0000, 0x0000, 0x0000, 0x0000}; -Uint16 dei_mask[] = {0x0000, 0x0000, 0x003c, 0x0014, 0x0014, 0x0014, 0x0014, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07ff, 0x0000, 0x0000, 0x0000}; +Uint16 dev_vers[0x10], dei_mask[0x10], deo_mask[0x10]; static int clamp(int val, int min, int max) @@ -201,13 +201,28 @@ int main(int argc, char **argv) { Uxn u; - int i, n; + int i = 1, n; char expirations[8]; char coninp[CONINBUFSIZE]; struct pollfd fds[3]; static const struct itimerspec screen_tspec = {{0, 16666666}, {0, 16666666}}; - if(argc < 2) - return system_error("usage", "uxn11 file.rom [args...]"); + if(i == argc) + return system_error("usage", "uxn11 [-v][-2x][-3x] file.rom [args...]"); + /* Connect Varvara */ + system_connect(0x0, SYSTEM_VERSION, SYSTEM_DEIMASK, SYSTEM_DEOMASK); + system_connect(0x1, CONSOLE_VERSION, CONSOLE_DEIMASK, CONSOLE_DEOMASK); + system_connect(0x2, SCREEN_VERSION, SCREEN_DEIMASK, SCREEN_DEOMASK); + system_connect(0x8, CONTROL_VERSION, CONTROL_DEIMASK, CONTROL_DEOMASK); + system_connect(0x9, MOUSE_VERSION, MOUSE_DEIMASK, MOUSE_DEOMASK); + system_connect(0xa, FILE_VERSION, FILE_DEIMASK, FILE_DEOMASK); + system_connect(0xb, FILE_VERSION, FILE_DEIMASK, FILE_DEOMASK); + system_connect(0xc, DATETIME_VERSION, DATETIME_DEIMASK, DATETIME_DEOMASK); + /* Read flags */ + if(argv[i][0] == '-' && argv[i][1] == 'v') + return system_version("Uxn11 - Graphical Varvara Emulator", "8 Aug 2023"); + + + rom_path = argv[1]; if(!uxn_boot(&u, (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)))) return system_error("boot", "Failed"); diff --git a/src/uxncli.c b/src/uxncli.c index bbeb519..bef999b 100644 --- a/src/uxncli.c +++ b/src/uxncli.c @@ -3,6 +3,7 @@ #include "uxn.h" #include "devices/system.h" +#include "devices/console.h" #include "devices/file.h" #include "devices/datetime.h" @@ -17,8 +18,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ -Uint16 deo_mask[] = {0xc028, 0x0300, 0xc028, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0x0000, 0x0000, 0xa260, 0xa260, 0x0000, 0x0000, 0x0000, 0x0000}; -Uint16 dei_mask[] = {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07ff, 0x0000, 0x0000, 0x0000}; +Uint16 dev_vers[0x10], dei_mask[0x10], deo_mask[0x10]; Uint8 emu_dei(Uxn *u, Uint8 addr) @@ -47,11 +47,23 @@ main(int argc, char **argv) Uxn u; int i = 1; if(i == argc) - return system_error("usage", "uxncli file.rom [args..]"); + return system_error("usage", "uxncli [-v] file.rom [args..]"); + /* Connect Varvara */ + system_connect(0x0, SYSTEM_VERSION, SYSTEM_DEIMASK, SYSTEM_DEOMASK); + system_connect(0x1, CONSOLE_VERSION, CONSOLE_DEIMASK, CONSOLE_DEOMASK); + system_connect(0xa, FILE_VERSION, FILE_DEIMASK, FILE_DEOMASK); + system_connect(0xb, FILE_VERSION, FILE_DEIMASK, FILE_DEOMASK); + system_connect(0xc, DATETIME_VERSION, DATETIME_DEIMASK, DATETIME_DEOMASK); + /* Read flags */ + if(argv[i][0] == '-' && argv[i][1] == 'v') + return system_version("Uxncli - Console Varvara Emulator", "8 Aug 2023"); + /* Continue.. */ if(!uxn_boot(&u, (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)))) return system_error("Boot", "Failed"); + /* Load rom */ if(!system_load(&u, argv[i++])) return system_error("Load", "Failed"); + /* Game Loop */ u.dev[0x17] = argc - i; if(uxn_eval(&u, PAGE_PROGRAM)) { for(; i < argc; i++) {