commit 40d8eb449ed072b47bfbe953a191708f761c53a0
parent 29894d56e144223629e558070cbc52080e21342e
Author: Louis Burda <quent.burda@gmail.com>
Date: Tue, 25 Jul 2023 00:47:01 +0200
Reimplement value passing and improve curses ui
Diffstat:
M | Makefile | | | 4 | ++-- |
A | asm.c | | | 433 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | asm.h | | | 8 | ++++++++ |
M | test/test.asm | | | 5 | ++++- |
M | tis-as.c | | | 471 | +++++++------------------------------------------------------------------------ |
M | tis-curses.c | | | 406 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- |
M | tpu.c | | | 161 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- |
M | tpu.h | | | 36 | ++++++++++++++++++++++++++++++------ |
M | util.c | | | 19 | +++++++++++++++++++ |
M | util.h | | | 10 | ++++++++++ |
10 files changed, 960 insertions(+), 593 deletions(-)
diff --git a/Makefile b/Makefile
@@ -9,10 +9,10 @@ all: tis-as tis-curses
clean:
rm -f tis-as tis-curses
-tis-as: tis-as.c tpu.c util.c
+tis-as: tis-as.c tpu.c util.c asm.c
$(CC) -o $@ $^ $(CFLAGS)
-tis-curses: tis-curses.c tpu.c util.c
+tis-curses: tis-curses.c tpu.c util.c asm.c
$(CC) -o $@ $^ $(CFLAGS) -lncursesw
install:
diff --git a/asm.c b/asm.c
@@ -0,0 +1,433 @@
+#include "asm.h"
+#include "util.h"
+#include "tpu.h"
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdint.h>
+
+#define NAMEALPH "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
+#define WHITESPACE " \t\v\r\n"
+
+enum asm_tok {
+ /* Global */
+ TOK_STDIN, TOK_STDOUT, TOK_TPU, TOK_END,
+
+ /* Operands (order like OP_*) */
+ TOK_ACC, TOK_BAK, TOK_NIL, TOK_LEFT, TOK_RIGHT,
+ TOK_UP, TOK_DOWN, TOK_ANY, TOK_LAST, TOK_LIT, TOK_NAME,
+
+ /* Instructions (order like INST_*) */
+ TOK_NOP, TOK_MOV, TOK_SWP, TOK_SAV, TOK_ADD, TOK_SUB,
+ TOK_NEG, TOK_JMP, TOK_JEZ, TOK_JNZ, TOK_JGZ, TOK_JLZ, TOK_JRO,
+
+ /* Misc */
+ TOK_COMMENT, TOK_LABEL, TOK_XPOS, TOK_YPOS, TOK_NL, TOK_EOF
+};
+
+struct asm_tokenizer {
+ const char *filepath;
+ FILE *file;
+ enum asm_tok tok;
+ char *tokstr;
+ size_t lineno, off;
+ char linebuf[256];
+};
+
+static const char *tok_reprs[] = {
+ /* Global */
+ "'STDIN'", "'STDOUT'", "'TPU'", "'END'",
+
+ /* Operands (order like OP_*) */
+ "'ACC'", "'BAK'", "'NIL'", "'LEFT'", "'RIGHT'",
+ "'UP'", "'DOWN'", "'ANY'", "'LAST'", "<LIT>", "<NAME>",
+
+ /* Instructions (order like INST_*) */
+ "'NOP'", "'MOV'", "'SWP'", "'SAV'", "'ADD'", "'SUB'",
+ "'NEG'", "'JMP'", "'JEZ'", "'JNZ'", "'JGZ'", "'JLZ'", "'JRO'",
+
+ /* Misc */
+ "#<COMMENT>", "<LABEL>:", "X<INT>", "Y<INT>", "<NL>", "<EOF>"
+};
+
+static bool
+is_lit(const char *str)
+{
+ unsigned long v;
+ char *end;
+
+ v = strtoul(str, &end, 10);
+ if (!end || *end) return false;
+
+ return v < 256;
+}
+
+static uint8_t
+str_to_lit(const char *str)
+{
+ return (uint8_t) atoi(str);
+}
+
+enum tpu_inst_type
+tok_to_inst(enum asm_tok tok)
+{
+ if (tok < TOK_NOP || tok > TOK_JRO) abort();
+ return tok - TOK_NOP + INST_NOP;
+}
+
+enum tpu_inst_op_type
+tok_to_optype(enum asm_tok tok)
+{
+ if (tok < TOK_ACC || tok > TOK_NAME) abort();
+ return tok - TOK_ACC + OP_ACC;
+}
+
+static size_t
+strlcat_op_name(char *buf, struct tpu_inst_op *op, size_t n)
+{
+ size_t len;
+
+ if (op->type == OP_LIT) {
+ len = strlen(buf);
+ snprintf(buf + len, n - len, "%hhu", op->lit);
+ return op->lit;
+ } else if (op->type == OP_LABEL) {
+ return strdcat(buf, op->label, n);
+ } else {
+ return strdcat(buf, op_reprs[op->type], n);
+ }
+}
+
+size_t
+asm_print_inst(char *buf, size_t n, struct tpu_inst *inst)
+{
+ size_t len;
+
+ len = strdcpy(buf, inst_reprs[inst->type], n);
+ if (inst->opcnt >= 1) {
+ len += strdcat(buf, " ", n);
+ len += strlcat_op_name(buf, &inst->ops[0], n);
+ }
+ if (inst->opcnt >= 2) {
+ len += strdcat(buf, ", ", n);
+ len += strlcat_op_name(buf, &inst->ops[1], n);
+ }
+
+ return len;
+}
+
+static enum asm_tok
+tok_next(struct asm_tokenizer *tok)
+{
+ size_t len;
+ char *s;
+
+ if (!tok->linebuf[tok->off]) {
+ if (feof(tok->file)) return TOK_EOF;
+ s = fgets(tok->linebuf, sizeof(tok->linebuf), tok->file);
+ if (!s && !feof(tok->file)) die("fgets:");
+ if (!s) return TOK_NL;
+
+ len = strlen(s);
+ if (len && s[len-1] != '\n' && !feof(tok->file))
+ die("tis_load: line %lu too long", tok->lineno);
+ if (len && s[len-1] == '\n') s[len-1] = '\0';
+
+ tok->lineno += 1;
+ tok->tokstr = s;
+ tok->off = 0;
+ return TOK_NL;
+ }
+
+ s = tok->linebuf + tok->off;
+ len = strspn(s, WHITESPACE);
+ tok->off += len;
+ s += len;
+ tok->tokstr = s;
+ if (!*s) return TOK_NL;
+
+ len = strcspn(s, WHITESPACE ",");
+ tok->off += len;
+ if (s[len]) {
+ s[len] = '\0';
+ tok->off += 1;
+ }
+
+ if (!strcasecmp(s, "stdin")) {
+ return TOK_STDIN;
+ } else if (!strcasecmp(s, "stdout")) {
+ return TOK_STDOUT;
+ } else if (!strcasecmp(s, "tpu")) {
+ return TOK_TPU;
+ } else if (!strcasecmp(s, "end")) {
+ return TOK_END;
+ } else if (!strcasecmp(s, "acc")) {
+ return TOK_ACC;
+ } else if (!strcasecmp(s, "bak")) {
+ return TOK_BAK;
+ } else if (!strcasecmp(s, "nil")) {
+ return TOK_NIL;
+ } else if (!strcasecmp(s, "left")) {
+ return TOK_LEFT;
+ } else if (!strcasecmp(s, "right")) {
+ return TOK_RIGHT;
+ } else if (!strcasecmp(s, "up")) {
+ return TOK_UP;
+ } else if (!strcasecmp(s, "down")) {
+ return TOK_DOWN;
+ } else if (!strcasecmp(s, "any")) {
+ return TOK_ANY;
+ } else if (!strcasecmp(s, "last")) {
+ return TOK_LAST;
+ } else if (is_lit(s)) {
+ return TOK_LIT;
+ } else if (!strcasecmp(s, "nop")) {
+ return TOK_NOP;
+ } else if (!strcasecmp(s, "mov")) {
+ return TOK_MOV;
+ } else if (!strcasecmp(s, "swp")) {
+ return TOK_SWP;
+ } else if (!strcasecmp(s, "sav")) {
+ return TOK_SAV;
+ } else if (!strcasecmp(s, "add")) {
+ return TOK_ADD;
+ } else if (!strcasecmp(s, "sub")) {
+ return TOK_SUB;
+ } else if (!strcasecmp(s, "neg")) {
+ return TOK_NEG;
+ } else if (!strcasecmp(s, "jmp")) {
+ return TOK_JMP;
+ } else if (!strcasecmp(s, "jez")) {
+ return TOK_JEZ;
+ } else if (!strcasecmp(s, "jnz")) {
+ return TOK_JNZ;
+ } else if (!strcasecmp(s, "jgz")) {
+ return TOK_JGZ;
+ } else if (!strcasecmp(s, "jlz")) {
+ return TOK_JLZ;
+ } else if (!strcasecmp(s, "jro")) {
+ return TOK_JRO;
+ } else if (*s == '#') {
+ tok->off += strlen(tok->linebuf + tok->off);
+ return TOK_COMMENT;
+ } else if (len && strspn(s, NAMEALPH) == len-1 && s[len-1] == ':') {
+ return TOK_LABEL;
+ } else if (*s == 'X' && atoi(s+1) > 0) {
+ return TOK_XPOS;
+ } else if (*s == 'Y' && atoi(s+1) > 0) {
+ return TOK_YPOS;
+ } else if (strspn(s, NAMEALPH) == strlen(s)) {
+ return TOK_NAME;
+ } else {
+ die("tis_load: line %lu, invalid token '%s'", tok->lineno, s);
+ }
+}
+
+static enum asm_tok
+tok_next_in(struct asm_tokenizer *tokenizer, ...)
+{
+ va_list ap, cpy;
+ enum asm_tok tok;
+ bool first;
+ int arg;
+
+ tok = tok_next(tokenizer);
+
+ va_copy(cpy, ap);
+
+ va_start(cpy, tokenizer);
+ while ((arg = va_arg(cpy, int)) > 0) {
+ if (tok == arg) return tok;
+ }
+ va_end(cpy);
+
+ fprintf(stderr, "tis-as: load: ");
+ fprintf(stderr, "line %lu, got tok %s, expected one of (",
+ tokenizer->lineno, tok_reprs[tok]);
+ first = true;
+ va_start(ap, tokenizer);
+ while ((arg = va_arg(ap, int)) > 0) {
+ if (!first) fputc(',', stderr);
+ fputs(tok_reprs[arg], stderr);
+ first = false;
+ }
+ va_end(ap);
+ fputs(")\n", stderr);
+
+ exit(1);
+}
+
+void
+tis_load(struct tis *tis, const char *filepath)
+{
+ struct asm_tokenizer tokenizer;
+ enum tpu_inst_op_type op1, op2;
+ enum asm_tok op1_tok, op2_tok;
+ uint8_t op1_lit, op2_lit;
+ enum tpu_inst_type inst;
+ struct tpu *tpu = NULL;
+ struct tpu_map_link *link;
+ struct tpu_port *port;
+ int stdin_x, stdin_y;
+ int stdout_x, stdout_y;
+ enum asm_tok tok;
+ char *label;
+ size_t i;
+
+ stdin_x = stdin_y = 0;
+ stdout_x = stdout_y = 0;
+
+ tokenizer.filepath = filepath;
+ tokenizer.file = fopen(filepath, "r");
+ if (!tokenizer.file) die("tis_load: fopen '%s':", filepath);
+
+ tokenizer.lineno = 0;
+ tokenizer.off = 0;
+ tokenizer.tokstr = NULL;
+ tokenizer.linebuf[tokenizer.off] = '\0';
+ while ((tok = tok_next(&tokenizer)) != TOK_EOF) {
+ switch (tok) {
+ case TOK_STDIN:
+ if (tpu) goto disallowed;
+ tok_next_in(&tokenizer, TOK_XPOS, -1);
+ stdin_x = atoi(tokenizer.tokstr + 1);
+ tok_next_in(&tokenizer, TOK_YPOS, -1);
+ stdin_y = atoi(tokenizer.tokstr + 1);
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ break;
+ case TOK_STDOUT:
+ if (tpu) goto disallowed;
+ tok_next_in(&tokenizer, TOK_XPOS, -1);
+ stdout_x = atoi(tokenizer.tokstr + 1);
+ tok_next_in(&tokenizer, TOK_YPOS, -1);
+ stdout_y = atoi(tokenizer.tokstr + 1);
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ break;
+ case TOK_TPU:
+ if (tpu) goto disallowed;
+ tpu = malloc(sizeof(struct tpu));
+ if (!tpu) die("malloc:");
+ tpu_init(tpu);
+ tok_next_in(&tokenizer, TOK_XPOS, -1);
+ tpu->x = (size_t) atoi(tokenizer.tokstr + 1);
+ tok_next_in(&tokenizer, TOK_YPOS, -1);
+ tpu->y = (size_t) atoi(tokenizer.tokstr + 1);
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ tpu_map_add(&tis->tpu_map, tpu);
+ break;
+ case TOK_END:
+ if (!tpu) goto disallowed;
+ tpu = NULL;
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ break;
+ case TOK_NOP: case TOK_MOV: case TOK_SWP: case TOK_SAV:
+ case TOK_ADD: case TOK_SUB: case TOK_NEG: case TOK_JMP:
+ case TOK_JEZ: case TOK_JNZ: case TOK_JGZ: case TOK_JLZ:
+ case TOK_JRO:
+ if (!tpu) goto disallowed;
+ inst = tok_to_inst(tok);
+
+ op1_tok = tok_next_in(&tokenizer, TOK_ACC, TOK_BAK,
+ TOK_NIL, TOK_LEFT, TOK_RIGHT, TOK_UP, TOK_DOWN,
+ TOK_ANY, TOK_LAST, TOK_LIT, TOK_NAME, TOK_NL, -1);
+ if (op1_tok == TOK_NL) {
+ tpu_add_inst(tpu, inst, -1, 0, -1, 0);
+ break;
+ }
+
+ op1 = tok_to_optype(op1_tok);
+ if (op1 == OP_LIT)
+ op1_lit = str_to_lit(tokenizer.tokstr);
+
+ op2_tok = tok_next_in(&tokenizer, TOK_ACC, TOK_BAK,
+ TOK_NIL, TOK_LEFT, TOK_RIGHT, TOK_UP, TOK_DOWN,
+ TOK_ANY, TOK_LAST, TOK_LIT, TOK_NAME, TOK_NL, -1);
+ if (op2_tok == TOK_NL) {
+ tpu_add_inst(tpu, inst, (int) op1,
+ op1_lit, -1, 0);
+ break;
+ }
+
+ op2 = tok_to_optype(op2_tok);
+ if (op2 == OP_LIT)
+ op2_lit = str_to_lit(tokenizer.tokstr);
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ tpu_add_inst(tpu, inst, (int) op1, op1_lit,
+ (int) op2, op2_lit);
+ break;
+ case TOK_COMMENT:
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ break;
+ case TOK_LABEL:
+ label = strdup(tokenizer.tokstr);
+ if (!label_map_add(&tpu->labels, label, tpu->inst_cnt))
+ die("tis_load: line %lu, duplicate label",
+ tokenizer.lineno);
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ break;
+ case TOK_NL:
+ break;
+ default:
+ goto disallowed;
+ }
+ }
+
+ if (stdin_x == 0 || stdin_y == 0)
+ die("tis_load: stdin tpu not set");
+
+ if (stdout_x == 0 || stdout_y == 0)
+ die("tis_load: stdout tpu not set");
+
+ for (i = 0; i < TPU_MAP_BUCKETS; i++) {
+ for (link = tis->tpu_map.buckets[i]; link; link = link->next) {
+ tpu_init_ports(link->tpu, &tis->tpu_map);
+
+ if (link->x == stdin_x && link->y == stdin_y) {
+ port = &link->tpu->ports[DIR_UP];
+ if (port->attached)
+ die("tis_load: stdin port in use");
+ port->attached = true;
+ port->dst_tpu = NULL;
+ port->dst_port = &tis->stdin_port;
+ port->type = PORT_IN;
+ tis->stdin_port.attached = true;
+ tis->stdin_port.dst_tpu = link->tpu;
+ tis->stdin_port.dst_port = port;
+ }
+
+ if (link->x == stdout_x && link->y == stdout_y) {
+ port = &link->tpu->ports[DIR_DOWN];
+ if (port->attached)
+ die("tis_load: stdout port in use");
+ port->attached = true;
+ port->dst_tpu = NULL;
+ port->dst_port = &tis->stdout_port;
+ port->type = PORT_OUT;
+ tis->stdout_port.attached = true;
+ tis->stdout_port.dst_tpu = link->tpu;
+ tis->stdout_port.dst_port = port;
+ }
+ }
+ }
+
+ if (!tis->stdin_port.attached)
+ die("tis_load: stdin tpu (X%i Y%i) not found",
+ stdin_x, stdin_y);
+
+ if (!tis->stdout_port.attached)
+ die("tis_load: stdout tpu (X%i Y%i) not found",
+ stdout_x, stdout_y);
+
+ fclose(tokenizer.file);
+
+ return;
+
+disallowed:
+ if (tok == TOK_NAME) {
+ die("tis_load: line %lu, unexpected token '%s'",
+ tokenizer.lineno, tokenizer.tokstr);
+ } else {
+ die("tis_load: line %lu, token %s not allowed here",
+ tokenizer.lineno, tok_reprs[tok]);
+ }
+}
diff --git a/asm.h b/asm.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "tpu.h"
+
+#include <stdio.h>
+
+size_t asm_print_inst(char *buf, size_t n, struct tpu_inst *inst);
+void tis_load(struct tis *tis, const char *filepath);
diff --git a/test/test.asm b/test/test.asm
@@ -6,7 +6,10 @@ tpu X1 Y1
end
tpu X2 Y1
- mov LEFT, RIGHT
+ mov LEFT, ACC
+ NEG
+ SUB 1
+ mov ACC, RIGHT
end
tpu X3 Y1
diff --git a/tis-as.c b/tis-as.c
@@ -1,7 +1,8 @@
+#include "asm.h"
#include "tpu.h"
#include "util.h"
-#include <libgen.h>
+#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
@@ -9,458 +10,64 @@
#include <stdbool.h>
#include <stdlib.h>
-#define NAMEALPH "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
-#define WHITESPACE " \t\v\r\n"
-
-enum tok {
- /* Global */
- TOK_STDIN, TOK_STDOUT, TOK_TPU, TOK_END,
-
- /* Operands (order like OP_*) */
- TOK_ACC, TOK_BAK, TOK_NIL, TOK_LEFT, TOK_RIGHT,
- TOK_UP, TOK_DOWN, TOK_ANY, TOK_LAST, TOK_LIT, TOK_NAME,
-
- /* Instructions (order like INST_*) */
- TOK_NOP, TOK_MOV, TOK_SWP, TOK_SAV, TOK_ADD, TOK_SUB,
- TOK_NEG, TOK_JMP, TOK_JEZ, TOK_JNZ, TOK_JGZ, TOK_JLZ, TOK_JRO,
-
- /* Misc */
- TOK_COMMENT, TOK_LABEL, TOK_XPOS, TOK_YPOS, TOK_NL, TOK_EOF
-};
-
-struct tokenizer {
- FILE *file;
- enum tok tok;
- char *tokstr;
- size_t lineno, off;
- char linebuf[256];
-};
-
-
-static int stdin_x = 0, stdin_y = 0;
-static struct tpu_port stdin_port;
-
-static int stdout_x = 0, stdout_y = 0;
-static struct tpu_port stdout_port;
-
-static struct tpu_map tpu_map;
-
-static const char *dir_names[] = {
- "LEFT", "RIGHT", "UP", "DOWN"
-};
-
-static const char *status_names[] = {
- "IDLE", "RUN", "READ", "WRITE"
-};
-
-static const char *tok_reprs[] = {
- /* Global */
- "'STDIN'", "'STDOUT'", "'TPU'", "'END'",
-
- /* Operands (order like OP_*) */
- "'ACC'", "'BAK'", "'NIL'", "'LEFT'", "'RIGHT'",
- "'UP'", "'DOWN'", "'ANY'", "'LAST'", "<LIT>", "<NAME>",
-
- /* Instructions (order like INST_*) */
- "'NOP'", "'MOV'", "'SWP'", "'SAV'", "'ADD'", "'SUB'",
- "'NEG'", "'JMP'", "'JEZ'", "'JNZ'", "'JGZ'", "'JLZ'", "'JRO'",
-
- /* Misc */
- "#<COMMENT>", "<LABEL>:", "X<INT>", "Y<INT>", "<NL>", "<EOF>"
-};
+static struct tis tis;
+static FILE *tis_stdin = NULL;
+static FILE *tis_stdout = NULL;
+void (*cleanup)(void) = NULL;
const char *progname = "tis-as";
-bool
-is_lit(const char *str)
-{
- unsigned long v;
- char *end;
-
- v = strtoul(str, &end, 10);
- if (!end || *end) return false;
-
- return v < 256;
-}
-
-uint8_t
-str2lit(const char *str)
-{
- return (uint8_t) atoi(str);
-}
-
-enum tpu_inst_type
-tok_to_inst(enum tok tok)
-{
- if (tok < TOK_NOP || tok > TOK_JRO) abort();
- return tok - TOK_NOP + INST_NOP;
-}
-
-enum tpu_inst_op_type
-tok_to_optype(enum tok tok)
-{
- if (tok < TOK_ACC || tok > TOK_NAME) abort();
- return tok - TOK_ACC + OP_ACC;
-}
-
-enum tok
-tok_next(struct tokenizer *tok)
+int
+main(int argc, const char **argv)
{
- size_t len;
- char *s;
-
- if (!tok->linebuf[tok->off]) {
- if (feof(tok->file)) return TOK_EOF;
- s = fgets(tok->linebuf, sizeof(tok->linebuf), tok->file);
- if (!s && !feof(tok->file)) die("fgets:");
- if (!s) return TOK_NL;
-
- len = strlen(s);
- if (len && s[len-1] != '\n' && !feof(tok->file))
- die("load: line %lu too long", tok->lineno);
- if (len && s[len-1] == '\n') s[len-1] = '\0';
-
- tok->lineno += 1;
- tok->tokstr = s;
- tok->off = 0;
- return TOK_NL;
- }
-
- s = tok->linebuf + tok->off;
- len = strspn(s, WHITESPACE);
- tok->off += len;
- s += len;
- tok->tokstr = s;
- if (!*s) return TOK_NL;
+ bool idle, prev_idle;
+ int c;
- len = strcspn(s, WHITESPACE ",");
- tok->off += len;
- printf("> %s\n", s);
- if (s[len]) {
- s[len] = '\0';
- tok->off += 1;
+ if (argc < 2 || argc > 4) {
+ fprintf(stderr, "Usage: tis-as FILE [STDIN] [STDOUT]\n");
+ exit(1);
}
- if (!strcasecmp(s, "stdin")) {
- return TOK_STDIN;
- } else if (!strcasecmp(s, "stdout")) {
- return TOK_STDOUT;
- } else if (!strcasecmp(s, "tpu")) {
- return TOK_TPU;
- } else if (!strcasecmp(s, "end")) {
- return TOK_END;
- } else if (!strcasecmp(s, "acc")) {
- return TOK_ACC;
- } else if (!strcasecmp(s, "bak")) {
- return TOK_BAK;
- } else if (!strcasecmp(s, "nil")) {
- return TOK_NIL;
- } else if (!strcasecmp(s, "left")) {
- return TOK_LEFT;
- } else if (!strcasecmp(s, "right")) {
- return TOK_RIGHT;
- } else if (!strcasecmp(s, "up")) {
- return TOK_UP;
- } else if (!strcasecmp(s, "down")) {
- return TOK_DOWN;
- } else if (!strcasecmp(s, "any")) {
- return TOK_ANY;
- } else if (!strcasecmp(s, "last")) {
- return TOK_LAST;
- } else if (is_lit(s)) {
- return TOK_LIT;
- } else if (!strcasecmp(s, "nop")) {
- return TOK_NOP;
- } else if (!strcasecmp(s, "mov")) {
- return TOK_MOV;
- } else if (!strcasecmp(s, "swp")) {
- return TOK_SWP;
- } else if (!strcasecmp(s, "sav")) {
- return TOK_SAV;
- } else if (!strcasecmp(s, "add")) {
- return TOK_ADD;
- } else if (!strcasecmp(s, "sub")) {
- return TOK_SUB;
- } else if (!strcasecmp(s, "neg")) {
- return TOK_NEG;
- } else if (!strcasecmp(s, "jmp")) {
- return TOK_JMP;
- } else if (!strcasecmp(s, "jez")) {
- return TOK_JEZ;
- } else if (!strcasecmp(s, "jnz")) {
- return TOK_JNZ;
- } else if (!strcasecmp(s, "jgz")) {
- return TOK_JGZ;
- } else if (!strcasecmp(s, "jlz")) {
- return TOK_JLZ;
- } else if (!strcasecmp(s, "jro")) {
- return TOK_JRO;
- } else if (*s == '#') {
- tok->off += strlen(tok->linebuf + tok->off);
- return TOK_COMMENT;
- } else if (len && strspn(s, NAMEALPH) == len-1 && s[len-1] == ':') {
- return TOK_LABEL;
- } else if (*s == 'X' && atoi(s+1) > 0) {
- return TOK_XPOS;
- } else if (*s == 'Y' && atoi(s+1) > 0) {
- return TOK_YPOS;
- } else if (strspn(s, NAMEALPH) == strlen(s)) {
- return TOK_NAME;
+ if (argc >= 3) {
+ tis_stdin = fopen(argv[2], "r");
+ if (!tis_stdin) die("fopen '%s':", argv[2]);
} else {
- die("load: line %lu, invalid token '%s'", tok->lineno, s);
+ tis_stdin = stdin;
}
-}
-
-enum tok
-tok_next_in(struct tokenizer *tokenizer, ...)
-{
- va_list ap, cpy;
- enum tok tok;
- bool first;
- int arg;
+ setvbuf(tis_stdin, NULL, _IONBF, 0);
- tok = tok_next(tokenizer);
-
- va_copy(cpy, ap);
-
- va_start(cpy, tokenizer);
- while ((arg = va_arg(cpy, int)) > 0) {
- if (tok == arg) return tok;
- }
- va_end(cpy);
-
- fprintf(stderr, "tis-as: load: ");
- fprintf(stderr, "line %lu, got tok %s, expected one of (",
- tokenizer->lineno, tok_reprs[tok]);
- first = true;
- va_start(ap, tokenizer);
- while ((arg = va_arg(ap, int)) > 0) {
- if (!first) fputc(',', stderr);
- fputs(tok_reprs[arg], stderr);
- first = false;
- }
- va_end(ap);
- fputs(")\n", stderr);
-
- exit(1);
-}
-
-static void
-load(const char *fname)
-{
- struct tokenizer tokenizer;
- enum tpu_inst_op_type op1, op2;
- enum tok op1_tok, op2_tok;
- uint8_t op1_lit, op2_lit;
- enum tpu_inst_type inst;
- struct tpu *tpu = NULL;
- struct tpu_map_link *link;
- struct tpu_port *port;
- enum tok tok;
- char *label;
- FILE *file;
- size_t i;
-
- file = fopen(fname, "r");
- if (!file) die("fopen:");
-
- tokenizer.lineno = 0;
- tokenizer.file = file;
- tokenizer.off = 0;
- tokenizer.tokstr = NULL;
- tokenizer.linebuf[tokenizer.off] = '\0';
- while ((tok = tok_next(&tokenizer)) != TOK_EOF) {
- switch (tok) {
- case TOK_STDIN:
- if (tpu) goto disallowed;
- tok_next_in(&tokenizer, TOK_XPOS, -1);
- stdin_x = atoi(tokenizer.tokstr + 1);
- tok_next_in(&tokenizer, TOK_YPOS, -1);
- stdin_y = atoi(tokenizer.tokstr + 1);
- tok_next_in(&tokenizer, TOK_NL, -1);
- break;
- case TOK_STDOUT:
- if (tpu) goto disallowed;
- tok_next_in(&tokenizer, TOK_XPOS, -1);
- stdout_x = atoi(tokenizer.tokstr + 1);
- tok_next_in(&tokenizer, TOK_YPOS, -1);
- stdout_y = atoi(tokenizer.tokstr + 1);
- tok_next_in(&tokenizer, TOK_NL, -1);
- break;
- case TOK_TPU:
- if (tpu) goto disallowed;
- tpu = malloc(sizeof(struct tpu));
- if (!tpu) die("malloc:");
- tpu_init(tpu);
- tok_next_in(&tokenizer, TOK_XPOS, -1);
- tpu->x = (size_t) atoi(tokenizer.tokstr + 1);
- tok_next_in(&tokenizer, TOK_YPOS, -1);
- tpu->y = (size_t) atoi(tokenizer.tokstr + 1);
- tok_next_in(&tokenizer, TOK_NL, -1);
- tpu_map_add(&tpu_map, tpu);
- break;
- case TOK_END:
- if (!tpu) goto disallowed;
- tpu = NULL;
- tok_next_in(&tokenizer, TOK_NL, -1);
- break;
- case TOK_NOP: case TOK_MOV: case TOK_SWP: case TOK_SAV:
- case TOK_ADD: case TOK_SUB: case TOK_NEG: case TOK_JMP:
- case TOK_JEZ: case TOK_JNZ: case TOK_JGZ: case TOK_JLZ:
- case TOK_JRO:
- if (!tpu) goto disallowed;
- inst = tok_to_inst(tok);
-
- op1_tok = tok_next_in(&tokenizer, TOK_ACC, TOK_BAK,
- TOK_NIL, TOK_LEFT, TOK_RIGHT, TOK_UP, TOK_DOWN,
- TOK_ANY, TOK_LAST, TOK_LIT, TOK_NAME, TOK_NL, -1);
- if (op1_tok == TOK_NL) {
- tpu_add_inst(tpu, inst, -1, 0, -1, 0);
- break;
- }
-
- op1 = tok_to_optype(op1_tok);
- if (op1 == OP_LIT)
- op1_lit = str2lit(tokenizer.tokstr);
-
- op2_tok = tok_next_in(&tokenizer, TOK_ACC, TOK_BAK,
- TOK_NIL, TOK_LEFT, TOK_RIGHT, TOK_UP, TOK_DOWN,
- TOK_ANY, TOK_LAST, TOK_LIT, TOK_NAME, TOK_NL, -1);
- if (op2_tok == TOK_NL) {
- tpu_add_inst(tpu, inst, (int) op1,
- op1_lit, -1, 0);
- break;
- }
-
- op2 = tok_to_optype(op2_tok);
- if (op2 == OP_LIT)
- op2_lit = str2lit(tokenizer.tokstr);
- tok_next_in(&tokenizer, TOK_NL, -1);
- tpu_add_inst(tpu, inst, (int) op1, op1_lit,
- (int) op2, op2_lit);
- break;
- case TOK_COMMENT:
- tok_next_in(&tokenizer, TOK_NL, -1);
- break;
- case TOK_LABEL:
- label = strdup(tokenizer.tokstr);
- if (!label_map_add(&tpu->labels, label, tpu->inst_cnt))
- die("load: line %lu, duplicate label",
- tokenizer.lineno);
- tok_next_in(&tokenizer, TOK_NL, -1);
- break;
- case TOK_NL:
- break;
- default:
- goto disallowed;
- }
- }
-
- if (stdin_x == 0 || stdin_y == 0 || stdout_x == 0 || stdout_y == 0)
- die("load: stdin/stdout tpu not set");
-
- for (i = 0; i < TPU_MAP_BUCKETS; i++) {
- for (link = tpu_map.buckets[i]; link; link = link->next) {
- tpu_init_ports(link->tpu, &tpu_map);
-
- if (link->x == stdin_x && link->y == stdin_y) {
- port = &link->tpu->ports[DIR_UP];
- if (port->attached)
- die("load: stdin port in use");
- port->attached = true;
- port->dst_tpu = NULL;
- port->dst_port = &stdin_port;
- stdin_port.attached = true;
- stdin_port.dst_tpu = NULL;
- stdin_port.dst_port = port;
- }
-
- if (link->x == stdout_x && link->y == stdout_y) {
- port = &link->tpu->ports[DIR_DOWN];
- if (port->attached)
- die("load: stdout port in use");
- port->attached = true;
- port->dst_tpu = NULL;
- port->dst_port = &stdout_port;
- stdout_port.attached = true;
- stdout_port.dst_tpu = NULL;
- stdout_port.dst_port = port;
- }
- }
- }
-
- if (!stdin_port.attached || !stdout_port.attached)
- die("load: stdin/stdout tpu not found");
-
- fclose(file);
-
- return;
-
-disallowed:
- if (tok == TOK_NAME) {
- die("load: line %lu, unexpected token '%s'",
- tokenizer.lineno, tokenizer.tokstr);
+ if (argc >= 4) {
+ tis_stdout = fopen(argv[3], "w+");
+ if (!tis_stdout) die("fopen '%s':", argv[3]);
} else {
- die("load: line %lu, token %s not allowed here",
- tokenizer.lineno, tok_reprs[tok]);
+ tis_stdout = stdout;
}
-}
-
-void
-run(void)
-{
- struct tpu_map_link *link;
- size_t i, k;
- int c;
+ setvbuf(tis_stdout, NULL, _IONBF, 0);
- stdin_port.out = -1;
- stdout_port.reading = true;
- while (1) {
- if (stdin_port.dst_port->reading) {
- c = getchar();
- if (c < 0) break;
- stdin_port.out = c;
- }
+ tis_init(&tis);
- printf("===\n");
+ tis_load(&tis, argv[1]);
- for (i = 0; i < TPU_MAP_BUCKETS; i++) {
- for (link = tpu_map.buckets[i]; link; link = link->next) {
- tpu_step(link->tpu);
- }
+ tis.stdin_port.out = -1;
+ idle = false;
+ while (!idle || !prev_idle || tis.stdin_port.reading && !feof(tis_stdin)) {
+ if (tis.stdin_port.out < 0) {
+ c = getc(tis_stdin);
+ if (c >= 0) tis.stdin_port.out = c;
}
- for (i = 0; i < TPU_MAP_BUCKETS; i++) {
- for (link = tpu_map.buckets[i]; link; link = link->next) {
- tpu_update_ports(link->tpu);
- printf("FINAL %lu %lu: %s\n", link->x, link->y,
- status_names[link->tpu->status]);
- for (k = 0; k < 4; k++) {
- if (link->tpu->ports[k].in >= 0)
- printf("%lu %lu %5s: %i\n",
- link->x, link->y, dir_names[k],
- link->tpu->ports[k].in);
- }
- }
+ if (tis.stdout_port.in >= 0) {
+ putc(tis.stdout_port.in, tis_stdout);
+ tis.stdout_port.in = -1;
}
- if (stdout_port.dst_port->out >= 0) {
- putchar(stdout_port.dst_port->out);
- stdout_port.dst_port->out = -1;
- }
- }
-}
-
-int
-main(int argc, const char **argv)
-{
- if (argc != 2) {
- fprintf(stderr, "Usage: tis-as FILE\n");
- exit(1);
+ prev_idle = idle;
+ idle = !tis_step(&tis);
}
- load(argv[1]);
+ fclose(tis_stdin);
+ fclose(tis_stdout);
- run();
+ tis_deinit(&tis);
}
diff --git a/tis-curses.c b/tis-curses.c
@@ -2,6 +2,7 @@
#include "tpu.h"
#include "util.h"
+#include "asm.h"
#include <curses.h>
@@ -17,45 +18,48 @@
#define KEY_ESC 0x1b
#define KEY_CTRL(c) ((c) & ~0x60)
-#define TCELL_INPUT_ROWS 14
-#define TCELL_INPUT_COLS 20
-#define TCELL_INFO_W 6
-#define TCELL_INFO_H 4
-#define TCELL_CNT 6
-#define TCELL_W (TCELL_INPUT_COLS + 2 + 6)
-#define TCELL_H (TCELL_INPUT_ROWS + 2)
+#define TPUT_INPUT_ROWS 14
+#define TPUT_INPUT_COLS 20
+#define TPUT_INFO_W 6
+#define TPUT_INFO_H 4
+#define TPUT_CNT 6
+#define TPUT_W (TPUT_INPUT_COLS + 2 + 6)
+#define TPUT_H (TPUT_INPUT_ROWS + 2)
+
+enum input_mode {
+ MAIN,
+ TPU_NAV
+};
enum {
- COLOR_HEADING,
- COLOR_VAL
+ NONE, MIN, MAX, MID
};
-struct tpu_cell {
- struct tpu tpu;
- enum tpu_status status;
- size_t x, y;
- const char source[TCELL_INPUT_ROWS][TCELL_INPUT_COLS + 1];
- bool enabled;
- char *warn;
- float idle;
+enum {
+ COLOR_HEADING,
+ COLOR_VAL
};
-static size_t tpu_cell_rows = 2;
-static size_t tpu_cell_cols = 3;
-
static int scrx = 0;
static int scry = 0;
static int scrw = 80;
static int scrh = 40;
-static struct tpu_cell *tpu_cells = NULL;
+static struct tis tis;
+static FILE *tis_stdin = NULL;
+static FILE *tis_stdout = NULL;
+
+static enum input_mode input_mode = MAIN;
+
+static struct tpu *tpu_sel = NULL;
+void (*cleanup)(void) = (void *) endwin;
const char *progname = "tis-curses";
static const char *
-cell_mode_str(struct tpu_cell *cell)
+tpu_mode_str(struct tpu *tpu)
{
- switch (cell->status) {
+ switch (tpu->status) {
case STATUS_READ:
return "=R=";
case STATUS_WRITE:
@@ -67,14 +71,45 @@ cell_mode_str(struct tpu_cell *cell)
}
}
+static enum tpu_port_dir
+key_to_dir(int key)
+{
+ switch (key) {
+ case KEY_LEFT:
+ return DIR_LEFT;
+ case KEY_RIGHT:
+ return DIR_RIGHT;
+ case KEY_UP:
+ return DIR_UP;
+ case KEY_DOWN:
+ return DIR_DOWN;
+ default:
+ abort();
+ }
+}
+
static const char *
-cell_last_str(struct tpu_cell *cell)
+tpu_last_str(struct tpu *tpu)
+{
+ if (tpu->last < 0) return "N/A";
+ return dir_reprs[tpu->last];
+}
+
+static int
+tpu_pos_x(struct tpu *tpu)
{
- return "N/A";
+ return 2 + (int) tpu->x * (TPUT_W + 4);
+}
+
+static int
+tpu_pos_y(struct tpu *tpu)
+{
+ return 2 * (int) tpu->y * (TPUT_H + 2);
}
static void
-tui_draw_box(int sx, int sy, int w, int h, const cchar_t *ul, const cchar_t *ur,
+tui_draw_box(int sx, int sy, int w, int h, attr_t attr,
+ const cchar_t *ul, const cchar_t *ur,
const cchar_t *ll, const cchar_t *lr)
{
int x, y;
@@ -84,6 +119,8 @@ tui_draw_box(int sx, int sy, int w, int h, const cchar_t *ul, const cchar_t *ur,
sx -= scrx;
sy -= scry;
+
+ attron(attr);
mvadd_wch(sy, sx, ul);
mvadd_wch(sy, sx + w - 1, ur);
mvadd_wch(sy + h - 1, sx, ll);
@@ -96,26 +133,29 @@ tui_draw_box(int sx, int sy, int w, int h, const cchar_t *ul, const cchar_t *ur,
mvadd_wch(y, sx, WACS_D_VLINE);
for (y = sy + 1; y < sy + h - 1; y++)
mvadd_wch(y, sx + w - 1, WACS_D_VLINE);
+ attroff(attr);
}
static void
__attribute__((format(printf, 4, 5)))
-tui_draw_text(int x, int y, int attr, const char *fmt, ...)
+tui_draw_text(int x, int y, attr_t attr, const char *fmt, ...)
{
char buf[256];
va_list ap;
+ int i;
va_start(ap, fmt);
vsnprintf(buf, 256, fmt, ap);
va_end(ap);
attron(attr);
- mvprintw(y - scry, x - scrx, "%s", buf);
+ for (i = 0; i < strlen(buf) && x + i < scrx + scrw; i++)
+ mvaddch(y - scry, x + i - scrx, (chtype) buf[i]);
attroff(attr);
}
static void
-tui_draw_wch(int x, int y, int attr, const cchar_t *c)
+tui_draw_wch(int x, int y, attr_t attr, const cchar_t *c)
{
attron(attr);
mvadd_wch(y - scry, x - scrx, c);
@@ -123,120 +163,244 @@ tui_draw_wch(int x, int y, int attr, const cchar_t *c)
}
static void
-tui_draw_tpu_cell(struct tpu_cell *cell)
+tui_set_attr(int x, int y, attr_t attr)
{
- struct tpu_port *port;
- int x, y, w, h;
-
- tui_draw_box((int) cell->x, (int) cell->y, TCELL_W, TCELL_H,
- WACS_D_ULCORNER, WACS_D_URCORNER, WACS_D_LLCORNER, WACS_D_LRCORNER);
+ (void) mvchgat(y - scry, x - scrx, 1, attr, 0, NULL);
+}
- x = (int) cell->x + TCELL_W - TCELL_INFO_W;
- w = TCELL_INFO_W;
- h = TCELL_INFO_H;
+static void
+tui_draw_tpu(struct tpu *tpu)
+{
+ char linebuf[TPUT_INPUT_COLS + 1];
+ struct tpu_port *port;
+ int sx, sy, x, y, w, h;
+ int i, idle, min;
+ attr_t attr;;
+
+ attr = (tpu_sel == tpu && input_mode == TPU_NAV) ? A_BOLD : 0;
+
+ sx = tpu_pos_x(tpu);
+ sy = tpu_pos_y(tpu);
+ tui_draw_box(sx, sy, TPUT_W, TPUT_H, attr,
+ WACS_D_ULCORNER, WACS_D_URCORNER,
+ WACS_D_LLCORNER, WACS_D_LRCORNER);
+
+ min = MIN(tpu->pc, MAX(0, (int) tpu->inst_cnt - TPUT_INPUT_ROWS));
+ for (i = 0; i < MIN((int) tpu->inst_cnt - min, TPUT_INPUT_ROWS); i++) {
+ asm_print_inst(linebuf, sizeof(linebuf), &tpu->insts[min + i]);
+ tui_draw_text(sx + 2, sy + 1 + i, i == tpu->pc ? A_STANDOUT : 0,
+ "%-*s", TPUT_INPUT_COLS, linebuf);
+ }
- tui_draw_box(x, (y = (int) cell->y), w, h,
+ x = sx + TPUT_W - TPUT_INFO_W;
+ y = sy;
+ w = TPUT_INFO_W;
+ h = TPUT_INFO_H;
+ tui_draw_box(x, y, w, h, attr,
WACS_D_TTEE, WACS_D_URCORNER, WACS_D_LTEE, WACS_D_RTEE);
tui_draw_text(x + 2, y + 1, A_BOLD, "ACC");
- tui_draw_text(x + 2, y + 2, 0, "%03i", cell->tpu.acc);
+ tui_draw_text(x + 2, y + 2, 0, "%03i", tpu->acc);
- tui_draw_box(x, (y += TCELL_INFO_H - 1), w, h,
+ tui_draw_box(x, (y += TPUT_INFO_H - 1), w, h, attr,
WACS_D_LTEE, WACS_D_RTEE, WACS_D_LTEE, WACS_D_RTEE);
tui_draw_text(x + 2, y + 1, A_BOLD, "BAK");
- tui_draw_text(x + 2, y + 2, 0, "%03i", cell->tpu.bak);
+ tui_draw_text(x + 2, y + 2, 0, "%03i", tpu->bak);
- tui_draw_box(x, (y += TCELL_INFO_H - 1), w, h,
+ tui_draw_box(x, (y += TPUT_INFO_H - 1), w, h, attr,
WACS_D_LTEE, WACS_D_RTEE, WACS_D_LTEE, WACS_D_RTEE);
tui_draw_text(x + 2, y + 1, A_BOLD, "LST");
- tui_draw_text(x + 2, y + 2, 0, "%s", cell_last_str(cell));
+ tui_draw_text(x + 2, y + 2, 0, "%s", tpu_last_str(tpu));
- tui_draw_box(x, (y += TCELL_INFO_H - 1), w, h,
+ tui_draw_box(x, (y += TPUT_INFO_H - 1), w, h, attr,
WACS_D_LTEE, WACS_D_RTEE, WACS_D_LTEE, WACS_D_RTEE);
tui_draw_text(x + 2, y + 1, A_BOLD, "MOD");
- tui_draw_text(x + 2, y + 2, 0, "%s", cell_mode_str(cell));
+ tui_draw_text(x + 2, y + 2, 0, "%s", tpu_mode_str(tpu));
- tui_draw_box(x, (y += TCELL_INFO_H - 1), w, h,
+ tui_draw_box(x, (y += TPUT_INFO_H - 1), w, h, attr,
WACS_D_LTEE, WACS_D_RTEE, WACS_D_BTEE, WACS_D_LRCORNER);
tui_draw_text(x + 2, y + 1, A_BOLD, "IDL");
- tui_draw_text(x + 2, y + 2, 0, "%03i", (int) (cell->idle * 100));
-
- if (cell->tpu.ports[DIR_LEFT].attached) {
- port = &cell->tpu.ports[DIR_LEFT];
+ if (tpu->steps > 0)
+ idle = (int) ((double) tpu->idle_steps * 100 / (double) tpu->steps);
+ else
+ idle = 100;
+ tui_draw_text(x + 2, y + 2, 0, "%03i", idle);
+
+ if (tpu->ports[DIR_LEFT].attached) {
+ port = &tpu->ports[DIR_LEFT];
+ if (port->in >= 0)
+ tui_draw_text(sx - 3, sy + 6,
+ A_BOLD, "%03i", port->in);
if (port->type & PORT_IN)
- tui_draw_wch((int) cell->x - 1, (int) cell->y + 8,
- port->reading ? A_BOLD : 0, WACS_RARROW);
+ tui_draw_wch(sx - 1, sy + 7,
+ port->in >= 0 ? A_BOLD : 0, WACS_RARROW);
if (port->type & PORT_OUT)
- tui_draw_wch((int) cell->x - 1, (int) cell->y + 7,
- port->out > 0 ? A_BOLD : 0, WACS_LARROW);
+ tui_draw_wch(sx - 1, sy + 8,
+ port->out >= 0 ? A_BOLD : 0, WACS_LARROW);
if (port->out >= 0)
- tui_draw_text((int) cell->x - 3, (int) cell->y + 6,
+ tui_draw_text(sx - 3, sy + 10,
A_BOLD, "%03i", port->out);
}
- if (cell->tpu.ports[DIR_RIGHT].attached) {
- port = &cell->tpu.ports[DIR_RIGHT];
- if (port->type & PORT_IN)
- tui_draw_wch((int) cell->x + TCELL_W + 1, (int) cell->y + 7,
- port->reading ? A_BOLD : 0, WACS_LARROW);
- if (port->type & PORT_OUT)
- tui_draw_wch((int) cell->x + TCELL_W + 1, (int) cell->y + 8,
- port->out > 0 ? A_BOLD : 0, WACS_RARROW);
+ if (tpu->ports[DIR_RIGHT].attached) {
+ port = &tpu->ports[DIR_RIGHT];
if (port->out >= 0)
- tui_draw_text((int) cell->x + TCELL_W + 1, (int) cell->y + 9,
+ tui_draw_text(sx + TPUT_W + 1, sy + 5,
A_BOLD, "%03i", port->out);
+ if (port->type & PORT_OUT)
+ tui_draw_wch(sx + TPUT_W + 1, sy + 7,
+ port->out >= 0 ? A_BOLD : 0, WACS_RARROW);
+ if (port->type & PORT_IN)
+ tui_draw_wch(sx + TPUT_W + 1, sy + 8,
+ port->in >= 0 ? A_BOLD : 0, WACS_LARROW);
+ if (port->in >= 0)
+ tui_draw_text(sx + TPUT_W + 1, sy + 9,
+ A_BOLD, "%03i", port->in);
}
- if (cell->tpu.ports[DIR_UP].attached) {
- port = &cell->tpu.ports[DIR_UP];
- if (port->type & PORT_IN)
- tui_draw_wch((int) cell->x + 13, (int) cell->y - 1,
- port->reading ? A_BOLD : 0, WACS_DARROW);
- if (port->type & PORT_OUT)
- tui_draw_wch((int) cell->x + 15, (int) cell->y - 1,
- port->out > 0 ? A_BOLD : 0, WACS_UARROW);
+ if (tpu->ports[DIR_UP].attached) {
+ port = &tpu->ports[DIR_UP];
if (port->out >= 0)
- tui_draw_text((int) cell->x + 16, (int) cell->y - 1,
+ tui_draw_text(sx + 9, sy - 1,
A_BOLD, "%03i", port->out);
+ if (port->type & PORT_OUT)
+ tui_draw_wch(sx + 13, sy - 1,
+ port->out >= 0 ? A_BOLD : 0, WACS_UARROW);
+ if (port->type & PORT_IN)
+ tui_draw_wch(sx + 15, sy - 1,
+ port->in >= 0 ? A_BOLD : 0, WACS_DARROW);
+ if (port->in >= 0)
+ tui_draw_text(sx + 17, sy - 1,
+ A_BOLD, "%03i", port->in);
}
- if (cell->tpu.ports[DIR_DOWN].attached) {
- port = &cell->tpu.ports[DIR_DOWN];
- if (port->type & PORT_IN)
- tui_draw_wch((int) cell->x + 13, (int) cell->y + TCELL_H,
- port->out > 0 ? A_BOLD : 0, WACS_DARROW);
- if (port->type & PORT_OUT)
- tui_draw_wch((int) cell->x + 15, (int) cell->y + TCELL_H,
- port->reading ? A_BOLD : 0, WACS_UARROW);
+ if (tpu->ports[DIR_DOWN].attached) {
+ port = &tpu->ports[DIR_DOWN];
if (port->out >= 0)
- tui_draw_text((int) cell->x + 10, (int) cell->y + TCELL_H,
+ tui_draw_text(sx + 9, sy + TPUT_H,
A_BOLD, "%03i", port->out);
+ if (port->type & PORT_IN)
+ tui_draw_wch(sx + 13, sy + TPUT_H,
+ port->in >= 0 ? A_BOLD : 0, WACS_UARROW);
+ if (port->type & PORT_OUT)
+ tui_draw_wch(sx + 15, sy + TPUT_H,
+ port->out >= 0 ? A_BOLD : 0, WACS_DARROW);
+ if (port->in >= 0)
+ tui_draw_text(sx + 17, sy + TPUT_H,
+ A_BOLD, "%03i", port->in);
}
}
static void
tui_draw(void)
{
- int i;
+ struct tpu_map_link *link;
+ size_t i;
clear();
- for (i = 0; i < TCELL_CNT; i++)
- tui_draw_tpu_cell(&tpu_cells[i]);
+ for (i = 0; i < TPU_MAP_BUCKETS; i++) {
+ for (link = tis.tpu_map.buckets[i]; link; link = link->next)
+ tui_draw_tpu(link->tpu);
+ }
refresh();
}
static void
tui_resize(void)
{
- size_t x, y, i;
-
scrw = getmaxx(stdscr);
scrh = getmaxy(stdscr);
+}
- for (y = 0; y < tpu_cell_rows; y++) {
- for (x = 0; x < tpu_cell_cols; x++) {
- i = y * tpu_cell_cols + x;
- tpu_cells[i].x = 2 + x * (TCELL_W + 4);
- tpu_cells[i].y = 2 + y * (TCELL_H + 2);
+static void
+tui_seek(struct tpu *tpu, int dx, int dy)
+{
+ struct tpu_map_link *link;
+ int minx, miny, maxx, maxy;
+ int x, y;
+ size_t i;
+
+ if (tpu) {
+ minx = maxx = tpu_pos_x(tpu);
+ miny = maxy = tpu_pos_y(tpu);
+ } else {
+ minx = miny = maxx = maxy = -1;
+ for (i = 0; i < TPU_MAP_BUCKETS; i++) {
+ link = tis.tpu_map.buckets[i];
+ for (; link; link = link->next) {
+ if (tpu && tpu != link->tpu)
+ continue;
+
+ x = tpu_pos_x(link->tpu);
+ if (minx == -1 || x < minx) minx = x;
+ if (maxx == -1 || x > maxx) maxx = x;
+
+ y = tpu_pos_y(link->tpu);
+ if (miny == -1 || y < miny) miny = y;
+ if (maxy == -1 || y > maxy) maxy = y;
+ }
+ }
+ }
+
+ if (dx == MIN) scrx = minx - 2;
+ else if (dx == MAX) scrx = maxx + TPUT_W + 2 - scrw;
+ else if (dx == MID) scrx = (minx + maxx + TPUT_W - scrw) / 2;
+
+ if (dy == MIN) scry = miny - 2;
+ else if (dy == MAX) scry = maxy + TPUT_H + 2 - scrh;
+ else if (dy == MID) scry = (miny + maxy + TPUT_H - scrh) / 2;
+}
+
+static void
+handlekey(int key)
+{
+ enum tpu_port_dir dir;
+ int c;
+
+ if (input_mode == MAIN) {
+ switch (key) {
+ case 'I':
+ input_mode = TPU_NAV;
+ break;
+ case KEY_UP:
+ scry -= 2;
+ break;
+ case KEY_DOWN:
+ scry += 2;
+ break;
+ case KEY_LEFT:
+ scrx -= 4;
+ break;
+ case KEY_RIGHT:
+ scrx += 4;
+ break;
+ case 's':
+ if (tis.stdin_port.out < 0) {
+ c = getc(tis_stdin);
+ if (c >= 0) tis.stdin_port.out = c;
+ }
+
+ if (tis.stdout_port.in >= 0) {
+ putc(tis.stdout_port.in, tis_stdout);
+ tis.stdout_port.in = -1;
+ }
+
+ tis_step(&tis);
+ break;
+ }
+ } else {
+ switch (key) {
+ case KEY_ESC:
+ input_mode = MAIN;
+ break;
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ dir = key_to_dir(key);
+ if (tpu_sel->ports[dir].dst_tpu)
+ tpu_sel = tpu_sel->ports[dir].dst_tpu;
+ tui_seek(tpu_sel, MID, MID);
+ break;
}
}
}
@@ -244,10 +408,14 @@ tui_resize(void)
int
main(int argc, char **argv)
{
- size_t x, y, i;
bool quit;
int key;
+ if (argc != 4) {
+ fprintf(stderr, "Usage: tis-curses FILE STDIN STDOUT\n");
+ exit(1);
+ }
+
setlocale(LC_ALL, "");
initscr();
@@ -257,23 +425,21 @@ main(int argc, char **argv)
keypad(stdscr, TRUE);
start_color();
curs_set(0);
+ tui_resize();
+ ESCDELAY = 0;
- /* TODO load like tis-as */
+ tis_init(&tis);
+ tis_load(&tis, argv[1]);
- tpu_cells = calloc(tpu_cell_rows * tpu_cell_cols, sizeof(struct tpu_cell));
- if (!tpu_cells) die("malloc:");
+ tis_stdin = fopen(argv[2], "r");
+ if (!tis_stdin) die("fopen '%s':", argv[2]);
- for (y = 0; y < tpu_cell_rows; y++) {
- for (x = 0; x < tpu_cell_cols; x++) {
- i = y * tpu_cell_cols + x;
- tpu_cells[i].enabled = true;
- tpu_init(&tpu_cells[i].tpu);
- memset((void *) tpu_cells[i].source, 0,
- TCELL_INPUT_ROWS * (TCELL_INPUT_COLS + 1));
- }
- }
+ tis_stdout = fopen(argv[3], "w+");
+ if (!tis_stdout) die("fopen '%s':", argv[3]);
+
+ tpu_sel = tis.stdin_port.dst_tpu;
+ tui_seek(NULL, MID, MID);
- tui_resize();
quit = false;
while (!quit) {
tui_draw();
@@ -282,27 +448,31 @@ main(int argc, char **argv)
case KEY_RESIZE:
tui_resize();
break;
- case KEY_UP:
- scry -= 1;
+ case 'g':
+ tui_seek(tpu_sel, MID, MID);
break;
- case KEY_DOWN:
- scry += 1;
+ case 'h':
+ tui_seek(NULL, MID, MID);
break;
- case KEY_LEFT:
- scrx -= 2;
+ case 'i':
+ tui_seek(tis.stdin_port.dst_tpu, MID, MID);
break;
- case KEY_RIGHT:
- scrx += 2;
+ case 'o':
+ tui_seek(tis.stdout_port.dst_tpu, MID, MID);
break;
case KEY_CTRL('c'):
quit = true;
break;
+ default:
+ handlekey(key);
+ break;
}
}
- for (i = 0; i < TCELL_CNT; i++)
- tpu_deinit(&tpu_cells[i].tpu);
- free(tpu_cells);
+ tis_deinit(&tis);
+
+ fclose(tis_stdin);
+ fclose(tis_stdout);
endwin();
}
diff --git a/tpu.c b/tpu.c
@@ -6,9 +6,23 @@
#include <stddef.h>
#include <string.h>
-/* NOTES:
- * do two passes (one with only movs) for 'async' ports, result is the same
- */
+const char *dir_reprs[] = {
+ "LEFT", "RIGHT", "UP", "DOWN"
+};
+
+const char *status_reprs[] = {
+ "IDLE", "RUN", "READ", "WRITE"
+};
+
+const char *inst_reprs[] = {
+ "NOP", "MOV", "SWP", "SAV", "ADD", "SUB",
+ "NEG", "JMP", "JEZ", "JNZ", "JGZ", "JLZ", "JRO"
+};
+
+const char *op_reprs[] = {
+ "ACC", "BAK", "NIL", "LEFT", "RIGHT",
+ "UP", "DOWN", "ANY", "LAST", "LIT", "<NAME>"
+};
static enum tpu_port_dir
op_to_dir(enum tpu_inst_op_type op)
@@ -109,28 +123,48 @@ label_map_get(struct label_map *map, const char *name)
}
void
+tpu_port_init(struct tpu_port *port)
+{
+ port->attached = false;
+ port->dst_port = NULL;
+ port->dst_tpu = NULL;
+ port->type = PORT_BIDI;
+ port->clr_post_run = false;
+ port->reading = false;
+ port->writing = false;
+ port->in = -1;
+ port->out = -1;
+}
+
+void
+tpu_port_deinit(struct tpu_port *port)
+{
+ /* empty */
+}
+
+void
tpu_init(struct tpu *tpu)
{
size_t i;
+ tpu->status = STATUS_IDLE;
+
tpu->x = 0;
tpu->y = 0;
- tpu->last = -1;
+
+ tpu->steps = 0;
+ tpu->idle_steps = 0;
+
+ tpu->pc = 0;
tpu->acc = 0;
tpu->bak = 0;
tpu->inst_cnt = 0;
- tpu->pc = 0;
- tpu->status = STATUS_IDLE;
label_map_init(&tpu->labels);
- for (i = 0; i < 4; i++) {
- tpu->ports[i].attached = false;
- tpu->ports[i].dst_port = NULL;
- tpu->ports[i].dst_tpu = NULL;
- tpu->ports[i].type = PORT_BIDI;
- tpu->ports[i].reading = false;
- tpu->ports[i].in = -1;
- tpu->ports[i].out = -1;
- }
+
+ tpu->last = -1;
+ tpu->io_port = -1;
+ for (i = 0; i < 4; i++)
+ tpu_port_init(&tpu->ports[i]);
}
void
@@ -195,18 +229,26 @@ void
tpu_update_ports(struct tpu *tpu)
{
struct tpu_port *port;
+ int i;
- if (tpu->read_port >= 0) {
- port = &tpu->ports[tpu->read_port];
- if (port->reading) {
- if (port->attached && port->dst_port->out >= 0) {
- port->in = port->dst_port->out;
- port->dst_port->out = -1;
- port->reading = false;
- }
- } else if (tpu->status == STATUS_RUN) {
+ for (i = 0; i < 4; i++) {
+ port = &tpu->ports[i];
+ if (!port->attached) continue;
+ if (port->out >= 0 && port->dst_port->in < 0) {
+ port->dst_port->reading = false;
+ port->dst_port->in = port->out;
+ port->writing = false;
+ port->out = -1;
+ }
+ if (port->dst_port->out >= 0 && port->in < 0) {
+ port->reading = false;
+ port->in = port->dst_port->out;
+ port->dst_port->writing = false;
+ port->dst_port->out = -1;
+ }
+ if (tpu->status == STATUS_RUN && port->clr_post_run) {
port->in = -1;
- tpu->read_port = -1;
+ port->clr_post_run = false;
}
}
}
@@ -268,9 +310,9 @@ tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst_type,
}
/* tpu can always write to an empty port (->out), but only
- * read values from a port (->in) if there is a writer attached
- * and offering a value (->dst_port->out). the read value (->in)
- * is cleared at the end of an instruction step */
+ * read values if there is a writer attached and offering a value
+ * (->dst_port->out) -- the read value (->in) is cleared at the end of
+ * an instruction step */
static int
tpu_port_read(struct tpu *tpu, enum tpu_port_dir dir)
@@ -278,9 +320,9 @@ tpu_port_read(struct tpu *tpu, enum tpu_port_dir dir)
struct tpu_port *port;
port = &tpu->ports[dir];
+ port->clr_post_run = true;
if (port->in < 0) {
port->reading = true;
- tpu->read_port = (int) dir;
return -1;
}
return port->in;
@@ -292,7 +334,10 @@ tpu_port_write(struct tpu *tpu, enum tpu_port_dir dir, uint8_t lit)
struct tpu_port *port;
port = &tpu->ports[dir];
- if (port->out >= 0) return false;
+ if (port->out >= 0) {
+ port->writing = true;
+ return false;
+ }
port->out = lit;
return true;
}
@@ -479,12 +524,21 @@ tpu_exec(struct tpu *tpu, struct tpu_inst *inst)
}
}
-void
+enum tpu_status
tpu_step(struct tpu *tpu)
{
- if (tpu->pc >= tpu->inst_cnt) return;
- tpu->status = tpu_exec(tpu, &tpu->insts[tpu->pc]);
- if (tpu->pc >= tpu->inst_cnt) tpu->pc = 0;
+ if (tpu->pc < tpu->inst_cnt) {
+ tpu->status = tpu_exec(tpu, &tpu->insts[tpu->pc]);
+ if (tpu->pc >= tpu->inst_cnt) tpu->pc = 0;
+ } else {
+ tpu->status = STATUS_IDLE;
+ }
+
+ tpu->steps += 1;
+ if (tpu->status != STATUS_RUN)
+ tpu->idle_steps += 1;
+
+ return tpu->status;
}
void
@@ -551,3 +605,42 @@ tpu_map_get(struct tpu_map *map, size_t x, size_t y)
return (*link)->tpu;
}
+
+void
+tis_init(struct tis *tis)
+{
+ tpu_map_init(&tis->tpu_map);
+ tpu_port_init(&tis->stdin_port);
+ tpu_port_init(&tis->stdout_port);
+}
+
+void
+tis_deinit(struct tis *tis)
+{
+ tpu_map_deinit(&tis->tpu_map);
+ tpu_port_deinit(&tis->stdin_port);
+ tpu_port_deinit(&tis->stdout_port);
+}
+
+bool
+tis_step(struct tis *tis)
+{
+ struct tpu_map_link *link;
+ bool running;
+ size_t i;
+
+ running = false;
+ for (i = 0; i < TPU_MAP_BUCKETS; i++) {
+ link = tis->tpu_map.buckets[i];
+ for (; link; link = link->next)
+ running |= (tpu_step(link->tpu) == STATUS_RUN);
+ }
+
+ for (i = 0; i < TPU_MAP_BUCKETS; i++) {
+ link = tis->tpu_map.buckets[i];
+ for (; link; link = link->next)
+ tpu_update_ports(link->tpu);
+ }
+
+ return running;
+}
diff --git a/tpu.h b/tpu.h
@@ -62,20 +62,26 @@ struct tpu_port {
struct tpu *dst_tpu;
enum tpu_port_type type;
struct tpu_port *dst_port;
- bool attached, reading;
+ bool clr_post_run;
+ bool reading, writing;
+ bool attached;
int in, out;
};
struct tpu {
enum tpu_status status;
- struct label_map labels;
- struct tpu_port ports[4];
- int read_port;
- uint8_t acc, bak;
size_t x, y;
+
+ struct tpu_port ports[4];
+ int io_port;
int last;
+ size_t steps;
+ size_t idle_steps;
+
+ uint8_t acc, bak;
uint8_t pc;
+ struct label_map labels;
struct tpu_inst insts[TPU_MAX_INST];
size_t inst_cnt;
};
@@ -90,11 +96,20 @@ struct tpu_map {
struct tpu_map_link *buckets[TPU_MAP_BUCKETS];
};
+struct tis {
+ struct tpu_map tpu_map;
+ struct tpu_port stdin_port;
+ struct tpu_port stdout_port;
+};
+
void label_map_init(struct label_map *map);
void label_map_deinit(struct label_map *map);
bool label_map_add(struct label_map *map, const char *name, size_t pc);
size_t label_map_get(struct label_map *map, const char *name);
+void tpu_port_init(struct tpu_port *port);
+void tpu_port_deinit(struct tpu_port *port);
+
void tpu_init(struct tpu *tpu);
void tpu_deinit(struct tpu *tpu);
struct tpu_inst *tpu_current_inst(struct tpu *tpu);
@@ -107,9 +122,18 @@ bool tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst,
void tpu_clear_ports(struct tpu *tpu);
enum tpu_status tpu_exec_mov(struct tpu *tpu, struct tpu_inst *inst);
enum tpu_status tpu_exec(struct tpu *tpu, struct tpu_inst *inst);
-void tpu_step(struct tpu *tpu);
+enum tpu_status tpu_step(struct tpu *tpu);
void tpu_map_init(struct tpu_map *map);
void tpu_map_deinit(struct tpu_map *map);
void tpu_map_add(struct tpu_map *map, struct tpu *tpu);
struct tpu *tpu_map_get(struct tpu_map *map, size_t x, size_t y);
+
+void tis_init(struct tis *tis);
+void tis_deinit(struct tis *tis);
+bool tis_step(struct tis *tis);
+
+extern const char *dir_reprs[];
+extern const char *status_reprs[];
+extern const char *inst_reprs[];
+extern const char *op_reprs[];
diff --git a/util.c b/util.c
@@ -10,6 +10,8 @@ die(const char *fmt, ...)
{
va_list ap;
+ if (cleanup) cleanup();
+
va_start(ap, fmt);
fprintf(stderr, "%s: ", progname);
vfprintf(stderr, fmt, ap);
@@ -23,3 +25,20 @@ die(const char *fmt, ...)
exit(1);
}
+
+size_t
+strdcpy(char *dst, const char *src, size_t n)
+{
+ strncpy(dst, src, n);
+ return strlen(src);
+}
+
+size_t
+strdcat(char *dst, const char *src, size_t n)
+{
+ size_t len;
+
+ len = strlen(dst);
+ strncpy(dst + len, src, n - len);
+ return strlen(src);
+}
diff --git a/util.h b/util.h
@@ -1,7 +1,17 @@
#pragma once
+#include <stddef.h>
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) < (b) ? (b) : (a))
+#define ABS(a) ((a) > 0 ? (a) : -(a))
+
__attribute__((noreturn))
__attribute__((format(printf, 1, 2)))
void die(const char *fmt, ...);
+size_t strdcpy(char *dst, const char *src, size_t n);
+size_t strdcat(char *dst, const char *src, size_t n);
+
extern const char *progname;
+extern void (*cleanup)(void);