/*************************************************************** crc's _ _ (_) | ___ | | |/ _ \ a tiny virtual computer | | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC |_|_|\___/ ilo.c (c) charles childers **************************************************************/ /* This implementation uses memory separated into multiple banks. This makes it easier to run on systems with less RAM. */ #include #include #define SLICES 64 #define SLICESIZE (65536/SLICES) int ip, sp, rp, data[33], address[257]; char *blocks, *rom; #ifdef MALLOC int *memory[SLICES]; #else int memory[SLICES][SLICESIZE]; #endif #define TOS data[sp] #define NOS data[sp-1] #define TORS address[rp] int stack_pop() { sp--; return data[sp + 1]; } void stack_push(int value) { sp++; data[sp] = value; } void store(int a, int v) { int slice = a / SLICESIZE; int actual = a - (slice * SLICESIZE); memory[slice][actual] = v; } int fetch(int a) { int slice = a / SLICESIZE; int actual = a - (slice * SLICESIZE); return memory[slice][actual]; } void prepare_vm() { for (ip = 0; ip < 32; ip++) data[ip] = 0; for (ip = 0; ip < 128; ip++) address[ip] = 0; ip = sp = rp = 0; } void load_image() { FILE *fp; int x, y; fp = fopen(rom, "rb"); for (y = 0; y < 65536; y++) { x = 0; fread(&x, 4, 1, fp); store(y, x); } fclose(fp); prepare_vm(); } void save_image() { FILE *fp; int i; fp = fopen(rom, "wb"); for (i = 0; i < SLICES; i++) fwrite(&memory[i], sizeof(int), SLICESIZE, fp); fclose(fp); } void read_block() { FILE *f; int block, buffer, x, c; buffer = stack_pop(); block = stack_pop(); f = fopen(blocks, "r+b"); fseek(f, 4096 * block, SEEK_SET); for (x = 0; x < 1024; x++) { c = 0; fread(&c, 4, 1, f); store(buffer + x, c); } fclose(f); } void write_block() { FILE *f; int block, buffer, x, c; buffer = stack_pop(); block = stack_pop(); f = fopen(blocks, "r+b"); fseek(f, 4096 * block, SEEK_SET); for (x = 0; x < 1024; x++) { c = fetch(buffer + x); fwrite(&c, 4, 1, f); } fclose(f); } void process(int o) { int a, b, target, flag; int src, dest, len; switch (o) { case 0: break; case 1: ip++; stack_push(fetch(ip)); break; case 2: stack_push(TOS); break; case 3: data[sp] = 0; sp--; break; case 4: a = TOS; TOS = NOS; NOS = a; break; case 5: rp++; TORS = stack_pop(); break; case 6: stack_push(TORS); rp--; break; case 7: ip = stack_pop() - 1; break; case 8: rp++; TORS = ip; ip = stack_pop() - 1; break; case 9: target = stack_pop(); flag = stack_pop(); if (flag != 0) { rp++; TORS = ip; ip = target - 1; } break; case 10: target = stack_pop(); flag = stack_pop(); if (flag != 0) ip = target - 1; break; case 11: ip = TORS; rp--; break; case 12: NOS = (NOS == TOS) ? -1 : 0; sp--; break; case 13: NOS = (NOS != TOS) ? -1 : 0; sp--; break; case 14: NOS = (NOS < TOS) ? -1 : 0; sp--; break; case 15: NOS = (NOS > TOS) ? -1 : 0; sp--; break; case 16: TOS = fetch(TOS); break; case 17: store(TOS, NOS); sp--; sp--; break; case 18: NOS += TOS; sp--; break; case 19: NOS -= TOS; sp--; break; case 20: NOS *= TOS; sp--; break; case 21: a = TOS; b = NOS; TOS = b / a; NOS = b % a; break; case 22: NOS = TOS & NOS; sp--; break; case 23: NOS = TOS | NOS; sp--; break; case 24: NOS = TOS ^ NOS; sp--; break; case 25: NOS = NOS << TOS; sp--; break; case 26: NOS = NOS >> TOS; sp--; break; case 27: len = stack_pop(); dest = stack_pop(); src = stack_pop(); flag = -1; while (len) { if (fetch(dest) != fetch(src)) flag = 0; len -= 1; src += 1; dest += 1; }; stack_push(flag); break; case 28: len = stack_pop(); dest = stack_pop(); src = stack_pop(); while (len) { store(dest, fetch(src)); len -= 1; src += 1; dest += 1; }; break; case 29: switch (stack_pop()) { case 0: putc(stack_pop(), stdout); break; case 1: stack_push(getc(stdin)); break; case 2: read_block(); break; case 3: write_block(); break; case 4: save_image(); break; case 5: load_image(); ip = -1; break; case 6: ip = 65536; break; case 7: stack_push(sp); stack_push(rp); break; default: break; } break; default: break; } } void process_opcode_bundle(int opcode) { process(opcode & 0xFF); process((opcode >> 8) & 0xFF); process((opcode >> 16) & 0xFF); process((opcode >> 24) & 0xFF); } void execute(int address) { ip = address; while (ip < 65536) { process_opcode_bundle(fetch(ip)); ip++; } } int main(int argc, char **argv) { int i; blocks = (argc > 1) ? argv[1] : "ilo.blocks"; rom = (argc > 2) ? argv[2] : "ilo.rom"; #ifdef MALLOC for (i = 0; i < SLICES; i++) memory[i] = malloc(SLICESIZE * sizeof(int)); #endif load_image(); execute(0); #ifdef MALLOC for (i = 0; i < SLICES; i++) free(memory[i]); #endif for (i = 1; sp >= i; i++) printf(" %d", data[i]); printf("\n"); }