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