diff --git a/boot.rom b/boot.rom new file mode 100644 index 0000000..37ad1b6 Binary files /dev/null and b/boot.rom differ diff --git a/etc/coverage.tal b/etc/coverage.tal new file mode 100644 index 0000000..122c2a3 --- /dev/null +++ b/etc/coverage.tal @@ -0,0 +1,79 @@ +( test file ) + +|0100 @program + + #01 ?{ ( skip ) #ffff } + !{ ( skip ) #ffff } + { ( skip ) #ffff } POP2r + + ( nested lambda ) + { { "hello 0a $1 } STH2r !print-str } STH2r JSR2 + + ( function application ) + { 01 02 03 04 05 } STH2r { LIT "0 ADD #18 DEO #0a18 DEO JMP2r } STH2r foreach + + ( get lambda length ) + { "Dindeldums $1 } STH2r get-lambda-length #0a18 DEO + + ( allocated string ) + ;hello-word print-str + + #800f DEO + +BRK + +( +@| test label inheritance ) + +@Object &x $1 &y $1 + +&get-x ( -- x ) + ,&x LDR + JMP2r + +@Object/get-y ( -- y ) + ,&y LDR + JMP2r + +@Object/get-both ( -- x y ) + /get-x /get-y + JMP2r + +( raw lambda length ) +_{ 01 02 03 } + +@get-lambda-length ( lambda* -- length* ) + #0002 SUB2 LDA2 +JMP2r + +@print-str ( str* -- ) + &while ( -- ) + ( send ) LDAk #18 DEO + ( loop ) INC2 LDAk ?&while + POP2 + +JMP2r + +@foreach ( arr* fn* -- ) + STH2 + DUP2 + DUP2 #0002 SUB2 LDA2 ADD2 + SWP2 + &l + LDAk STH2kr JSR2 + INC2 NEQ2k ?&l + POP2 POP2 POP2r +JMP2r + +@ ( short* -- ) + #2710 [ LIT2r 00fb ] + &w ( -- ) + DIV2k #000a DIV2k MUL2 SUB2 SWPr EQUk OVR STHkr EQU AND ?&>skip + DUP [ LIT "0 ] ADD #19 DEO + INCr &>skip + POP2 #000a DIV2 SWPr INCr STHkr ?&w + POP2r POP2 POP2 JMP2r + +$20 @label2 + +@hello-word "Hello 20 "World! 0a $1 diff --git a/makefile b/makefile index 7e2c675..6d59e68 100644 --- a/makefile +++ b/makefile @@ -5,28 +5,26 @@ EMU_src=${CLI_src} src/devices/screen.c src/devices/controller.c src/devices/mou 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 -.PHONY: all debug dest rom run test install uninstall format clean +.PHONY: all debug dest run test install uninstall format clean all: dest bin/uxnasm bin/uxncli bin/uxn11 dest: @ mkdir -p bin -rom: - @ ./bin/uxnasm etc/screen.bounds.tal bin/res.rom -run: all bin/uxnasm bin/uxncli bin/uxn11 rom - @ ./bin/uxn11 bin/res.rom +run: all bin/uxnasm bin/uxncli bin/uxn11 + @ ./bin/uxn11 test: bin/uxnasm bin/uxncli bin/uxn11 - @ ./bin/uxnasm && ./bin/uxncli && ./bin/uxn11 && ./bin/uxnasm -v && ./bin/uxncli -v && ./bin/uxn11 -v + @ ./bin/uxnasm -v && ./bin/uxncli -v && ./bin/uxn11 -v @ ./bin/uxnasm etc/opctest.tal bin/opctest.rom @ ./bin/uxncli bin/opctest.rom -install: bin/uxnasm bin/uxncli bin/uxn11 +install: all bin/uxnasm bin/uxncli bin/uxn11 @ cp bin/uxn11 bin/uxnasm bin/uxncli ~/bin/ uninstall: @ rm -f ~/bin/uxn11 ~/bin/uxnasm ~/bin/uxncli format: @ clang-format -i src/uxnasm.c src/uxncli.c src/uxn11.c src/devices/* clean: - @ rm -f bin/uxnasm bin/uxncli bin/uxn11 bin/polycat.rom bin/polycat.rom.sym + @ rm -fr bin bin/uxnasm: src/uxnasm.c @ cc ${RELEASE_flags} ${CFLAGS} src/uxnasm.c -o bin/uxnasm diff --git a/src/uxn11.c b/src/uxn11.c index 907537a..8bd6167 100644 --- a/src/uxn11.c +++ b/src/uxn11.c @@ -296,16 +296,14 @@ main(int argc, char **argv) { Uxn u = {0}; int i = 1; - if(i == argc) { - fprintf(stdout, "usage: %s [-v] file.rom [args..]\n", argv[0]); - return 0; - } - if(argv[i][0] == '-' && argv[i][1] == 'v') { - fprintf(stdout, "Uxn11 - Varvara Emulator, 14 Feb 2023.\n"); + char *rom; + if(i != argc && argv[i][0] == '-' && argv[i][1] == 'v') { + fprintf(stdout, "Uxn11 - Varvara Emulator, 22 Feb 2023.\n"); i++; } - if(!system_boot(&u, (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)), argv[i++])) { - fprintf(stdout, "Could not boot.\n"); + rom = i == argc ? "boot.rom" : argv[i++]; + if(!system_boot(&u, (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)), rom)) { + fprintf(stdout, "usage: %s [-v] file.rom [args..]\n", argv[0]); return 0; } if(!display_init()) { diff --git a/src/uxnasm.c b/src/uxnasm.c index f80d63b..d1dcf09 100644 --- a/src/uxnasm.c +++ b/src/uxnasm.c @@ -55,6 +55,8 @@ static char ops[][4] = { "ADD", "SUB", "MUL", "DIV", "AND", "ORA", "EOR", "SFT" }; +static char *runes = "|$@&,_.-;=!?#\"%~"; + static int scmp(char *a, char *b, int len) { int i = 0; while(a[i] == b[i]) if(!a[i] || ++i >= len) return 1; return 0; } /* string compare */ static int sihx(char *s) { int i = 0; char c; while((c = s[i++])) if(!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f')) return 0; return i > 1; } /* string is hexadecimal */ static int shex(char *s) { int n = 0, i = 0; char c; while((c = s[i++])) if(c >= '0' && c <= '9') n = n * 16 + (c - '0'); else if(c >= 'a' && c <= 'f') n = n * 16 + 10 + (c - 'a'); return n; } /* string to num */ @@ -156,6 +158,15 @@ makemacro(char *name, FILE *f) return 1; } +static int +isrune(char c) +{ + char cc, *r = runes; + while((cc = *r++)) + if(c == cc) return 1; + return 0; +} + static int makelabel(char *name) { @@ -166,6 +177,8 @@ makelabel(char *name) return error("Label name is hex number", name); if(findopcode(name) || scmp(name, "BRK", 4) || !slen(name)) return error("Label name is invalid", name); + if(isrune(name[0])) + return error("Label name is runic", name); if(p.label_len == 0x400) return error("Labels limit exceeded", name); l = &p.labels[p.label_len++]; @@ -195,7 +208,7 @@ makereference(char *scope, char *label, char rune, Uint16 addr) if(label[0] == '{') { p.lambda_stack[p.lambda_ptr++] = p.lambda_count; scpy(makelambda(p.lambda_count++), r->name, 0x40); - } else if(label[0] == '&') { + } else if(label[0] == '&' || label[0] == '/') { if(!sublabel(subw, scope, label + 1)) return error("Invalid sublabel", label); scpy(subw, r->name, 0x40); @@ -320,7 +333,10 @@ parse(char *w, FILE *f) case '@': /* label */ if(!makelabel(w + 1)) return error("Invalid label", w); - scpy(w + 1, p.scope, 0x40); + i = 0; + while(w[i + 1] != '/' && i < 0x3e && (p.scope[i] = w[i + 1])) + i++; + p.scope[i] = '\0'; break; case '&': /* sublabel */ if(!sublabel(subw, p.scope, w + 1) || !makelabel(subw)) @@ -346,7 +362,6 @@ parse(char *w, FILE *f) case '.': /* literal byte zero-page */ makereference(p.scope, w + 1, w[0], p.ptr + 1); return writelitbyte(0xff); - case ':': case '=': /* raw short absolute */ makereference(p.scope, w + 1, w[0], p.ptr); return writeshort(0xffff, 0); @@ -420,7 +435,6 @@ resolve(void) p.data[r->addr] = l->addr & 0xff; l->refs++; break; - case ':': case '=': case ';': if(!(l = findlabel(r->name))) @@ -501,14 +515,12 @@ main(int argc, char *argv[]) if(argc == 1) return error("usage", "uxnasm [-v] input.tal output.rom"); if(argv[1][0] == '-' && argv[1][1] == 'v') - return !fprintf(stdout, "Uxnasm - Uxntal Assembler, 27 Oct 2023.\n"); + return !fprintf(stdout, "Uxnasm - Uxntal Assembler, 25 Feb 2024.\n"); if(!(src = fopen(argv[1], "r"))) return !error("Invalid input", argv[1]); if(!assemble(src)) return !error("Assembly", "Failed to assemble rom."); - if(scmp(argv[2], "-", 2)) - dst = stdout; - else if(!(dst = fopen(argv[2], "wb"))) + if(!(dst = fopen(argv[2], "wb"))) return !error("Invalid Output", argv[2]); if(p.length <= TRIM) return !error("Assembly", "Output rom is empty.");