| Paste number 23177: | UM implementation |
| Pasted by: | Per Vognsen |
| When: | 2 years, 11 months ago |
| Share: | Tweet this! | http://paste.lisp.org/+HVT |
| Channel: | None |
| Paste contents: |
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef unsigned int word_t;
struct array_t
{
size_t size;
word_t elements[1];
};
array_t* program = NULL;
word_t registers[8] = {0};
array_t* alloc_array(size_t size)
{
array_t* array = (array_t*) malloc(sizeof(size_t) + size * sizeof(word_t));
array->size = size;
memset(&array->elements[0], 0, size * sizeof(word_t));
return array;
}
array_t* array_from_word(word_t word)
{
return (word == 0) ? program : (array_t*) word;
}
void run_program()
{
size_t pc = 0;
while (pc < program->size) {
const word_t word = program->elements[pc++];
const int op = (word >> 28) & 0xF;
if (op == 13) { // orthography
const int i = (word >> 25) & 0x7;
const word_t value = word & ((1 << 25) - 1);
registers[i] = value;
} else {
const int a = (word >> 6) & 0x7;
const int b = (word >> 3) & 0x7;
const int c = word & 0x7;
switch (op) {
case 0: // conditional move
if (registers[c] != 0) {
registers[a] = registers[b];
}
break;
case 1: // array index
{
const array_t* array = array_from_word(registers[b]);
const word_t offset = registers[c];
assert(offset < array->size);
registers[a] = array->elements[offset];
break;
}
case 2: // array amendment
{
array_t* array = array_from_word(registers[a]);
const word_t offset = registers[b];
assert(offset < array->size);
array->elements[offset] = registers[c];
break;
}
case 3: // addition
registers[a] = registers[b] + registers[c];
break;
case 4: // multiplication
registers[a] = registers[b] * registers[c];
break;
case 5: // division
registers[a] = registers[b] / registers[c];
break;
case 6: // not-and
registers[a] = ~(registers[b] & registers[c]);
break;
case 7: // halt
return;
case 8: // allocation
registers[b] = word_t(alloc_array(registers[c]));
break;
case 9: // abandonment
{
array_t* array = array_from_word(registers[c]);
assert(array != program);
free(array);
break;
}
case 10: // output
fputc(registers[c], stdout);
break;
case 11: // input
{
const char ch = fgetc(stdin);
registers[c] = word_t((ch != EOF) ? ch : ~0);
break;
}
case 12: // load program
{
pc = registers[c];
const array_t* array = array_from_word(registers[b]);
if (array != program) {
free(program);
program = alloc_array(array->size);
memcpy(&program->elements[0], &array->elements[0], array->size * sizeof(word_t));
}
break;
}
default:
fprintf(stderr, "invalid opcode");
exit(EXIT_FAILURE);
}
}
}
}
array_t* load_array_from_file(const char* filename)
{
if (FILE* fp = fopen(filename, "rb")) {
fseek(fp, 0, SEEK_END);
const size_t size = ftell(fp) / 4;
fseek(fp, 0, SEEK_SET);
array_t* array = alloc_array(size);
for (size_t i = 0; i < size; i++) {
unsigned char bytes[4];
if (fread(bytes, 1, 4, fp) != 4) {
perror("load_array_from_file");
exit(EXIT_FAILURE);
}
array->elements[i] = word_t((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);
}
fclose(fp);
return array;
} else {
perror("load_array_from_file");
exit(EXIT_FAILURE);
return NULL;
}
}
int main(int argc, char** argv)
{
if (argc < 2) {
fprintf(stderr, "Usage: %s <program-file>\n", argv[0]);
exit(EXIT_FAILURE);
}
program = load_array_from_file(argv[1]);
run_program();
return 0;
}
This paste has no annotations.