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