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 }