232 lines
6.9 KiB
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]);
|
|
}
|
|
}
|
|
}
|