iccmp.c (14328B)
1#include "iccmp.h" 2#include "allocator.h" 3#include "aoc.h" 4#include "hmap.h" 5#include "maxint.h" 6#include "util.h" 7 8#include <assert.h> 9#include <stdbool.h> 10#include <stdint.h> 11 12const char *icc_err[] = { 13 [ICC_OK] = "ok", 14 [ICC_INV_INST] = "invalid instruction", 15 [ICC_OOB_WRITE] = "write addr oob", 16 [ICC_OOB_READ] = "read addr oob", 17}; 18 19static struct maxint * 20mi_tmp(int64_t val) 21{ 22 static mi_ul data = 0; 23 static struct maxint m = { &data, 1, 1, MI_POS }; 24 25 data = (mi_ul) ABS(val); 26 m.sign = val >= 0 ? MI_POS : MI_NEG; 27 28 return &m; 29} 30 31static bool 32icc_hmap_keycmp(struct hmap_key k1, struct hmap_key k2) 33{ 34 return mi_cmp(k1.p, k2.p) == 0; 35} 36 37static uint32_t 38icc_hmap_hash(struct hmap_key key) 39{ 40 return (uint32_t) mi_cast_ul(key.p); 41} 42 43void 44icc_init(struct icc *icc) 45{ 46 int rc; 47 48 icc->state = ICC_RUN; 49 50 icc->debug = getenv("ICC_DEBUG") != NULL; 51 52 mi_init(&icc->rip); 53 mi_setv(&icc->rip, 0, MI_POS); 54 55 mi_init(&icc->base); 56 mi_setv(&icc->base, 0, MI_POS); 57 58 mi_init(&icc->in); 59 mi_init(&icc->out); 60 mi_init(&icc->read_addr); 61 mi_init(&icc->write_addr); 62 63 mi_init(&icc->r1); 64 mi_init(&icc->r2); 65 mi_init(&icc->r3); 66 mi_init(&icc->r4); 67 mi_init(&icc->tmp); 68 69 icc->abort_on_err = true; 70 71 icc->line_terminated = true; 72 73 rc = hmap_init(&icc->instructions, 1024, icc_hmap_hash, 74 icc_hmap_keycmp, &stdlib_strict_heap_allocator); 75 assert(!rc); 76} 77 78void 79icc_deinit(struct icc *icc) 80{ 81 struct hmap_iter iter; 82 83 mi_deinit(&icc->rip); 84 mi_deinit(&icc->base); 85 mi_deinit(&icc->in); 86 mi_deinit(&icc->out); 87 mi_deinit(&icc->read_addr); 88 mi_deinit(&icc->write_addr); 89 mi_deinit(&icc->r1); 90 mi_deinit(&icc->r2); 91 mi_deinit(&icc->r3); 92 mi_deinit(&icc->r4); 93 mi_deinit(&icc->tmp); 94 95 for (HMAP_ITER(&icc->instructions, iter)) { 96 mi_deinit(iter.link->key._p); 97 free(iter.link->key._p); 98 mi_deinit(iter.link->value._p); 99 free(iter.link->value._p); 100 } 101 102 hmap_deinit(&icc->instructions); 103} 104 105void 106icc_copy(struct icc *dst, struct icc *src) 107{ 108 struct hmap_iter hmap_iter; 109 struct maxint *key, *value; 110 111 dst->state = src->state; 112 mi_set(&dst->rip, &src->rip); 113 mi_set(&dst->base, &src->base); 114 mi_set(&dst->in, &src->in); 115 mi_set(&dst->out, &src->out); 116 117 for (HMAP_ITER(&dst->instructions, hmap_iter)) { 118 mi_deinit(hmap_iter.link->key._p); 119 free(hmap_iter.link->key._p); 120 mi_deinit(hmap_iter.link->value._p); 121 free(hmap_iter.link->value._p); 122 } 123 hmap_clear(&dst->instructions); 124 125 for (HMAP_ITER(&src->instructions, hmap_iter)) { 126 key = malloc(sizeof(struct maxint)); 127 mi_init(key); 128 mi_set(key, hmap_iter.link->key.p); 129 value = malloc(sizeof(struct maxint)); 130 mi_init(value); 131 mi_set(value, hmap_iter.link->value.p); 132 hmap_add(&dst->instructions, (struct hmap_key) {.p = key}, 133 (struct hmap_val) {.p = value}); 134 } 135} 136 137void 138icc_reset(struct icc *icc, struct hmap *inst) 139{ 140 int rc; 141 142 icc->state = ICC_RUN; 143 mi_setv(&icc->rip, 0, MI_POS); 144 mi_setv(&icc->base, 0, MI_POS); 145 if (inst) { 146 rc = hmap_copy(&icc->instructions, inst); 147 assert(!rc); 148 } 149} 150 151void 152icc_parse_inst(struct icc *icc, const char *str, size_t len) 153{ 154 struct maxint *key, *val; 155 const char *pos, *end; 156 char buf[256]; 157 int64_t v; 158 int rc, rip; 159 160 pos = str; 161 end = str + len; 162 rip = 0; 163 while (readtok(buf, sizeof(buf), ',', &pos, end)) { 164 v = parsei64(buf); 165 166 key = malloc(sizeof(struct maxint)); 167 assert(key != NULL); 168 mi_init(key); 169 mi_setv(key, (mi_ul) rip, MI_POS); 170 171 val = malloc(sizeof(struct maxint)); 172 assert(val != NULL); 173 mi_init(val); 174 mi_setv(val, (mi_ul) ABS(v), v >= 0 ? MI_POS : MI_NEG); 175 176 rc = hmap_add(&icc->instructions, (struct hmap_key) {.p = key}, 177 (struct hmap_val) {.p = val}); 178 assert(!rc); 179 180 rip += 1; 181 } 182} 183 184const char * 185icc_literal_str(struct icc *icc, struct maxint *addr, size_t zfill) 186{ 187 static char buf[64]; 188 189 mi_dec(addr, buf, sizeof(buf), zfill); 190 191 return buf; 192} 193 194const char * 195icc_value_str(struct icc *icc, struct maxint *addr, size_t zfill) 196{ 197 static char buf[62]; 198 struct maxint *val; 199 int rc; 200 201 rc = icc_read(icc, addr, &val); 202 if (rc) { 203 snprintf(buf, sizeof(buf), "???"); 204 } else { 205 mi_dec(val, buf, sizeof(buf), zfill); 206 } 207 208 return buf; 209} 210 211static void 212icc_debug_op_pre(struct icc *icc) 213{ 214 if (!icc->debug) return; 215 216 fprintf(stderr, "%*s: ", 5, icc_literal_str(icc, &icc->rip, 0)); 217 fprintf(stderr, "(%*s) ", 5, icc_value_str(icc, &icc->rip, 5)); 218 icc->line_terminated = false; 219} 220 221static void 222icc_debug_op_main(struct icc *icc, struct maxint *tmp, const char *opstr, int n) 223{ 224 struct maxint *inst, *val; 225 int i, rc, instint; 226 227 if (!icc->debug) return; 228 229 rc = icc_read(icc, &icc->rip, &inst); 230 assert(!rc); 231 232 fprintf(stderr, "%s ", opstr); 233 icc->line_terminated = false; 234 235 mi_set(tmp, &icc->rip); 236 instint = (int) mi_cast_ul(inst); 237 for (i = 1; i <= n; i++) { 238 if (i > 1) fprintf(stderr, ", "); 239 mi_add(tmp, tmp, mi_tmp(1)); 240 rc = icc_read(icc, tmp, &val); 241 if (rc) { 242 fprintf(stderr, "???"); 243 continue; 244 } 245 switch (icc_param_mode(instint, i)) { 246 case ICC_PARAM_IMM: 247 fprintf(stderr, "%s", icc_literal_str(icc, val, 0)); 248 break; 249 case ICC_PARAM_POS: 250 fprintf(stderr, "[%s]=%s", icc_literal_str(icc, val, 0), 251 icc_value_str(icc, val, 0)); 252 break; 253 case ICC_PARAM_REL: 254 mi_add(tmp, &icc->base, val); 255 fprintf(stderr, "[%s+", icc_literal_str(icc, &icc->base, 0)); 256 fprintf(stderr, "%s", icc_literal_str(icc, val, 0)); 257 fprintf(stderr, "=%s]=%s", icc_literal_str(icc, tmp, 0), 258 icc_value_str(icc, tmp, 0)); 259 break; 260 default: 261 assert(0); 262 } 263 } 264} 265 266static void 267icc_debug_op_post(struct icc *icc, struct maxint *addr) 268{ 269 if (!icc->debug) return; 270 271 fprintf(stderr, " -> [%s]=%s\n", icc_literal_str(icc, addr, 0), 272 icc_value_str(icc, addr, 0)); 273 icc->line_terminated = true; 274} 275 276static void 277icc_debug_op(struct icc *icc, struct maxint *tmp, const char *opstr, int n) 278{ 279 if (!icc->debug) return; 280 281 icc_debug_op_main(icc, tmp, opstr, n); 282 fprintf(stderr, "\n"); 283 icc->line_terminated = true; 284} 285 286int 287icc_inst_add(struct icc *icc) 288{ 289 struct maxint *dst; 290 int rc; 291 292 icc_debug_op_main(icc, &icc->tmp, "ADD", 3); 293 294 rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1); 295 if (rc) return rc; 296 rc = icc_get_param(icc, &icc->tmp, 2, &icc->r2); 297 if (rc) return rc; 298 rc = icc_get_dest(icc, &icc->tmp, 3, &icc->r3); 299 if (rc) return rc; 300 301 mi_add(&icc->tmp, &icc->r1, &icc->r2); 302 rc = icc_write(icc, &icc->r3, &icc->tmp); 303 if (rc) return rc; 304 305 icc_debug_op_post(icc, dst); 306 307 mi_add(&icc->rip, &icc->rip, mi_tmp(4)); 308 icc->state = ICC_RUN; 309 310 return 0; 311} 312 313int 314icc_inst_mul(struct icc *icc) 315{ 316 int rc; 317 318 icc_debug_op_main(icc, &icc->tmp, "MUL", 3); 319 320 rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1); 321 if (rc) return rc; 322 rc = icc_get_param(icc, &icc->tmp, 2, &icc->r2); 323 if (rc) return rc; 324 rc = icc_get_dest(icc, &icc->tmp, 3, &icc->r3); 325 if (rc) return rc; 326 327 mi_mul(&icc->tmp, &icc->r1, &icc->r2); 328 rc = icc_write(icc, &icc->r3, &icc->tmp); 329 if (rc) return rc; 330 331 icc_debug_op_post(icc, &icc->r3); 332 333 mi_add(&icc->rip, &icc->rip, mi_tmp(4)); 334 icc->state = ICC_RUN; 335 336 return 0; 337} 338 339int 340icc_inst_store(struct icc *icc) 341{ 342 int rc; 343 344 if (icc->state != ICC_INPUT || !icc->in.size) { 345 icc_debug_op(icc, &icc->tmp, "INPUT", 0); 346 icc->state = ICC_INPUT; 347 icc->in.size = 0; 348 } else { 349 icc_debug_op_main(icc, &icc->tmp, "STORE", 1); 350 351 rc = icc_get_dest(icc, &icc->tmp, 1, &icc->r1); 352 if (rc) return rc; 353 354 rc = icc_write(icc, &icc->r1, &icc->in); 355 if (rc) return rc; 356 357 icc_debug_op_post(icc, &icc->r1); 358 359 mi_add(&icc->rip, &icc->rip, mi_tmp(2)); 360 icc->state = ICC_RUN; 361 } 362 363 return 0; 364} 365 366int 367icc_inst_load(struct icc *icc) 368{ 369 int rc; 370 371 if (icc->state != ICC_OUTPUT) { 372 icc_debug_op(icc, &icc->tmp, "LOAD", 1); 373 374 rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1); 375 if (rc) return rc; 376 377 mi_set(&icc->out, &icc->r1); 378 icc->state = ICC_OUTPUT; 379 380 icc_debug_op(icc, &icc->tmp, "OUTPUT", 0); 381 } else { 382 mi_add(&icc->rip, &icc->rip, mi_tmp(2)); 383 icc->state = ICC_RUN; 384 } 385 386 return 0; 387} 388 389int 390icc_inst_jmp_true(struct icc *icc) 391{ 392 int rc; 393 394 icc_debug_op(icc, &icc->tmp, "JMPT", 2); 395 396 rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1); 397 if (rc) return rc; 398 rc = icc_get_param(icc, &icc->tmp, 2, &icc->r2); 399 if (rc) return rc; 400 401 if (!mi_zero(&icc->r1)) { 402 mi_set(&icc->rip, &icc->r2); 403 } else { 404 mi_add(&icc->rip, &icc->rip, mi_tmp(3)); 405 } 406 407 icc->state = ICC_RUN; 408 409 return 0; 410} 411 412int 413icc_inst_jmp_false(struct icc *icc) 414{ 415 int rc; 416 417 icc_debug_op(icc, &icc->tmp, "JMPF", 2); 418 419 rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1); 420 if (rc) return rc; 421 rc = icc_get_param(icc, &icc->tmp, 2, &icc->r2); 422 if (rc) return rc; 423 424 if (mi_zero(&icc->r1)) { 425 mi_set(&icc->rip, &icc->r2); 426 } else { 427 mi_add(&icc->rip, &icc->rip, mi_tmp(3)); 428 } 429 430 icc->state = ICC_RUN; 431 432 return 0; 433} 434 435int 436icc_inst_test_lt(struct icc *icc) 437{ 438 int rc; 439 440 icc_debug_op_main(icc, &icc->tmp, "TLT", 3); 441 442 rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1); 443 if (rc) return rc; 444 rc = icc_get_param(icc, &icc->tmp, 2, &icc->r2); 445 if (rc) return rc; 446 rc = icc_get_dest(icc, &icc->tmp, 3, &icc->r3); 447 if (rc) return rc; 448 449 mi_setv(&icc->tmp, mi_cmp(&icc->r1, &icc->r2) == -1, MI_POS); 450 rc = icc_write(icc, &icc->r3, &icc->tmp); 451 if (rc) return rc; 452 453 icc_debug_op_post(icc, &icc->r3); 454 455 mi_add(&icc->rip, &icc->rip, mi_tmp(4)); 456 icc->state = ICC_RUN; 457 458 return 0; 459} 460 461int 462icc_inst_test_eq(struct icc *icc) 463{ 464 int rc; 465 466 icc_debug_op_main(icc, &icc->tmp, "TEQ", 3); 467 468 rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1); 469 if (rc) return rc; 470 rc = icc_get_param(icc, &icc->tmp, 2, &icc->r2); 471 if (rc) return rc; 472 rc = icc_get_dest(icc, &icc->tmp, 3, &icc->r3); 473 if (rc) return rc; 474 475 mi_setv(&icc->tmp, mi_cmp(&icc->r1, &icc->r2) == 0, MI_POS); 476 rc = icc_write(icc, &icc->r3, &icc->tmp); 477 if (rc) return rc; 478 479 icc_debug_op_post(icc, &icc->r3); 480 481 mi_add(&icc->rip, &icc->rip, mi_tmp(4)); 482 icc->state = ICC_RUN; 483 484 return 0; 485} 486 487int 488icc_inst_base(struct icc *icc) 489{ 490 int rc; 491 492 icc_debug_op_main(icc, &icc->tmp, "BASE", 1); 493 494 rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1); 495 if (rc) return rc; 496 497 mi_add(&icc->base, &icc->base, &icc->r1); 498 mi_add(&icc->rip, &icc->rip, mi_tmp(2)); 499 icc->state = ICC_RUN; 500 501 if (icc->debug) { 502 fprintf(stderr, " -> BASE:%s\n", 503 icc_literal_str(icc, &icc->base, 0)); 504 icc->line_terminated = true; 505 } 506 507 return 0; 508} 509 510int 511icc_inst_halt(struct icc *icc) 512{ 513 icc_debug_op(icc, &icc->tmp, "HALT", 0); 514 515 icc->state = ICC_HALT; 516 517 return 0; 518} 519 520int 521icc_step_inst(struct icc *icc) 522{ 523 struct maxint *inst; 524 int rc; 525 526 icc_debug_op_pre(icc); 527 528 rc = icc_read(icc, &icc->rip, &inst); 529 if (rc) return rc; 530 531 switch (mi_cast_ul(inst) % 100) { 532 case ICC_INST_ADD: 533 rc = icc_inst_add(icc); 534 break; 535 case ICC_INST_MULT: 536 rc = icc_inst_mul(icc); 537 break; 538 case ICC_INST_STORE: 539 rc = icc_inst_store(icc); 540 break; 541 case ICC_INST_LOAD: 542 rc = icc_inst_load(icc); 543 break; 544 case ICC_INST_JMPT: 545 rc = icc_inst_jmp_true(icc); 546 break; 547 case ICC_INST_JMPF: 548 rc = icc_inst_jmp_false(icc); 549 break; 550 case ICC_INST_TLT: 551 rc = icc_inst_test_lt(icc); 552 break; 553 case ICC_INST_TEQ: 554 rc = icc_inst_test_eq(icc); 555 break; 556 case ICC_INST_BASE: 557 rc = icc_inst_base(icc); 558 break; 559 case ICC_INST_HALT: 560 rc = icc_inst_halt(icc); 561 break; 562 default: 563 rc = ICC_INV_INST; 564 break; 565 } 566 567 if (icc->debug) { 568 if (!icc->line_terminated) { 569 fprintf(stderr, "\n"); 570 icc->line_terminated = true; 571 } 572 if (rc != ICC_OK) 573 fprintf(stderr, " -- error: %s --\n", icc_err[rc]); 574 } 575 576 return rc; 577} 578 579struct hmap_link * 580icc_write_any(struct icc *icc, struct maxint *addr, struct maxint *value) 581{ 582 struct hmap_link **link; 583 struct maxint *key, *val; 584 585 link = hmap_link_pos(&icc->instructions, (struct hmap_key) {.p = addr}); 586 if (*link) { 587 mi_set((*link)->value._p, value); 588 } else { 589 key = malloc(sizeof(struct maxint)); 590 assert(key != NULL); 591 mi_init(key); 592 mi_set(key, addr); 593 594 val = malloc(sizeof(struct maxint)); 595 assert(val != NULL); 596 mi_init(val); 597 mi_set(val, value); 598 599 *link = hmap_link_alloc(&icc->instructions, 600 (struct hmap_key) {.p = key}, 601 (struct hmap_val) {.p = val}, NULL); 602 } 603 604 return *link; 605} 606 607int 608icc_write(struct icc *icc, struct maxint *addr, struct maxint *val) 609{ 610 struct hmap_link *link; 611 612 link = hmap_get(&icc->instructions, (struct hmap_key) {.p = addr}); 613 if (!link) { 614 if (addr->sign != MI_POS) { 615 mi_set(&icc->read_addr, addr); 616 assert(!icc->abort_on_err); 617 return ICC_OOB_READ; 618 } 619 620 icc_write_any(icc, addr, val); 621 } else { 622 mi_set(link->value._p, val); 623 } 624 625 return 0; 626} 627 628int 629icc_read(struct icc *icc, struct maxint *addr, struct maxint **out) 630{ 631 struct hmap_link *link; 632 633 link = hmap_get(&icc->instructions, (struct hmap_key) {.p = addr}); 634 if (!link) { 635 if (addr->sign != MI_POS) { 636 mi_set(&icc->read_addr, addr); 637 assert(!icc->abort_on_err); 638 return ICC_OOB_READ; 639 } 640 641 link = icc_write_any(icc, addr, mi_tmp(0)); 642 } 643 *out = link->value._p; 644 645 return 0; 646} 647 648int 649icc_param_mode(int inst, int param) 650{ 651 int div, i; 652 653 div = 100; 654 for (i = 1; i < param; i++) div *= 10; 655 656 return (inst / div) % 10; 657} 658 659int 660icc_get_param(struct icc *icc, struct maxint *tmp, int param, struct maxint *out) 661{ 662 struct maxint *inst, *val, *val2; 663 int rc; 664 665 /* TODO: make out double pointer and optimize out mi_set */ 666 667 rc = icc_read(icc, &icc->rip, &inst); 668 if (rc) return rc; 669 670 mi_setv(tmp, (mi_ul) ABS(param), param >= 0 ? MI_POS : MI_NEG); 671 mi_add(tmp, tmp, &icc->rip); 672 rc = icc_read(icc, tmp, &val); 673 if (rc) return rc; 674 675 assert(mi_lastset(inst) == 0); 676 switch (icc_param_mode((int) mi_cast_ul(inst), param)) { 677 case ICC_PARAM_IMM: 678 mi_set(out, val); 679 break; 680 case ICC_PARAM_POS: 681 rc = icc_read(icc, val, &val2); 682 if (rc) return rc; 683 mi_set(out, val2); 684 break; 685 case ICC_PARAM_REL: 686 mi_add(tmp, &icc->base, val); 687 rc = icc_read(icc, tmp, &val2); 688 mi_set(out, val2); 689 break; 690 default: 691 assert(0); 692 }; 693 694 return 0; 695} 696 697int 698icc_get_dest(struct icc *icc, struct maxint *tmp, int param, struct maxint *out) 699{ 700 struct maxint *inst, *val; 701 int rc; 702 703 rc = icc_read(icc, &icc->rip, &inst); 704 if (rc) return rc; 705 706 mi_setv(tmp, (mi_ul) ABS(param), param >= 0 ? MI_POS : MI_NEG); 707 mi_add(tmp, tmp, &icc->rip); 708 rc = icc_read(icc, tmp, &val); 709 if (rc) return rc; 710 711 switch (icc_param_mode((int) mi_cast_ul(inst), param)) { 712 case ICC_PARAM_POS: 713 mi_set(out, val); 714 break; 715 case ICC_PARAM_REL: 716 mi_add(out, &icc->base, val); 717 break; 718 default: 719 assert(0); 720 } 721 722 return 0; 723} 724 725void 726icc_debug_print(struct icc *icc, struct maxint *addr) 727{ 728 if (!icc->debug) return; 729 730 fprintf(stderr, "[%s] = %s\n", icc_literal_str(icc, addr, 0), 731 icc_value_str(icc, addr, 0)); 732} 733