diff options
Diffstat (limited to 'tpu.c')
| -rw-r--r-- | tpu.c | 196 |
1 files changed, 111 insertions, 85 deletions
@@ -1,6 +1,7 @@ #include "tpu.h" #include "util.h" +#include <stdio.h> #include <stdbool.h> #include <stddef.h> #include <string.h> @@ -119,15 +120,16 @@ tpu_init(struct tpu *tpu) tpu->bak = 0; tpu->inst_cnt = 0; tpu->pc = 0; + tpu->status = STATUS_IDLE; label_map_init(&tpu->labels); for (i = 0; i < 4; i++) { tpu->ports[i].attached = false; tpu->ports[i].dst_port = NULL; tpu->ports[i].dst_tpu = NULL; - tpu->ports[i].read = false; - tpu->ports[i].write = false; tpu->ports[i].type = PORT_BIDI; - tpu->ports[i].val = 0; + tpu->ports[i].reading = false; + tpu->ports[i].in = -1; + tpu->ports[i].out = -1; } } @@ -189,14 +191,33 @@ tpu_init_ports(struct tpu *tpu, struct tpu_map *map) } } +void +tpu_update_ports(struct tpu *tpu) +{ + struct tpu_port *port; + + if (tpu->read_port >= 0) { + port = &tpu->ports[tpu->read_port]; + if (port->reading) { + if (port->attached && port->dst_port->out >= 0) { + port->in = port->dst_port->out; + port->dst_port->out = -1; + port->reading = false; + } + } else if (tpu->status == STATUS_RUN) { + port->in = -1; + tpu->read_port = -1; + } + } +} + bool -tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst_type, +tpu_set_inst(struct tpu *tpu, uint8_t pc, enum tpu_inst_type inst_type, int op1, uint8_t op1_lit, int op2, uint8_t op2_lit) { struct tpu_inst *inst; - inst = calloc(1, sizeof(struct tpu_inst)); - if (!inst) die("malloc:"); + inst = &tpu->insts[pc]; inst->type = inst_type; if (op2 > 0) { @@ -226,6 +247,8 @@ tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst_type, break; case INST_MOV: if (inst->opcnt != 2) return false; + if (inst->ops[0].type == OP_LABEL) return false; + if (inst->ops[1].type == OP_LABEL) return false; if (inst->ops[1].type == OP_LIT) return false; break; } @@ -233,23 +256,62 @@ tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst_type, return true; } -void -tpu_ports_clear(struct tpu *tpu) +bool +tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst_type, + int op1, uint8_t op1_lit, int op2, uint8_t op2_lit) { - int i; + if (tpu->inst_cnt == TPU_MAX_INST) + die("tpu_add_inst: tpu X%lu Y%lu, too many instructions", + tpu->x, tpu->y); + return tpu_set_inst(tpu, (uint8_t) tpu->inst_cnt++, inst_type, + op1, op1_lit, op2, op2_lit); +} - for (i = 0; i < 4; i++) { - tpu->ports[i].read = false; - tpu->ports[i].write = false; +/* tpu can always write to an empty port (->out), but only + * read values from a port (->in) 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 */ + +static int +tpu_port_read(struct tpu *tpu, enum tpu_port_dir dir) +{ + struct tpu_port *port; + + port = &tpu->ports[dir]; + if (port->in < 0) { + port->reading = true; + tpu->read_port = (int) dir; + return -1; } + return port->in; +} + +static bool +tpu_port_write(struct tpu *tpu, enum tpu_port_dir dir, uint8_t lit) +{ + struct tpu_port *port; + + port = &tpu->ports[dir]; + if (port->out >= 0) return false; + port->out = lit; + return true; +} + +static void +tpu_jmp_label(struct tpu *tpu, const char *label) +{ + size_t pc; + + pc = label_map_get(&tpu->labels, label); + if (pc >= TPU_MAX_INST) abort(); + tpu->pc = (uint8_t) pc; } int tpu_exec_get(struct tpu *tpu, struct tpu_inst_op *op) { - struct tpu_port *port; uint8_t lit; - int i; + int i, v; switch (op->type) { case OP_ACC: @@ -262,71 +324,50 @@ tpu_exec_get(struct tpu *tpu, struct tpu_inst_op *op) lit = 0; break; case OP_LEFT: case OP_RIGHT: case OP_UP: case OP_DOWN: - port = &tpu->ports[op_to_dir(op->type)]; - port->read = true; - if (!port->attached || !port->dst_port->write) - return -1; - tpu->last = (int) op_to_dir(op->type); - lit = port->dst_port->val; - break; + return tpu_port_read(tpu, op_to_dir(op->type)); case OP_ANY: for (i = 0; i < 4; i++) { - port = &tpu->ports[i]; - port->read = true; - if (port->attached && port->dst_port->write) { + v = tpu_port_read(tpu, (enum tpu_port_dir) i); + if (v >= 0) { tpu->last = i; - lit = port->dst_port->val; break; } } if (i == 4) return -1; + lit = (uint8_t) v; break; case OP_LAST: if (tpu->last < 0) return 0; - port = &tpu->ports[tpu->last]; - port->read = true; - if (!port->attached || !port->dst_port->write) - return -1; - lit = port->dst_port->val; - break; + return tpu_port_read(tpu, (enum tpu_port_dir) tpu->last); case OP_LIT: lit = op->lit; break; - default: + case OP_LABEL: abort(); } - tpu_ports_clear(tpu); - return (int) lit; } bool tpu_exec_put(struct tpu *tpu, struct tpu_inst_op *op, uint8_t lit) { - struct tpu_port *port; int i; switch (op->type) { + case OP_ACC: + tpu->acc = lit; + break; case OP_BAK: tpu->bak = lit; break; case OP_NIL: break; case OP_LEFT: case OP_RIGHT: case OP_UP: case OP_DOWN: - port = &tpu->ports[op_to_dir(op->type)]; - port->write = true; - if (!port->attached || !port->dst_port->write) - return false; - lit = port->dst_port->val; - tpu->last = (int) op_to_dir(op->type); - break; + return tpu_port_write(tpu, op_to_dir(op->type), lit); case OP_ANY: for (i = 0; i < 4; i++) { - port = &tpu->ports[i]; - port->write = true; - if (port->attached && port->dst_port->write) { - port->dst_port->val = lit; + if (tpu_port_write(tpu, (enum tpu_port_dir) i, lit)) { tpu->last = i; break; } @@ -335,17 +376,12 @@ tpu_exec_put(struct tpu *tpu, struct tpu_inst_op *op, uint8_t lit) break; case OP_LAST: if (tpu->last < 0) break; - port = &tpu->ports[tpu->last]; - port->write = true; - if (!port->attached || !port->dst_port->write) - return false; - break; - default: + return tpu_port_write(tpu, (enum tpu_port_dir) tpu->last, lit); + case OP_LABEL: + case OP_LIT: abort(); } - tpu_ports_clear(tpu); - return true; } @@ -359,16 +395,16 @@ tpu_exec_mov(struct tpu *tpu, struct tpu_inst *inst) lit = tpu_exec_get(tpu, &inst->ops[0]); if (lit < 0) return STATUS_READ; - if (!tpu_exec_put(tpu, &inst->ops[0], (uint8_t) lit)) + if (!tpu_exec_put(tpu, &inst->ops[1], (uint8_t) lit)) return STATUS_WRITE; - tpu->pc += 1; return STATUS_RUN; } enum tpu_status tpu_exec(struct tpu *tpu, struct tpu_inst *inst) { + enum tpu_status status; uint8_t lit; int val; @@ -377,7 +413,10 @@ tpu_exec(struct tpu *tpu, struct tpu_inst *inst) tpu->pc += 1; return STATUS_RUN; case INST_MOV: - return tpu_exec_mov(tpu, inst); + status = tpu_exec_mov(tpu, inst); + if (status == STATUS_RUN) + tpu->pc += 1; + return status; case INST_SWP: lit = tpu->acc; tpu->acc = tpu->bak; @@ -404,45 +443,32 @@ tpu_exec(struct tpu *tpu, struct tpu_inst *inst) tpu->acc = -tpu->acc; tpu->pc += 1; return STATUS_RUN; - case INST_JMP: - tpu->pc = label_map_get(&tpu->labels, inst->ops[0].label); - if (tpu->pc >= TPU_MAX_INST) abort(); + case INST_JMP: + tpu_jmp_label(tpu, inst->ops[0].label); return STATUS_RUN; case INST_JEZ: - if (tpu->acc == 0) { - tpu->pc = label_map_get(&tpu->labels, - inst->ops[0].label); - if (tpu->pc >= TPU_MAX_INST) abort(); - } else { + if (tpu->acc == 0) + tpu_jmp_label(tpu, inst->ops[0].label); + else tpu->pc += 1; - } return STATUS_RUN; case INST_JNZ: - if (tpu->acc != 0) { - tpu->pc = label_map_get(&tpu->labels, - inst->ops[0].label); - if (tpu->pc >= TPU_MAX_INST) abort(); - } else { + if (tpu->acc != 0) + tpu_jmp_label(tpu, inst->ops[0].label); + else tpu->pc += 1; - } return STATUS_RUN; case INST_JGZ: - if (tpu->acc > 0) { - tpu->pc = label_map_get(&tpu->labels, - inst->ops[0].label); - if (tpu->pc >= TPU_MAX_INST) abort(); - } else { + if (tpu->acc > 0) + tpu_jmp_label(tpu, inst->ops[0].label); + else tpu->pc += 1; - } return STATUS_RUN; case INST_JLZ: - if (tpu->acc < 0) { - tpu->pc = label_map_get(&tpu->labels, - inst->ops[0].label); - if (tpu->pc >= TPU_MAX_INST) abort(); - } else { + if (tpu->acc < 0) + tpu_jmp_label(tpu, inst->ops[0].label); + else tpu->pc += 1; - } return STATUS_RUN; case INST_JRO: tpu->pc += inst->ops[0].lit; @@ -457,7 +483,7 @@ void tpu_step(struct tpu *tpu) { if (tpu->pc >= tpu->inst_cnt) return; - tpu_exec(tpu, &tpu->insts[tpu->pc]); + tpu->status = tpu_exec(tpu, &tpu->insts[tpu->pc]); if (tpu->pc >= tpu->inst_cnt) tpu->pc = 0; } |
