ilo-vm/source/ilo.d

232 lines
6.9 KiB
D

/***************************************************************
crc's _ _
(_) | ___
| | |/ _ \ a tiny virtual computer
| | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
|_|_|\___/ ilo.d (c) charles childers
**************************************************************/
import std.stdio;
Stack data, addr; /* data & address stacks */
RAM memory; /* system memory */
int ip; /* instruction pointer */
string blocks; /* name of block file (ilo.blocks) */
string rom; /* name of image (ilo.rom) */
void load_image() {
data = new Stack(33);
addr = new Stack(257);
memory = new RAM();
FILE *file = fopen(rom.ptr, "rb");
if (file is null) { return; }
fread(memory.pointer(), 1, 65536 * 4, file);
fclose(file);
ip = 0;
}
void save_image() {
FILE *file = fopen(rom.ptr, "wb");
fwrite(memory.pointer(), 1, 65536 * 4, file);
fclose(file);
}
void read_block() {
int[1024] block;
FILE *file = fopen(blocks.ptr, "rb");
if (file is null) { return; }
int b = data.pop(); /* block buffer */
int a = data.pop(); /* block number */
fseek(file, 4096 * a, SEEK_SET);
fread(block.ptr, 1, 4096, file);
foreach(i; 0 .. 1024) { memory.store(b + i, block[i]); }
fclose(file);
}
void write_block() {
int[1024] block;
FILE *file = fopen(blocks.ptr, "r+b");
if (file is null) { return; }
int b = data.pop(); /* block buffer */
int a = data.pop(); /* block number */
fseek(file, 4096 * a, SEEK_SET);
foreach(i; 0 .. 1024) { block[i] = memory.fetch(b + i); }
fwrite(block.ptr, 1, 4096, file);
fclose(file);
}
void li() { ip += 1; data.push(memory.fetch(ip)); }
void du() { data.dup(); }
void dr() { data.pop(); }
void sw() { data.swap(); }
void pu() { addr.push(data.pop()); }
void po() { data.push(addr.pop()); }
void ju() { ip = data.pop() - 1; }
void ca() { addr.push(ip); ip = data.pop() - 1; }
void cc() { int a = data.pop(); if (data.pop()) { addr.push(ip); ip = a - 1; } }
void cj() { int a = data.pop(); if (data.pop()) { ip = a - 1; } }
void re() { ip = addr.pop(); }
void eq() { data.swap(); data.push((data.pop() == data.pop()) ? -1 : 0); }
void ne() { data.swap(); data.push((data.pop() != data.pop()) ? -1 : 0); }
void lt() { data.swap(); data.push((data.pop() < data.pop()) ? -1 : 0); }
void gt() { data.swap(); data.push((data.pop() > data.pop()) ? -1 : 0); }
void fe() { data.push(memory.fetch(data.pop())); }
void st() { int a = data.pop(); memory.store(a, data.pop()); }
void ad() { data.swap(); data.push(data.pop() + data.pop()); }
void su() { data.swap(); data.push(data.pop() - data.pop()); }
void mu() { data.swap(); data.push(data.pop() * data.pop()); }
void di() { int a = data.pop(); int b = data.pop(); data.push(b % a); data.push(b / a); }
void an() { data.push(data.pop() & data.pop()); }
void or() { data.push(data.pop() | data.pop()); }
void xo() { data.push(data.pop() ^ data.pop()); }
void sl() { data.swap(); data.push(data.pop() << data.pop()); }
void sr() { data.swap(); data.push(data.pop() >> data.pop()); }
void cp() { int l = data.pop(); int d = data.pop(); int s = data.pop(); data.push(-1);
while (l) { if (memory.fetch(d) != memory.fetch(s)) { data.pop(); data.push(0); }
l -= 1; s += 1; d += 1; } }
void cy() { int l = data.pop(); int d = data.pop(); int s = data.pop();
while (l) { memory.store(d, memory.fetch(s)); l -= 1; s += 1; d += 1; } }
void ioa() { writef("%c", cast(char)data.pop()); }
void iob() { data.push(getchar()); }
void ioc() { read_block(); }
void iod() { write_block(); }
void ioe() { save_image(); }
void iof() { load_image(); ip = -1; }
void iog() { ip = 65536; }
void ioh() { data.push(data.depth()); data.push(addr.depth()); }
void io() {
switch (data.pop()) {
case 0: ioa(); break; case 1: iob(); break;
case 2: ioc(); break; case 3: iod(); break;
case 4: ioe(); break; case 5: iof(); break;
case 6: iog(); break; case 7: ioh(); break;
default: break;
}
}
void process(int o) {
switch (o) {
case 0: break; case 1: li(); break;
case 2: du(); break; case 3: dr(); break;
case 4: sw(); break; case 5: pu(); break;
case 6: po(); break; case 7: ju(); break;
case 8: ca(); break; case 9: cc(); break;
case 10: cj(); break; case 11: re(); break;
case 12: eq(); break; case 13: ne(); break;
case 14: lt(); break; case 15: gt(); break;
case 16: fe(); break; case 17: st(); break;
case 18: ad(); break; case 19: su(); break;
case 20: mu(); break; case 21: di(); break;
case 22: an(); break; case 23: or(); break;
case 24: xo(); break; case 25: sl(); break;
case 26: sr(); break; case 27: cp(); break;
case 28: cy(); break; case 29: io(); break;
default: break;
}
}
void process_bundle(int opcode) {
process(opcode & 0xFF);
process((opcode >> 8) & 0xFF);
process((opcode >> 16) & 0xFF);
process((opcode >> 24) & 0xFF);
}
void execute() {
while (ip < 65536) {
process_bundle(memory.fetch(ip));
ip += 1;
}
}
void main(string[] args) {
blocks = "ilo.blocks";
rom = "ilo.rom";
load_image();
execute();
data.print();
writef("\n");
}
class RAM {
private int[65536] data;
this() {
}
int fetch(int a) {
if (a < 0 || a > 65535)
throw new Exception("Invalid memory access");
return data[a];
}
void store(int a, int v) {
if (a < 0 || a > 65535)
throw new Exception("Invalid memory access");
data[a] = v;
}
int* pointer() {
return data.ptr;
}
}
class Stack {
private int[] stack;
private int top;
private int capacity;
this(int capacity) {
this.capacity = capacity;
stack = new int[capacity];
top = -1;
}
bool isEmpty() {
return top == -1;
}
bool isFull() {
return top == capacity - 1;
}
void push(int value) {
if (isFull())
throw new Exception("Stack overflow");
stack[++top] = value;
}
int pop() {
if (isEmpty())
throw new Exception("Stack underflow");
return stack[top--];
}
void dup() {
if (isEmpty())
throw new Exception("Stack is empty");
if (isFull())
throw new Exception("Stack overflow");
push(stack[top]);
}
void swap() {
if (top < 1)
throw new Exception("Insufficient elements to swap");
int temp = stack[top];
stack[top] = stack[top - 1];
stack[top - 1] = temp;
}
int depth() {
return top + 1;
}
void print() {
for (int i = top; i >= 0; i--) {
writeln(stack[i]);
}
}
}