2019-12-08 11:27:24 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint8_t opcode;
|
|
|
|
uint32_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;
|
|
|
|
}
|
|
|
|
|
2019-12-08 15:21:03 +00:00
|
|
|
void instruction_execute(const Instruction* instructions, uint32_t* r, uint32_t* ip_r) {
|
|
|
|
const Instruction i = instructions[r[*ip_r]];
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
const char *name = names[i.opcode];
|
|
|
|
printf(
|
|
|
|
"ip=%2u [%10u, %10u, %10u, %10u, %10u, %10u] %4s %2u %2u %2u ",
|
|
|
|
r[*ip_r], r[0], r[1], r[2], r[3], r[4], r[5], name, i.a, i.b, i.c
|
|
|
|
);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
switch (i.opcode) {
|
2019-12-08 11:27:24 +00:00
|
|
|
// Addition
|
2019-12-08 15:21:03 +00:00
|
|
|
case ADDR: r[i.c] = r[i.a] + r[i.b]; break;
|
|
|
|
case ADDI: r[i.c] = r[i.a] + i.b; break;
|
2019-12-08 11:27:24 +00:00
|
|
|
|
|
|
|
// Multiplication
|
2019-12-08 15:21:03 +00:00
|
|
|
case MULR: r[i.c] = r[i.a] * r[i.b]; break;
|
|
|
|
case MULI: r[i.c] = r[i.a] * i.b; break;
|
2019-12-08 11:27:24 +00:00
|
|
|
|
|
|
|
// Bitwise AND
|
2019-12-08 15:21:03 +00:00
|
|
|
case BANR: r[i.c] = (r[i.a] & r[i.b]); break;
|
|
|
|
case BANI: r[i.c] = (r[i.a] & i.b); break;
|
2019-12-08 11:27:24 +00:00
|
|
|
|
|
|
|
// Bitwise OR
|
2019-12-08 15:21:03 +00:00
|
|
|
case BORR: r[i.c] = (r[i.a] | r[i.b]); break;
|
|
|
|
case BORI: r[i.c] = (r[i.a] | i.b); break;
|
2019-12-08 11:27:24 +00:00
|
|
|
|
|
|
|
// Assignment
|
2019-12-08 15:21:03 +00:00
|
|
|
case SETR: r[i.c] = r[i.a]; break;
|
|
|
|
case SETI: r[i.c] = i.a; break;
|
2019-12-08 11:27:24 +00:00
|
|
|
|
|
|
|
// Greater-than testing
|
2019-12-08 15:21:03 +00:00
|
|
|
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;
|
2019-12-08 11:27:24 +00:00
|
|
|
|
|
|
|
// Equality testing
|
2019-12-08 15:21:03 +00:00
|
|
|
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;
|
2019-12-08 11:27:24 +00:00
|
|
|
|
|
|
|
default: assert(0);
|
|
|
|
}
|
|
|
|
|
2019-12-08 15:21:03 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf("[%10u, %10u, %10u, %10u, %10u, %10u]\r", r[0], r[1], r[2], r[3], r[4], r[5]);
|
|
|
|
#endif
|
|
|
|
getchar();
|
2019-12-08 11:27:24 +00:00
|
|
|
|
2019-12-08 15:21:03 +00:00
|
|
|
r[*ip_r] += 1;
|
2019-12-08 11:27:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
if (argc != 2) {
|
|
|
|
printf("Usage: %s [input]\n", argv[0]);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *file = fopen(argv[1], "r");
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2019-12-08 15:21:03 +00:00
|
|
|
puts("=================");
|
|
|
|
puts(" READING INPUT");
|
|
|
|
puts("=================");
|
2019-12-08 11:27:24 +00:00
|
|
|
#endif
|
2019-12-08 15:21:03 +00:00
|
|
|
uint32_t registers[6] = {1, 0};
|
|
|
|
uint32_t ip_reg = 0;
|
|
|
|
size_t instr_count = 0;
|
|
|
|
for (instr_count = 0; instr_count < 1024 && instruction_read(&instructions[instr_count], file); instr_count++) {
|
|
|
|
const Instruction instr = instructions[instr_count];
|
|
|
|
if (instr.opcode == IP) {
|
|
|
|
// Assuming that an #ip can only occur once here
|
|
|
|
ip_reg = instr.a;
|
|
|
|
instr_count -= 1;
|
|
|
|
}
|
2019-12-08 11:27:24 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2019-12-08 15:21:03 +00:00
|
|
|
printf("opcode: %2d (%s), a: %d, b: %d, c: %d\n", instr.opcode, names[instr.opcode], instr.a, instr.b, instr.c);
|
2019-12-08 11:27:24 +00:00
|
|
|
#endif
|
2019-12-08 15:21:03 +00:00
|
|
|
}
|
2019-12-08 11:27:24 +00:00
|
|
|
|
2019-12-08 15:21:03 +00:00
|
|
|
fclose(file);
|
2019-12-08 11:27:24 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2019-12-08 15:21:03 +00:00
|
|
|
puts("");
|
|
|
|
puts("=======================");
|
|
|
|
puts(" STARTING SIMULATION");
|
|
|
|
puts("=======================");
|
2019-12-08 11:27:24 +00:00
|
|
|
#endif
|
2019-12-08 15:21:03 +00:00
|
|
|
|
|
|
|
while (registers[ip_reg] < instr_count) {
|
|
|
|
instruction_execute(instructions, registers, &ip_reg);
|
2019-12-08 11:27:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
printf("%d\n", registers[0]);
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|