commit 5ff5bb25cc864e7fa06aa8fed0c4ec92e99f103a
parent 70d48f0db2ff618436df7c8c52ead5a0701fd7ab
Author: Louis Burda <quent.burda@gmail.com>
Date: Mon, 25 Dec 2023 01:46:55 +0100
Make mode/state behaviour compatible with game
Diffstat:
M | asm.c | | | 40 | +++++++++++++++++++++++++++++----------- |
M | asm.h | | | 4 | ++-- |
M | tis100-curses.c | | | 88 | ++++++++++++++++++++++++++++++++++++++++++++----------------------------------- |
M | tis100.c | | | 21 | ++++++++++++++++----- |
M | tpu.c | | | 256 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
M | tpu.h | | | 47 | ++++++++++++++++++++++++++++++++--------------- |
6 files changed, 286 insertions(+), 170 deletions(-)
diff --git a/asm.c b/asm.c
@@ -250,6 +250,7 @@ tok_next(struct asm_tokenizer *tok)
} else if (asm_is_lit(s)) {
return TOK_LIT;
} else if (*s == '#') {
+ tok->tokstr = tok->linebuf + tok->off;
tok->off += strlen(tok->linebuf + tok->off);
return TOK_COMMENT;
} else if (len && strchr(TEXTALPH, *s)
@@ -321,7 +322,7 @@ tpu_validate(struct tpu *tpu)
}
void
-tis_load(struct tis *tis, const char *filepath)
+tis_load_asm(struct tis *tis, const char *filepath)
{
struct tpu_io_port *io_port;
struct asm_tokenizer tokenizer;
@@ -338,9 +339,6 @@ tis_load(struct tis *tis, const char *filepath)
size_t len;
char c;
- tis_deinit(tis);
- tis_init(tis);
-
tokenizer.filepath = filepath;
tokenizer.file = fopen(filepath, "r");
if (!tokenizer.file) die("load: fopen '%s':", filepath);
@@ -452,6 +450,8 @@ tis_load(struct tis *tis, const char *filepath)
tokenizer.lineno-1);
break;
case TOK_COMMENT:
+ if (tpu && !strcmp(tokenizer.tokstr, "DISABLED"))
+ tpu->disabled = true;
tok_next_in(&tokenizer, TOK_NL, -1);
break;
case TOK_LABEL:
@@ -459,7 +459,7 @@ tis_load(struct tis *tis, const char *filepath)
die("load: line %lu, label too long",
tokenizer.lineno);
if (!label_map_add(&tpu->label_map,
- tokenizer.tokstr, tpu->inst_cnt))
+ tokenizer.tokstr, (int) tpu->inst_cnt))
die("load: line %lu, duplicate label (pos)",
tokenizer.lineno);
tpu->label_cnt += 1;
@@ -491,11 +491,9 @@ tis_load(struct tis *tis, const char *filepath)
dir_reprs[io_port->dir]);
}
port->attached = true;
- port->dst_tpu = NULL;
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;
}
}
@@ -525,13 +523,35 @@ disallowed:
}
void
-tis_load_io(struct tis *tis, const char **argv)
+tis_load(struct tis *tis, const char **argv)
{
const char **arg;
int n, i;
char c;
- for (arg = argv; *arg; arg++) {
+ if (!*argv) die("missing argv[0]");
+
+ for (arg = argv + 1; *arg; arg++) {
+ if (!strcmp(*arg, "-h") || !strcmp(*arg, "--help")) {
+ fprintf(stderr, "Usage: %s [-h] [-s] "
+ "[--in.X IN].. [--out.X OUT].. ASM\n", argv[0]);
+ } else if (!strcmp(*arg, "-s") || !strcmp(*arg, "--stats")) {
+ tis->show_stats = true;
+ } else if (sscanf(*arg, "--in.%c%n", &c, &n) == 1 && n == 6) {
+ /* after tis_load_asm.. */
+ arg++;
+ } else if (sscanf(*arg, "--out.%c%n", &c, &n) == 1 && n == 7) {
+ /* after tis_load_asm.. */
+ arg++;
+ } else {
+ if (tis->asm_init)
+ die("multiple asm files");
+ tis_load_asm(tis, *arg);
+ tis->asm_init = true;
+ }
+ }
+
+ for (arg = argv + 1; *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])
@@ -548,8 +568,6 @@ tis_load_io(struct tis *tis, const char **argv)
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
@@ -5,5 +5,5 @@
#include <stdio.h>
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);
+void tis_load_asm(struct tis *tis, const char *filepath);
+void tis_load(struct tis *tis, const char **argv);
diff --git a/tis100-curses.c b/tis100-curses.c
@@ -37,8 +37,8 @@ enum {
};
enum {
- COLOR_HEADING,
- COLOR_VAL
+ THEME_DEFAULT,
+ THEME_DISABLED
};
static const char *mode_repr[] = {
@@ -182,6 +182,7 @@ tui_draw_tpu(struct tpu *tpu)
int idle;
attr = (tpu_sel == tpu && input_mode == TPU_NAV) ? A_BOLD : 0;
+ attr |= tpu->disabled ? COLOR_PAIR(THEME_DISABLED) : COLOR_PAIR(THEME_DEFAULT);
sx = tpu_pos_x(tpu);
sy = tpu_pos_y(tpu);
@@ -189,7 +190,12 @@ tui_draw_tpu(struct tpu *tpu)
WACS_D_ULCORNER, WACS_D_URCORNER,
WACS_D_LLCORNER, WACS_D_LRCORNER);
- if (tpu->inst_cnt > 0) {
+ if (tpu->disabled) {
+ tui_draw_text(sx + 4, sy + 1 + 1, attr | A_REVERSE, " ");
+ tui_draw_text(sx + 4, sy + 1 + 3, attr | A_BOLD, "COMMUNICATION");
+ 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));
inst = start;
for (off = 0; off < TPU_INPUT_ROWS && inst < tpu->inst_cnt; ) {
@@ -219,98 +225,98 @@ tui_draw_tpu(struct tpu *tpu)
h = TPU_INFO_H;
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_lit(x + 1, y + 2, 0, tpu->acc);
+ tui_draw_text(x + 2, y + 1, attr | A_BOLD, "ACC");
+ tui_draw_lit(x + 1, y + 2, attr, 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_lit(x + 1, y + 2, 0, tpu->bak);
+ tui_draw_text(x + 2, y + 1, attr | A_BOLD, "BAK");
+ tui_draw_lit(x + 1, y + 2, attr, 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);
- tui_draw_text(x + 2, y + 1, A_BOLD, "LST");
+ tui_draw_text(x + 2, y + 1, attr | A_BOLD, "LST");
if (tpu->last < 0) {
- tui_draw_text(x + 2, y + 2, 0, "N/A");
+ tui_draw_text(x + 2, y + 2, attr, "N/A");
} else {
- tui_draw_wch(x + 2, y + 2, 0,
+ tui_draw_wch(x + 2, y + 2, attr,
dir_to_arrow((enum tpu_port_dir) tpu->last));
- tui_draw_wch(x + 3, y + 2, 0,
+ tui_draw_wch(x + 3, y + 2, attr,
dir_to_arrow((enum tpu_port_dir) tpu->last));
- tui_draw_wch(x + 4, y + 2, 0,
+ tui_draw_wch(x + 4, y + 2, attr,
dir_to_arrow((enum tpu_port_dir) tpu->last));
}
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, "MOD");
- tui_draw_text(x + 2, y + 2, 0, "%s", mode_repr[tpu->status]);
+ tui_draw_text(x + 2, y + 1, attr | A_BOLD, "MOD");
+ tui_draw_text(x + 2, y + 2, attr, "%s", mode_repr[tpu->mode]);
tui_draw_box(x, (y += TPU_INFO_H - 1), w, h, attr,
WACS_D_LTEE, WACS_D_RTEE, WACS_D_BTEE, WACS_D_RTEE);
- tui_draw_text(x + 2, y + 1, A_BOLD, "IDL");
+ tui_draw_text(x + 2, y + 1, attr | A_BOLD, "IDL");
if (tpu->steps > 0)
idle = (int) ((double) tpu->idle_steps * 100 / (double) tpu->steps);
else
- idle = 100;
- tui_draw_text(x + 2, y + 2, 0, "%03i", idle);
+ idle = 0;
+ tui_draw_text(x + 2, y + 2, attr, "%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_set)
+ if (port->avail)
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);
+ port->avail ? A_BOLD : 0, WACS_RARROW);
if (port->type & PORT_OUT)
tui_draw_wch(sx - 1, sy + 8,
- port->out_set ? A_BOLD : 0, WACS_LARROW);
- if (port->out_set)
+ port->writing ? A_BOLD : 0, WACS_LARROW);
+ if (port->writing)
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)
+ if (port->writing)
tui_draw_lit(sx + TPU_W, sy + 5, A_BOLD, port->out);
if (port->type & PORT_OUT)
tui_draw_wch(sx + TPU_W, sy + 7,
- port->out_set ? A_BOLD : 0, WACS_RARROW);
+ port->writing ? A_BOLD : 0, WACS_RARROW);
if (port->type & PORT_IN)
tui_draw_wch(sx + TPU_W, sy + 8,
- port->in_set ? A_BOLD : 0, WACS_LARROW);
- if (port->in_set)
+ port->avail ? A_BOLD : 0, WACS_LARROW);
+ if (port->avail)
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)
+ if (port->writing)
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);
+ port->writing ? A_BOLD : 0, WACS_UARROW);
if (port->type & PORT_IN)
tui_draw_wch(sx + 15, sy - 1,
- port->in_set ? A_BOLD : 0, WACS_DARROW);
- if (port->in_set)
+ port->avail ? A_BOLD : 0, WACS_DARROW);
+ if (port->avail)
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)
+ if (port->avail)
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);
+ port->avail ? A_BOLD : 0, WACS_UARROW);
if (port->type & PORT_OUT)
tui_draw_wch(sx + 15, sy + TPU_H,
- port->out_set ? A_BOLD : 0, WACS_DARROW);
- if (port->out_set)
+ port->writing ? A_BOLD : 0, WACS_DARROW);
+ if (port->writing)
tui_draw_lit(sx + 16, sy + TPU_H, A_BOLD, port->out);
}
}
@@ -404,7 +410,6 @@ handlekey(int key)
scrx += 4;
break;
case 's':
- tis_communicate(&tis);
tis_step(&tis);
break;
}
@@ -418,8 +423,8 @@ handlekey(int key)
case KEY_LEFT:
case KEY_RIGHT:
dir = key_to_dir(key);
- if (tpu_sel && tpu_sel->ports[dir].dst_tpu)
- tpu_sel = tpu_sel->ports[dir].dst_tpu;
+ if (tpu_sel && tpu_sel->ports[dir].dst_port->tpu)
+ tpu_sel = tpu_sel->ports[dir].dst_port->tpu;
tui_seek(tpu_sel, MID, MID);
break;
}
@@ -442,12 +447,14 @@ first_tpu(void)
static void
reset(int ifd, int argc, const char **argv, bool watch)
{
- tis_load(&tis, argv[1]);
- tis_load_io(&tis, argv + 2);
+ tis_deinit(&tis);
+ tis_init(&tis);
+ tis_load(&tis, argv);
- if (watch)
+ if (watch) {
if (inotify_add_watch(ifd, argv[1], IN_MODIFY) < 0)
die("inotify_add_watch '%s':", argv[1]);
+ }
tpu_sel = first_tpu();
}
@@ -474,6 +481,8 @@ main(int argc, const char **argv)
noecho();
keypad(stdscr, TRUE);
start_color();
+ init_pair(THEME_DEFAULT, COLOR_WHITE, COLOR_BLACK);
+ init_pair(THEME_DISABLED, COLOR_RED, COLOR_BLACK);
curs_set(0);
tui_resize();
timeout(TIMEOUT);
@@ -510,6 +519,7 @@ main(int argc, const char **argv)
case 'r':
reset(ifd, argc, argv, false);
break;
+ case 'q':
case KEY_CTRL('c'):
quit = true;
break;
diff --git a/tis100.c b/tis100.c
@@ -24,16 +24,18 @@ io_active(struct tis *tis)
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)
+ if (io_port->port.attached && !io_port->port.writing
+ && !feof(io_port->file))
return true;
}
+
return false;
}
int
main(int argc, const char **argv)
{
+ struct tis_stats stats;
bool idle, prev_idle;
if (argc < 2) {
@@ -43,15 +45,24 @@ main(int argc, const char **argv)
tis_init(&tis);
- tis_load(&tis, argv[1]);
- tis_load_io(&tis, argv + 2);
+ tis_load(&tis, argv);
idle = false;
while (!idle || !prev_idle || io_active(&tis)) {
- tis_communicate(&tis);
prev_idle = idle;
idle = !tis_step(&tis);
}
+ tis.steps -= 1; /* remove last idle step */
+
+ if (tis.show_stats) {
+ stats = tis_gen_stats(&tis);
+ printf("=== stats ===\n");
+ printf(" cycles: %zu\n", stats.steps);
+ printf(" blocks: %zu\n", stats.blocks);
+ printf(" insts: %zu\n", stats.blocks);
+ printf(" idle: %2.1f%%\n", stats.idle * 100);
+ printf("=============\n");
+ }
tis_deinit(&tis);
}
diff --git a/tpu.c b/tpu.c
@@ -2,6 +2,7 @@
#include "util.h"
#include <ctype.h>
+#include <assert.h>
#include <stdio.h>
#include <stdbool.h>
#include <stddef.h>
@@ -11,7 +12,7 @@ const char *dir_reprs[] = {
"LEFT", "RIGHT", "UP", "DOWN"
};
-const char *status_reprs[] = {
+const char *mode_reprs[] = {
"IDLE", "RUN", "READ", "WRITE"
};
@@ -129,18 +130,18 @@ label_map_get(struct label_map *map, const char *name)
}
void
-tpu_port_init(struct tpu_port *port)
+tpu_port_init(struct tpu_port *port, struct tpu *tpu)
{
+ port->tpu = tpu;
port->attached = false;
port->dst_port = NULL;
- port->dst_tpu = NULL;
port->type = PORT_BIDI;
- port->clr_post_run = false;
+ port->reset_in = false;
port->reading = false;
port->writing = false;
- port->in_set = false;
+ port->avail = false;
port->in = -1;
- port->out_set = false;
+ port->writing = false;
port->out = -1;
}
@@ -151,10 +152,35 @@ tpu_port_deinit(struct tpu_port *port)
}
void
+tpu_port_update(struct tpu_port *port)
+{
+ struct tpu *tpu;
+
+ if (!port->attached) return;
+
+ if (port->writing && !port->dst_port->avail) {
+ port->dst_port->in = port->out;
+ port->dst_port->avail = true;
+ }
+
+ if (port->reset_in && (!port->tpu || !port->tpu->idle)) {
+ port->avail = false;
+ port->dst_port->writing = false;
+ port->reset_in = false;
+ if ((tpu = port->dst_port->tpu)) {
+ /* hacky: only allow mode to be RUN after receive */
+ tpu->mode = MODE_RUN;
+ tpu->idle = false;
+ if (++tpu->pc >= tpu->inst_cnt) tpu->pc = 0;
+ }
+ }
+}
+
+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);
+ tpu_port_init(&io_port->port, NULL);
io_port->type = type;
io_port->file = NULL;
io_port->dir = dir;
@@ -175,7 +201,10 @@ tpu_init(struct tpu *tpu)
{
size_t i;
- tpu->status = STATUS_IDLE;
+ tpu->disabled = false;
+
+ tpu->mode = MODE_IDLE;
+ tpu->idle = true;
tpu->x = 0;
tpu->y = 0;
@@ -193,7 +222,7 @@ tpu_init(struct tpu *tpu)
tpu->last = -1;
tpu->io_port = -1;
for (i = 0; i < 4; i++)
- tpu_port_init(&tpu->ports[i]);
+ tpu_port_init(&tpu->ports[i], tpu);
}
void
@@ -226,6 +255,7 @@ tpu_init_ports(struct tpu *tpu, struct tpu_map *map)
for (i = 0; i < 4; i++) {
if (tpu->ports[i].attached) continue;
+ if (tpu->disabled) continue;
switch (i) {
case DIR_LEFT:
@@ -247,45 +277,25 @@ tpu_init_ports(struct tpu *tpu, struct tpu_map *map)
}
neighbor = tpu_map_get(map, x, y);
- if (neighbor) {
+ if (neighbor && !neighbor->disabled) {
odir = opposite_dir((enum tpu_port_dir) i);
tpu->ports[i].attached = true;
- tpu->ports[i].dst_tpu = neighbor;
tpu->ports[i].dst_port = &neighbor->ports[odir];
neighbor->ports[odir].attached = true;
- neighbor->ports[odir].dst_tpu = tpu;
neighbor->ports[odir].dst_port = &tpu->ports[i];
}
}
}
void
-tpu_update_ports(struct tpu *tpu)
+tpu_update(struct tpu *tpu)
{
struct tpu_port *port;
int i;
for (i = 0; i < 4; i++) {
port = &tpu->ports[i];
- if (!port->attached) continue;
- 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;
- }
- 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;
- }
- if (tpu->status == STATUS_RUN && port->clr_post_run) {
- port->in_set = false;
- port->clr_post_run = false;
- }
+ tpu_port_update(port);
}
}
@@ -342,38 +352,40 @@ tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst_type,
return &tpu->insts[tpu->inst_cnt++];
}
-/* tpu can always write to an empty port (->out), but only
- * read values if there is a writer attached and offering a value
- * (->dst_port->out) -- the read value (->in) is cleared at the end of
- * an instruction step */
+/* tpu can only read values if there is a writer attached and offering a
+ * value (->dst_port->out) -- which is cleared on successful read */
static bool
tpu_port_read(struct tpu *tpu, enum tpu_port_dir dir, int *lit)
{
- struct tpu_port *port;
+ struct tpu_port *port = &tpu->ports[dir];
- port = &tpu->ports[dir];
- port->clr_post_run = true;
- if (!port->in_set) {
+ if (!port->avail) {
port->reading = true;
return false;
}
+
*lit = port->in;
+ port->reset_in = true;
+
return true;
}
+/* tpu can always write values (->out) but only finish writing once the
+ * written value is read and cleared by the reader (->dst_port->in) */
+
static bool
tpu_port_write(struct tpu *tpu, enum tpu_port_dir dir, int lit)
{
- struct tpu_port *port;
+ struct tpu_port *port = &tpu->ports[dir];
- port = &tpu->ports[dir];
- if (port->out_set) {
- port->writing = true;
+ if (port->writing) {
return false;
}
- port->out_set = true;
+
+ port->writing = true;
port->out = lit;
+
return true;
}
@@ -447,117 +459,106 @@ tpu_exec_put(struct tpu *tpu, struct tpu_inst_op *op, int lit)
}
}
-enum tpu_status
-tpu_exec_mov(struct tpu *tpu, struct tpu_inst *inst)
-{
- int lit;
-
- if (inst->type != INST_MOV) abort();
-
- if (!tpu_exec_get(tpu, &inst->ops[0], &lit))
- return STATUS_READ;
-
- if (!tpu_exec_put(tpu, &inst->ops[1], lit))
- return STATUS_WRITE;
-
- return STATUS_RUN;
-}
-
-enum tpu_status
+enum tpu_mode
tpu_exec(struct tpu *tpu, struct tpu_inst *inst)
{
- enum tpu_status status;
int lit;
int val;
+ tpu->idle = false;
switch (inst->type) {
case INST_NOP:
tpu->pc += 1;
- return STATUS_RUN;
+ return MODE_RUN;
case INST_MOV:
- status = tpu_exec_mov(tpu, inst);
- if (status == STATUS_RUN)
- tpu->pc += 1;
- return status;
+ if (tpu->mode != MODE_WRITE) {
+ if (!tpu_exec_get(tpu, &inst->ops[0], &lit)) {
+ tpu->idle = true;
+ return MODE_READ;
+ }
+ }
+ /* tpu->idle/mode fixed up via tpu->reset_in if value is read */
+ if (!tpu_exec_put(tpu, &inst->ops[1], lit))
+ tpu->idle = true;
+ return MODE_WRITE;
case INST_SWP:
lit = tpu->acc;
tpu->acc = tpu->bak;
tpu->bak = lit;
tpu->pc += 1;
- return STATUS_RUN;
+ return MODE_RUN;
case INST_SAV:
tpu->bak = tpu->acc;
tpu->pc += 1;
- return STATUS_RUN;
+ return MODE_RUN;
case INST_ADD:
- if (!tpu_exec_get(tpu, &inst->ops[0], &val))
- return STATUS_READ;
+ if (!tpu_exec_get(tpu, &inst->ops[0], &val)) {
+ tpu->idle = true;
+ return MODE_READ;
+ }
tpu->acc = MIN(MAX(tpu->acc + val, -999), 999);
tpu->pc += 1;
- return STATUS_RUN;
+ return MODE_RUN;
case INST_SUB:
if (!tpu_exec_get(tpu, &inst->ops[0], &val))
- return STATUS_READ;
+ return MODE_READ;
tpu->acc = MIN(MAX(tpu->acc - val, -999), 999);
tpu->pc += 1;
- return STATUS_RUN;
+ return MODE_RUN;
case INST_NEG:
tpu->acc = -tpu->acc;
tpu->pc += 1;
- return STATUS_RUN;
+ return MODE_RUN;
case INST_JMP:
tpu_jmp_label(tpu, inst->ops[0].val.label);
- return STATUS_RUN;
+ return MODE_RUN;
case INST_JEZ:
if (tpu->acc == 0)
tpu_jmp_label(tpu, inst->ops[0].val.label);
else
tpu->pc += 1;
- return STATUS_RUN;
+ return MODE_RUN;
case INST_JNZ:
if (tpu->acc != 0)
tpu_jmp_label(tpu, inst->ops[0].val.label);
else
tpu->pc += 1;
- return STATUS_RUN;
+ return MODE_RUN;
case INST_JGZ:
if (tpu->acc > 0)
tpu_jmp_label(tpu, inst->ops[0].val.label);
else
tpu->pc += 1;
- return STATUS_RUN;
+ return MODE_RUN;
case INST_JLZ:
if (tpu->acc < 0)
tpu_jmp_label(tpu, inst->ops[0].val.label);
else
tpu->pc += 1;
- return STATUS_RUN;
+ return MODE_RUN;
case INST_JRO:
tpu->pc += inst->ops[0].val.lit;
if (tpu->pc < 0) tpu->pc = 0;
if (tpu->pc >= tpu->inst_cnt)
tpu->pc = (int) tpu->inst_cnt - 1;
- return STATUS_RUN;
+ return MODE_RUN;
default:
abort();
}
}
-enum tpu_status
+void
tpu_step(struct tpu *tpu)
{
+ int prev_mode;
+
+ prev_mode = tpu->mode;
if (tpu->pc < tpu->inst_cnt) {
- tpu->status = tpu_exec(tpu, &tpu->insts[tpu->pc]);
+ tpu->mode = tpu_exec(tpu, &tpu->insts[tpu->pc]);
if (tpu->pc >= tpu->inst_cnt) tpu->pc = 0;
} else {
- tpu->status = STATUS_IDLE;
+ tpu->mode = MODE_IDLE;
}
-
- tpu->steps += 1;
- if (tpu->status != STATUS_RUN)
- tpu->idle_steps += 1;
-
- return tpu->status;
}
void
@@ -633,6 +634,9 @@ tis_init(struct tis *tis)
tpu_map_init(&tis->tpu_map);
memset(&tis->in_ports, 0, TIS_MAX_IO_PORTS * sizeof(void *));
memset(&tis->out_ports, 0, TIS_MAX_IO_PORTS * sizeof(void *));
+ tis->steps = 0;
+ tis->show_stats = false;
+ tis->asm_init = false;
}
void
@@ -660,19 +664,43 @@ tis_step(struct tis *tis)
bool running;
size_t i;
+ tis_communicate(tis);
+
running = false;
for (i = 0; i < TPU_MAP_BUCKETS; i++) {
link = tis->tpu_map.buckets[i];
for (; link; link = link->next)
- running |= (tpu_step(link->tpu) == STATUS_RUN);
+ tpu_step(link->tpu);
}
for (i = 0; i < TPU_MAP_BUCKETS; i++) {
link = tis->tpu_map.buckets[i];
- for (; link; link = link->next)
- tpu_update_ports(link->tpu);
+ for (; link; link = link->next) {
+ tpu_update(link->tpu);
+ running |= !link->tpu->idle;
+ }
+ }
+
+ for (i = 0; i < TPU_MAP_BUCKETS; i++) {
+ link = tis->tpu_map.buckets[i];
+ for (; link; link = link->next) {
+ if (link->tpu->pc < link->tpu->inst_cnt) {
+ link->tpu->steps += 1;
+ if (link->tpu->idle)
+ link->tpu->idle_steps += 1;
+ }
+ }
+ }
+
+ for (i = 0; i < TIS_MAX_IO_PORTS; i++) {
+ if (tis->in_ports[i])
+ tpu_port_update(&tis->in_ports[i]->port);
+ if (tis->out_ports[i])
+ tpu_port_update(&tis->out_ports[i]->port);
}
+ tis->steps += 1;
+
return running;
}
@@ -686,7 +714,7 @@ tis_communicate(struct tis *tis)
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)
+ if (!io_port->port.attached || io_port->port.writing)
continue;
if (!io_port->file) continue;
while ((s = fgets(buf, sizeof(buf), io_port->file))) {
@@ -696,7 +724,7 @@ tis_communicate(struct tis *tis)
if (!s || *s != '\0')
die("communicate: invalid input '%s'", buf);
io_port->port.out = val;
- io_port->port.out_set = true;
+ io_port->port.writing = true;
break;
}
}
@@ -704,10 +732,42 @@ tis_communicate(struct tis *tis)
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)
+ if (!io_port->port.attached || !io_port->port.avail)
continue;
if (io_port->file)
fprintf(io_port->file, "%i\n", io_port->port.in);
- io_port->port.in_set = false;
+ io_port->port.reset_in = true;
+ tpu_port_update(&io_port->port);
+ }
+}
+
+struct tis_stats
+tis_gen_stats(struct tis *tis)
+{
+ struct tis_stats stats;
+ struct tpu_map_link *link;
+ size_t idle_steps;
+ size_t all_steps;
+ int i;
+
+ stats.steps = tis->steps;
+ stats.blocks = 0;
+ stats.insts = 0;
+ stats.idle = 0;
+
+ all_steps = 0;
+ idle_steps = 0;
+ for (i = 0; i < TPU_MAP_BUCKETS; i++) {
+ link = tis->tpu_map.buckets[i];
+ for (; link; link = link->next) {
+ stats.insts += link->tpu->inst_cnt;
+ idle_steps += link->tpu->idle_steps;
+ all_steps += link->tpu->steps;
+ stats.blocks += (link->tpu->inst_cnt > 0);
+ }
}
+
+ stats.idle = (float) idle_steps / (float) all_steps;
+
+ return stats;
}
diff --git a/tpu.h b/tpu.h
@@ -11,10 +11,9 @@
#define TPU_MAX_INST_LEN 18
#define TIS_MAX_IO_PORTS 36
-/* enum order is important ! */
-
-enum tpu_status {
- STATUS_IDLE, STATUS_RUN, STATUS_READ, STATUS_WRITE
+/* what tpu will attempt next (order important) */
+enum tpu_mode {
+ MODE_IDLE, MODE_RUN, MODE_READ, MODE_WRITE
};
enum tpu_inst_type {
@@ -65,18 +64,26 @@ struct tpu_inst {
};
struct tpu_port {
- struct tpu *dst_tpu;
+ struct tpu *tpu;
enum tpu_port_type type;
+
+ /* NOTE: dont access dst_port during execution,
+ * values are transfered in post execution phase */
struct tpu_port *dst_port;
- bool clr_post_run;
- bool reading, writing;
bool attached;
- bool in_set, out_set;
+
int in, out;
+ bool avail, reading, writing;
+
+ bool reset_in;
};
struct tpu {
- enum tpu_status status;
+ enum tpu_mode mode;
+ bool idle;
+
+ bool disabled;
+
int x, y;
struct tpu_port ports[4];
@@ -91,7 +98,7 @@ struct tpu {
struct label_map label_map;
struct tpu_inst insts[TPU_MAX_INST_CNT];
- int inst_cnt, label_cnt;
+ size_t inst_cnt, label_cnt;
};
struct tpu_map_link {
@@ -117,6 +124,16 @@ struct tis {
struct tpu_map tpu_map;
struct tpu_io_port *in_ports[TIS_MAX_IO_PORTS];
struct tpu_io_port *out_ports[TIS_MAX_IO_PORTS];
+ size_t steps;
+ bool show_stats;
+ bool asm_init;
+};
+
+struct tis_stats {
+ size_t steps;
+ size_t blocks;
+ size_t insts;
+ float idle;
};
void label_map_init(struct label_map *map);
@@ -124,7 +141,7 @@ void label_map_deinit(struct label_map *map);
bool label_map_add(struct label_map *map, const char *name, int pc);
int label_map_get(struct label_map *map, const char *name);
-void tpu_port_init(struct tpu_port *port);
+void tpu_port_init(struct tpu_port *port, struct tpu *tpu);
void tpu_port_deinit(struct tpu_port *port);
void tpu_io_port_init(struct tpu_io_port *io_port, char c,
@@ -142,9 +159,8 @@ bool tpu_set_inst(struct tpu *tpu, int pc, 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);
-enum tpu_status tpu_exec(struct tpu *tpu, struct tpu_inst *inst);
-enum tpu_status tpu_step(struct tpu *tpu);
+enum tpu_mode tpu_exec(struct tpu *tpu, struct tpu_inst *inst);
+void tpu_step(struct tpu *tpu);
void tpu_map_init(struct tpu_map *map);
void tpu_map_deinit(struct tpu_map *map);
@@ -155,8 +171,9 @@ void tis_init(struct tis *tis);
void tis_deinit(struct tis *tis);
bool tis_step(struct tis *tis);
void tis_communicate(struct tis *tis);
+struct tis_stats tis_gen_stats(struct tis *tis);
extern const char *dir_reprs[];
-extern const char *status_reprs[];
+extern const char *mode_reprs[];
extern const char *inst_reprs[];
extern const char *op_reprs[];