#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
// begin C++ pain
#include <queue>
using namespace std;
#define A(inst) ((inst >> 0x6) & 0x7)
#define B(inst) ((inst >> 0x3) & 0x7)
#define C(inst) (inst & 0x7)
#define A13(inst) ((inst >> 25) & 0x7)
#define DATA(inst) (inst & 0x1ffffff)
#define OP(inst) (inst >> 28)
#define REG(num) (registers[num])
#define REGA(inst) (REG(A(inst)))
#define REGB(inst) (REG(B(inst)))
#define REGC(inst) (REG(C(inst)))
#define REGA13(inst) (REG(A13(inst)))
#define MEMSIZ (1024 * 1024 * 32)
typedef unsigned int platter;
platter registers[8] = {0,0,0,0,0,0,0,0};
platter * arrays[MEMSIZ];
size_t siz_arrays[MEMSIZ];
size_t num_array = 1;
platter finger = 0;
int last_free = 0;
int main(int argc, char *argv[]) {
int lastloc = 0, i;
platter cur;
platter * temp;
struct stat x;
queue<int> free_list;
stat(argv[1], &x);
temp = (platter *) mmap(NULL, x.st_size,
PROT_READ | PROT_WRITE, MAP_PRIVATE,
open(argv[1], O_RDONLY, 0600), (off_t) 0);
arrays[0] = (platter *) malloc(x.st_size);
memcpy(arrays[0], temp, x.st_size);
munmap(temp, x.st_size);
siz_arrays[0] = x.st_size;
while(1) {
cur = htonl(arrays[0][finger++]);
switch(OP(cur)) {
// condmove
case 0:
if (REGC(cur) != 0) {
REGA(cur) = REGB(cur);
}
break;
// index
case 1:
REGA(cur) = arrays[REGB(cur)][REGC(cur)];
break;
// amend
case 2:
assert(arrays[REGA(cur)] != 0);
arrays[REGA(cur)][REGB(cur)] = REGC(cur);
break;
// add
case 3:
REGA(cur) = REGB(cur) + REGC(cur);
break;
// mult
case 4:
REGA(cur) = REGB(cur) * REGC(cur);
break;
// div
case 5:
REGA(cur) = REGB(cur) / REGC(cur);
break;
// not_and
case 6:
REGA(cur) = ~ (REGB(cur) & REGC(cur));
break;
// halt
case 7:
exit(0);
break;
// alloc
case 8:
// try and pop a location off the stack, otherwise start counting up
if (!free_list.empty()) {
i = free_list.front();
free_list.pop();
} else {
for (i = lastloc+1;
arrays[i] != NULL && i != lastloc;
i = (i + 1) % MEMSIZ) ;
}
// this tracks the last insertion instead
/* for (i = last_free;
arrays[i] != NULL && i != last_free-1;
i = (i + 1) % MEMSIZ) ; */
// this version walks forward in the array
/* for (i = lastloc+1;
arrays[i] != NULL && i != lastloc;
i = (i + 1) % MEMSIZ) ; */
//assert(i != lastloc);
//assert(i != last_free-1);
// move last_free somewhere random, for fun
//last_free = rand() % MEMSIZ;
lastloc = i;
arrays[i] = (platter *) calloc(REGC(cur), sizeof(platter));
siz_arrays[i] = REGC(cur);
REGB(cur) = i;
break;
// abandon
case 9:
free(arrays[REGC(cur)]);
arrays[REGC(cur)] = 0;
//last_free = REGC(cur);
free_list.push(REGC(cur));
break;
// out
case 10:
if (REGC(cur) < 256) {
putchar(REGC(cur));
fflush(stdout);
}
break;
// in
case 11:
REGC(cur) = getchar();
break;
// load
case 12:
if (REGB(cur) != 0) {
free(arrays[0]);
arrays[0] = (platter *) calloc(siz_arrays[REGB(cur)], sizeof(platter));
assert(arrays[0] != 0);
assert(arrays[REGB(cur)] != 0);
memcpy(arrays[0], arrays[REGB(cur)],
siz_arrays[REGB(cur)] * sizeof(platter));
siz_arrays[0] = siz_arrays[REGB(cur)];
}
finger = REGC(cur);
break;
// data
case 13:
REGA13(cur) = DATA(cur);
break;
default:
fprintf(stderr, "Died!\n");
exit(1);
}
}
}