ilo-vm/source/ilo.ha

239 lines
6.7 KiB
Hare

// ilo.ha, an ilo in hare
use bufio;
use fmt;
use fs;
use io;
use math;
use os;
let ds: [33]i32 = [0...];
let rs: [257]i32 = [0...];
let m: [65536]i32 = [0...];
let sp: i32 = 0;
let rp: i32 = 0;
let ip: i32 = 0;
let a: i32 = 0;
let b: i32 = 0;
let c: i32 = 0;
fn initialize() void = {
sp = 0;
rp = 0;
ip = 0;
load();
};
fn load() void = {
const input = match (os::open("ilo.rom")) {
case let file: io::file =>
yield file;
case let err: fs::error =>
fmt::fatalf("Error opening {}: {}",
os::args[1], fs::strerror(err));
};
defer io::close(input)!;
let rdbuf: [os::BUFSZ]u8 = [0...];
let input = &bufio::init(input, rdbuf, []);
let i = 0;
let buf: [4]u8 = [0, 0, 0, 0];
for (!(io::read(input, buf)! is io::EOF)) {
let x: u32 = m[i]:u32;
x = x + (buf[3]:u32 << 24);
x = x + (buf[2]:u32 << 16);
x = x + (buf[1]:u32 << 8);
x = x + (buf[0]:u32 << 0);
m[i] = x:i32;
i = i + 1;
};
};
fn read_block(block:i32, buffer:i32) void = {
const block_store = match (os::open("ilo.blocks")) {
case let file: io::file =>
yield file;
case let err: fs::error =>
fmt::fatalf("Error opening {}: {}",
"ilo.blocks", fs::strerror(err));
};
defer io::close(block_store)!;
let rdbuf: [os::BUFSZ]u8 = [0...];
let block_store = &bufio::init(block_store, rdbuf, []);
let i: i32 = 0;
let buf: [4096]u8 = [0...];
// this is not an optimal way, need to figure out
// io::seek
// io::seek(block_store, block * 4096, io::whence::SET)!;
let za:i32 = 0;
for (za < block) {
io::read(block_store, buf)!;
za = za + 1;
};
let cell: [4]u8 = [0...];
// read in the block
for (i < 1024) {
io::read(block_store, cell)!;
let x: u32 = 0;
x = x + (cell[3]:u32 << 24);
x = x + (cell[2]:u32 << 16);
x = x + (cell[1]:u32 << 8);
x = x + (cell[0]:u32 << 0);
let t:i32 = buffer + i;
m[t] = x:i32;
i = i + 1;
};
};
fn write_block(block:i32, buffer:i32) void = {
const block_store = match (os::open("ilo.blocks", fs::flag::RDWR)) {
case let file: io::file =>
yield file;
case let err: fs::error =>
fmt::fatalf("Error opening {}: {}",
"ilo.blocks", fs::strerror(err));
};
defer io::close(block_store)!;
let rdbuf: [os::BUFSZ]u8 = [0...];
let wrbuf: [os::BUFSZ]u8 = [0...];
let block_store = &bufio::init(block_store, rdbuf, wrbuf);
let i: i32 = 0;
let buf: [4096]u8 = [0...];
let za:i32 = 0;
for (za < block) {
io::read(block_store, buf)!;
za = za + 1;
};
let cell: [4]u8 = [0...];
// read in the block
for (i < 1024) {
let t:i32 = buffer + i;
let x: u32 = m[t]:u32;
cell[3] = ((x >> 24) & 0xFF):u8;
cell[2] = ((x >> 16) & 0xFF):u8;
cell[1] = ((x >> 8) & 0xFF):u8;
cell[0] = ((x >> 0) & 0xFF):u8;
io::write(block_store, cell)!;
i = i + 1;
};
io::close(block_store)!;
};
fn push(v: i32) void = { sp = sp + 1; ds[sp] = v; };
fn pop() i32 = { sp = sp - 1; return ds[sp + 1]; };
fn save_ip() void = { rp = rp + 1; rs[rp] = ip; };
fn no() void = { return; };
fn li() void = { ip = ip + 1; push(m[ip]); };
fn du() void = { push(ds[sp]); };
fn dr() void = { pop(); };
fn sw() void = { a = pop(); b = pop(); push(a); push(b); };
fn pu() void = { rp = rp + 1; rs[rp] = pop(); };
fn po() void = { push(rs[rp]); rp = rp - 1; };
fn ju() void = { ip = pop() - 1; };
fn ca() void = { save_ip(); ip = pop() - 1; };
fn cc() void = { a = pop(); if (pop() != 0) { save_ip(); ip = a - 1; }; };
fn cj() void = { a = pop(); if (pop() != 0) { ip = a - 1; }; };
fn re() void = { ip = rs[rp]; rp = rp - 1; };
fn eq() void = { a = pop(); b = pop();
if (a == b) { push(-1); } else { push(0); }; };
fn ne() void = { a = pop(); b = pop();
if (a != b) { push(-1); } else { push(0); }; };
fn lt() void = { a = pop(); b = pop();
if (b < a) { push(-1); } else { push(0); }; };
fn gt() void = { a = pop(); b = pop();
if (b > a) { push(-1); } else { push(0); }; };
fn fe() void = { ds[sp] = m[ds[sp]]; };
fn st() void = { m[ds[sp]] = ds[sp - 1]; sp = sp - 2; };
fn ad() void = { ds[sp - 1] = ds[sp - 1] + ds[sp]; pop(); };
fn su() void = { ds[sp - 1] = ds[sp - 1] - ds[sp]; pop(); };
fn mu() void = { ds[sp - 1] = ds[sp - 1] * ds[sp]; pop(); };
fn di() void = { a = ds[sp]; b = ds[sp - 1];
ds[sp] = b / a; ds[sp - 1] = b % a; };
fn an() void = { ds[sp - 1] = ds[sp - 1] & ds[sp]; pop(); };
fn or() void = { ds[sp - 1] = ds[sp - 1] | ds[sp]; pop(); };
fn xo() void = { ds[sp - 1] = ds[sp - 1] ^ ds[sp]; pop(); };
fn sl() void = { ds[sp - 1] = ds[sp - 1] << ds[sp]; pop(); };
fn sr() void = { ds[sp - 1] = ds[sp - 1] >> ds[sp]; pop(); };
fn cp() void = {
a = pop(); b = pop(); c = pop(); push(-1);
for (a > 0; a = a - 1) {
if (m[b] != m[c]) { ds[sp] = 0; };
b = b + 1;
c = c + 1;
};
};
fn cy() void = {
a = pop(); b = pop(); c = pop();
for (a > 0; a = a - 1) {
m[b] = m[c];
b = b + 1;
c = c + 1;
};
};
fn io() void = {
switch (pop()) {
case => return;
case 0 => fmt::printf("{}", pop():rune)!; return;
case 1 => let buf: [1]u8 = [0];
io::read(os::stdin, buf)!;
let z:i32 = buf[0]:i32;
push(z); return;
case 2 => let buf = pop(); let blk = pop();
read_block(blk, buf);
return;
case 3 => let buf = pop(); let blk = pop();
write_block(blk, buf);
return;
case 4 => return;
case 5 => initialize(); ip = -1; return;
case 6 => fmt::fatal("BYE!");
case 7 => push(sp); push(rp); return;
};
};
fn process(o: i32) void = {
switch (o) {
case => return;
case 0 => return; case 1 => return li();
case 2 => return du(); case 3 => return dr();
case 4 => return sw(); case 5 => return pu();
case 6 => return po(); case 7 => return ju();
case 8 => return ca(); case 9 => return cc();
case 10 => return cj(); case 11 => return re();
case 12 => return eq(); case 13 => return ne();
case 14 => return lt(); case 15 => return gt();
case 16 => return fe(); case 17 => return st();
case 18 => return ad(); case 19 => return su();
case 20 => return mu(); case 21 => return di();
case 22 => return an(); case 23 => return or();
case 24 => return xo(); case 25 => return sl();
case 26 => return sr(); case 27 => return cp();
case 28 => return cy(); case 29 => return io();
};
};
fn execute() void = {
for (ip < 65536) {
let opcode = m[ip];
process(opcode & 0xFF);
process((opcode >> 8) & 0xFF);
process((opcode >> 16) & 0xFF);
process((opcode >> 24) & 0xFF);
ip = ip + 1;
};
};
export fn main() void = {
initialize();
execute();
};