diff --git a/data/bootsand.um b/data/bootsand.um new file mode 100644 index 0000000..0310f41 Binary files /dev/null and b/data/bootsand.um differ diff --git a/src/cpu.rs b/src/cpu.rs index 24412f0..79502f5 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -3,32 +3,28 @@ use std::vec::Vec; use crate::instruction::{Instruction, NormalInstruction, SpecialInstruction}; pub trait Console { - fn read(&self) -> Option; + fn read(&mut self) -> Option; fn write(&mut self, c: u8); } -struct NoConsole; - -impl Console for NoConsole { - fn read(&self) -> Option { - None - } - fn write(&mut self, _c: u8) {} -} - #[derive(Debug)] pub enum CpuError { ProgramEnd, InvalidInstruction, UnexpectedInput, InvalidArray, - ArrayOutOfBounds + ArrayOutOfBounds, + DivideByZero, + Halt, + LargeAlloc, + InvalidOutput } #[derive(Debug)] pub struct Cpu { reg: [u32; 8], arr: HashMap>, + iarr: u32, finger: u32, out: Option, in_reg: Option @@ -42,6 +38,7 @@ impl Cpu { Cpu { reg: [0;8], arr: arrays, + iarr: 1, finger: 0, in_reg: None, out: None @@ -159,6 +156,65 @@ impl Cpu { Ok(()) } + fn handle_div(&mut self, i:NormalInstruction) -> Result<(), CpuError>{ + let b = self.gr(i.b); + let c = self.gr(i.c); + if c == 0 { + return Err(CpuError::DivideByZero); + } + let (a, _) = b.overflowing_div(c); + self.sr(i.a, a); + Ok(()) + } + + fn handle_nand(&mut self, i:NormalInstruction) -> Result<(), CpuError>{ + let b = ! self.gr(i.b); + let c = ! self.gr(i.c); + let a = b & c; + self.sr(i.a, a); + Ok(()) + } + + fn handle_halt(&mut self, _i:NormalInstruction) -> Result<(), CpuError>{ + Err(CpuError::Halt) + } + + fn handle_alc(&mut self, i:NormalInstruction) -> Result<(), CpuError>{ + let c = self.gr(i.c) as usize; + if c > 1048576 { + return Err(CpuError::LargeAlloc); + } + let aid = self.iarr; + self.iarr += 1; + let v = vec![0; c]; + self.arr.insert(aid, v); + self.sr(i.b, aid); + Ok(()) + } + + fn handle_abn(&mut self, i:NormalInstruction) -> Result<(), CpuError>{ + let c = self.gr(i.c); + if c == 0 || ! self.arr.contains_key(&c){ + return Err(CpuError::InvalidArray); + } + self.arr.remove(&c); + Ok(()) + } + fn handle_out(&mut self, i:NormalInstruction) -> Result<(), CpuError>{ + let c = self.gr(i.c); + if c > 255 { + return Err(CpuError::InvalidOutput); + } + self.out = Some(c as u8); + Ok(()) + } + + fn handle_inp(&mut self, i:NormalInstruction) -> Result<(), CpuError>{ + self.sr(i.c, 0xffffffff); + self.in_reg = Some(i.c); + Ok(()) + } + fn exec(&mut self, instruction: Instruction)-> Result<(), CpuError>{ //println!("{:?}", instruction); match instruction { @@ -168,6 +224,13 @@ impl Cpu { Instruction::ArrayAmend(i) => self.handle_amd(i), Instruction::Add(i) => self.handle_add(i), Instruction::Multiply(i) => self.handle_mul(i), + Instruction::Divide(i) => self.handle_div(i), + Instruction::NotAnd(i) => self.handle_nand(i), + Instruction::Halt(i) => self.handle_halt(i), + Instruction::Allocate(i) => self.handle_alc(i), + Instruction::Abandon(i) => self.handle_abn(i), + Instruction::Output(i) => self.handle_out(i), + Instruction::Input(i) => self.handle_inp(i), _ => Err(CpuError::InvalidInstruction) } } @@ -207,6 +270,45 @@ impl Cpu { #[cfg(test)] mod tests{ use super::*; + struct NoConsole; + + impl Console for NoConsole { + fn read(&mut self) -> Option { + None + } + fn write(&mut self, _c: u8) {} + } + + struct BufConsole { + inb: Vec, + inptr: usize, + outb: Vec + } + + impl BufConsole { + fn make() -> BufConsole { + BufConsole { + inb: vec![], + inptr: 0, + outb: vec![] + } + } + } + + impl Console for BufConsole { + fn read(&mut self) -> Option { + if self.inptr >= self.inb.len() { + None + } else { + let r = self.inb[self.inptr]; + self.inptr += 1; + Some(r) + } + } + fn write(&mut self, c: u8) { + self.outb.push(c); + } + } fn ezop(op:u32, a:u32, b:u32, c:u32) -> u32 { match op { @@ -317,7 +419,7 @@ mod tests{ } - #[test] + #[test] fn test_amd_nooff() -> Result<(), String> { let pgm = vec!( ezop(2, 1, 2, 3) ); let mut c = Cpu::new(pgm); @@ -373,4 +475,161 @@ mod tests{ assert_eq!(c.reg, exp); Ok(()) } + + #[test] + fn test_div() -> Result<(), CpuError> { + let pgm = vec!( ezop(5, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 2048, 2, 0, 0, 0, 0]; + c.run(&mut NoConsole{})?; + let exp = [0, 1024, 2048, 2, 0, 0, 0, 0]; + assert_eq!(c.reg, exp); + Ok(()) + } + + #[test] + fn test_div_zero() -> Result<(), String> { + let pgm = vec!( ezop(5, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 1338, 3, 0, 0, 0, 0, 0]; + match c.run(&mut NoConsole{}) { + Err(CpuError::DivideByZero) => Ok(()), + Err(_) => Err(String::from("Invalid error")), + Ok(_) => Err(String::from("Expected err got ok")) + } + } + + #[test] + fn test_nand() -> Result<(), CpuError> { + let pgm = vec!( ezop(6, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 0x5a5a00ff, 0xdede00ff, 0, 0, 0, 0]; + c.run(&mut NoConsole{})?; + let exp = [0, 0x2121ff00, 0x5a5a00ff, 0xdede00ff, 0, 0, 0, 0]; + assert_eq!(c.reg, exp); + Ok(()) + } + + #[test] + fn test_halt() -> Result<(), String> { + let pgm = vec!( ezop(7, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + match c.run(&mut NoConsole{}) { + Err(CpuError::Halt) => Ok(()), + Err(_) => Err(String::from("Invalid error")), + Ok(_) => Err(String::from("Expected err got ok")) + } + } + + #[test] + fn test_alc_large() -> Result<(), String> { + let pgm = vec!( ezop(8, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 1338, 33, 0xffffffff, 0, 0, 0, 0]; + match c.run(&mut NoConsole{}) { + Err(CpuError::LargeAlloc) => Ok(()), + Err(_) => Err(String::from("Invalid error")), + Ok(_) => Err(String::from("Expected err got ok")) + } + } + + #[test] + fn test_alc() -> Result<(), CpuError> { + let pgm = vec!( ezop(8, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 1338, 33, 5, 0, 0, 0, 0]; + if let Err(e) = c.run(&mut NoConsole{}) { + return Err(e) + } + let exp = [0, 1338, 1, 5, 0, 0, 0, 0]; + assert_eq!(c.reg, exp); + if let Some(arr) = c.arr.get(&1){ + assert_eq!(arr,&vec![0,0,0,0,0] ); + Ok(()) + } else { + Err(CpuError::InvalidArray) + } + } + + #[test] + fn test_abn() -> Result<(), CpuError> { + let pgm = vec!( ezop(9, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.arr.insert(1338, vec![0,0,0,0]); + c.reg = [0, 0, 0, 1338, 0, 0, 0, 0]; + c.run(&mut NoConsole{})?; + if c.arr.contains_key(&1338) { + Err(CpuError::InvalidArray) + } else { + Ok(()) + } + } + + #[test] + fn test_abn_zero() -> Result<(), String> { + let pgm = vec!( ezop(9, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 0, 0, 0, 0, 0, 0]; + match c.run(&mut NoConsole{}) { + Err(CpuError::InvalidArray) => Ok(()), + Err(_) => Err(String::from("Invalid error")), + Ok(_) => Err(String::from("Expected err got ok")) + } + } + + #[test] + fn test_out() -> Result<(), String> { + let pgm = vec!( ezop(10, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 0, 128, 0, 0, 0, 0]; + let mut cons = BufConsole::make(); + if let Err(e) = c.run(&mut cons) { + return Err(format!("unexpected err {:?}", e)); + }; + assert_eq!(cons.outb, vec!(128)); + Ok(()) + } + + #[test] + fn test_out_inv() -> Result<(), String> { + let pgm = vec!( ezop(10, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 0, 1337, 0, 0, 0, 0]; + let mut cons = BufConsole::make(); + match c.run(&mut cons) { + Err(CpuError::InvalidOutput) => Ok(()), + Ok(_) => Err(format!("unexpected ok")), + Err(e) => Err(format!("unexpected err {:?}", e)) + } + + } + + #[test] + fn test_inp() -> Result<(), String> { + let pgm = vec!( ezop(11, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 0, 0, 0, 0, 0, 0]; + let mut cons = BufConsole::make(); + cons.inb.push(128); + if let Err(e) = c.run(&mut cons) { + return Err(format!("unexpected err {:?}", e)); + }; + let exp = [0, 0, 0, 128, 0, 0, 0, 0]; + assert_eq!(c.reg, exp); + Ok(()) + } + + #[test] + fn test_inp_fail() -> Result<(), String> { + let pgm = vec!( ezop(11, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 0, 0, 0, 0, 0, 0]; + let mut cons = BufConsole::make(); + if let Err(e) = c.run(&mut cons) { + return Err(format!("unexpected err {:?}", e)); + }; + let exp = [0, 0, 0, 0xffffffff, 0, 0, 0, 0]; + assert_eq!(c.reg, exp); + Ok(()) + } } \ No newline at end of file