commit 34df73e83962ecc8f4b0a2f6e8cae6d67000a5a3
Author: phoebos <ben@bvnf.space>
Date: Sat, 2 Apr 2022 02:35:27 +0100
initial
Diffstat:
A | .gitignore | | | 2 | ++ |
A | LICENSE | | | 13 | +++++++++++++ |
A | Makefile | | | 19 | +++++++++++++++++++ |
A | uxntrp.c | | | 327 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
4 files changed, 361 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,2 @@
+*.o
+uxntrp
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2022 phoebos <ben@bvnf.space>
+
+Permission to use, copy, modify, and/or 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 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
diff --git a/Makefile b/Makefile
@@ -0,0 +1,19 @@
+.POSIX:
+
+XCFLAGS = $(CFLAGS) -Wall -Wextra -pedantic -g -Og
+XLDFLAGS = $(LDFLAGS)
+OBJS = uxntrp.o
+BIN = uxntrp
+
+all: $(BIN)
+
+$(BIN): $(OBJS)
+ $(CC) $(XDLFLAGS) $(OBJS) -o $(BIN)
+
+.c.o:
+ $(CC) $(XCFLAGS) -c $<
+
+clean:
+ rm -f $(OBJS) $(BIN)
+
+.PHONY: clean
diff --git a/uxntrp.c b/uxntrp.c
@@ -0,0 +1,327 @@
+#define _POSIX_C_SOURCE 200809L
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define STACKSIZE 0xff
+#define PAGESIZE 0x0100
+#define RAMSIZE 0x10000
+
+struct stack {
+ uint8_t sp;
+ uint8_t s[STACKSIZE];
+};
+struct state {
+ int lit;
+ int litr;
+ int in_string;
+ int in_comment;
+ struct stack *wst, *rst;
+ uint16_t pctr;
+ uint8_t *ram;
+};
+struct state Global_State = {0};
+
+
+
+#define PEEK8(o) { o = src->s[*src_p-1]; }
+#define PEEK16(o) { o = (src->s[*src_p-1] << 8) + src->s[*src_p-2]; }
+#define PEEK(o) { if(s) PEEK16(o) else PEEK8(o); }
+#define POP8(o) { if (*src_p == 0x00) fprintf(stderr, "stack underflow!\n"); o = src->s[--*src_p]; }
+#define POP16(o) { if (*src_p <= 0x01) fprintf(stderr, "stack underflow!\n"); o = src->s[--*src_p]; o += src->s[--*src_p] << 8; }
+#define POP(o) { if(s) POP16(o) else POP8(o); }
+#define PUSH8(st, o) { if(st->sp == 0xff) fprintf(stderr, "stack overflow!\n"); st->s[st->sp++] = o;}
+#define PUSH16(st, o) { uint16_t x; if(st->sp >= 0xfe) fprintf(stderr, "stack overflow!\n"); x = o; st->s[st->sp++] = (x) >> 8; st->s[st->sp++] = (x) & 0xff;}
+#define PUSH(st, o) { if(s) PUSH16(st, o) else PUSH8(st,o); }
+
+int
+parse(FILE *f);
+
+int
+parse_op(char *s);
+
+int
+parse_macro(char *s);
+
+uint8_t ops[][4] = {
+ "LIT", "INC", "POP", "DUP", "NIP", "SWP", "OVR", "ROT",
+ "EQU", "NEQ", "GTH", "LTH", "JMP", "JCN", "JSR", "STH",
+ "LDZ", "STZ", "LDR", "STR", "LDA", "STA", "DEI", "DEO",
+ "ADD", "SUB", "MUL", "DIV", "AND", "ORA", "EOR", "SFT"
+};
+#define NUMOPS (sizeof(ops) / sizeof(ops[0]))
+
+/* returns 0 if op not found */
+uint8_t
+find_op(char *s) {
+ uint8_t i;
+ for (i = 0; i < NUMOPS; i++) {
+ if (strncmp((char *)ops[i], s, 3) != 0)
+ continue;
+
+ if (i == 0) /* LIT */
+ i = 0x80;
+ if (strchr(s + 3, '2') != NULL)
+ i |= 0x20;
+ if (strchr(s + 3, 'r') != NULL)
+ i |= 0x40;
+ if (strchr(s + 3, 'k') != NULL)
+ i |= 0x80;
+ /* TODO: check for extra letters - eg INCz is currently interpreted as INC */
+
+ return i;
+ }
+ return 0;
+}
+
+int
+run_op(uint8_t op) {
+ uint8_t s, r, k, bop, ksrc_p, *src_p;
+ uint16_t a, b, c;
+ struct stack *src, *dst;
+
+ a = b = c = s = r = k = 0;
+ s = op & 0x20 ? 1 : 0;
+ r = op & 0x40 ? 1 : 0;
+ k = op & 0x80 ? 1 : 0;
+
+ src = Global_State.wst;
+ dst = Global_State.rst;
+ if (r) {
+ src = Global_State.rst;
+ dst = Global_State.wst;
+ }
+
+ src_p = &src->sp;
+ if (k) {
+ /* local copy of src stack pointer just for the POPs */
+ ksrc_p = src->sp;
+ src_p = &ksrc_p;
+ }
+
+ bop = op & 0x1f;
+ switch (bop) {
+ case 0x00: /* LIT */ Global_State.lit = 1; Global_State.litr = (int)r; break;
+ case 0x01: /* INC */ POP(a); PUSH(src, a+1); break;
+ case 0x02: /* POP */ POP(a); break;
+ case 0x03: /* DUP */ POP(a); PUSH(src, a); PUSH(src, a); break;
+ case 0x04: /* NIP */ POP(a); POP(b); PUSH(src, a); break;
+ case 0x05: /* SWP */ POP(a); POP(b); PUSH(src, a); PUSH(src, b); break;
+ case 0x06: /* OVR */ POP(a); POP(b); PUSH(src, b); PUSH(src, a); PUSH(src, b); break;
+ case 0x07: /* ROT */ POP(a); POP(b); POP(c); PUSH(src, b); PUSH(src, a); PUSH(src, c); break;
+ case 0x08: /* EQU */ POP(a); POP(b); PUSH(src, a == b); break;
+ case 0x09: /* NEQ */ POP(a); POP(b); PUSH(src, a != b); break;
+ case 0x0a: /* GTH */ POP(a); POP(b); PUSH(src, b>a); break;
+ case 0x0b: /* LTH */ POP(a); POP(b); PUSH(src, b<a); break;
+ case 0x0c: /* JMP */ break;
+ case 0x0d: /* JCN */ break;
+ case 0x0e: /* JSR */ break;
+ case 0x0f: /* STH */ POP(a); PUSH(dst, a); break;
+ case 0x10: /* LDZ */ break;
+ case 0x11: /* STZ */ break;
+ case 0x12: /* LDR */ break;
+ case 0x13: /* STR */ break;
+ case 0x14: /* LDA */ break;
+ case 0x15: /* STA */ break;
+ case 0x16: /* DEI */ break;
+ case 0x17: /* DEO */ break;
+ case 0x18: /* ADD */ POP(a); POP(b); PUSH(src, a+b); break;
+ case 0x19: /* SUB */ POP(a); POP(b); PUSH(src, b-a); break;
+ case 0x1a: /* MUL */ POP(a); POP(b); PUSH(src, a*b); break;
+ case 0x1b: /* DIV */ POP(a); POP(b); if (a == 0) fprintf(stderr, "divide by zero\n"); PUSH(src, b/a); break;
+ case 0x1c: /* AND */ POP(a); POP(b); PUSH(src, a&b); break;
+ case 0x1d: /* ORA */ POP(a); POP(b); PUSH(src, a|b); break;
+ case 0x1e: /* EOR */ POP(a); POP(b); PUSH(src, a^b); break;
+ case 0x1f: /* SFT */ POP8(a); POP(b); c = b << (a >> 4); PUSH(src, c >> (a & 0x0f)); break;
+ }
+ return 0;
+}
+
+int
+parse_op(char *s) {
+ uint8_t op = find_op(s);
+ if (op == 0)
+ return 1;
+ return run_op(op);
+}
+
+int
+parse_macro(char *s) {
+
+ return 0;
+}
+
+void
+print_stacks(void) {
+ uint8_t a;
+ printf("wst:");
+ for (a = 0; a < Global_State.wst->sp; a++)
+ printf(" %02X", Global_State.wst->s[a]);
+ printf("\nrst:");
+ for (a = 0; a < Global_State.rst->sp; a++)
+ printf(" %02X", Global_State.rst->s[a]);
+ printf("\n");
+}
+
+int
+is_space(int c) {
+ /* whitespace in this program is one of ' ', '\t', '\n'. don't use the standard
+ * library function because can't guarantee all locales agree with this
+ */
+ unsigned char uc = (unsigned char)c;
+ return c == EOF || uc == ' ' || uc == '\t' || uc == '\n';
+}
+
+int
+ishex(char *s) {
+ do {
+ if (isxdigit(*s) == 0) {
+ return 0;
+ }
+ } while (*++s);
+ return 1;
+}
+
+int
+parse_line(char *buf) {
+ const char sep[] = " \t\n";
+ char *tok = strtok(buf, sep);
+ if (tok == NULL)
+ return 1;
+ do {
+ size_t toklen = strlen(tok);
+ switch (tok[0]) {
+ case '%':
+ /* macro */
+ break;
+ case '{':
+ case '}':
+ /* macro content */
+ break;
+ case '@':
+ /* label */
+ break;
+ case '&':
+ /* sublabel */
+ break;
+ case '|':
+ /* absolute offset */
+ break;
+ case '$':
+ /* relative offset */
+ break;
+ case '#':
+ /* literal byte or short */
+ if (ishex(tok + 1) == 0 || (toklen != 3 && toklen != 5)) {
+ fprintf(stderr, "invalid hex literal\n");
+ return 1;
+ }
+ errno = 0;
+ uintmax_t a = strtoumax(tok + 1, NULL, 16);
+ if (errno || a == UINTMAX_MAX) {
+ fprintf(stderr, "invalid hex literal\n");
+ return 1;
+ }
+ if (toklen == 3) {
+ PUSH8(Global_State.wst, (uint8_t)a);
+ } else {
+ PUSH16(Global_State.wst, (uint16_t)a);
+ }
+
+ break;
+ case '\'':
+ /* literal char */
+ break;
+ case '"':
+ /* literal string */
+ break;
+ case '(':
+ case ')':
+ /* possible comment */
+ if (toklen == 1)
+ Global_State.in_comment = !Global_State.in_comment;
+ else {
+ /* TODO */
+ }
+ break;
+ default:
+ if (strncmp(tok, "BRK", 3) == 0) {
+ return -1;
+ } else if (parse_op(tok) == 0) {
+ /* done opcode */
+ } else if (parse_macro(tok) == 0) {
+ /* done macro */
+ } else {
+ /* raw hex */
+ }
+ break;
+ }
+
+ } while ((tok = strtok(NULL, sep)) != NULL);
+ return 0;
+}
+
+
+int
+parse(FILE *f) {
+ int ret = 0;
+ ssize_t n;
+ char *buf = NULL;
+ size_t buflen = 0;
+ while ((n = getline(&buf, &buflen, f)) != -1) {
+ int r = parse_line(buf);
+ if (r == -1)
+ break;
+ else if (r != 0)
+ ret = 1;
+ print_stacks();
+ }
+ free(buf);
+ if (ferror(f)) {
+ perror("getline");
+ ret = 1;
+ }
+ return ret;
+}
+
+int
+prompt_loop(void) {
+ fprintf(stderr, "reading from stdin\n");
+ return parse(stdin);
+}
+
+int
+main(int argc, char **argv) {
+ int ret = 0;
+ if (argc > 1) {
+ if (strcmp("-h", argv[1]) == 0) {
+ fprintf(stderr, "usage: %s [startup.tal] ...\n", argv[0]);
+ return 0;
+ }
+ for (int i = 0; i < argc; i++) {
+ FILE *f = fopen(argv[i], "r");
+ if (f == NULL) {
+ perror(argv[i]);
+ ret = 1;
+ continue;
+ }
+ parse(f);
+ fclose(f);
+ }
+ }
+
+ Global_State.wst = calloc(STACKSIZE, sizeof(uint8_t));
+ Global_State.rst = calloc(STACKSIZE, sizeof(uint8_t));
+ Global_State.ram = calloc(RAMSIZE, sizeof(uint8_t));
+
+ prompt_loop();
+
+ free(Global_State.wst);
+ free(Global_State.rst);
+ free(Global_State.ram);
+ return ret;
+}