commit 29894d56e144223629e558070cbc52080e21342e
parent 5835917f57d4dc04b406c8e3e06bf3b046d709e3
Author: Louis Burda <quent.burda@gmail.com>
Date: Mon, 24 Jul 2023 20:12:26 +0200
Fully implement tokenizer and port value passing
Diffstat:
M | .gitignore | | | 3 | +++ |
M | Makefile | | | 1 | + |
M | test/test.asm | | | 11 | ++++------- |
M | tis-as.c | | | 143 | ++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------- |
M | tis-curses.c | | | 65 | ++++++++++++++++++++++++++++++++++++++++++----------------------- |
M | tpu.c | | | 196 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
M | tpu.h | | | 14 | ++++++++++---- |
7 files changed, 265 insertions(+), 168 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -2,3 +2,6 @@ tis-as
tis-curses
compile_commands.json
.cache
+notes
+.gdb_history
+vgcore*
diff --git a/Makefile b/Makefile
@@ -2,6 +2,7 @@ PREFIX ?= /usr/local
BINDIR ?= /bin
CFLAGS = -Wunused-function -Wunused-variable -Wconversion -Wswitch
+CFLAGS += -Og -g
all: tis-as tis-curses
diff --git a/test/test.asm b/test/test.asm
@@ -2,16 +2,13 @@ stdin X1 Y1
stdout X3 Y1
tpu X1 Y1
- mov acc, bak
-label:
- goto label
+ mov UP, RIGHT
end
tpu X2 Y1
- mov UP, RIGHT
- mov RIGHT
+ mov LEFT, RIGHT
end
tpu X3 Y1
-
-edn
+ mov LEFT, DOWN
+end
diff --git a/tis-as.c b/tis-as.c
@@ -25,8 +25,7 @@ enum tok {
TOK_NEG, TOK_JMP, TOK_JEZ, TOK_JNZ, TOK_JGZ, TOK_JLZ, TOK_JRO,
/* Misc */
- TOK_COMMENT, TOK_LABEL, TOK_XPOS, TOK_YPOS,
- TOK_SEP, TOK_NL, TOK_EOF
+ TOK_COMMENT, TOK_LABEL, TOK_XPOS, TOK_YPOS, TOK_NL, TOK_EOF
};
struct tokenizer {
@@ -46,20 +45,28 @@ 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 */
- "'ACC'", "'BAK'", "'NIL'", "'LEFT'", "'RIGHT'", "'UP'",
- "'DOWN'", "'ANY'", "'LAST'", "<LIT>", "<NAME>",
+ /* Operands (order like OP_*) */
+ "'ACC'", "'BAK'", "'NIL'", "'LEFT'", "'RIGHT'",
+ "'UP'", "'DOWN'", "'ANY'", "'LAST'", "<LIT>", "<NAME>",
- /* Instructions */
+ /* 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>"
+ "#<COMMENT>", "<LABEL>:", "X<INT>", "Y<INT>", "<NL>", "<EOF>"
};
const char *progname = "tis-as";
@@ -106,26 +113,38 @@ tok_next(struct tokenizer *tok)
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_EOF;
- if (*s && s[strlen(s)-1] != '\n')
+ 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;
- len = strcspn(s, WHITESPACE);
- s[len] = '\0';
+ len = strcspn(s, WHITESPACE ",");
tok->off += len;
- if (!len) return TOK_NL;
+ printf("> %s\n", s);
+ if (s[len]) {
+ s[len] = '\0';
+ tok->off += 1;
+ }
if (!strcasecmp(s, "stdin")) {
return TOK_STDIN;
} else if (!strcasecmp(s, "stdout")) {
- return TOK_STDIN;
+ return TOK_STDOUT;
} else if (!strcasecmp(s, "tpu")) {
return TOK_TPU;
} else if (!strcasecmp(s, "end")) {
@@ -150,8 +169,6 @@ tok_next(struct tokenizer *tok)
return TOK_LAST;
} else if (is_lit(s)) {
return TOK_LIT;
- } else if (strspn(s, NAMEALPH) == strlen(s)) {
- return TOK_NAME;
} else if (!strcasecmp(s, "nop")) {
return TOK_NOP;
} else if (!strcasecmp(s, "mov")) {
@@ -179,7 +196,7 @@ tok_next(struct tokenizer *tok)
} else if (!strcasecmp(s, "jro")) {
return TOK_JRO;
} else if (*s == '#') {
- tok->off = strlen(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;
@@ -187,6 +204,8 @@ tok_next(struct tokenizer *tok)
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("load: line %lu, invalid token '%s'", tok->lineno, s);
}
@@ -211,9 +230,8 @@ tok_next_in(struct tokenizer *tokenizer, ...)
va_end(cpy);
fprintf(stderr, "tis-as: load: ");
- fprintf(stderr, "line %lu, got tok '%s', expected one of ",
+ 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) {
@@ -222,8 +240,8 @@ tok_next_in(struct tokenizer *tokenizer, ...)
first = false;
}
va_end(ap);
+ fputs(")\n", stderr);
- fprintf(stderr, "\n");
exit(1);
}
@@ -246,7 +264,7 @@ load(const char *fname)
file = fopen(fname, "r");
if (!file) die("fopen:");
- tokenizer.lineno = 1;
+ tokenizer.lineno = 0;
tokenizer.file = file;
tokenizer.off = 0;
tokenizer.tokstr = NULL;
@@ -284,6 +302,7 @@ load(const char *fname)
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:
@@ -292,11 +311,10 @@ load(const char *fname)
if (!tpu) goto disallowed;
inst = tok_to_inst(tok);
- op1_tok = tok_next_in(&tokenizer, TOK_ACC,
- TOK_BAK, TOK_UP, TOK_DOWN,
- TOK_LEFT, TOK_RIGHT, TOK_NL, -1);
+ 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) {
- tok_next_in(&tokenizer, TOK_NL, -1);
tpu_add_inst(tpu, inst, -1, 0, -1, 0);
break;
}
@@ -305,13 +323,12 @@ load(const char *fname)
if (op1 == OP_LIT)
op1_lit = str2lit(tokenizer.tokstr);
- op2_tok = tok_next_in(&tokenizer, TOK_ACC,
- TOK_BAK, TOK_UP, TOK_DOWN,
- TOK_LEFT, TOK_RIGHT, TOK_NL, -1);
+ 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) {
- tok_next_in(&tokenizer, TOK_NL, -1);
- tpu_add_inst(tpu, inst,
- (int) op1, op1_lit, -1, 0);
+ tpu_add_inst(tpu, inst, (int) op1,
+ op1_lit, -1, 0);
break;
}
@@ -332,6 +349,8 @@ load(const char *fname)
tokenizer.lineno);
tok_next_in(&tokenizer, TOK_NL, -1);
break;
+ case TOK_NL:
+ break;
default:
goto disallowed;
}
@@ -356,14 +375,14 @@ load(const char *fname)
stdin_port.dst_port = port;
}
- if (link->x == stdout_x && link->y == stdout_x) {
+ 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.dst_port = port;
+ stdout_port.attached = true;
stdout_port.dst_tpu = NULL;
stdout_port.dst_port = port;
}
@@ -375,34 +394,59 @@ load(const char *fname)
fclose(file);
+ return;
+
disallowed:
- die("load: line %lu, token %s not allowed here",
- tokenizer.lineno, tok_reprs[tok]);
+ if (tok == TOK_NAME) {
+ die("load: line %lu, unexpected token '%s'",
+ tokenizer.lineno, tokenizer.tokstr);
+ } else {
+ die("load: line %lu, token %s not allowed here",
+ tokenizer.lineno, tok_reprs[tok]);
+ }
}
void
run(void)
{
struct tpu_map_link *link;
- struct tpu_inst *inst;
- size_t i, pc;
+ size_t i, k;
+ int c;
+
+ 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;
+ }
- /* initial pass to propagate moves */
- for (i = 0; i < TPU_MAP_BUCKETS; i++) {
- for (link = tpu_map.buckets[i]; link; link = link->next) {
- inst = tpu_current_inst(link->tpu);
- if (inst && inst->type == INST_MOV) {
- pc = link->tpu->pc;
- tpu_exec(link->tpu, inst);
- link->tpu->pc = pc;
+ printf("===\n");
+
+ for (i = 0; i < TPU_MAP_BUCKETS; i++) {
+ for (link = tpu_map.buckets[i]; link; link = link->next) {
+ tpu_step(link->tpu);
}
}
- }
- for (i = 0; i < TPU_MAP_BUCKETS; i++) {
- for (link = tpu_map.buckets[i]; link; link = link->next) {
- inst = tpu_current_inst(link->tpu);
- tpu_step(link->tpu);
+ 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 (stdout_port.dst_port->out >= 0) {
+ putchar(stdout_port.dst_port->out);
+ stdout_port.dst_port->out = -1;
}
}
}
@@ -419,3 +463,4 @@ main(int argc, const char **argv)
run();
}
+
diff --git a/tis-curses.c b/tis-curses.c
@@ -43,8 +43,10 @@ struct tpu_cell {
static size_t tpu_cell_rows = 2;
static size_t tpu_cell_cols = 3;
-static size_t screenw = 80;
-static size_t screenh = 40;
+static int scrx = 0;
+static int scry = 0;
+static int scrw = 80;
+static int scrh = 40;
static struct tpu_cell *tpu_cells = NULL;
@@ -77,6 +79,11 @@ tui_draw_box(int sx, int sy, int w, int h, const cchar_t *ul, const cchar_t *ur,
{
int x, y;
+ if (sx + w < scrx || sx >= scrx + scrw) return;
+ if (sy + h < scry || sy >= scry + scrh) return;
+
+ sx -= scrx;
+ sy -= scry;
mvadd_wch(sy, sx, ul);
mvadd_wch(sy, sx + w - 1, ur);
mvadd_wch(sy + h - 1, sx, ll);
@@ -103,7 +110,7 @@ tui_draw_text(int x, int y, int attr, const char *fmt, ...)
va_end(ap);
attron(attr);
- mvprintw(y, x, "%s", buf);
+ mvprintw(y - scry, x - scrx, "%s", buf);
attroff(attr);
}
@@ -111,7 +118,7 @@ static void
tui_draw_wch(int x, int y, int attr, const cchar_t *c)
{
attron(attr);
- mvadd_wch(y, x, c);
+ mvadd_wch(y - scry, x - scrx, c);
attroff(attr);
}
@@ -157,52 +164,52 @@ tui_draw_tpu_cell(struct tpu_cell *cell)
port = &cell->tpu.ports[DIR_LEFT];
if (port->type & PORT_IN)
tui_draw_wch((int) cell->x - 1, (int) cell->y + 8,
- port->read ? A_BOLD : 0, WACS_RARROW);
+ port->reading ? A_BOLD : 0, WACS_RARROW);
if (port->type & PORT_OUT)
tui_draw_wch((int) cell->x - 1, (int) cell->y + 7,
- port->write ? A_BOLD : 0, WACS_LARROW);
- if (port->write)
+ port->out > 0 ? A_BOLD : 0, WACS_LARROW);
+ if (port->out >= 0)
tui_draw_text((int) cell->x - 3, (int) cell->y + 6,
- A_BOLD, "%03i", port->val);
+ 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->read ? A_BOLD : 0, WACS_LARROW);
+ 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->write ? A_BOLD : 0, WACS_RARROW);
- if (port->write)
+ port->out > 0 ? A_BOLD : 0, WACS_RARROW);
+ if (port->out >= 0)
tui_draw_text((int) cell->x + TCELL_W + 1, (int) cell->y + 9,
- A_BOLD, "%03i", port->val);
+ A_BOLD, "%03i", port->out);
}
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->read ? A_BOLD : 0, WACS_DARROW);
+ port->reading ? A_BOLD : 0, WACS_DARROW);
if (port->type & PORT_OUT)
tui_draw_wch((int) cell->x + 15, (int) cell->y - 1,
- port->write ? A_BOLD : 0, WACS_UARROW);
- if (port->write)
+ port->out > 0 ? A_BOLD : 0, WACS_UARROW);
+ if (port->out >= 0)
tui_draw_text((int) cell->x + 16, (int) cell->y - 1,
- A_BOLD, "%03i", port->val);
+ A_BOLD, "%03i", port->out);
}
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->write ? A_BOLD : 0, WACS_DARROW);
+ 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->read ? A_BOLD : 0, WACS_UARROW);
- if (port->write)
+ port->reading ? A_BOLD : 0, WACS_UARROW);
+ if (port->out >= 0)
tui_draw_text((int) cell->x + 10, (int) cell->y + TCELL_H,
- A_BOLD, "%03i", port->val);
+ A_BOLD, "%03i", port->out);
}
}
@@ -211,9 +218,9 @@ tui_draw(void)
{
int i;
+ clear();
for (i = 0; i < TCELL_CNT; i++)
tui_draw_tpu_cell(&tpu_cells[i]);
-
refresh();
}
@@ -222,8 +229,8 @@ tui_resize(void)
{
size_t x, y, i;
- screenw = (size_t) getmaxx(stdscr);
- screenh = (size_t) getmaxy(stdscr);
+ scrw = getmaxx(stdscr);
+ scrh = getmaxy(stdscr);
for (y = 0; y < tpu_cell_rows; y++) {
for (x = 0; x < tpu_cell_cols; x++) {
@@ -275,6 +282,18 @@ main(int argc, char **argv)
case KEY_RESIZE:
tui_resize();
break;
+ case KEY_UP:
+ scry -= 1;
+ break;
+ case KEY_DOWN:
+ scry += 1;
+ break;
+ case KEY_LEFT:
+ scrx -= 2;
+ break;
+ case KEY_RIGHT:
+ scrx += 2;
+ break;
case KEY_CTRL('c'):
quit = true;
break;
diff --git a/tpu.c b/tpu.c
@@ -1,6 +1,7 @@
#include "tpu.h"
#include "util.h"
+#include <stdio.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
@@ -119,15 +120,16 @@ tpu_init(struct tpu *tpu)
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].read = false;
- tpu->ports[i].write = false;
tpu->ports[i].type = PORT_BIDI;
- tpu->ports[i].val = 0;
+ tpu->ports[i].reading = false;
+ tpu->ports[i].in = -1;
+ tpu->ports[i].out = -1;
}
}
@@ -189,14 +191,33 @@ tpu_init_ports(struct tpu *tpu, struct tpu_map *map)
}
}
+void
+tpu_update_ports(struct tpu *tpu)
+{
+ struct tpu_port *port;
+
+ 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) {
+ port->in = -1;
+ tpu->read_port = -1;
+ }
+ }
+}
+
bool
-tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst_type,
+tpu_set_inst(struct tpu *tpu, uint8_t pc, enum tpu_inst_type inst_type,
int op1, uint8_t op1_lit, int op2, uint8_t op2_lit)
{
struct tpu_inst *inst;
- inst = calloc(1, sizeof(struct tpu_inst));
- if (!inst) die("malloc:");
+ inst = &tpu->insts[pc];
inst->type = inst_type;
if (op2 > 0) {
@@ -226,6 +247,8 @@ tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst_type,
break;
case INST_MOV:
if (inst->opcnt != 2) return false;
+ if (inst->ops[0].type == OP_LABEL) return false;
+ if (inst->ops[1].type == OP_LABEL) return false;
if (inst->ops[1].type == OP_LIT) return false;
break;
}
@@ -233,23 +256,62 @@ tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst_type,
return true;
}
-void
-tpu_ports_clear(struct tpu *tpu)
+bool
+tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst_type,
+ int op1, uint8_t op1_lit, int op2, uint8_t op2_lit)
{
- int i;
+ if (tpu->inst_cnt == TPU_MAX_INST)
+ die("tpu_add_inst: tpu X%lu Y%lu, too many instructions",
+ tpu->x, tpu->y);
+ return tpu_set_inst(tpu, (uint8_t) tpu->inst_cnt++, inst_type,
+ op1, op1_lit, op2, op2_lit);
+}
- for (i = 0; i < 4; i++) {
- tpu->ports[i].read = false;
- tpu->ports[i].write = false;
+/* 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 */
+
+static int
+tpu_port_read(struct tpu *tpu, enum tpu_port_dir dir)
+{
+ struct tpu_port *port;
+
+ port = &tpu->ports[dir];
+ if (port->in < 0) {
+ port->reading = true;
+ tpu->read_port = (int) dir;
+ return -1;
}
+ return port->in;
+}
+
+static bool
+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;
+ port->out = lit;
+ return true;
+}
+
+static void
+tpu_jmp_label(struct tpu *tpu, const char *label)
+{
+ size_t pc;
+
+ pc = label_map_get(&tpu->labels, label);
+ if (pc >= TPU_MAX_INST) abort();
+ tpu->pc = (uint8_t) pc;
}
int
tpu_exec_get(struct tpu *tpu, struct tpu_inst_op *op)
{
- struct tpu_port *port;
uint8_t lit;
- int i;
+ int i, v;
switch (op->type) {
case OP_ACC:
@@ -262,71 +324,50 @@ tpu_exec_get(struct tpu *tpu, struct tpu_inst_op *op)
lit = 0;
break;
case OP_LEFT: case OP_RIGHT: case OP_UP: case OP_DOWN:
- port = &tpu->ports[op_to_dir(op->type)];
- port->read = true;
- if (!port->attached || !port->dst_port->write)
- return -1;
- tpu->last = (int) op_to_dir(op->type);
- lit = port->dst_port->val;
- break;
+ return tpu_port_read(tpu, op_to_dir(op->type));
case OP_ANY:
for (i = 0; i < 4; i++) {
- port = &tpu->ports[i];
- port->read = true;
- if (port->attached && port->dst_port->write) {
+ v = tpu_port_read(tpu, (enum tpu_port_dir) i);
+ if (v >= 0) {
tpu->last = i;
- lit = port->dst_port->val;
break;
}
}
if (i == 4) return -1;
+ lit = (uint8_t) v;
break;
case OP_LAST:
if (tpu->last < 0) return 0;
- port = &tpu->ports[tpu->last];
- port->read = true;
- if (!port->attached || !port->dst_port->write)
- return -1;
- lit = port->dst_port->val;
- break;
+ return tpu_port_read(tpu, (enum tpu_port_dir) tpu->last);
case OP_LIT:
lit = op->lit;
break;
- default:
+ case OP_LABEL:
abort();
}
- tpu_ports_clear(tpu);
-
return (int) lit;
}
bool
tpu_exec_put(struct tpu *tpu, struct tpu_inst_op *op, uint8_t lit)
{
- struct tpu_port *port;
int i;
switch (op->type) {
+ case OP_ACC:
+ tpu->acc = lit;
+ break;
case OP_BAK:
tpu->bak = lit;
break;
case OP_NIL:
break;
case OP_LEFT: case OP_RIGHT: case OP_UP: case OP_DOWN:
- port = &tpu->ports[op_to_dir(op->type)];
- port->write = true;
- if (!port->attached || !port->dst_port->write)
- return false;
- lit = port->dst_port->val;
- tpu->last = (int) op_to_dir(op->type);
- break;
+ return tpu_port_write(tpu, op_to_dir(op->type), lit);
case OP_ANY:
for (i = 0; i < 4; i++) {
- port = &tpu->ports[i];
- port->write = true;
- if (port->attached && port->dst_port->write) {
- port->dst_port->val = lit;
+ if (tpu_port_write(tpu, (enum tpu_port_dir) i, lit)) {
tpu->last = i;
break;
}
@@ -335,17 +376,12 @@ tpu_exec_put(struct tpu *tpu, struct tpu_inst_op *op, uint8_t lit)
break;
case OP_LAST:
if (tpu->last < 0) break;
- port = &tpu->ports[tpu->last];
- port->write = true;
- if (!port->attached || !port->dst_port->write)
- return false;
- break;
- default:
+ return tpu_port_write(tpu, (enum tpu_port_dir) tpu->last, lit);
+ case OP_LABEL:
+ case OP_LIT:
abort();
}
- tpu_ports_clear(tpu);
-
return true;
}
@@ -359,16 +395,16 @@ tpu_exec_mov(struct tpu *tpu, struct tpu_inst *inst)
lit = tpu_exec_get(tpu, &inst->ops[0]);
if (lit < 0) return STATUS_READ;
- if (!tpu_exec_put(tpu, &inst->ops[0], (uint8_t) lit))
+ if (!tpu_exec_put(tpu, &inst->ops[1], (uint8_t) lit))
return STATUS_WRITE;
- tpu->pc += 1;
return STATUS_RUN;
}
enum tpu_status
tpu_exec(struct tpu *tpu, struct tpu_inst *inst)
{
+ enum tpu_status status;
uint8_t lit;
int val;
@@ -377,7 +413,10 @@ tpu_exec(struct tpu *tpu, struct tpu_inst *inst)
tpu->pc += 1;
return STATUS_RUN;
case INST_MOV:
- return tpu_exec_mov(tpu, inst);
+ status = tpu_exec_mov(tpu, inst);
+ if (status == STATUS_RUN)
+ tpu->pc += 1;
+ return status;
case INST_SWP:
lit = tpu->acc;
tpu->acc = tpu->bak;
@@ -404,45 +443,32 @@ tpu_exec(struct tpu *tpu, struct tpu_inst *inst)
tpu->acc = -tpu->acc;
tpu->pc += 1;
return STATUS_RUN;
- case INST_JMP:
- tpu->pc = label_map_get(&tpu->labels, inst->ops[0].label);
- if (tpu->pc >= TPU_MAX_INST) abort();
+ case INST_JMP:
+ tpu_jmp_label(tpu, inst->ops[0].label);
return STATUS_RUN;
case INST_JEZ:
- if (tpu->acc == 0) {
- tpu->pc = label_map_get(&tpu->labels,
- inst->ops[0].label);
- if (tpu->pc >= TPU_MAX_INST) abort();
- } else {
+ if (tpu->acc == 0)
+ tpu_jmp_label(tpu, inst->ops[0].label);
+ else
tpu->pc += 1;
- }
return STATUS_RUN;
case INST_JNZ:
- if (tpu->acc != 0) {
- tpu->pc = label_map_get(&tpu->labels,
- inst->ops[0].label);
- if (tpu->pc >= TPU_MAX_INST) abort();
- } else {
+ if (tpu->acc != 0)
+ tpu_jmp_label(tpu, inst->ops[0].label);
+ else
tpu->pc += 1;
- }
return STATUS_RUN;
case INST_JGZ:
- if (tpu->acc > 0) {
- tpu->pc = label_map_get(&tpu->labels,
- inst->ops[0].label);
- if (tpu->pc >= TPU_MAX_INST) abort();
- } else {
+ if (tpu->acc > 0)
+ tpu_jmp_label(tpu, inst->ops[0].label);
+ else
tpu->pc += 1;
- }
return STATUS_RUN;
case INST_JLZ:
- if (tpu->acc < 0) {
- tpu->pc = label_map_get(&tpu->labels,
- inst->ops[0].label);
- if (tpu->pc >= TPU_MAX_INST) abort();
- } else {
+ if (tpu->acc < 0)
+ tpu_jmp_label(tpu, inst->ops[0].label);
+ else
tpu->pc += 1;
- }
return STATUS_RUN;
case INST_JRO:
tpu->pc += inst->ops[0].lit;
@@ -457,7 +483,7 @@ void
tpu_step(struct tpu *tpu)
{
if (tpu->pc >= tpu->inst_cnt) return;
- tpu_exec(tpu, &tpu->insts[tpu->pc]);
+ tpu->status = tpu_exec(tpu, &tpu->insts[tpu->pc]);
if (tpu->pc >= tpu->inst_cnt) tpu->pc = 0;
}
diff --git a/tpu.h b/tpu.h
@@ -62,19 +62,20 @@ struct tpu_port {
struct tpu *dst_tpu;
enum tpu_port_type type;
struct tpu_port *dst_port;
- bool write, read;
- uint8_t val;
- bool attached;
+ bool attached, reading;
+ 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;
int last;
- size_t pc;
+ uint8_t pc;
struct tpu_inst insts[TPU_MAX_INST];
size_t inst_cnt;
};
@@ -98,8 +99,13 @@ void tpu_init(struct tpu *tpu);
void tpu_deinit(struct tpu *tpu);
struct tpu_inst *tpu_current_inst(struct tpu *tpu);
void tpu_init_ports(struct tpu *tpu, struct tpu_map *map);
+void tpu_update_ports(struct tpu *tpu);
+bool tpu_set_inst(struct tpu *tpu, uint8_t pc, enum tpu_inst_type inst,
+ int op1, uint8_t op1_lit, int op2, uint8_t op2_lit);
bool tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst,
int op1, uint8_t op1_lit, int op2, uint8_t op2_lit);
+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);