tis100

Reimplementation of Zachtronics TIS-100 as a TUI game
git clone https://git.sinitax.com/sinitax/tis100
Log | Files | Refs | sfeed.txt

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+++
MMakefile | 1+
Mtest/test.asm | 11++++-------
Mtis-as.c | 143++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mtis-curses.c | 65++++++++++++++++++++++++++++++++++++++++++-----------------------
Mtpu.c | 196+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mtpu.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);