#include "icc.h" #include "allocator.h" #include "aoc.h" #include "util.h" #include "dvec_s.h" #include #include const char *icc_err[] = { [ICC_OK] = "ok", [ICC_INV_INST] = "invalid instruction", [ICC_OOB_WRITE] = "write addr oob", [ICC_OOB_READ] = "read addr oob", }; void icc_init(struct icc *icc) { int rc; icc->rip = 0; icc->state = ICC_RUN; icc->base = 0; icc->in = 0; icc->out = 0; icc->read_addr = 0; icc->write_addr = 0; icc->abort_on_err = true; icc->debug = getenv("ICC_DEBUG") != NULL; icc->line_terminated = true; rc = dvec_init(&icc->instructions, sizeof(int), 0, &stdlib_heap_allocator); assert(!rc); } void icc_deinit(struct icc *icc) { dvec_deinit(&icc->instructions); } void icc_copy(struct icc *dst, struct icc *src) { dst->rip = src->rip; dst->in = src->in; dst->out = src->out; dst->state = src->state; dst->base = src->base; dvec_copy(&dst->instructions, &src->instructions); } void icc_reset(struct icc *icc, struct dvec *inst) { int rc; icc->state = ICC_RUN; icc->rip = 0; icc->base = 0; if (inst) { rc = dvec_copy(&icc->instructions, inst); assert(!rc); } } void icc_parse_inst(struct icc *icc, const char *str, size_t len) { const char *pos, *end; char buf[256]; int val, *slot; pos = str; end = str + len; while (readtok(buf, sizeof(buf), ',', &pos, end)) { val = (int) parsei64(buf); slot = dvec_add_slot(&icc->instructions); *slot = val; } } const char* icc_param_str(struct icc *icc, int param) { static char buf[32]; int val; icc_get_inst(icc, icc->rip + param, &val); snprintf(buf, sizeof(buf), "%i", val); return buf; } void icc_debug_op_pre(struct icc *icc) { int inst, rc; if (!icc->debug) return; rc = icc_get_inst(icc, icc->rip, &inst); if (!rc) fprintf(stderr, "%04i: (%05i) ", icc->rip, inst); else fprintf(stderr, "%04i: (\?\?\?\?\?) ", icc->rip); icc->line_terminated = false; } void icc_debug_op_main(struct icc *icc, const char *opstr, size_t n) { int i, rc, val, val2, inst; if (!icc->debug) return; rc = icc_get_inst(icc, icc->rip, &inst); assert(!rc); fprintf(stderr, "%s ", opstr); icc->line_terminated = false; for (i = 1; i <= (int) n; i++) { if (i > 1) fprintf(stderr, ", "); rc = icc_get_inst(icc, icc->rip + i, &val); assert(!rc); switch (icc_param_mode(inst, i)) { case ICC_PARAM_IMM: fprintf(stderr, "%i", val); break; case ICC_PARAM_POS: rc = icc_get_inst(icc, val, &val2); if (!rc) fprintf(stderr, "[%i]=%i", val, val2); else fprintf(stderr, "[%i]=?", val); break; default: assert(0); } } } void icc_debug_op_post(struct icc *icc, int dst) { int val, inst; int rc; if (!icc->debug) return; rc = icc_get_inst(icc, icc->rip, &inst); assert(!rc); fprintf(stderr, " -> "); rc = icc_get_inst(icc, dst, &val); if (!rc) fprintf(stderr, "[%i]=%i", dst, val); else fprintf(stderr, "[%i]=?", dst); fprintf(stderr, "\n"); icc->line_terminated = true; } void icc_debug_op(struct icc *icc, const char *opstr, size_t n) { if (!icc->debug) return; icc_debug_op_main(icc, opstr, n); fprintf(stderr, "\n"); icc->line_terminated = true; } int icc_inst_add(struct icc *icc) { int a, b, dst; int rc; icc_debug_op_main(icc, "ADD", 3); rc = icc_get_param(icc, 1, &a); if (rc) return rc; rc = icc_get_param(icc, 2, &b); if (rc) return rc; rc = icc_get_dest(icc, 3, &dst); if (rc) return rc; rc = icc_set_inst(icc, dst, a + b); if (rc) return rc; icc_debug_op_post(icc, dst); icc->rip += 4; icc->state = ICC_RUN; return 0; } int icc_inst_mul(struct icc *icc) { int a, b, dst; int rc; icc_debug_op_main(icc, "MUL", 3); rc = icc_get_param(icc, 1, &a); if (rc) return rc; rc = icc_get_param(icc, 2, &b); if (rc) return rc; rc = icc_get_dest(icc, 3, &dst); if (rc) return rc; rc = icc_set_inst(icc, dst, a * b); if (rc) return rc; icc_debug_op_post(icc, dst); icc->rip += 4; icc->state = ICC_RUN; return 0; } int icc_inst_store(struct icc *icc) { int dst, rc; if (icc->state != ICC_INPUT) { icc_debug_op(icc, "INPUT", 0); icc->state = ICC_INPUT; } else { icc_debug_op_main(icc, "STORE", 1); rc = icc_get_dest(icc, 1, &dst); if (rc) return rc; rc = icc_set_inst(icc, dst, icc->in); if (rc) return rc; icc_debug_op_post(icc, dst); icc->rip += 2; icc->state = ICC_RUN; } return 0; } int icc_inst_load(struct icc *icc) { int out, rc; if (icc->state != ICC_OUTPUT) { icc_debug_op(icc, "LOAD", 1); rc = icc_get_param(icc, 1, &out); if (rc) return rc; icc->out = out; icc->state = ICC_OUTPUT; icc_debug_op(icc, "OUTPUT", 0); } else { icc->rip += 2; icc->state = ICC_RUN; } return 0; } int icc_inst_jmp_true(struct icc *icc) { int cond, addr; int rc; icc_debug_op(icc, "JMPT", 2); rc = icc_get_param(icc, 1, &cond); if (rc) return rc; rc = icc_get_param(icc, 2, &addr); if (rc) return rc; if (cond) icc->rip = addr; else icc->rip += 3; icc->state = ICC_RUN; return 0; } int icc_inst_jmp_false(struct icc *icc) { int cond, addr; int rc; icc_debug_op(icc, "JMPF", 2); rc = icc_get_param(icc, 1, &cond); if (rc) return rc; rc = icc_get_param(icc, 2, &addr); if (rc) return rc; if (!cond) icc->rip = addr; else icc->rip += 3; icc->state = ICC_RUN; return 0; } int icc_inst_test_lt(struct icc *icc) { int a, b, dst; int rc; icc_debug_op(icc, "TLT", 3); rc = icc_get_param(icc, 1, &a); if (rc) return rc; rc = icc_get_param(icc, 2, &b); if (rc) return rc; rc = icc_get_dest(icc, 3, &dst); if (rc) return rc; rc = icc_set_inst(icc, dst, a < b); if (rc) return rc; icc->rip += 4; icc->state = ICC_RUN; return 0; } int icc_inst_test_eq(struct icc *icc) { int a, b, dst; int rc; icc_debug_op(icc, "TEQ", 3); rc = icc_get_param(icc, 1, &a); if (rc) return rc; rc = icc_get_param(icc, 2, &b); if (rc) return rc; rc = icc_get_dest(icc, 3, &dst); if (rc) return rc; rc = icc_set_inst(icc, dst, a == b); if (rc) return rc; icc->rip += 4; icc->state = ICC_RUN; return 0; } int icc_inst_base(struct icc *icc) { int off, rc; icc_debug_op(icc, "BASE", 1); rc = icc_get_param(icc, 1, &off); if (rc) return rc; icc->base += off; icc->rip += 2; icc->state = ICC_RUN; return 0; } int icc_inst_halt(struct icc *icc) { icc_debug_op(icc, "HALT", 0); icc->state = ICC_HALT; return 0; } int icc_step_inst(struct icc *icc) { int inst, rc; icc_debug_op_pre(icc); rc = icc_get_inst(icc, icc->rip, &inst); if (rc) return rc; switch (inst % 100) { case ICC_INST_ADD: rc = icc_inst_add(icc); break; case ICC_INST_MULT: rc = icc_inst_mul(icc); break; case ICC_INST_STORE: rc = icc_inst_store(icc); break; case ICC_INST_LOAD: rc = icc_inst_load(icc); break; case ICC_INST_JMPT: rc = icc_inst_jmp_true(icc); break; case ICC_INST_JMPF: rc = icc_inst_jmp_false(icc); break; case ICC_INST_TLT: rc = icc_inst_test_lt(icc); break; case ICC_INST_TEQ: rc = icc_inst_test_eq(icc); break; case ICC_INST_BASE: rc = icc_inst_base(icc); break; case ICC_INST_HALT: rc = icc_inst_halt(icc); break; default: rc = ICC_INV_INST; break; } if (icc->debug) { if (!icc->line_terminated) { fprintf(stderr, "\n"); icc->line_terminated = true; } if (rc != ICC_OK) fprintf(stderr, " -- error: %s --\n", icc_err[rc]); } return rc; } int icc_set_inst(struct icc *icc, int addr, int val) { int *slot; if ((size_t) addr >= icc->instructions.len) { icc->write_addr = addr; assert(icc->abort_on_err); return ICC_OOB_WRITE; } slot = dvec_at(&icc->instructions, (size_t) addr); *slot = val; return 0; } int icc_get_inst(struct icc *icc, int addr, int *out) { if ((size_t) addr >= icc->instructions.len) { icc->read_addr = addr; assert(icc->abort_on_err); return ICC_OOB_READ; } *out = *(int*)dvec_at(&icc->instructions, (size_t) addr); return 0; } int icc_param_mode(int inst, int param) { int div, i; div = 100; for (i = 1; i < param; i++) div *= 10; return (inst / div) % 10 == 1 ? ICC_PARAM_IMM : ICC_PARAM_POS; } int icc_get_param(struct icc *icc, int param, int *out) { int inst, val; int rc; rc = icc_get_inst(icc, icc->rip, &inst); if (rc) return rc; rc = icc_get_inst(icc, icc->rip + param, &val); if (rc) return rc; switch (icc_param_mode(inst, param)) { case ICC_PARAM_IMM: *out = val; break; case ICC_PARAM_POS: rc = icc_get_inst(icc, val, out); if (rc) return rc; break; case ICC_PARAM_REL: *out = icc->base + val; break; default: assert(0); }; return 0; } int icc_get_dest(struct icc *icc, int param, int *out) { return icc_get_inst(icc, icc->rip + param, out); } void icc_debug_dump(struct icc *icc, struct dvec *inst) { int *rip; size_t i; if (!icc->debug) return; rip = icc->instructions.data; for (i = 0; i < icc->instructions.len; i++, rip++) { if (i % 8 == 0) fprintf(stderr, "%4u: ", (int) i); if (inst != NULL && (i >= inst->len || *(int *)dvec_at(inst, i) != *rip)) { fprintf(stderr, "\x1b[1m%8i\x1b[0m ", *rip); } else { fprintf(stderr, "%8i ", *rip); } if ((i + 1) % 8 == 0) fprintf(stderr, "\n"); } if (i % 8 != 0) fprintf(stderr, "\n"); }