diff options
| author | Louis Burda <quent.burda@gmail.com> | 2023-12-25 01:46:55 +0100 |
|---|---|---|
| committer | Louis Burda <quent.burda@gmail.com> | 2023-12-25 01:46:55 +0100 |
| commit | 5ff5bb25cc864e7fa06aa8fed0c4ec92e99f103a (patch) | |
| tree | 646a3a56d5e9d831e81d64c48a2e39e594cf0685 /tpu.c | |
| parent | 70d48f0db2ff618436df7c8c52ead5a0701fd7ab (diff) | |
| download | tis100-5ff5bb25cc864e7fa06aa8fed0c4ec92e99f103a.tar.gz tis100-5ff5bb25cc864e7fa06aa8fed0c4ec92e99f103a.zip | |
Make mode/state behaviour compatible with game
Diffstat (limited to 'tpu.c')
| -rw-r--r-- | tpu.c | 256 |
1 files changed, 158 insertions, 98 deletions
@@ -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; } |
