diff options
Diffstat (limited to 'vm.c')
-rw-r--r-- | vm.c | 412 |
1 files changed, 412 insertions, 0 deletions
@@ -0,0 +1,412 @@ +// synacor challenge (@waffle87) +#include "vm.h" + +u16 rPC = 0; +u16 r0 = 0; +u16 r1 = 0; +u16 r2 = 0; +u16 r3 = 0; +u16 r4 = 0; +u16 r5 = 0; +u16 r6 = 0; +u16 r7 = 0; + +int parse(char const *filename) { + FILE *fptr = fopen(filename, "rb"); + if (!fptr) { + fprintf(stderr, "error: opening file: %s\n", filename); + return EXIT_FAILURE; + } + if (fseek(fptr, 0, SEEK_END)) { + fprintf(stderr, "error: opening file: %s\n", filename); + fclose(fptr); + return EXIT_FAILURE; + } + long file_size = ftell(fptr); + if (file_size == EOF) { + fprintf(stderr, "error: opening file: %s\n", filename); + fclose(fptr); + return EXIT_FAILURE; + } + if (fseek(fptr, 0, SEEK_SET)) { + fprintf(stderr, "error: opening file: %s\n", filename); + fclose(fptr); + return EXIT_FAILURE; + } + size_t size_read = fread(m.mem, 1, file_size, fptr); + if (size_read != file_size) { + fprintf(stderr, "error: reading file: %s\n", filename); + fclose(fptr); + return EXIT_FAILURE; + } + int res; + u16 opcode; + u8 *buffer = m.mem; + rPC = 0; + while (1) { + get_next_pair(buffer + rPC, &opcode); + res = operate(opcode, buffer + rPC + 2); + if (res == -1) + break; + rPC = res; + } + fclose(fptr); + return EXIT_SUCCESS; +} + +int operate(u16 opcode, unsigned char *buffer) { + instruction_ptr instr; + int next; + instr = get_instruction(opcode); + if (!instr) + LOG("opcode: %d\n", opcode); + assert(instr); + next = instr(buffer); + if (next == -1) + return EXIT_FAILURE; + return next; +} + +int is_valid(u16 opcode) { return opcode < 32776; } + +int is_literal(u16 opcode) { return opcode < 32768; } + +int is_register(u16 opcode) { return opcode >= 32768 && opcode <= 32775; } + +u16 *get_register(u16 opcode) { + switch (opcode) { + case 32768: + return &r0; + case 32769: + return &r1; + case 32770: + return &r2; + case 32771: + return &r3; + case 32772: + return &r4; + case 32773: + return &r5; + case 32774: + return &r6; + case 32775: + return &r7; + default: + return NULL; + } +} + +instruction_ptr get_instruction(u16 opcode) { + switch (opcode) { + case 0: + return &instruction_halt; + case 1: + return &instruction_set; + case 2: + return &instruction_push; + case 3: + return &instruction_pop; + case 4: + return &instruction_eq; + case 5: + return &instruction_gt; + case 6: + return &instruction_jmp; + case 7: + return &instruction_jt; + case 8: + return &instruction_jf; + case 9: + return &instruction_add; + case 10: + return &instruction_mult; + case 11: + return &instruction_mod; + case 12: + return &instruction_and; + case 13: + return &instruction_or; + case 14: + return &instruction_not; + case 15: + return &instruction_rmem; + case 16: + return &instruction_wmem; + case 17: + return &instruction_call; + case 18: + return &instruction_ret; + case 19: + return &instruction_out; + case 20: + return &instruction_in; + case 21: + return &instruction_noop; + default: + return NULL; + } +} + +int instruction_halt(u8 *buffer) { return -1; } + +int instruction_set(u8 *buffer) { + u16 next, *a; + buffer = get_next_pair(buffer, &next); + LOG("set: %d", next); + a = get_register(next); + buffer = get_next_pair(buffer, &next); + if (is_register(next)) + next = *get_register(next); + LOG(" %d\n", next); + *a = next; + return rPC + 6; +} + +int instruction_push(u8 *buffer) { + u16 next; + buffer = get_next_pair(buffer, &next); + if (is_register(next)) + next = *get_register(next); + stack_push(&s, next); + LOG("push: %d\n", next); + return rPC + 4; +} + +int instruction_pop(u8 *buffer) { + u16 next, *a; + buffer = get_next_pair(buffer, &next); + a = get_register(next); + *a = stack_pop(&s); + LOG("pop: %d\n", *a); + return rPC + 4; +} + +int instruction_eq(u8 *buffer) { + u16 next, *a, b, c; + buffer = get_next_pair(buffer, &next); + LOG("%d: eq: %s", rPC, REG(next)); + a = get_register(next); + buffer = get_next_pair(buffer, &b); + LOG(" %s", REG(b)); + if (is_register(b)) + b = *get_register(b); + LOG("(%d)", b); + buffer = get_next_pair(buffer, &c); + LOG(" %s", REG(c)); + if (is_register(c)) + c = *get_register(c); + LOG("(%d)\n", c); + *a = b == c ? 1 : 0; + return rPC + 8; +} + +int instruction_gt(u8 *buffer) { + u16 next, *a, b, c; + buffer = get_next_pair(buffer, &next); + LOG("gt: %d", next); + a = get_register(next); + buffer = get_next_pair(buffer, &b); + if (is_register(b)) + b = *get_register(b); + buffer = get_next_pair(buffer, &c); + if (is_register(c)) + c = *get_register(c); + *a = b > c ? 1 : 0; + LOG(" %d %d\n", b, c); + return rPC + 2 + 6; +} + +int instruction_jmp(u8 *buffer) { + u16 next; + buffer = get_next_pair(buffer, &next); + if (is_register(next)) + next = *get_register(next); + LOG("jmp: %d\n", next); + return next * 2; +} + +int instruction_jt(u8 *buffer) { + u16 a, b; + buffer = get_next_pair(buffer, &a); + LOG("jt: %d", a); + if (is_register(a)) + a = *get_register(a); + buffer = get_next_pair(buffer, &b); + if (is_register(b)) + b = *get_register(b); + LOG(" %d\n", b); + return a ? b * 2 : rPC + 6; +} + +int instruction_jf(u8 *buffer) { + u16 a, b; + buffer = get_next_pair(buffer, &a); + LOG("jf: %d", a); + if (is_register(a)) + a = *get_register(a); + buffer = get_next_pair(buffer, &b); + if (is_register(b)) + b = *get_register(b); + LOG(" %d\n", b); + return !a ? b * 2 : rPC + 6; +} + +int instruction_add(u8 *buffer) { + u16 next, *a, b, c; + buffer = get_next_pair(buffer, &next); + a = get_register(next); + LOG("add: %d ", next); + buffer = get_next_pair(buffer, &b); + if (is_register(b)) + b = *get_register(b); + buffer = get_next_pair(buffer, &c); + if (is_register(c)) + c = *get_register(c); + *a = (b + c) % 32768; + LOG("%d %d\n", b, c); + return rPC + 8; +} + +int instruction_mult(u8 *buffer) { + u16 next, *a, b, c; + buffer = get_next_pair(buffer, &next); + a = get_register(next); + LOG("mult: %d ", next); + buffer = get_next_pair(buffer, &b); + if (is_register(b)) + b = *get_register(b); + buffer = get_next_pair(buffer, &c); + if (is_register(c)) + c = *get_register(c); + *a = (b * c) % 32768; + LOG("%d %d\n", b, c); + return rPC + 8; +} + +int instruction_mod(u8 *buffer) { + u16 next, *a, b, c; + buffer = get_next_pair(buffer, &next); + a = get_register(next); + LOG("mod: %d ", next); + buffer = get_next_pair(buffer, &b); + if (is_register(b)) + b = *get_register(b); + buffer = get_next_pair(buffer, &c); + if (is_register(c)) + c = *get_register(c); + *a = (b % c); + LOG("%d %d\n", b, c); + return rPC + 8; +} + +int instruction_and(u8 *buffer) { + u16 next, *a, b, c; + buffer = get_next_pair(buffer, &next); + LOG("and: %d", next); + a = get_register(next); + buffer = get_next_pair(buffer, &b); + if (is_register(b)) + b = *get_register(b); + buffer = get_next_pair(buffer, &c); + if (is_register(c)) + c = *get_register(c); + LOG(" %d %d\n", b, c); + *a = b & c; + return rPC + 8; +} + +int instruction_or(u8 *buffer) { + u16 next, *a, b, c; + buffer = get_next_pair(buffer, &next); + LOG("or: %d", next); + a = get_register(next); + buffer = get_next_pair(buffer, &b); + if (is_register(b)) + b = *get_register(b); + buffer = get_next_pair(buffer, &c); + if (is_register(c)) + c = *get_register(c); + LOG(" %d %d\n", b, c); + *a = b | c; + return rPC + 8; +} + +int instruction_not(u8 *buffer) { + u16 next, *a, b; + buffer = get_next_pair(buffer, &next); + LOG("not: %d", next); + a = get_register(next); + buffer = get_next_pair(buffer, &b); + if (is_register(b)) + b = *get_register(b); + LOG(" %d\n", b); + *a = ~b; + *a ^= 0x8000; + return rPC + 6; +} + +int instruction_rmem(u8 *buffer) { + u16 next, *a, b; + buffer = get_next_pair(buffer, &next); + LOG("%d: rmem: %d", rPC, next); + a = get_register(next); + buffer = get_next_pair(buffer, &b); + LOG(" %d\n", b); + if (is_register(b)) + b = *get_register(b); + *a = mem_get(&m, b); + return rPC + 6; +} + +int instruction_wmem(u8 *buffer) { + u16 a, b; + buffer = get_next_pair(buffer, &a); + LOG("wmem: %d", a); + if (is_register(a)) + a = *get_register(a); + buffer = get_next_pair(buffer, &b); + LOG(" %d\n", b); + if (is_register(b)) + b = *get_register(b); + mem_set(&m, a, b); + return rPC + 6; +} + +int instruction_call(u8 *buffer) { + u16 a; + buffer = get_next_pair(buffer, &a); + if (is_register(a)) + a = *get_register(a); + LOG("call: %d\n", a); + stack_push(&s, (rPC + 4) / 2); + return a * 2; +} + +int instruction_ret(u8 *buffer) { + u16 addr; + LOG("ret\n"); + addr = stack_pop(&s); + return addr * 2; +} + +int instruction_out(u8 *buffer) { + u16 next; + buffer = get_next_pair(buffer, &next); + if (is_register(next)) + next = *get_register(next); + fprintf(stdout, "%c", next); + return rPC + 4; +} + +int instruction_in(u8 *buffer) { + char in; + u16 addr, *reg = NULL; + get_next_pair(buffer, &addr); + reg = get_register(addr); + LOG("in: %d\n", addr); + in = getchar(); + *reg = in; + return rPC + 4; +} + +int instruction_noop(u8 *buffer) { return rPC + 2; } |