uxnrepl

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | LICENSE

commit 34df73e83962ecc8f4b0a2f6e8cae6d67000a5a3
Author: phoebos <ben@bvnf.space>
Date:   Sat,  2 Apr 2022 02:35:27 +0100

initial

Diffstat:
A.gitignore | 2++
ALICENSE | 13+++++++++++++
AMakefile | 19+++++++++++++++++++
Auxntrp.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; +}