aoc-2019-c

Advent of Code 2019 Solutions in C
git clone https://git.sinitax.com/sinitax/aoc-2019-c
Log | Files | Refs | README | sfeed.txt

icc.c (9183B)


      1#include "icc.h"
      2#include "allocator.h"
      3#include "aoc.h"
      4#include "util.h"
      5#include "dvec_s.h"
      6
      7#include <assert.h>
      8#include <stdbool.h>
      9
     10const char *icc_err[] = {
     11	[ICC_OK] = "ok",
     12	[ICC_INV_INST] = "invalid instruction",
     13	[ICC_OOB_WRITE] = "write addr oob",
     14	[ICC_OOB_READ] = "read addr oob",
     15};
     16
     17void
     18icc_init(struct icc *icc)
     19{
     20	int rc;
     21
     22	icc->rip = 0;
     23	icc->state = ICC_RUN;
     24	icc->base = 0;
     25
     26	icc->in = 0;
     27	icc->out = 0;
     28
     29	icc->read_addr = 0;
     30	icc->write_addr = 0;
     31	icc->abort_on_err = true;
     32
     33	icc->debug = getenv("ICC_DEBUG") != NULL;
     34
     35	icc->line_terminated = true;
     36
     37	rc = dvec_init(&icc->instructions,
     38		sizeof(int), 0, &stdlib_heap_allocator);
     39	assert(!rc);
     40}
     41
     42void
     43icc_deinit(struct icc *icc)
     44{
     45	dvec_deinit(&icc->instructions);
     46}
     47
     48void
     49icc_copy(struct icc *dst, struct icc *src)
     50{
     51	dst->rip = src->rip;
     52	dst->in = src->in;
     53	dst->out = src->out;
     54	dst->state = src->state;
     55	dst->base = src->base;
     56	dvec_copy(&dst->instructions, &src->instructions);
     57}
     58
     59void
     60icc_reset(struct icc *icc, struct dvec *inst)
     61{
     62	int rc;
     63
     64	icc->state = ICC_RUN;
     65	icc->rip = 0;
     66	icc->base = 0;
     67	if (inst) {
     68		rc = dvec_copy(&icc->instructions, inst);
     69		assert(!rc);
     70	}
     71}
     72
     73void
     74icc_parse_inst(struct icc *icc, const char *str, size_t len)
     75{
     76	const char *pos, *end;
     77	char buf[256];
     78	int val, *slot;
     79
     80	pos = str;
     81	end = str + len;
     82	while (readtok(buf, sizeof(buf), ',', &pos, end)) {
     83		val = (int) parsei64(buf);
     84		slot = dvec_add_slot(&icc->instructions);
     85		*slot = val;
     86	}
     87}
     88
     89const char*
     90icc_param_str(struct icc *icc, int param)
     91{
     92	static char buf[32];
     93	int val;
     94
     95	icc_get_inst(icc, icc->rip + param, &val);
     96	snprintf(buf, sizeof(buf), "%i", val);
     97
     98	return buf;
     99}
    100
    101void
    102icc_debug_op_pre(struct icc *icc)
    103{
    104	int inst, rc;
    105
    106	if (!icc->debug) return;
    107
    108	rc = icc_get_inst(icc, icc->rip, &inst);
    109	if (!rc) fprintf(stderr, "%04i: (%05i) ", icc->rip, inst);
    110	else fprintf(stderr, "%04i: (\?\?\?\?\?) ", icc->rip);
    111
    112	icc->line_terminated = false;
    113}
    114
    115void
    116icc_debug_op_main(struct icc *icc, const char *opstr, size_t n)
    117{
    118	int i, rc, val, val2, inst;
    119
    120	if (!icc->debug) return;
    121
    122	rc = icc_get_inst(icc, icc->rip, &inst);
    123	assert(!rc);
    124
    125	fprintf(stderr, "%s ", opstr);
    126	icc->line_terminated = false;
    127
    128	for (i = 1; i <= (int) n; i++) {
    129		if (i > 1) fprintf(stderr, ", ");
    130		rc = icc_get_inst(icc, icc->rip + i, &val);
    131		assert(!rc);
    132		switch (icc_param_mode(inst, i)) {
    133		case ICC_PARAM_IMM:
    134			fprintf(stderr, "%i", val);
    135			break;
    136		case ICC_PARAM_POS:
    137			rc = icc_get_inst(icc, val, &val2);
    138			if (!rc) fprintf(stderr, "[%i]=%i", val, val2);
    139			else fprintf(stderr, "[%i]=?", val);
    140			break;
    141		default:
    142			assert(0);
    143		}
    144	}
    145}
    146
    147void
    148icc_debug_op_post(struct icc *icc, int dst)
    149{
    150	int val, inst;
    151	int rc;
    152
    153	if (!icc->debug) return;
    154
    155	rc = icc_get_inst(icc, icc->rip, &inst);
    156	assert(!rc);
    157
    158	fprintf(stderr, " -> ");
    159
    160	rc = icc_get_inst(icc, dst, &val);
    161	if (!rc) fprintf(stderr, "[%i]=%i", dst, val);
    162	else fprintf(stderr, "[%i]=?", dst);
    163
    164	fprintf(stderr, "\n");
    165	icc->line_terminated = true;
    166}
    167
    168void
    169icc_debug_op(struct icc *icc, const char *opstr, size_t n)
    170{
    171	if (!icc->debug) return;
    172
    173	icc_debug_op_main(icc, opstr, n);
    174	fprintf(stderr, "\n");
    175	icc->line_terminated = true;
    176}
    177
    178int
    179icc_inst_add(struct icc *icc)
    180{
    181	int a, b, dst;
    182	int rc;
    183
    184	icc_debug_op_main(icc, "ADD", 3);
    185
    186	rc = icc_get_param(icc, 1, &a);
    187	if (rc) return rc;
    188	rc = icc_get_param(icc, 2, &b);
    189	if (rc) return rc;
    190	rc = icc_get_dest(icc, 3, &dst);
    191	if (rc) return rc;
    192
    193	rc = icc_set_inst(icc, dst, a + b);
    194	if (rc) return rc;
    195
    196	icc_debug_op_post(icc, dst);
    197
    198	icc->rip += 4;
    199	icc->state = ICC_RUN;
    200
    201	return 0;
    202}
    203
    204int
    205icc_inst_mul(struct icc *icc)
    206{
    207	int a, b, dst;
    208	int rc;
    209
    210	icc_debug_op_main(icc, "MUL", 3);
    211
    212	rc = icc_get_param(icc, 1, &a);
    213	if (rc) return rc;
    214	rc = icc_get_param(icc, 2, &b);
    215	if (rc) return rc;
    216	rc = icc_get_dest(icc, 3, &dst);
    217	if (rc) return rc;
    218
    219	rc = icc_set_inst(icc, dst, a * b);
    220	if (rc) return rc;
    221
    222	icc_debug_op_post(icc, dst);
    223
    224	icc->rip += 4;
    225	icc->state = ICC_RUN;
    226
    227	return 0;
    228}
    229
    230int
    231icc_inst_store(struct icc *icc)
    232{
    233	int dst, rc;
    234
    235	if (icc->state != ICC_INPUT) {
    236		icc_debug_op(icc, "INPUT", 0);
    237		icc->state = ICC_INPUT;
    238	} else {
    239		icc_debug_op_main(icc, "STORE", 1);
    240
    241		rc = icc_get_dest(icc, 1, &dst);
    242		if (rc) return rc;
    243
    244		rc = icc_set_inst(icc, dst, icc->in);
    245		if (rc) return rc;
    246
    247		icc_debug_op_post(icc, dst);
    248
    249		icc->rip += 2;
    250		icc->state = ICC_RUN;
    251	}
    252
    253	return 0;
    254}
    255
    256int
    257icc_inst_load(struct icc *icc)
    258{
    259	int out, rc;
    260
    261	if (icc->state != ICC_OUTPUT) {
    262		icc_debug_op(icc, "LOAD", 1);
    263
    264		rc = icc_get_param(icc, 1, &out);
    265		if (rc) return rc;
    266
    267		icc->out = out;
    268		icc->state = ICC_OUTPUT;
    269
    270		icc_debug_op(icc, "OUTPUT", 0);
    271	} else {
    272		icc->rip += 2;
    273		icc->state = ICC_RUN;
    274	}
    275
    276	return 0;
    277}
    278
    279int
    280icc_inst_jmp_true(struct icc *icc)
    281{
    282	int cond, addr;
    283	int rc;
    284
    285	icc_debug_op(icc, "JMPT", 2);
    286
    287	rc = icc_get_param(icc, 1, &cond);
    288	if (rc) return rc;
    289	rc = icc_get_param(icc, 2, &addr);
    290	if (rc) return rc;
    291
    292	if (cond) icc->rip = addr;
    293	else icc->rip += 3;
    294
    295	icc->state = ICC_RUN;
    296
    297	return 0;
    298}
    299
    300int
    301icc_inst_jmp_false(struct icc *icc)
    302{
    303	int cond, addr;
    304	int rc;
    305
    306	icc_debug_op(icc, "JMPF", 2);
    307
    308	rc = icc_get_param(icc, 1, &cond);
    309	if (rc) return rc;
    310	rc = icc_get_param(icc, 2, &addr);
    311	if (rc) return rc;
    312
    313	if (!cond) icc->rip = addr;
    314	else icc->rip += 3;
    315
    316	icc->state = ICC_RUN;
    317
    318	return 0;
    319}
    320
    321int
    322icc_inst_test_lt(struct icc *icc)
    323{
    324	int a, b, dst;
    325	int rc;
    326
    327	icc_debug_op(icc, "TLT", 3);
    328
    329	rc = icc_get_param(icc, 1, &a);
    330	if (rc) return rc;
    331	rc = icc_get_param(icc, 2, &b);
    332	if (rc) return rc;
    333	rc = icc_get_dest(icc, 3, &dst);
    334	if (rc) return rc;
    335
    336	rc = icc_set_inst(icc, dst, a < b);
    337	if (rc) return rc;
    338
    339	icc->rip += 4;
    340	icc->state = ICC_RUN;
    341
    342	return 0;
    343}
    344
    345int
    346icc_inst_test_eq(struct icc *icc)
    347{
    348	int a, b, dst;
    349	int rc;
    350
    351	icc_debug_op(icc, "TEQ", 3);
    352
    353	rc = icc_get_param(icc, 1, &a);
    354	if (rc) return rc;
    355	rc = icc_get_param(icc, 2, &b);
    356	if (rc) return rc;
    357	rc = icc_get_dest(icc, 3, &dst);
    358	if (rc) return rc;
    359
    360	rc = icc_set_inst(icc, dst, a == b);
    361	if (rc) return rc;
    362
    363	icc->rip += 4;
    364	icc->state = ICC_RUN;
    365
    366	return 0;
    367}
    368
    369int
    370icc_inst_base(struct icc *icc)
    371{
    372	int off, rc;
    373
    374	icc_debug_op(icc, "BASE", 1);
    375
    376	rc = icc_get_param(icc, 1, &off);
    377	if (rc) return rc;
    378
    379	icc->base += off;
    380	icc->rip += 2;
    381	icc->state = ICC_RUN;
    382
    383	return 0;
    384}
    385
    386int
    387icc_inst_halt(struct icc *icc)
    388{
    389	icc_debug_op(icc, "HALT", 0);
    390
    391	icc->state = ICC_HALT;
    392
    393	return 0;
    394}
    395
    396int
    397icc_step_inst(struct icc *icc)
    398{
    399	int inst, rc;
    400
    401	icc_debug_op_pre(icc);
    402
    403	rc = icc_get_inst(icc, icc->rip, &inst);
    404	if (rc) return rc;
    405
    406	switch (inst % 100) {
    407	case ICC_INST_ADD:
    408		rc = icc_inst_add(icc);
    409		break;
    410	case ICC_INST_MULT:
    411		rc = icc_inst_mul(icc);
    412		break;
    413	case ICC_INST_STORE:
    414		rc = icc_inst_store(icc);
    415		break;
    416	case ICC_INST_LOAD:
    417		rc = icc_inst_load(icc);
    418		break;
    419	case ICC_INST_JMPT:
    420		rc = icc_inst_jmp_true(icc);
    421		break;
    422	case ICC_INST_JMPF:
    423		rc = icc_inst_jmp_false(icc);
    424		break;
    425	case ICC_INST_TLT:
    426		rc = icc_inst_test_lt(icc);
    427		break;
    428	case ICC_INST_TEQ:
    429		rc = icc_inst_test_eq(icc);
    430		break;
    431	case ICC_INST_BASE:
    432		rc = icc_inst_base(icc);
    433		break;
    434	case ICC_INST_HALT:
    435		rc = icc_inst_halt(icc);
    436		break;
    437	default:
    438		rc = ICC_INV_INST;
    439		break;
    440	}
    441
    442	if (icc->debug) {
    443		if (!icc->line_terminated) {
    444			fprintf(stderr, "\n");
    445			icc->line_terminated = true;
    446		}
    447		if (rc != ICC_OK)
    448			fprintf(stderr, " -- error: %s --\n", icc_err[rc]);
    449	}
    450
    451	return rc;
    452}
    453
    454int
    455icc_set_inst(struct icc *icc, int addr, int val)
    456{
    457	int *slot;
    458
    459	if ((size_t) addr >= icc->instructions.len) {
    460		icc->write_addr = addr;
    461		assert(icc->abort_on_err);
    462		return ICC_OOB_WRITE;
    463	}
    464
    465	slot = dvec_at(&icc->instructions, (size_t) addr);
    466	*slot = val;
    467
    468	return 0;
    469}
    470
    471int
    472icc_get_inst(struct icc *icc, int addr, int *out)
    473{
    474	if ((size_t) addr >= icc->instructions.len) {
    475		icc->read_addr = addr;
    476		assert(icc->abort_on_err);
    477		return ICC_OOB_READ;
    478	}
    479
    480	*out = *(int*)dvec_at(&icc->instructions, (size_t) addr);
    481
    482	return 0;
    483}
    484
    485int
    486icc_param_mode(int inst, int param)
    487{
    488	int div, i;
    489
    490	div = 100;
    491	for (i = 1; i < param; i++) div *= 10;
    492
    493	return (inst / div) % 10 == 1 ? ICC_PARAM_IMM : ICC_PARAM_POS;
    494}
    495
    496int
    497icc_get_param(struct icc *icc, int param, int *out)
    498{
    499	int inst, val;
    500	int rc;
    501
    502	rc = icc_get_inst(icc, icc->rip, &inst);
    503	if (rc) return rc;
    504	rc = icc_get_inst(icc, icc->rip + param, &val);
    505	if (rc) return rc;
    506
    507	switch (icc_param_mode(inst, param)) {
    508	case ICC_PARAM_IMM:
    509		*out = val;
    510		break;
    511	case ICC_PARAM_POS:
    512		rc = icc_get_inst(icc, val, out);
    513		if (rc) return rc;
    514		break;
    515	case ICC_PARAM_REL:
    516		*out = icc->base + val;
    517		break;
    518	default:
    519		assert(0);
    520	};
    521
    522	return 0;
    523}
    524
    525int
    526icc_get_dest(struct icc *icc, int param, int *out)
    527{
    528	return icc_get_inst(icc, icc->rip + param, out);
    529}
    530
    531void
    532icc_debug_dump(struct icc *icc, struct dvec *inst)
    533{
    534	int *rip;
    535	size_t i;
    536
    537	if (!icc->debug) return;
    538
    539	rip = icc->instructions.data;
    540	for (i = 0; i < icc->instructions.len; i++, rip++) {
    541		if (i % 8 == 0)
    542			fprintf(stderr, "%4u: ", (int) i);
    543		if (inst != NULL && (i >= inst->len
    544				|| *(int *)dvec_at(inst, i) != *rip)) {
    545			fprintf(stderr, "\x1b[1m%8i\x1b[0m ", *rip);
    546		} else {
    547			fprintf(stderr, "%8i ", *rip);
    548		}
    549		if ((i + 1) % 8 == 0)
    550			fprintf(stderr, "\n");
    551	}
    552	if (i % 8 != 0)
    553		fprintf(stderr, "\n");
    554}
    555