tis100

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

commit 33995e119a16fbf13c51cf3a72a6cc52d70a75a8
parent 0f06ef7127b669207fd8f09b88ecb660b38eb971
Author: Louis Burda <quent.burda@gmail.com>
Date:   Wed, 26 Jul 2023 22:15:15 +0200

Add support for multiple input and output ports

Diffstat:
Masm.c | 180++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Masm.h | 3+--
Mtest.sh | 34++++++++++++++++++++++++----------
Mtest/jro.asm | 4++--
Rtest/jro.in -> test/jro.in.a | 0
Rtest/jro.out -> test/jro.out.a | 0
Mtest/ports.asm | 4++--
Dtest/ports.in | 4----
Rtest/jro.in -> test/ports.in.a | 0
Dtest/ports.out | 4----
Rtest/jro.in -> test/ports.out.a | 0
Mtis100-curses.c | 83+++++++++++++++++++++++++++----------------------------------------------------
Mtis100.c | 51++++++++++++++++++++++-----------------------------
Mtpu.c | 70+++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mtpu.h | 21++++++++++++++++++---
15 files changed, 270 insertions(+), 188 deletions(-)

diff --git a/asm.c b/asm.c @@ -5,6 +5,7 @@ #include <ctype.h> #include <stdarg.h> #include <stdbool.h> +#include <stdio.h> #include <string.h> #include <stdint.h> @@ -15,7 +16,7 @@ enum asm_tok { /* Global */ - TOK_STDIN, TOK_STDOUT, TOK_TPU, TOK_END, + TOK_IN, TOK_OUT, TOK_TPU, TOK_END, /* Operands (order like OP_*) */ TOK_ACC, TOK_NIL, TOK_LEFT, TOK_RIGHT, TOK_UP, TOK_DOWN, @@ -40,7 +41,7 @@ struct asm_tokenizer { static const char *tok_strs[] = { /* Global */ - "stdin", "stdout", "tpu", "end", + NULL, NULL, "tpu", "end", /* Operands (order like OP_*) */ "acc", "nil", "left", "right", "up", "down", @@ -56,15 +57,15 @@ static const char *tok_strs[] = { static const char *tok_reprs[] = { /* Global */ - "'STDIN'", "'STDOUT'", "'TPU'", "'END'", + "IN.<C>", "OUT.<C>", "TPU", "END", /* Operands (order like OP_*) */ - "'ACC'", "'NIL'", "'LEFT'", "'RIGHT'", "'UP'", "'DOWN'", - "'ANY'", "'LAST'", "<LIT>", "<NAME>", + "ACC", "NIL", "LEFT", "RIGHT", "UP", "DOWN", + "ANY", "LAST", "<LIT>", "<NAME>", /* Instructions (order like INST_*) */ - "'NOP'", "'MOV'", "'SWP'", "'SAV'", "'ADD'", "'SUB'", - "'NEG'", "'JMP'", "'JEZ'", "'JNZ'", "'JGZ'", "'JLZ'", "'JRO'", + "NOP", "MOV", "SWP", "SAV", "ADD", "SUB", + "NEG", "JMP", "JEZ", "JNZ", "JGZ", "JLZ", "JRO", /* Misc */ "#<COMMENT>", "<LABEL>:", "X<INT>", "Y<INT>", "<NL>", "<EOF>" @@ -83,7 +84,15 @@ is_int(const char *str) return true; } -bool +static int +asm_port_char_to_index(char c) +{ + if (!isalpha(c)) + die("invalid io port char '%c'", c); + return tolower(c) - 'a'; +} + +static bool asm_is_lit(const char *str) { const char *c; @@ -95,7 +104,7 @@ asm_is_lit(const char *str) return !*c; } -int +static int asm_str_to_lit(const char *str) { int m, v, b, i, o; @@ -159,11 +168,11 @@ tok_to_op(struct asm_tokenizer *tokenizer, enum asm_tok tok) static size_t strlcat_op_name(char *buf, struct tpu_inst_op *op, size_t n) { - char hhbuf[5]; + char tmp[5]; if (op->type == OP_LIT) { - snprintf(hhbuf, 5, "%i", op->val.lit); - return strdcat(buf, hhbuf, n); + snprintf(tmp, 5, "%i", op->val.lit); + return strdcat(buf, tmp, n); } else if (op->type == OP_LABEL) { return strdcat(buf, op->val.label, n); } else { @@ -231,7 +240,11 @@ tok_next(struct asm_tokenizer *tok) return (enum asm_tok) i; } - if (asm_is_lit(s)) { + if (!strncasecmp(s, "in.", 3) && len == 4) { + return TOK_IN; + } else if (!strncasecmp(s, "out.", 4) && len == 5) { + return TOK_OUT; + } else if (asm_is_lit(s)) { return TOK_LIT; } else if (*s == '#') { tok->off += strlen(tok->linebuf + tok->off); @@ -307,6 +320,7 @@ tpu_validate(struct tpu *tpu) void tis_load(struct tis *tis, const char *filepath) { + struct tpu_io_port *io_port; struct asm_tokenizer tokenizer; struct tpu_inst_op op1, op2; enum tpu_inst_type inst_type; @@ -314,18 +328,16 @@ tis_load(struct tis *tis, const char *filepath) struct tpu *tpu = NULL; struct tpu_map_link *link; struct tpu_port *port; - bool stdin_set, stdout_set; - int stdin_x, stdin_y; - int stdout_x, stdout_y; enum asm_tok tok, optok; char instbuf[TPU_MAX_INST_LEN+1]; - size_t i, len; + int io_x, io_y; + ssize_t i, k; + size_t len; + char c; tis_deinit(tis); tis_init(tis); - stdin_set = stdout_set = false; - tokenizer.filepath = filepath; tokenizer.file = fopen(filepath, "r"); if (!tokenizer.file) die("load: fopen '%s':", filepath); @@ -336,23 +348,41 @@ tis_load(struct tis *tis, const char *filepath) tokenizer.linebuf[tokenizer.off] = '\0'; while ((tok = tok_next(&tokenizer)) != TOK_EOF) { switch (tok) { - case TOK_STDIN: - if (tpu || stdin_set) goto disallowed; - tok_next_in(&tokenizer, TOK_XPOS, -1); - stdin_x = atoi(tokenizer.tokstr + 1); - tok_next_in(&tokenizer, TOK_YPOS, -1); - stdin_y = atoi(tokenizer.tokstr + 1); - tok_next_in(&tokenizer, TOK_NL, -1); - stdin_set = true; - break; - case TOK_STDOUT: - if (tpu || stdout_set) goto disallowed; + case TOK_IN: + case TOK_OUT: + if (tpu) goto disallowed; + + io_port = malloc(sizeof(struct tpu_io_port)); + if (!io_port) die("malloc:"); + + len = strlen(tokenizer.tokstr); + c = tokenizer.tokstr[len-1]; + k = asm_port_char_to_index(c); + + if (tok == TOK_IN) { + if (tis->in_ports[k]) + die("load: line %lu, duplicate in.%c", + tokenizer.lineno, c); + tis->in_ports[k] = io_port; + } else { + if (tis->out_ports[k]) + die("load: loute %lu, duplicate out.%c", + tokenizer.lineno, c); + tis->out_ports[k] = io_port; + } + tok_next_in(&tokenizer, TOK_XPOS, -1); - stdout_x = atoi(tokenizer.tokstr + 1); + io_x = atoi(tokenizer.tokstr + 1); tok_next_in(&tokenizer, TOK_YPOS, -1); - stdout_y = atoi(tokenizer.tokstr + 1); + io_y = atoi(tokenizer.tokstr + 1); tok_next_in(&tokenizer, TOK_NL, -1); - stdout_set = true; + + if (tok == TOK_IN) + tpu_io_port_init(io_port, c, DIR_UP, + PORT_IN, io_x, io_y); + else + tpu_io_port_init(io_port, c, DIR_DOWN, + PORT_OUT, io_x, io_y); break; case TOK_TPU: if (tpu) goto disallowed; @@ -445,41 +475,37 @@ tis_load(struct tis *tis, const char *filepath) for (link = tis->tpu_map.buckets[i]; link; link = link->next) { tpu_init_ports(link->tpu, &tis->tpu_map); - if (stdin_set && link->x == stdin_x && link->y == stdin_y) { - port = &link->tpu->ports[DIR_UP]; - if (port->attached) - die("load: stdin port in use"); + for (k = -TIS_MAX_IO_PORTS; k < TIS_MAX_IO_PORTS; k++) { + io_port = k < 0 ? tis->in_ports[-k-1] + : tis->out_ports[k]; + if (!io_port || io_port->port.attached) continue; + if (link->tpu->x != io_port->x) continue; + if (link->tpu->y != io_port->y) continue; + port = &link->tpu->ports[io_port->dir]; + if (port->attached) { + die("load: io_port X%i Y%i (%s) busy", + io_port->x, io_port->y, + dir_reprs[io_port->dir]); + } port->attached = true; port->dst_tpu = NULL; - port->dst_port = &tis->stdin_port; - port->type = PORT_IN; - tis->stdin_port.attached = true; - tis->stdin_port.dst_tpu = link->tpu; - tis->stdin_port.dst_port = port; - } - - if (stdout_set && 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 = &tis->stdout_port; - port->type = PORT_OUT; - tis->stdout_port.attached = true; - tis->stdout_port.dst_tpu = link->tpu; - tis->stdout_port.dst_port = port; + port->dst_port = &io_port->port; + port->type = io_port->type; + io_port->port.attached = true; + io_port->port.dst_tpu = link->tpu; + io_port->port.dst_port = port; } } } - if (stdin_set && !tis->stdin_port.attached) - die("load: stdin tpu (X%i Y%i) not found", - stdin_x, stdin_y); - - if (stdout_set && !tis->stdout_port.attached) - die("load: stdout tpu (X%i Y%i) not found", - stdout_x, stdout_y); + for (i = -TIS_MAX_IO_PORTS; i < TIS_MAX_IO_PORTS; i++) { + io_port = i < 0 ? tis->in_ports[-i-1] : tis->out_ports[i]; + if (io_port && !io_port->port.attached) { + die("load: io_port X%i Y%i (%s) not found", + io_port->x, io_port->y, + dir_reprs[io_port->dir]); + } + } fclose(tokenizer.file); @@ -494,3 +520,33 @@ disallowed: tokenizer.lineno, tok_reprs[tok]); } } + +void +tis_load_io(struct tis *tis, const char **argv) +{ + const char **arg; + int n, i; + char c; + + for (arg = argv; *arg; arg++) { + if (sscanf(*arg, "--in.%c%n", &c, &n) == 1 && n == 6) { + i = asm_port_char_to_index(c); + if (!tis->in_ports[i]) + die("in.%c io port not initialized", c); + tis->in_ports[i]->file = fopen(*++arg, "r"); + if (!tis->in_ports[i]->file) + die("fopen '%s':", *arg); + setvbuf(tis->in_ports[i]->file, NULL, _IONBF, 0); + } else if (sscanf(*arg, "--out.%c%n", &c, &n) == 1 && n == 7) { + i = asm_port_char_to_index(c); + if (!tis->out_ports[i]) + die("out.%c io port not initialized", c); + tis->out_ports[i]->file = fopen(*++arg, "w+"); + if (!tis->out_ports[i]->file) + die("fopen '%s':", *arg); + setvbuf(tis->out_ports[i]->file, NULL, _IONBF, 0); + } else { + die("parse: unknown cmdline option '%s'", *arg); + } + } +} diff --git a/asm.h b/asm.h @@ -4,7 +4,6 @@ #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); +void tis_load_io(struct tis *tis, const char **argv); diff --git a/test.sh b/test.sh @@ -1,16 +1,30 @@ -#!/bin/sh - +#!/bin/bash for f in test/*.asm; do - in="$(echo "$f" | cut -d. -f1).in" - out="$(echo "$f" | cut -d. -f1).out" - tmp="/tmp/tis-test.out" - ./tis100 "$f" "$in" "$tmp" + base=$(echo "$f" | cut -d. -f1) + args="" + for i in $base.in.*; do + c=$(echo "$i" | cut -d. -f3) + args="$args --in.$c $i" + done + for i in $base.out.*; do + c=$(echo "$i" | cut -d. -f3) + args="$args --out.$c /tmp/tis100-test.out.$c" + done + ./tis100 "$f" $args if [ $? -ne 0 ]; then echo "$f" - elif ! diff "$out" "$tmp"; then - cat "$tmp" | xxd 1>&2 - cat "$out" | xxd 1>&2 - echo "$f" + else + bad=0 + for c in "abcdefghijklmnopqrstuvwyxz"; do + out="$base.in.$c" + tmp="/tmp/tis100-test.out.$c" + if [ -e "$out" -a -e "$tmp" ] && ! diff "$out" "$tmp"; then + cat "$tmp" | xxd 1>&2 + cat "$out" | xxd 1>&2 + bad=1 + fi + done + [ $bad -ne 0 ] && echo "$f" fi done diff --git a/test/jro.asm b/test/jro.asm @@ -1,5 +1,5 @@ -stdin X1 Y1 -stdout X1 Y1 +in.a X1 Y1 +out.a X1 Y1 tpu X1 Y1 mov UP, ACC diff --git a/test/jro.in b/test/jro.in.a diff --git a/test/jro.out b/test/jro.out.a diff --git a/test/ports.asm b/test/ports.asm @@ -1,5 +1,5 @@ -stdin X1 Y1 -stdout X3 Y2 +in.a X1 Y1 +out.a X3 Y2 tpu X1 Y1 mov UP, RIGHT diff --git a/test/ports.in b/test/ports.in @@ -1,4 +0,0 @@ -1 -99 --123 -1000 diff --git a/test/jro.in b/test/ports.in.a diff --git a/test/ports.out b/test/ports.out @@ -1,4 +0,0 @@ -1 -99 --123 -1000 diff --git a/test/jro.in b/test/ports.out.a diff --git a/tis100-curses.c b/tis100-curses.c @@ -52,8 +52,6 @@ static int scrw = 80; static int scrh = 40; static struct tis tis; -static FILE *tis_stdin = NULL; -static FILE *tis_stdout = NULL; static int show_reloaded = 0; @@ -62,7 +60,7 @@ static enum input_mode input_mode = MAIN; static struct tpu *tpu_sel = NULL; int (*cleanup)(void) = endwin; -const char *progname = "tis-curses"; +const char *progname = "tis100-curses"; static enum tpu_port_dir key_to_dir(int key) @@ -156,6 +154,16 @@ tui_draw_text(int x, int y, attr_t attr, const char *fmt, ...) } static void +tui_draw_lit(int x, int y, attr_t attr, int lit) +{ + char buf[6]; + + snprintf(buf, 5, "%03i", lit); + if (buf[0] != '-') x += 1; + tui_draw_text(x, y, attr, "%.*s", 4, buf); +} + +static void tui_draw_wch(int x, int y, attr_t attr, const cchar_t *c) { attron(attr); @@ -213,12 +221,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 + (tpu->acc >= 0), y + 2, 0, "%03i", tpu->acc); + tui_draw_lit(x + 1, y + 2, 0, 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 + (tpu->bak >= 0), y + 2, 0, "%03i", tpu->bak); + tui_draw_lit(x + 1, y + 2, 0, 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); @@ -254,8 +262,7 @@ tui_draw_tpu(struct tpu *tpu) if (tpu->ports[DIR_LEFT].attached) { port = &tpu->ports[DIR_LEFT]; if (port->in_set) - tui_draw_text(sx - 3, sy + 6, - A_BOLD, "%03i", port->in); + tui_draw_lit(sx - 4, sy + 6, A_BOLD, port->in); if (port->type & PORT_IN) tui_draw_wch(sx - 1, sy + 7, port->in_set ? A_BOLD : 0, WACS_RARROW); @@ -263,15 +270,13 @@ tui_draw_tpu(struct tpu *tpu) tui_draw_wch(sx - 1, sy + 8, port->out_set ? A_BOLD : 0, WACS_LARROW); if (port->out_set) - tui_draw_text(sx - 3, sy + 10, - A_BOLD, "%03i", port->out); + tui_draw_lit(sx - 4, sy + 10, A_BOLD, port->out); } if (tpu->ports[DIR_RIGHT].attached) { port = &tpu->ports[DIR_RIGHT]; if (port->out_set) - tui_draw_text(sx + TPU_W + 1, sy + 5, - A_BOLD, "%03i", port->out); + tui_draw_lit(sx + TPU_W, sy + 5, A_BOLD, port->out); if (port->type & PORT_OUT) tui_draw_wch(sx + TPU_W + 1, sy + 7, port->out_set ? A_BOLD : 0, WACS_RARROW); @@ -279,15 +284,13 @@ tui_draw_tpu(struct tpu *tpu) tui_draw_wch(sx + TPU_W + 1, sy + 8, 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); + tui_draw_lit(sx + TPU_W, sy + 9, A_BOLD, port->in); } if (tpu->ports[DIR_UP].attached) { port = &tpu->ports[DIR_UP]; if (port->out_set) - tui_draw_text(sx + 9, sy - 1, - A_BOLD, "%03i", port->out); + tui_draw_lit(sx + 8, sy - 1, A_BOLD, port->out); if (port->type & PORT_OUT) tui_draw_wch(sx + 13, sy - 1, port->out_set ? A_BOLD : 0, WACS_UARROW); @@ -295,15 +298,13 @@ tui_draw_tpu(struct tpu *tpu) tui_draw_wch(sx + 15, sy - 1, port->in_set ? A_BOLD : 0, WACS_DARROW); if (port->in_set) - tui_draw_text(sx + 17, sy - 1, - A_BOLD, "%03i", port->in); + tui_draw_lit(sx + 16, sy - 1, A_BOLD, port->in); } if (tpu->ports[DIR_DOWN].attached) { port = &tpu->ports[DIR_DOWN]; if (port->in_set) - tui_draw_text(sx + 9, sy + TPU_H, - A_BOLD, "%03i", port->in); + tui_draw_lit(sx + 8, sy + TPU_H, A_BOLD, port->in); if (port->type & PORT_IN) tui_draw_wch(sx + 13, sy + TPU_H, port->in_set ? A_BOLD : 0, WACS_UARROW); @@ -311,8 +312,7 @@ tui_draw_tpu(struct tpu *tpu) tui_draw_wch(sx + 15, sy + TPU_H, 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); + tui_draw_lit(sx + 16, sy + TPU_H, A_BOLD, port->out); } } @@ -405,7 +405,7 @@ handlekey(int key) scrx += 4; break; case 's': - tis_communicate(&tis, tis_stdin, tis_stdout); + tis_communicate(&tis); tis_step(&tis); break; } @@ -441,37 +441,21 @@ first_tpu(void) } static void -reset(int ifd, int argc, char **argv, bool watch) +reset(int ifd, int argc, const char **argv, bool watch) { tis_load(&tis, argv[1]); + tis_load_io(&tis, argv + 2); if (watch) if (inotify_add_watch(ifd, argv[1], IN_MODIFY) < 0) die("inotify_add_watch '%s':", argv[1]); - if (argc >= 3) { - if (tis_stdin) fclose(tis_stdin); - tis_stdin = fopen(argv[2], "r"); - if (!tis_stdin) die("fopen '%s':", argv[2]); - } - - if (argc >= 4) { - if (tis_stdout) fclose(tis_stdout); - tis_stdout = fopen(argv[3], "w+"); - if (!tis_stdout) die("fopen '%s':", argv[3]); - } - - if (tis.stdin_port.attached) { - tpu_sel = tis.stdin_port.dst_tpu; - } else { - tpu_sel = first_tpu(); - } + tpu_sel = first_tpu(); tui_seek(NULL, MID, MID); - } int -main(int argc, char **argv) +main(int argc, const char **argv) { struct inotify_event event; ssize_t len; @@ -479,8 +463,8 @@ main(int argc, char **argv) int key; int ifd; - if (argc < 2 || argc > 4) { - fprintf(stderr, "Usage: tis-curses FILE [STDIN] [STDOUT]\n"); + if (argc < 2) { + fprintf(stderr, "Usage: tis100-curses FILE [IO..]\n"); exit(1); } @@ -525,14 +509,6 @@ main(int argc, char **argv) case 'h': tui_seek(NULL, MID, MID); break; - case 'i': - if (tis.stdin_port.attached) - tui_seek(tis.stdin_port.dst_tpu, MID, MID); - break; - case 'o': - if (tis.stdout_port.attached) - tui_seek(tis.stdout_port.dst_tpu, MID, MID); - break; case 'r': reset(ifd, argc, argv, false); break; @@ -549,8 +525,5 @@ main(int argc, char **argv) close(ifd); - if (tis_stdin) fclose(tis_stdin); - if (tis_stdout) fclose(tis_stdout); - endwin(); } diff --git a/tis100.c b/tis100.c @@ -11,55 +11,48 @@ #include <stdlib.h> static struct tis tis; -static FILE *tis_stdin = NULL; -static FILE *tis_stdout = NULL; int (*cleanup)(void) = NULL; -const char *progname = "tis-as"; +const char *progname = "tis100"; + +static bool +io_active(struct tis *tis) +{ + struct tpu_io_port *io_port; + int i; + + for (i = 0; i < TIS_MAX_IO_PORTS; i++) { + io_port = tis->in_ports[i]; + if (!io_port || !io_port->file) continue; + if (!feof(io_port->file) && io_port->port.attached + && io_port->port.dst_port->reading) + return true; + } + return false; +} int main(int argc, const char **argv) { bool idle, prev_idle; - if (argc < 2 || argc > 4) { - fprintf(stderr, "Usage: tis-as FILE [STDIN] [STDOUT]\n"); + if (argc < 2) { + fprintf(stderr, "Usage: tis100 FILE [IO..]\n"); exit(1); } - if (argc >= 3) { - tis_stdin = fopen(argv[2], "r"); - if (!tis_stdin) die("fopen '%s':", argv[2]); - } else { - tis_stdin = stdin; - } - setvbuf(tis_stdin, NULL, _IONBF, 0); - - if (argc >= 4) { - tis_stdout = fopen(argv[3], "w+"); - if (!tis_stdout) die("fopen '%s':", argv[3]); - } else { - tis_stdout = stdout; - } - setvbuf(tis_stdout, NULL, _IONBF, 0); - tis_init(&tis); tis_load(&tis, argv[1]); + tis_load_io(&tis, argv + 2); - tis.stdin_port.out = -1; idle = false; - while (!idle || !prev_idle || tis.stdin_port.attached - && tis.stdin_port.reading && !feof(tis_stdin)) { - tis_communicate(&tis, tis_stdin, tis_stdout); - + while (!idle || !prev_idle || io_active(&tis)) { + tis_communicate(&tis); prev_idle = idle; idle = !tis_step(&tis); } - fclose(tis_stdin); - fclose(tis_stdout); - tis_deinit(&tis); } diff --git a/tpu.c b/tpu.c @@ -151,6 +151,26 @@ tpu_port_deinit(struct tpu_port *port) } void +tpu_io_port_init(struct tpu_io_port *io_port, char c, enum tpu_port_dir dir, + enum tpu_port_type type, int x, int y) +{ + tpu_port_init(&io_port->port); + io_port->type = type; + io_port->file = NULL; + io_port->dir = dir; + io_port->c = c; + io_port->x = x; + io_port->y = y; +} + +void +tpu_io_port_deinit(struct tpu_io_port *io_port) +{ + tpu_port_deinit(&io_port->port); + if (io_port->file) fclose(io_port->file); +} + +void tpu_init(struct tpu *tpu) { size_t i; @@ -611,16 +631,26 @@ void tis_init(struct tis *tis) { tpu_map_init(&tis->tpu_map); - tpu_port_init(&tis->stdin_port); - tpu_port_init(&tis->stdout_port); + memset(&tis->in_ports, 0, TIS_MAX_IO_PORTS * sizeof(void *)); + memset(&tis->out_ports, 0, TIS_MAX_IO_PORTS * sizeof(void *)); } void tis_deinit(struct tis *tis) { + int i; + tpu_map_deinit(&tis->tpu_map); - tpu_port_deinit(&tis->stdin_port); - tpu_port_deinit(&tis->stdout_port); + for (i = 0; i < TIS_MAX_IO_PORTS; i++) { + if (tis->in_ports[i]) { + tpu_io_port_deinit(tis->in_ports[i]); + free(tis->in_ports[i]); + } + if (tis->out_ports[i]) { + tpu_io_port_deinit(tis->out_ports[i]); + free(tis->out_ports[i]); + } + } } bool @@ -647,27 +677,37 @@ tis_step(struct tis *tis) } void -tis_communicate(struct tis *tis, FILE *tis_stdin, FILE *tis_stdout) +tis_communicate(struct tis *tis) { + struct tpu_io_port *io_port; 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))) { + int val, i; + + for (i = 0; i < TIS_MAX_IO_PORTS; i++) { + io_port = tis->in_ports[i]; + if (!io_port) continue; + if (!io_port->port.attached || io_port->port.out_set) + continue; + if (!io_port->file) continue; + while ((s = fgets(buf, sizeof(buf), io_port->file))) { 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; + io_port->port.out = val; + io_port->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; + for (i = 0; i < TIS_MAX_IO_PORTS; i++) { + io_port = tis->out_ports[i]; + if (!io_port) continue; + if (!io_port->port.attached || !io_port->port.in_set) + continue; + if (io_port->file) + fprintf(io_port->file, "%i\n", io_port->port.in); + io_port->port.in_set = false; } } diff --git a/tpu.h b/tpu.h @@ -9,6 +9,7 @@ #define LABEL_MAP_BUCKETS 64 #define TPU_MAX_INST_CNT 15 #define TPU_MAX_INST_LEN 18 +#define TIS_MAX_IO_PORTS 26 /* enum order is important ! */ @@ -103,10 +104,19 @@ struct tpu_map { struct tpu_map_link *buckets[TPU_MAP_BUCKETS]; }; +struct tpu_io_port { + struct tpu_port port; + enum tpu_port_dir dir; + enum tpu_port_type type; + FILE *file; + int x, y; + char c; +}; + struct tis { struct tpu_map tpu_map; - struct tpu_port stdin_port; - struct tpu_port stdout_port; + struct tpu_io_port *in_ports[26]; + struct tpu_io_port *out_ports[26]; }; void label_map_init(struct label_map *map); @@ -117,6 +127,11 @@ int label_map_get(struct label_map *map, const char *name); void tpu_port_init(struct tpu_port *port); void tpu_port_deinit(struct tpu_port *port); +void tpu_io_port_init(struct tpu_io_port *io_port, char c, + enum tpu_port_dir dir, enum tpu_port_type type, int x, int y); +void tpu_io_port_deinit(struct tpu_io_port *io_port); +void tpu_io_port_attach(struct tpu_io_port *io_port, FILE *file); + void tpu_init(struct tpu *tpu); void tpu_deinit(struct tpu *tpu); struct tpu_inst *tpu_current_inst(struct tpu *tpu); @@ -139,7 +154,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); +void tis_communicate(struct tis *tis); extern const char *dir_reprs[]; extern const char *status_reprs[];