tis100

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

commit 238ac5ab6c47bfe0c9cda1490f97f2d7f5d3eaf6
parent 8ec5b039472f9fbe24f2eb1c5d8e66a7551a33fd
Author: Louis Burda <quent.burda@gmail.com>
Date:   Mon, 25 Dec 2023 16:49:51 +0100

Add support for prefix labels

Diffstat:
Masm.c | 70+++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mtis100-curses.c | 44+++++++++++++++++++++++---------------------
Mtpu.c | 22+++++++++++-----------
Mtpu.h | 16+++++++++++-----
4 files changed, 96 insertions(+), 56 deletions(-)

diff --git a/asm.c b/asm.c @@ -16,6 +16,9 @@ #define WHITESPACE " \t\v\r\n," enum asm_tok { + /* Missing */ + TOK_NONE = -1, + /* Global */ TOK_IN, TOK_OUT, TOK_TPU, TOK_END, @@ -28,13 +31,13 @@ enum asm_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_NL, TOK_EOF + TOK_COMMENT, TOK_LABEL, TOK_XPOS, TOK_YPOS, TOK_NL, TOK_EOF, }; struct asm_tokenizer { const char *filepath; FILE *file; - enum asm_tok tok; + enum asm_tok next; char *tokstr; size_t lineno, off; char linebuf[256]; @@ -204,10 +207,17 @@ asm_print_inst(char *buf, size_t n, struct tpu_inst *inst) static enum asm_tok tok_next(struct asm_tokenizer *tok) { + enum asm_tok v; size_t len; char *s; int i; + if (tok->next != TOK_NONE) { + v = tok->next; + tok->next = TOK_NONE; + return v; + } + if (!tok->linebuf[tok->off]) { if (feof(tok->file)) return TOK_EOF; s = fgets(tok->linebuf, sizeof(tok->linebuf), tok->file); @@ -333,7 +343,8 @@ tis_load_asm(struct tis *tis, const char *filepath) struct tpu_map_link *link; struct tpu_port *port; enum asm_tok tok, optok; - char instbuf[TPU_MAX_INST_LEN+1]; + char rowbuf[TPU_MAX_COLS+1]; + size_t colsused; int io_x, io_y; ssize_t i, k; size_t len; @@ -345,10 +356,13 @@ tis_load_asm(struct tis *tis, const char *filepath) tokenizer.file = fopen(filepath, "r"); if (!tokenizer.file) die("load: fopen '%s':", filepath); + tokenizer.next = TOK_NONE; tokenizer.lineno = 0; tokenizer.off = 0; tokenizer.tokstr = NULL; tokenizer.linebuf[tokenizer.off] = '\0'; + + colsused = 0; while ((tok = tok_next(&tokenizer)) != TOK_EOF) { switch (tok) { case TOK_IN: @@ -380,12 +394,15 @@ tis_load_asm(struct tis *tis, const char *filepath) io_y = atoi(tokenizer.tokstr + 1); tok_next_in(&tokenizer, TOK_NL, -1); - if (tok == TOK_IN) + if (tok == TOK_IN) { tpu_io_port_init(io_port, c, DIR_UP, PORT_IN, io_x, io_y); - else + } else { tpu_io_port_init(io_port, c, DIR_DOWN, PORT_OUT, io_x, io_y); + } + + colsused = 0; break; case TOK_TPU: if (tpu) goto disallowed; @@ -400,12 +417,14 @@ tis_load_asm(struct tis *tis, const char *filepath) if (!tpu_map_add(&tis->tpu_map, tpu)) die("load: duplicate tpu location X%i Y%i", tpu->x, tpu->y); + colsused = 0; break; case TOK_END: if (!tpu) goto disallowed; tpu_validate(tpu); tpu = NULL; tok_next_in(&tokenizer, TOK_NL, -1); + colsused = 0; 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: @@ -442,14 +461,17 @@ tis_load_asm(struct tis *tis, const char *filepath) 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", + tpu->rows += 1; + if (tpu->inst_cnt > TPU_MAX_INST_CNT || tpu->rows > TPU_MAX_ROWS) + die("load: line %lu, tpu has too many rows", tokenizer.lineno-1); - if (tpu->inst_cnt + tpu->label_cnt > TPU_MAX_INST_CNT) - die("load: line %lu, line does not fit", + len = asm_print_inst(rowbuf, sizeof(rowbuf), inst); + if (colsused + len > TPU_MAX_COLS) + die("load: line %lu, tpu row is too long", tokenizer.lineno-1); + + colsused = 0; break; case TOK_COMMENT: if (tpu && !strcmp(tokenizer.tokstr, "DISABLED")) @@ -457,19 +479,29 @@ tis_load_asm(struct tis *tis, const char *filepath) tok_next_in(&tokenizer, TOK_NL, -1); break; case TOK_LABEL: - if (strlen(tokenizer.tokstr) > TPU_MAX_INST_LEN - 1) + len = strlen(tokenizer.tokstr); + strncpy(rowbuf, tokenizer.tokstr, TPU_MAX_COLS); + optok = tok_next(&tokenizer); + if (!label_map_add(&tpu->label_map, rowbuf, + (int) tpu->inst_cnt, optok != TOK_NL)) + die("load: line %lu, duplicate label %s (pos)", + tokenizer.lineno, rowbuf); + if (optok == TOK_NL) { + tpu->rows += 1; + if (tpu->rows > TPU_MAX_ROWS) + die("load: line %lu, line does not fit", + tokenizer.lineno); + colsused = 0; + } else { + tokenizer.next = optok; + colsused = len + 1; + } + if (len + 1 > TPU_MAX_COLS) die("load: line %lu, label too long", tokenizer.lineno); - if (!label_map_add(&tpu->label_map, - tokenizer.tokstr, (int) 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: + colsused = 0; break; default: goto disallowed; diff --git a/tis100-curses.c b/tis100-curses.c @@ -18,12 +18,10 @@ #define KEY_ESC 0x1b #define KEY_CTRL(c) ((c) & ~0x60) -#define TPU_INPUT_ROWS 15 -#define TPU_INPUT_COLS 19 #define TPU_INFO_W 7 #define TPU_INFO_H 4 -#define TPU_W (1 + TPU_INPUT_COLS + TPU_INFO_W) -#define TPU_H (1 + TPU_INPUT_ROWS + 1) +#define TPU_W (1 + TPU_MAX_COLS + TPU_INFO_W) +#define TPU_H (1 + TPU_MAX_ROWS + 1) #define TIMEOUT 50 @@ -172,10 +170,11 @@ tui_draw_wch(int x, int y, attr_t attr, const cchar_t *c) static void tui_draw_tpu(struct tpu *tpu) { - char linebuf[TPU_INPUT_COLS + 1]; + char rowbuf[TPU_MAX_COLS + 1]; struct tpu_port *port; int sx, sy, x, y, w, h; - int off, start, inst; + int offx, offy, start, inst; + struct label *label; size_t len; attr_t attr; int idle; @@ -195,26 +194,29 @@ tui_draw_tpu(struct tpu *tpu) tui_draw_text(sx + 4, sy + 1 + 4, attr | A_BOLD, " FAILURE "); tui_draw_text(sx + 4, sy + 1 + 6, attr | A_REVERSE, " "); } else if (tpu->inst_cnt > 0) { - start = MAX(0, MIN(tpu->pc - 4, (int) tpu->inst_cnt - TPU_INPUT_ROWS)); + start = MAX(0, MIN(tpu->pc - 4, (int) tpu->inst_cnt - TPU_MAX_ROWS)); inst = start; - for (off = 0; off < TPU_INPUT_ROWS && inst < tpu->inst_cnt; ) { - if (tpu->label_map.labels[inst]) { - len = strlen(tpu->label_map.labels[inst]); - if (len > TPU_INPUT_COLS - 1) { - tui_draw_text(sx + 2, sy + 1 + off, A_DIM, - "%.*s..:", TPU_INPUT_COLS - 3, - tpu->label_map.labels[inst]); + for (offy = 0; offy < TPU_MAX_ROWS && inst < tpu->inst_cnt; ) { + asm_print_inst(rowbuf, sizeof(rowbuf), &tpu->insts[inst]); + label = &tpu->label_map.labels[inst]; + if (label->str) { + len = strlen(label->str); + tui_draw_text(sx + 1 + offx, sy + 1 + offy, + A_DIM, "%s:", label->str); + if (label->prefix) { + offx += (int) strlen(label->str) + 1; + if (offx + 1 + (int) strlen(rowbuf) <= TPU_MAX_COLS) + offx += 1; } else { - tui_draw_text(sx + 2, sy + 1 + off, A_DIM, - "%s:", tpu->label_map.labels[inst]); + offy += 1; } - off++; } - asm_print_inst(linebuf, sizeof(linebuf), &tpu->insts[inst]); - tui_draw_text(sx + 2, sy + 1 + off, + tui_draw_text(sx + 1 + offx, sy + 1 + offy, inst == tpu->pc ? A_STANDOUT | (tpu->idle ? A_DIM : 0) : 0, - "%-*.*s", TPU_INPUT_COLS, TPU_INPUT_COLS, linebuf); - inst++; off++; + "%-*.*s", TPU_MAX_COLS, TPU_MAX_COLS, rowbuf); + inst += 1; + offy += 1; + offx = 0; } } diff --git a/tpu.c b/tpu.c @@ -63,8 +63,7 @@ djb_hash(const char *str) void label_map_init(struct label_map *map) { - memset(map->labels, 0, sizeof(char *) * TPU_MAX_INST_CNT); - memset(map->buckets, 0, sizeof(void *) * LABEL_MAP_BUCKETS); + memset(map, 0, sizeof(struct label_map)); } void @@ -77,11 +76,13 @@ label_map_deinit(struct label_map *map) link = map->buckets[i]; while (link) { next = link->next; - free(link->label); free(link); link = next; } } + + for (i = 0; i < TPU_MAX_INST_CNT; i++) + free(map->labels[i].str); } static struct label_map_link ** @@ -90,31 +91,30 @@ label_map_link_pos(struct label_map *map, const char *name) struct label_map_link **link; link = &map->buckets[djb_hash(name) % LABEL_MAP_BUCKETS]; - while (*link && strcasecmp((*link)->label, name)) + while (*link && strcasecmp(map->labels[(*link)->pc].str, name)) link = &(*link)->next; return link; } bool -label_map_add(struct label_map *map, const char *name, int pc) +label_map_add(struct label_map *map, const char *name, int pc, bool prefix) { struct label_map_link **pos, *link; pos = label_map_link_pos(map, name); if (*pos) return false; - if (map->labels[pc]) return false; + if (map->labels[pc].str) return false; + map->labels[pc].str = strdup(name); + if (!map->labels[pc].str) die("strdup:"); + map->labels[pc].prefix = prefix; *pos = link = malloc(sizeof(struct label_map_link)); if (!link) die("malloc:"); - link->label = strdup(name); - if (!link->label) die("strdup:"); link->pc = pc; link->next = NULL; - map->labels[pc] = link->label; - return true; } @@ -217,7 +217,7 @@ tpu_init(struct tpu *tpu) tpu->acc = 0; tpu->bak = 0; tpu->inst_cnt = 0; - tpu->label_cnt = 0; + tpu->rows = 0; label_map_init(&tpu->label_map); tpu->last = -1; diff --git a/tpu.h b/tpu.h @@ -8,7 +8,8 @@ #define TPU_MAP_BUCKETS 64 #define LABEL_MAP_BUCKETS 64 #define TPU_MAX_INST_CNT 15 -#define TPU_MAX_INST_LEN 18 +#define TPU_MAX_ROWS 15 +#define TPU_MAX_COLS 18 #define TIS_MAX_IO_PORTS 36 /* what tpu will attempt next (order important) */ @@ -42,13 +43,18 @@ union tpu_inst_op_val { }; struct label_map_link { - char *label; int pc; + bool prefix; struct label_map_link *next; }; +struct label { + char *str; + bool prefix; +}; + struct label_map { - char *labels[TPU_MAX_INST_CNT]; /* borrowed from label_map_links */ + struct label labels[TPU_MAX_INST_CNT]; struct label_map_link *buckets[LABEL_MAP_BUCKETS]; }; @@ -98,7 +104,7 @@ struct tpu { struct label_map label_map; struct tpu_inst insts[TPU_MAX_INST_CNT]; - size_t inst_cnt, label_cnt; + size_t inst_cnt, rows; }; struct tpu_map_link { @@ -139,7 +145,7 @@ struct tis_stats { 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, int pc); +bool label_map_add(struct label_map *map, const char *name, int pc, bool prefix); int label_map_get(struct label_map *map, const char *name); void tpu_port_init(struct tpu_port *port, struct tpu *tpu);