#include #include #include #include #include #include #include #include #include typedef struct { uint8_t opcode; int32_t a, b, c; } Instruction; Instruction instructions[1024]; enum { ADDR, ADDI, MULR, MULI, BANR, BANI, BORR, BORI, SETR, SETI, GTIR, GTRI, GTRR, EQIR, EQRI, EQRR, IP, }; const char *names[] = { "addr", "addi", "mulr", "muli", "banr", "bani", "borr", "bori", "setr", "seti", "gtir", "gtri", "gtrr", "eqir", "eqri", "eqrr", "#ip", }; int instruction_read(Instruction *i, FILE *file) { char mnemonic[64] = {0}; size_t count = fscanf(file, "%s %u %u %u", mnemonic, &i->a, &i->b, &i->c); if (count != 4 && count != 2) return 0; for (int opcode = 0; opcode <= IP; opcode++) { if (strcmp(names[opcode], mnemonic) == 0) { i->opcode = opcode; return 1; } } printf("Unknown mnemonic '%s'\n", mnemonic); return 0; } void instruction_execute(const Instruction *i, int32_t *r, int32_t *ip, int32_t *ip_r) { if (*ip_r != -1) r[*ip_r] = *ip; switch (i->opcode) { // Addition case ADDR: r[i->c] = r[i->a] + r[i->b]; break; case ADDI: r[i->c] = r[i->a] + i->b; break; // Multiplication case MULR: r[i->c] = r[i->a] * r[i->b]; break; case MULI: r[i->c] = r[i->a] * i->b; break; // Bitwise AND case BANR: r[i->c] = (r[i->a] & r[i->b]); break; case BANI: r[i->c] = (r[i->a] & i->b); break; // Bitwise OR case BORR: r[i->c] = (r[i->a] | r[i->b]); break; case BORI: r[i->c] = (r[i->a] | i->b); break; // Assignment case SETR: r[i->c] = r[i->a]; break; case SETI: r[i->c] = i->a; break; // Greater-than testing case GTIR: r[i->c] = (i->a > r[i->b]); break; case GTRI: r[i->c] = (r[i->a] > i->b); break; case GTRR: r[i->c] = (r[i->a] > r[i->b]); break; // Equality testing case EQIR: r[i->c] = (i->a == r[i->b]); break; case EQRI: r[i->c] = (r[i->a] == i->b); break; case EQRR: r[i->c] = (r[i->a] == r[i->b]); break; case IP: *ip_r = i->a; *ip -= 1; break; default: assert(0); } if (*ip_r != -1) *ip = r[*ip_r]; *ip += 1; } int main(int argc, char **argv) { setlocale(LC_NUMERIC, ""); if (argc != 2) { printf("Usage: %s [input]\n", argv[0]); return EXIT_FAILURE; } FILE *file = fopen(argv[1], "r"); int32_t jump_regs[6] = {-1}; int32_t registers[6] = {INT_MAX, 0}; int32_t ip_reg = -1; size_t instr_count = 0; for (instr_count = 0; instr_count < 1024 && instruction_read(&instructions[instr_count], file); instr_count++) { if (instructions[instr_count].opcode == IP) { ip_reg = instructions[instr_count].a; instr_count -= 1; continue; } printf("[%2zu] %s %d %d %d\n", instr_count, names[instructions[instr_count].opcode], instructions[instr_count].a, instructions[instr_count].b, instructions[instr_count].c); } printf("\n"); std::unordered_set breakpoints; bool stepping = true; uint64_t instructions_executed = 0; for (int32_t i = 0; i < instr_count;) { Instruction instruction = instructions[i]; if (breakpoints.find(i) != breakpoints.end()) stepping = true; if (stepping) { const char *name = names[instruction.opcode]; printf("[%2d] \033[33m%s %d %d %d\033[0m\r", i, name, instruction.a, instruction.b, instruction.c); } instruction_execute(&instruction, registers, &i, &ip_reg); if (stepping) { printf("\033[30C[%d, %d, %d, %d, %d, %d]\n", registers[0], registers[1], registers[2], registers[3], registers[4], registers[5]); read: printf("> "); char c; scanf(" %c", &c); switch (c) { case 0: printf("q\n"); [[fallthrough]]; case 'q': i = instr_count; break; case 'c': stepping = false; break; case 'b': breakpoints.insert(i); break; case 's': break; case '\n': goto read; default: printf("Unknown command '%c'\n", c); goto read; } } instructions_executed += 1; if (!stepping && instructions_executed % (1 << 20) == 0) { printf("%'lu %d ", instructions_executed, i); printf("[%'d, %'d, %'d, %'d, %'d, %'d]\033[K\r", registers[0], registers[1], registers[2], registers[3], registers[4], registers[5]); } } printf("instructions: %lu\n", instructions_executed); fclose(file); printf("%d\n", registers[0]); return EXIT_SUCCESS; }