// ilo.rs, (c) charles childers use std::io; use std::convert::TryInto; use std::io::{Read, Write, Seek, SeekFrom}; use std::fs::{File, OpenOptions}; static mut M: [i32; 65536] = [0; 65536]; // memory static mut D: [i32; 33] = [0; 33]; // data stack static mut A: [i32; 257] = [0; 257]; // address stack static mut SP: usize = 0; // data stack pointer static mut RP: usize = 0; // address stack pointer static mut IP: usize = 0; // instruction pointer fn load_image() { if let Ok(image) = std::fs::read("ilo.rom") { for (i, c) in image.chunks(4).enumerate() { store(i32::from_le_bytes(c.try_into().unwrap()), i); } } } fn read_block(block: i32, buffer: i32) -> io::Result<()> { let mut f = File::open("ilo.blocks")?; let mut data = [0; 4096]; f.seek(SeekFrom::Start(4096 * (block as u64)))?; f.read(&mut data)?; for (i, c) in data.chunks(4).enumerate() { let x = c[0] as i32; store(x, (buffer as usize) + i); } Ok(()) } fn write_block(block: i32, buffer: i32) -> io::Result<()> { let mut f = OpenOptions::new() .read(true) .write(true) .open("ilo.blocks")?; let mut data = [0; 4096]; let mut x: usize = 0; let mut y: usize = 0; while x < 1024 { let v = fetch((buffer as usize) + x); let a = v & 0xFF; let b = (v >> 8) & 0xFF; let c = (v >> 16) & 0xFF; let d = (v >> 24) & 0xFF; data[y + 0] = a as u8; data[y + 1] = b as u8; data[y + 2] = c as u8; data[y + 3] = d as u8; x += 1; y += 4; } f.seek(SeekFrom::Start(4096 * (block as u64)))?; f.write(&mut data)?; Ok(()) } fn push(x: i32) { unsafe { SP += 1; D[SP] = x; } } fn pop() -> i32 { unsafe { SP -= 1; return D[SP + 1]; } } fn fetch(a: usize) -> i32 { unsafe { return M[a]; } } fn store(v: i32, a: usize) { unsafe { M[a] = v; } } fn reset() { unsafe { IP = 0; SP = 0; RP = 0; } } fn next() { unsafe { IP += 1; } } fn li() { next(); push(fetch(here())); } fn du() { unsafe { push(D[SP]); } } fn dr() { pop(); } fn sw() { let x = pop(); let y = pop(); push(x); push(y); } fn pu() { unsafe { RP += 1; A[RP] = pop(); } } fn po() { unsafe { push(A[RP]); RP -= 1; } } fn ju() { unsafe { IP = (pop() - 1) as usize; } } fn ca() { unsafe { RP += 1; A[RP] = (IP) as i32; IP = (pop() - 1) as usize; } } fn cc() { let t = pop(); if pop() != 0 { push(t); ca(); } } fn cj() { let t = pop(); if pop() != 0 { push(t); ju(); } } fn re() { unsafe { IP = (A[RP]) as usize; RP -= 1; } } fn eq() { let y = pop(); let x = pop(); push(if x == y { -1 } else { 0 }); } fn ne() { let y = pop(); let x = pop(); push(if x != y { -1 } else { 0 }); } fn lt() { let y = pop(); let x = pop(); push(if x < y { -1 } else { 0 }); } fn gt() { let y = pop(); let x = pop(); push(if x > y { -1 } else { 0 }); } fn fe() { let x = pop() as usize; push(fetch(x)); } fn st() { let x = pop() as usize; store(pop(), x); } fn ad() { let y = pop(); let x = pop(); push(x.wrapping_add(y)); } fn su() { let y = pop(); let x = pop(); push(x.wrapping_sub(y)); } fn mu() { let y = pop(); let x = pop(); push(x.wrapping_mul(y)); } fn di() { let y = pop(); let x = pop(); push(x.wrapping_rem(y)); push(x.wrapping_div(y)); } fn an() { let y = pop(); let x = pop(); push(x & y); } fn or() { let y = pop(); let x = pop(); push(x | y); } fn xo() { let y = pop(); let x = pop(); push(x ^ y); } fn sl() { let y = pop(); let x = pop(); push(x.wrapping_shl(y.try_into().unwrap())); } fn sr() { let y = pop(); let x = pop(); push(x.wrapping_shr(y.try_into().unwrap())); } fn cp() { let mut len = pop() as usize; let dest = pop() as usize; let src = pop() as usize; let mut flag: i32 = -1; while len > 0 { if fetch(dest + len) != fetch(src + len) { flag = 0; } len -= 1; } push(flag); } fn cy() { let mut len = pop(); let mut dest = pop() as usize; let mut src = pop() as usize; while len > 0 { store(fetch(src), dest); len -= 1; src += 1; dest += 1; } } fn io() { let dev = pop(); if dev == 0 { let mut c = pop(); if c == 0 { c = 32; } std::io::stdout() .lock() .write(&[c as u8]) .unwrap(); std::io::stdout() .lock() .flush() .unwrap(); } if dev == 1 { match std::io::stdin() .lock() .bytes() .next() .unwrap() { Ok(127) => push(8), Ok(val) => push(val as i32), Err(_) => std::process::exit(1), } } if dev == 2 { let buffer = pop(); let block = pop(); let _e = read_block(block, buffer); } if dev == 3 { let buffer = pop(); let block = pop(); let _e = write_block(block, buffer); } if dev == 4 { } if dev == 5 { load_image(); unsafe { IP = 70000; } } if dev == 6 { unsafe { IP = 65536; } } if dev == 7 { unsafe { push((SP) as i32); push((RP) as i32); } } } fn process(inst: i32) { if inst == 0 { return; } if inst == 1 { li(); } if inst == 2 { du(); } if inst == 3 { dr(); } if inst == 4 { sw(); } if inst == 5 { pu(); } if inst == 6 { po(); } if inst == 7 { ju(); } if inst == 8 { ca(); } if inst == 9 { cc(); } if inst == 10 { cj(); } if inst == 11 { re(); } if inst == 12 { eq(); } if inst == 13 { ne(); } if inst == 14 { lt(); } if inst == 15 { gt(); } if inst == 16 { fe(); } if inst == 17 { st(); } if inst == 18 { ad(); } if inst == 19 { su(); } if inst == 20 { mu(); } if inst == 21 { di(); } if inst == 22 { an(); } if inst == 23 { or(); } if inst == 24 { xo(); } if inst == 25 { sl(); } if inst == 26 { sr(); } if inst == 27 { cp(); } if inst == 28 { cy(); } if inst == 29 { io(); } } fn not_done() -> bool { unsafe { return IP < 65536; } } fn here() -> usize { unsafe { return IP; } } fn execute() { reset(); while not_done() { let opcode = fetch(here()); process(opcode & 0xFF); process((opcode >> 8) & 0xFF); process((opcode >> 16) & 0xFF); process((opcode >> 24) & 0xFF); if here() == 70000 { reset(); } else { next(); } } } fn dump_stack() { unsafe { while SP > 0 { let x = pop(); println!("{x}"); } } } fn main() { load_image(); execute(); dump_stack(); }