umx

UMX VM implementation (icfpc '06)
git clone git://bsandro.tech/umx
Log | Files | Refs | README | LICENSE

main.c (5443B)


      1 #pragma gcc_extensions on
      2 
      3 #include <stdio.h>
      4 #include <assert.h>
      5 #include <stdint.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <unistd.h>
      9 #include <sys/stat.h>
     10 
     11 #ifndef __MWERKS__
     12 #define _NTOHL ntohl
     13 #define _HTONL htonl
     14 #else
     15 #define _NTOHL
     16 #define _HTONL
     17 #endif
     18 
     19 #define FILENAME "SANDMARK.UMZ"
     20 #define PLATTER_SIZE 4
     21 
     22 struct array_t {
     23 	uint32_t *data;
     24 	uint32_t size;
     25 };
     26 
     27 struct arena_t {
     28 	struct array_t *arrays;
     29 	uint32_t size;
     30 };
     31 
     32 struct state_t {
     33 	uint32_t registers[8];
     34 	uint32_t finger;
     35 	struct arena_t arena;
     36 };
     37 
     38 enum opcode_t {
     39 	CMOV = 0,
     40 	ARRI = 1,
     41 	ARRA = 2,
     42 	ADD  = 3,
     43 	MUL  = 4,
     44 	DIV  = 5,
     45 	NOTA = 6,
     46 	HALT = 7,
     47 	ALLO = 8,
     48 	ABAN = 9,
     49 	OUTP = 10,
     50 	INP  = 11,
     51 	LOAD = 12,
     52 	ORTH = 13
     53 };
     54 
     55 struct instruction_t {
     56 	enum opcode_t opcode;
     57 	uint8_t reg_a, reg_b, reg_c;
     58 	uint32_t value;
     59 };
     60 
     61 char * int2bin(uint32_t num);
     62 void print_instruction(struct instruction_t *instruction);
     63 void exec_instruction(struct state_t *state, struct instruction_t *in);
     64 uint32_t array_new(struct arena_t *arena, uint32_t size);
     65 void array_free(struct arena_t *arena, uint32_t index);
     66 void array_dup(struct arena_t *arena, uint32_t index);
     67 
     68 int main(int argc, char *argv[])
     69 {
     70 	char *fname = argc > 1 ? argv[1] : FILENAME;
     71 	FILE *f = fopen(fname, "rb");
     72 	struct state_t *state = (struct state_t *)malloc(sizeof(struct state_t));
     73 	struct stat fileinfo;
     74 	size_t read_platters = 0;
     75 
     76 	memset(state, 0, sizeof(struct state_t));
     77 
     78 	assert(f != NULL);
     79 	stat(fname, &fileinfo);
     80 	assert(fileinfo.st_size % PLATTER_SIZE == 0);
     81 	array_new(&state->arena, fileinfo.st_size / PLATTER_SIZE); // Initial array #0
     82 	read_platters = fread(state->arena.arrays[0].data, PLATTER_SIZE, fileinfo.st_size / PLATTER_SIZE, f);
     83 	assert(fileinfo.st_size == read_platters * PLATTER_SIZE);
     84 	fclose(f);
     85 
     86 	while (1) {
     87 		struct instruction_t instruction = {0};
     88 		uint32_t platter = _NTOHL(state->arena.arrays[0].data[state->finger]);
     89 		instruction.opcode = platter >> 28;
     90 		if (instruction.opcode == ORTH) {
     91 			instruction.reg_a = (platter >> 25) & 7;
     92 			instruction.value = platter & 0x1FFFFFFUL;
     93 		} else {
     94 			instruction.reg_a = (platter & 448) >> 6; // mask 111 000 000 = 448
     95 			instruction.reg_b = (platter & 56) >> 3;  // mask 000 111 000 = 56
     96 			instruction.reg_c = platter & 7;          // mask 000 000 111 = 7
     97 		}
     98 		state->finger++;
     99 		exec_instruction(state, &instruction);
    100 	}
    101 
    102 	return 0;
    103 }
    104 
    105 char * int2bin(uint32_t num) {
    106 	static char str[33] = {'\0'};
    107 	int cnt = 0;
    108 	uint32_t i;
    109 	for (i = 1 << 31; i > 0; i >>= 1) {
    110 		str[cnt++] = ((num & i) == i) ? '1' : '0';
    111 		assert(cnt < 34);
    112 	}
    113 	str[32] = '\0';
    114 	return str;
    115 }
    116 
    117 void print_instruction(struct instruction_t *instruction) {
    118 	printf("%2d: A:%d B:%d C:%d value:%lu\n", instruction->opcode, instruction->reg_a, instruction->reg_b, instruction->reg_c, instruction->value);
    119 }
    120 
    121 void exec_instruction(struct state_t *state, struct instruction_t *in) {
    122 	switch (in->opcode) {
    123 	case CMOV:
    124 		if (state->registers[in->reg_c] != 0) state->registers[in->reg_a] = state->registers[in->reg_b];
    125 		break;
    126 	case ARRI:
    127 		state->registers[in->reg_a] = _NTOHL(state->arena.arrays[state->registers[in->reg_b]].data[state->registers[in->reg_c]]);
    128 		break;
    129 	case ARRA:
    130 		state->arena.arrays[state->registers[in->reg_a]].data[state->registers[in->reg_b]] = _HTONL(state->registers[in->reg_c]);
    131 		break;
    132 	case ADD:
    133 		state->registers[in->reg_a] = state->registers[in->reg_b] + state->registers[in->reg_c]; //@todo: modulo 2^32 ?
    134 		break;
    135 	case MUL:
    136 		state->registers[in->reg_a] = state->registers[in->reg_b] * state->registers[in->reg_c]; //@todo: modulo 2^32 ?
    137 		break;
    138 	case DIV:
    139 		state->registers[in->reg_a] = state->registers[in->reg_b] / state->registers[in->reg_c]; //@todo: modulo 2^32 ?
    140 		break;
    141 	case NOTA:
    142 		state->registers[in->reg_a] = ~(state->registers[in->reg_b] & state->registers[in->reg_c]);
    143 		break;
    144 	case HALT:
    145 		exit(0);
    146 		break;
    147 	case ALLO:
    148 		state->registers[in->reg_b] = array_new(&state->arena, state->registers[in->reg_c]);
    149 		break;
    150 	case ABAN:
    151 		array_free(&state->arena, state->registers[in->reg_c]);
    152 		break;
    153 	case OUTP:
    154 		putchar(state->registers[in->reg_c]);
    155 		break;
    156 	case INP:
    157 		{
    158 			int c = getchar();
    159 			state->registers[in->reg_c] = (c == EOF) ? 0xFFFFFFFFUL : c;
    160 		}
    161 		break;
    162 	case LOAD:
    163 		if (state->registers[in->reg_b] != 0) {
    164 			array_dup(&state->arena, state->registers[in->reg_b]);
    165 		}
    166 		state->finger = state->registers[in->reg_c];
    167 		break;
    168 	case ORTH:
    169 		state->registers[in->reg_a] = in->value;
    170 		break;
    171 	default:
    172 		printf("invalid opcode\n");
    173 		exit(1);
    174 	}
    175 }
    176 
    177 uint32_t array_new(struct arena_t *arena, uint32_t size) {
    178 	uint32_t array_index = arena->size++;
    179 	assert(arena != NULL);
    180 	arena->arrays = (struct array_t *)realloc(arena->arrays, arena->size * sizeof(struct array_t));
    181 	arena->arrays[array_index].data = (uint32_t *)calloc(size, PLATTER_SIZE);
    182 	arena->arrays[array_index].size = size;
    183 	if (size > 0) {
    184 		assert(arena->arrays[array_index].data != NULL);
    185 	}
    186 	return array_index;
    187 }
    188 
    189 void array_free(struct arena_t *arena, uint32_t index) {
    190 	assert(index < arena->size);
    191 	free(arena->arrays[index].data);
    192 	arena->arrays[index].size = 0;
    193 }
    194 
    195 void array_dup(struct arena_t *arena, uint32_t index) {
    196 	assert(index < arena->size);
    197 	array_free(arena, 0);
    198 	arena->arrays[0].data = (uint32_t *)malloc(arena->arrays[index].size * PLATTER_SIZE);
    199 	memcpy(arena->arrays[0].data, arena->arrays[index].data, arena->arrays[index].size * PLATTER_SIZE);
    200 	arena->arrays[0].size = arena->arrays[index].size;
    201 }