ilo-vm/source/ilo-banked.c

205 lines
5.2 KiB
C

/***************************************************************
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 <stdio.h>
#include <stdlib.h>
#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");
}