tis100

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

commit 130db985e5594204897ad28d7463e7e9b5ef94c7
parent d9dd10cd6a69f6da102814ebefe1d7ad2a32a020
Author: Louis Burda <quent.burda@gmail.com>
Date:   Wed, 26 Jul 2023 18:38:11 +0200

Restrict assembly input to fit game spec

Diffstat:
Masm.c | 37++++++++++++++++++++++++++++---------
Mtis100 | 0
Mtis100-curses | 0
Mtis100-curses.c | 15++++++++++-----
Mtpu.c | 23+++++++++++++----------
Mtpu.h | 20+++++++++++---------
6 files changed, 62 insertions(+), 33 deletions(-)

diff --git a/asm.c b/asm.c @@ -136,7 +136,7 @@ strlcat_op_name(char *buf, struct tpu_inst_op *op, size_t n) char hhbuf[4]; if (op->type == OP_LIT) { - snprintf(hhbuf, 4, "%hhu", op->val.lit); + snprintf(hhbuf, 4, "%i", op->val.lit); return strdcat(buf, hhbuf, n); } else if (op->type == OP_LABEL) { return strdcat(buf, op->val.label, n); @@ -271,7 +271,7 @@ tpu_validate(struct tpu *tpu) && tpu->insts[i].ops[0].type == OP_LABEL) { dst = label_map_get(&tpu->label_map, tpu->insts[i].ops[0].val.label); - if (dst == TPU_MAX_INST) + if (dst == TPU_MAX_INST_CNT) die("load: tpu X%i Y%i, label '%s' not defined", tpu->x, tpu->y, tpu->insts[i].ops[0].val.label); @@ -284,7 +284,8 @@ tis_load(struct tis *tis, const char *filepath) { struct asm_tokenizer tokenizer; struct tpu_inst_op op1, op2; - enum tpu_inst_type inst; + enum tpu_inst_type inst_type; + struct tpu_inst *inst; struct tpu *tpu = NULL; struct tpu_map_link *link; struct tpu_port *port; @@ -292,7 +293,8 @@ tis_load(struct tis *tis, const char *filepath) int stdin_x, stdin_y; int stdout_x, stdout_y; enum asm_tok tok, optok; - size_t i; + char instbuf[TPU_MAX_INST_LEN+1]; + size_t i, len; tis_deinit(tis); tis_init(tis); @@ -352,13 +354,13 @@ tis_load(struct tis *tis, const char *filepath) case TOK_JEZ: case TOK_JNZ: case TOK_JGZ: case TOK_JLZ: case TOK_JRO: if (!tpu) goto disallowed; - inst = tok_to_inst(tok); + inst_type = tok_to_inst(tok); optok = tok_next_in(&tokenizer, TOK_ACC, TOK_NIL, TOK_LEFT, TOK_RIGHT, TOK_UP, TOK_DOWN, TOK_ANY, TOK_LAST, TOK_LIT, TOK_NAME, TOK_NL, -1); if (optok == TOK_NL) { - if (!tpu_add_inst(tpu, inst, 0, op1, op2)) + if (!tpu_add_inst(tpu, inst_type, 0, op1, op2)) die("load: line %lu, invalid instruction", tokenizer.lineno-1); break; @@ -369,7 +371,7 @@ tis_load(struct tis *tis, const char *filepath) TOK_NIL, TOK_LEFT, TOK_RIGHT, TOK_UP, TOK_DOWN, TOK_ANY, TOK_LAST, TOK_LIT, TOK_NAME, TOK_NL, -1); if (optok == TOK_NL) { - if (!tpu_add_inst(tpu, inst, 1, op1, op2)) + if (!tpu_add_inst(tpu, inst_type, 1, op1, op2)) die("load: line %lu, invalid instruction", tokenizer.lineno-1); break; @@ -377,18 +379,35 @@ tis_load(struct tis *tis, const char *filepath) op2 = tok_to_op(&tokenizer, optok); tok_next_in(&tokenizer, TOK_NL, -1); - if (!tpu_add_inst(tpu, inst, 2, op1, op2)) - die("load: line %lu, invalid instruction", + + inst = tpu_add_inst(tpu, inst_type, 2, op1, op2); + if (!inst) die("load: line %lu, invalid instruction", + tokenizer.lineno-1); + + len = asm_print_inst(instbuf, sizeof(instbuf), inst); + if (len >= sizeof(instbuf)) + die("load: line %lu, inst too long", + tokenizer.lineno-1); + + if (tpu->inst_cnt + tpu->label_cnt > TPU_MAX_INST_CNT) + die("load: line %lu, line does not fit", tokenizer.lineno-1); break; case TOK_COMMENT: tok_next_in(&tokenizer, TOK_NL, -1); break; case TOK_LABEL: + if (strlen(tokenizer.tokstr) > TPU_MAX_INST_LEN - 1) + die("load: line %lu, label too long", + tokenizer.lineno); if (!label_map_add(&tpu->label_map, tokenizer.tokstr, tpu->inst_cnt)) die("load: line %lu, duplicate label (pos)", tokenizer.lineno); + tpu->label_cnt += 1; + if (tpu->inst_cnt + tpu->label_cnt > TPU_MAX_INST_CNT) + die("load: line %lu, line does not fit", + tokenizer.lineno); break; case TOK_NL: break; diff --git a/tis100 b/tis100 Binary files differ. diff --git a/tis100-curses b/tis100-curses Binary files differ. diff --git a/tis100-curses.c b/tis100-curses.c @@ -18,8 +18,8 @@ #define KEY_ESC 0x1b #define KEY_CTRL(c) ((c) & ~0x60) -#define TPU_INPUT_ROWS 14 -#define TPU_INPUT_COLS 20 +#define TPU_INPUT_ROWS 15 +#define TPU_INPUT_COLS 19 #define TPU_INFO_W 6 #define TPU_INFO_H 4 #define TPU_CNT 6 @@ -213,12 +213,14 @@ 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 + 2, y + 2, 0, "%03i", tpu->acc); + tui_draw_text(x + 1, y + 2, 0, + tpu->acc >= 0 ? " %03i" : "-%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 + 2, y + 2, 0, "%03i", tpu->bak); + tui_draw_text(x + 1, y + 2, 0, + tpu->bak >= 0 ? " %03i" : "-%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); @@ -240,7 +242,7 @@ tui_draw_tpu(struct tpu *tpu) tui_draw_text(x + 2, y + 2, 0, "%s", mode_repr[tpu->status]); tui_draw_box(x, (y += TPU_INFO_H - 1), w, h, attr, - WACS_D_LTEE, WACS_D_RTEE, WACS_D_BTEE, WACS_D_LRCORNER); + WACS_D_LTEE, WACS_D_RTEE, WACS_D_BTEE, WACS_D_RTEE); tui_draw_text(x + 2, y + 1, A_BOLD, "IDL"); if (tpu->steps > 0) idle = (int) ((double) tpu->idle_steps * 100 / (double) tpu->steps); @@ -248,6 +250,9 @@ tui_draw_tpu(struct tpu *tpu) idle = 100; tui_draw_text(x + 2, y + 2, 0, "%03i", idle); + tui_draw_box(x, (y += TPU_INFO_H - 1), w, 2, attr, + WACS_D_LTEE, WACS_D_RTEE, WACS_D_BTEE, WACS_D_LRCORNER); + if (tpu->ports[DIR_LEFT].attached) { port = &tpu->ports[DIR_LEFT]; if (port->in >= 0) diff --git a/tpu.c b/tpu.c @@ -62,7 +62,7 @@ djb_hash(const char *str) void label_map_init(struct label_map *map) { - memset(map->labels, 0, sizeof(char *) * TPU_MAX_INST); + memset(map->labels, 0, sizeof(char *) * TPU_MAX_INST_CNT); memset(map->buckets, 0, sizeof(void *) * LABEL_MAP_BUCKETS); } @@ -123,7 +123,7 @@ label_map_get(struct label_map *map, const char *name) struct label_map_link **link; link = label_map_link_pos(map, name); - if (!*link) return TPU_MAX_INST; + if (!*link) return TPU_MAX_INST_CNT; return (*link)->pc; } @@ -165,6 +165,7 @@ tpu_init(struct tpu *tpu) tpu->acc = 0; tpu->bak = 0; tpu->inst_cnt = 0; + tpu->label_cnt = 0; label_map_init(&tpu->label_map); tpu->last = -1; @@ -265,7 +266,7 @@ tpu_update_ports(struct tpu *tpu) } bool -tpu_set_inst(struct tpu *tpu, uint8_t pc, enum tpu_inst_type inst_type, +tpu_set_inst(struct tpu *tpu, int pc, enum tpu_inst_type inst_type, unsigned opcnt, struct tpu_inst_op op1, struct tpu_inst_op op2) { struct tpu_inst *inst; @@ -304,15 +305,17 @@ tpu_set_inst(struct tpu *tpu, uint8_t pc, enum tpu_inst_type inst_type, return true; } -bool +struct tpu_inst * tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst_type, unsigned opcnt, struct tpu_inst_op op1, struct tpu_inst_op op2) { - if (tpu->inst_cnt >= TPU_MAX_INST) + if (tpu->inst_cnt >= TPU_MAX_INST_CNT) die("tpu_add_inst: tpu X%i Y%i, >= max %i instructions", - tpu->x, tpu->y, TPU_MAX_INST); - return tpu_set_inst(tpu, (uint8_t) tpu->inst_cnt++, - inst_type, opcnt, op1, op2); + tpu->x, tpu->y, TPU_MAX_INST_CNT); + if (!tpu_set_inst(tpu, (uint8_t) tpu->inst_cnt, + inst_type, opcnt, op1, op2)) + return false; + return &tpu->insts[tpu->inst_cnt++]; } /* tpu can always write to an empty port (->out), but only @@ -354,7 +357,7 @@ tpu_jmp_label(struct tpu *tpu, const char *label) size_t pc; pc = label_map_get(&tpu->label_map, label); - if (pc >= TPU_MAX_INST) abort(); + if (pc >= TPU_MAX_INST_CNT) abort(); tpu->pc = (uint8_t) pc; } @@ -439,7 +442,7 @@ enum tpu_status tpu_exec(struct tpu *tpu, struct tpu_inst *inst) { enum tpu_status status; - uint8_t lit; + int lit; int val; switch (inst->type) { diff --git a/tpu.h b/tpu.h @@ -6,7 +6,8 @@ #define TPU_MAP_BUCKETS 64 #define LABEL_MAP_BUCKETS 64 -#define TPU_MAX_INST 256 +#define TPU_MAX_INST_CNT 15 +#define TPU_MAX_INST_LEN 18 /* enum order is important ! */ @@ -35,7 +36,7 @@ enum tpu_port_type { }; union tpu_inst_op_val { - uint8_t lit; + int lit; char *label; }; @@ -46,7 +47,7 @@ struct label_map_link { }; struct label_map { - char *labels[TPU_MAX_INST]; /* borrowed from label_map_links */ + char *labels[TPU_MAX_INST_CNT]; /* borrowed from label_map_links */ struct label_map_link *buckets[LABEL_MAP_BUCKETS]; }; @@ -82,11 +83,12 @@ struct tpu { size_t steps; size_t idle_steps; - uint8_t acc, bak; - uint8_t pc; + int acc, bak; + int pc; + struct label_map label_map; - struct tpu_inst insts[TPU_MAX_INST]; - size_t inst_cnt; + struct tpu_inst insts[TPU_MAX_INST_CNT]; + size_t inst_cnt, label_cnt; }; struct tpu_map_link { @@ -118,9 +120,9 @@ 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, +bool tpu_set_inst(struct tpu *tpu, int pc, enum tpu_inst_type inst, unsigned opcnt, struct tpu_inst_op op1, struct tpu_inst_op op2); -bool tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst, +struct tpu_inst *tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst, unsigned opcnt, struct tpu_inst_op op1, struct tpu_inst_op op2); void tpu_clear_ports(struct tpu *tpu); enum tpu_status tpu_exec_mov(struct tpu *tpu, struct tpu_inst *inst);