tis100

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

commit 0f06ef7127b669207fd8f09b88ecb660b38eb971
parent 29465804bb9f3bc0eb0f538ec450e9177c0c4767
Author: Louis Burda <quent.burda@gmail.com>
Date:   Wed, 26 Jul 2023 19:38:36 +0200

Fix more issues caused by negative literals

Diffstat:
Masm.c | 32++++++++++++++++----------------
Masm.h | 2++
Mtest/jro.in | 3++-
Mtest/jro.out | 3++-
Mtest/ports.in | 5++++-
Mtest/ports.out | 5++++-
Mtis100-curses.c | 52+++++++++++++++++++---------------------------------
Mtis100.c | 11+----------
Mtpu.c | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mtpu.h | 3+++
10 files changed, 118 insertions(+), 94 deletions(-)

diff --git a/asm.c b/asm.c @@ -71,18 +71,6 @@ static const char *tok_reprs[] = { }; static bool -is_lit(const char *str) -{ - const char *c; - - c = str; - if (*c == '-') c++; - else if (*c == '+') c++; - for (; *c && isdigit(*c); c++); - return !*c; -} - -static bool is_int(const char *str) { char *end; @@ -95,8 +83,20 @@ is_int(const char *str) return true; } -static int -str_to_lit(const char *str) +bool +asm_is_lit(const char *str) +{ + const char *c; + + c = str; + if (*c == '-') c++; + else if (*c == '+') c++; + for (; *c && isdigit(*c); c++); + return !*c; +} + +int +asm_str_to_lit(const char *str) { int m, v, b, i, o; @@ -147,7 +147,7 @@ tok_to_op(struct asm_tokenizer *tokenizer, enum asm_tok tok) op.type = tok_to_optype(tok); if (op.type == OP_LIT) { - op.val.lit = str_to_lit(tokenizer->tokstr); + op.val.lit = asm_str_to_lit(tokenizer->tokstr); } else if (op.type == OP_LABEL) { op.val.label = strdup(tokenizer->tokstr); if (!op.val.label) die("strdup:"); @@ -231,7 +231,7 @@ tok_next(struct asm_tokenizer *tok) return (enum asm_tok) i; } - if (is_lit(s)) { + if (asm_is_lit(s)) { return TOK_LIT; } else if (*s == '#') { tok->off += strlen(tok->linebuf + tok->off); diff --git a/asm.h b/asm.h @@ -4,5 +4,7 @@ #include <stdio.h> +bool asm_is_lit(const char *str); +int asm_str_to_lit(const char *str); 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/jro.in b/test/jro.in @@ -1 +1,2 @@ -test +123 +-123 diff --git a/test/jro.out b/test/jro.out @@ -1 +1,2 @@ -test +123 +-123 diff --git a/test/ports.in b/test/ports.in @@ -1 +1,4 @@ -test +1 +99 +-123 +1000 diff --git a/test/ports.out b/test/ports.out @@ -1 +1,4 @@ -test +1 +99 +-123 +1000 diff --git a/tis100-curses.c b/tis100-curses.c @@ -213,14 +213,12 @@ tui_draw_tpu(struct tpu *tpu) 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 + 1, y + 2, 0, - tpu->acc >= 0 ? " %03i" : "-%03i", tpu->acc); + tui_draw_text(x + 1 + (tpu->acc >= 0), y + 2, 0, "%03i", tpu->acc); tui_draw_box(x, (y += TPU_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 + 1, y + 2, 0, - tpu->bak >= 0 ? " %03i" : "-%03i", tpu->bak); + tui_draw_text(x + 1 + (tpu->bak >= 0), y + 2, 0, "%03i", tpu->bak); tui_draw_box(x, (y += TPU_INFO_H - 1), w, h, attr, WACS_D_LTEE, WACS_D_RTEE, WACS_D_LTEE, WACS_D_RTEE); @@ -255,64 +253,64 @@ tui_draw_tpu(struct tpu *tpu) if (tpu->ports[DIR_LEFT].attached) { port = &tpu->ports[DIR_LEFT]; - if (port->in >= 0) + if (port->in_set) tui_draw_text(sx - 3, sy + 6, A_BOLD, "%03i", port->in); if (port->type & PORT_IN) tui_draw_wch(sx - 1, sy + 7, - port->in >= 0 ? A_BOLD : 0, WACS_RARROW); + port->in_set ? A_BOLD : 0, WACS_RARROW); if (port->type & PORT_OUT) tui_draw_wch(sx - 1, sy + 8, - port->out >= 0 ? A_BOLD : 0, WACS_LARROW); - if (port->out >= 0) + port->out_set ? A_BOLD : 0, WACS_LARROW); + if (port->out_set) tui_draw_text(sx - 3, sy + 10, A_BOLD, "%03i", port->out); } if (tpu->ports[DIR_RIGHT].attached) { port = &tpu->ports[DIR_RIGHT]; - if (port->out >= 0) + if (port->out_set) tui_draw_text(sx + TPU_W + 1, sy + 5, A_BOLD, "%03i", port->out); if (port->type & PORT_OUT) tui_draw_wch(sx + TPU_W + 1, sy + 7, - port->out >= 0 ? A_BOLD : 0, WACS_RARROW); + port->out_set ? A_BOLD : 0, WACS_RARROW); if (port->type & PORT_IN) tui_draw_wch(sx + TPU_W + 1, sy + 8, - port->in >= 0 ? A_BOLD : 0, WACS_LARROW); - if (port->in >= 0) + port->in_set ? A_BOLD : 0, WACS_LARROW); + if (port->in_set) tui_draw_text(sx + TPU_W + 1, sy + 9, A_BOLD, "%03i", port->in); } if (tpu->ports[DIR_UP].attached) { port = &tpu->ports[DIR_UP]; - if (port->out >= 0) + if (port->out_set) 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); + port->out_set ? 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) + port->in_set ? A_BOLD : 0, WACS_DARROW); + if (port->in_set) tui_draw_text(sx + 17, sy - 1, A_BOLD, "%03i", port->in); } if (tpu->ports[DIR_DOWN].attached) { port = &tpu->ports[DIR_DOWN]; - if (port->in >= 0) + if (port->in_set) tui_draw_text(sx + 9, sy + TPU_H, A_BOLD, "%03i", port->in); if (port->type & PORT_IN) tui_draw_wch(sx + 13, sy + TPU_H, - port->in >= 0 ? A_BOLD : 0, WACS_UARROW); + port->in_set ? A_BOLD : 0, WACS_UARROW); if (port->type & PORT_OUT) tui_draw_wch(sx + 15, sy + TPU_H, - port->out >= 0 ? A_BOLD : 0, WACS_DARROW); - if (port->out >= 0) + port->out_set ? A_BOLD : 0, WACS_DARROW); + if (port->out_set) tui_draw_text(sx + 17, sy + TPU_H, A_BOLD, "%03i", port->out); } @@ -388,7 +386,6 @@ static void handlekey(int key) { enum tpu_port_dir dir; - int c; if (input_mode == MAIN) { switch (key) { @@ -408,18 +405,7 @@ handlekey(int key) scrx += 4; break; case 's': - if (tis_stdin && tis.stdin_port.attached - && tis.stdin_port.out < 0) { - c = getc(tis_stdin); - if (c >= 0) tis.stdin_port.out = c; - } - - if (tis.stdout_port.attached && tis.stdout_port.in >= 0) { - if (tis_stdout) - putc(tis.stdout_port.in, tis_stdout); - tis.stdout_port.in = -1; - } - + tis_communicate(&tis, tis_stdin, tis_stdout); tis_step(&tis); break; } diff --git a/tis100.c b/tis100.c @@ -21,7 +21,6 @@ int main(int argc, const char **argv) { bool idle, prev_idle; - int c; if (argc < 2 || argc > 4) { fprintf(stderr, "Usage: tis-as FILE [STDIN] [STDOUT]\n"); @@ -52,15 +51,7 @@ main(int argc, const char **argv) idle = false; while (!idle || !prev_idle || tis.stdin_port.attached && tis.stdin_port.reading && !feof(tis_stdin)) { - if (tis.stdin_port.attached && tis.stdin_port.out < 0) { - c = getc(tis_stdin); - if (c >= 0) tis.stdin_port.out = c; - } - - if (tis.stdout_port.attached && tis.stdout_port.in >= 0) { - putc(tis.stdout_port.in, tis_stdout); - tis.stdout_port.in = -1; - } + tis_communicate(&tis, tis_stdin, tis_stdout); prev_idle = idle; idle = !tis_step(&tis); diff --git a/tpu.c b/tpu.c @@ -138,7 +138,9 @@ tpu_port_init(struct tpu_port *port) port->clr_post_run = false; port->reading = false; port->writing = false; + port->in_set = false; port->in = -1; + port->out_set = false; port->out = -1; } @@ -246,20 +248,22 @@ tpu_update_ports(struct tpu *tpu) 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; + if (port->out_set && !port->dst_port->in_set) { port->dst_port->in = port->out; + port->dst_port->in_set = true; + port->dst_port->reading = false; + port->out_set = false; port->writing = false; - port->out = -1; } - if (port->dst_port->out >= 0 && port->in < 0) { - port->reading = false; + if (port->dst_port->out_set && !port->in_set) { port->in = port->dst_port->out; + port->in_set = true; + port->reading = false; + port->dst_port->out_set = false; port->dst_port->writing = false; - port->dst_port->out = -1; } if (tpu->status == STATUS_RUN && port->clr_post_run) { - port->in = -1; + port->in_set = false; port->clr_post_run = false; } } @@ -323,18 +327,19 @@ tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst_type, * (->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) +static bool +tpu_port_read(struct tpu *tpu, enum tpu_port_dir dir, int *lit) { struct tpu_port *port; port = &tpu->ports[dir]; port->clr_post_run = true; - if (port->in < 0) { + if (!port->in_set) { port->reading = true; - return -1; + return false; } - return port->in; + *lit = port->in; + return true; } static bool @@ -343,10 +348,11 @@ tpu_port_write(struct tpu *tpu, enum tpu_port_dir dir, int lit) struct tpu_port *port; port = &tpu->ports[dir]; - if (port->out >= 0) { + if (port->out_set) { port->writing = true; return false; } + port->out_set = true; port->out = lit; return true; } @@ -359,31 +365,33 @@ tpu_jmp_label(struct tpu *tpu, const char *label) } int -tpu_exec_get(struct tpu *tpu, struct tpu_inst_op *op) +tpu_exec_get(struct tpu *tpu, struct tpu_inst_op *op, int *lit) { - int i, v; + int i; switch (op->type) { case OP_ACC: - return tpu->acc; + *lit = tpu->acc; + return true; case OP_NIL: - return 0; + *lit = 0; + return true; case OP_LEFT: case OP_RIGHT: case OP_UP: case OP_DOWN: - return tpu_port_read(tpu, op_to_dir(op->type)); + return tpu_port_read(tpu, op_to_dir(op->type), lit); case OP_ANY: for (i = 0; i < 4; i++) { - v = tpu_port_read(tpu, (enum tpu_port_dir) i); - if (v >= 0) { + if (tpu_port_read(tpu, (enum tpu_port_dir) i, lit)) { tpu->last = i; - return v; + return true; } } - return -1; + return false; case OP_LAST: - if (tpu->last < 0) return 0; - return tpu_port_read(tpu, (enum tpu_port_dir) tpu->last); + if (tpu->last < 0) return false; + return tpu_port_read(tpu, (enum tpu_port_dir) tpu->last, lit); case OP_LIT: - return op->val.lit; + *lit = op->val.lit; + return true; case OP_LABEL: abort(); } @@ -426,8 +434,8 @@ tpu_exec_mov(struct tpu *tpu, struct tpu_inst *inst) if (inst->type != INST_MOV) abort(); - lit = tpu_exec_get(tpu, &inst->ops[0]); - if (lit < 0) return STATUS_READ; + if (!tpu_exec_get(tpu, &inst->ops[0], &lit)) + return STATUS_READ; if (!tpu_exec_put(tpu, &inst->ops[1], lit)) return STATUS_WRITE; @@ -462,14 +470,14 @@ tpu_exec(struct tpu *tpu, struct tpu_inst *inst) tpu->pc += 1; return STATUS_RUN; case INST_ADD: - val = tpu_exec_get(tpu, &inst->ops[0]); - if (val < 0) return STATUS_READ; + if (!tpu_exec_get(tpu, &inst->ops[0], &val)) + return STATUS_READ; tpu->acc = MIN(MAX(tpu->acc + val, -999), 999); tpu->pc += 1; return STATUS_RUN; case INST_SUB: - val = tpu_exec_get(tpu, &inst->ops[0]); - if (val < 0) return STATUS_READ; + if (!tpu_exec_get(tpu, &inst->ops[0], &val)) + return STATUS_READ; tpu->acc = MIN(MAX(tpu->acc - val, -999), 999); tpu->pc += 1; return STATUS_RUN; @@ -637,3 +645,29 @@ tis_step(struct tis *tis) return running; } + +void +tis_communicate(struct tis *tis, FILE *tis_stdin, FILE *tis_stdout) +{ + char buf[16], *s; + int val; + + if (tis_stdin && tis->stdin_port.attached && !tis->stdin_port.out_set) { + while ((s = fgets(buf, sizeof(buf), tis_stdin))) { + if ((s = strchr(buf, '\n'))) *s = '\0'; + if (!*buf) continue; + val = (int) strtol(buf, &s, 10); + if (!s || *s != '\0') + die("communicate: invalid input '%s'", buf); + tis->stdin_port.out = val; + tis->stdin_port.out_set = true; + break; + } + } + + if (tis->stdout_port.attached && tis->stdout_port.in_set) { + if (tis_stdout) + fprintf(tis_stdout, "%i\n", tis->stdout_port.in); + tis->stdout_port.in_set = false; + } +} diff --git a/tpu.h b/tpu.h @@ -1,5 +1,6 @@ #pragma once +#include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <stdlib.h> @@ -69,6 +70,7 @@ struct tpu_port { bool clr_post_run; bool reading, writing; bool attached; + bool in_set, out_set; int in, out; }; @@ -137,6 +139,7 @@ struct tpu *tpu_map_get(struct tpu_map *map, int x, int y); void tis_init(struct tis *tis); void tis_deinit(struct tis *tis); bool tis_step(struct tis *tis); +void tis_communicate(struct tis *tis, FILE *tis_stdin, FILE *tis_stdout); extern const char *dir_reprs[]; extern const char *status_reprs[];