diff options
| author | Louis Burda <quent.burda@gmail.com> | 2023-07-26 22:15:15 +0200 |
|---|---|---|
| committer | Louis Burda <quent.burda@gmail.com> | 2023-07-26 22:15:15 +0200 |
| commit | 33995e119a16fbf13c51cf3a72a6cc52d70a75a8 (patch) | |
| tree | 872cb861564b452468954639851635410d714697 /asm.c | |
| parent | 0f06ef7127b669207fd8f09b88ecb660b38eb971 (diff) | |
| download | tis100-33995e119a16fbf13c51cf3a72a6cc52d70a75a8.tar.gz tis100-33995e119a16fbf13c51cf3a72a6cc52d70a75a8.zip | |
Add support for multiple input and output ports
Diffstat (limited to 'asm.c')
| -rw-r--r-- | asm.c | 180 |
1 files changed, 118 insertions, 62 deletions
@@ -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); + } + } +} |
