From 1ea7908fcafb85043291f7d0de9e6e046e55ea9f Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 28 Aug 2025 19:34:25 +0200 Subject: [PATCH] ops --- src/cpu.rs | 275 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 234 insertions(+), 41 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 518e560..24412f0 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -2,12 +2,27 @@ use std::collections::HashMap; use std::vec::Vec; use crate::instruction::{Instruction, NormalInstruction, SpecialInstruction}; +pub trait Console { + fn read(&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 + UnexpectedInput, + InvalidArray, + ArrayOutOfBounds } #[derive(Debug)] @@ -95,11 +110,64 @@ impl Cpu { Ok(()) } + fn handle_aix(&mut self, i: NormalInstruction) -> Result<(), CpuError> { + let aidx = self.gr(i.b); + let aoff = self.gr(i.c) as usize; + + if let Some(arr) = self.arr.get(&aidx){ + if arr.len() > aoff { + self.sr(i.a, arr[aoff]); + Ok(()) + } else { + Err(CpuError::ArrayOutOfBounds) + } + } else { + Err(CpuError::InvalidArray) + } + } + + fn handle_amd(&mut self, i: NormalInstruction) -> Result<(), CpuError> { + let aidx = self.gr(i.a); + let aoff = self.gr(i.b) as usize; + let v = self.gr(i.c); + + if let Some(arr) = self.arr.get_mut(&aidx){ + if arr.len() > aoff { + arr[aoff] = v; + Ok(()) + } else { + Err(CpuError::ArrayOutOfBounds) + } + } else { + Err(CpuError::InvalidArray) + } + } + + fn handle_add(&mut self, i:NormalInstruction) -> Result<(), CpuError>{ + let b = self.gr(i.b); + let c = self.gr(i.c); + let (a, _) = b.overflowing_add(c); + self.sr(i.a, a); + Ok(()) + } + + fn handle_mul(&mut self, i:NormalInstruction) -> Result<(), CpuError>{ + let b = self.gr(i.b); + let c = self.gr(i.c); + let (a, _) = b.overflowing_mul(c); + self.sr(i.a, a); + Ok(()) + } + fn exec(&mut self, instruction: Instruction)-> Result<(), CpuError>{ //println!("{:?}", instruction); match instruction { Instruction::Ortho(i) => self.handle_ortho(i), Instruction::ConditionalMove(i) => self.handle_cmov(i), + Instruction::ArrayIndex(i) => self.handle_aix(i), + Instruction::ArrayAmend(i) => self.handle_amd(i), + Instruction::Add(i) => self.handle_add(i), + Instruction::Multiply(i) => self.handle_mul(i), _ => Err(CpuError::InvalidInstruction) } } @@ -112,7 +180,29 @@ impl Cpu { self.finger += 1; Ok(()) } + + pub fn run(&mut self, console: &mut impl Console) -> Result<(), CpuError> { + let mut cont = true; + while cont { + cont = match self.step() { + Ok(_) => true, + Err(CpuError::ProgramEnd) => false, + Err(e) => return Err(e) + }; + if self.expecting_input() { + if let Some(c) = console.read() { + self.set_in(c)?; + } + }; + if let Some(c) = self.output() { + console.write(c); + } + }; + Ok(()) } +} + + #[cfg(test)] mod tests{ @@ -125,59 +215,162 @@ mod tests{ } } - - #[test] - fn test_ortho() -> Result<(), String> { - let pgm = vec!(ezop(13, 3, 1337, 0)); + fn test_ortho() -> Result<(), CpuError> { + let pgm = vec!( ezop(13, 3, 1337, 0) ); let mut c = Cpu::new(pgm); - let result = c.step(); - assert!(matches!(result, Ok(_))); - assert_eq!(c.reg[0], 0); - assert_eq!(c.reg[3], 1337); + let exp = [0, 0, 0, 1337, 0, 0, 0, 0]; + c.run(&mut NoConsole{})?; + assert_eq!(c.reg, exp); Ok(()) } #[test] - fn test_cmov() -> Result<(), String> { - let pgm = vec!( - ezop(13, 1, 65535, 0), - ezop(13, 2, 1337, 0), - ezop(13, 3, 1, 0), - ezop(0, 1, 2, 3), - ); + fn test_cmov() -> Result<(), CpuError> { + let pgm = vec!( ezop(0, 1, 2, 3) ); let mut c = Cpu::new(pgm); - _ = c.step(); - _ = c.step(); - _ = c.step(); - let result = c.step(); - assert!(matches!(result, Ok(_))); - assert_eq!(c.reg[0], 0); - assert_eq!(c.reg[3], 1); - assert_eq!(c.reg[2], 1337); - assert_eq!(c.reg[1], 1337); + c.reg = [0, 0, 1337, 1, 0, 0, 0, 0]; + c.run(&mut NoConsole{})?; + let exp = [0, 1337, 1337, 1, 0, 0, 0, 0]; + assert_eq!(c.reg, exp); Ok(()) } #[test] - fn test_cmov_neg() -> Result<(), String> { - let pgm = vec!( - ezop(13, 1, 65535, 0), - ezop(13, 2, 1337, 0), - ezop(13, 3, 0, 0), - ezop(0, 1, 2, 3), - ); + fn test_cmov_neg() -> Result<(), CpuError> { + let pgm = vec!( ezop(0, 1, 2, 3) ); let mut c = Cpu::new(pgm); - _ = c.step(); - _ = c.step(); - _ = c.step(); - let result = c.step(); - assert!(matches!(result, Ok(_))); - assert_eq!(c.reg[0], 0); - assert_eq!(c.reg[3], 0); - assert_eq!(c.reg[2], 1337); - assert_eq!(c.reg[1], 65535); + c.reg = [0, 0, 1337, 0, 0, 0, 0, 0]; + c.run(&mut NoConsole{})?; + let exp = [0, 0, 1337, 0, 0, 0, 0, 0]; + assert_eq!(c.reg, exp); Ok(()) } + #[test] + fn test_aix() -> Result<(), CpuError> { + let pgm = vec!( ezop(1, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.arr.insert(1338, vec![0,0,0,1337]); + c.reg = [0, 0, 1338, 3, 0, 0, 0, 0]; + c.run(&mut NoConsole{})?; + let exp = [0, 1337, 1338, 3, 0, 0, 0, 0]; + assert_eq!(c.reg, exp); + Ok(()) + } + + #[test] + fn test_aix_noarr() -> Result<(), String> { + let pgm = vec!( ezop(1, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 1338, 3, 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_aix_nooff() -> Result<(), String> { + let pgm = vec!( ezop(1, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 1338, 3, 0, 0, 0, 0]; + c.arr.insert(1338, vec![0]); + match c.run(&mut NoConsole{}) { + Err(CpuError::ArrayOutOfBounds) => Ok(()), + Err(_) => Err(String::from("Invalid error")), + Ok(_) => Err(String::from("Expected err got ok")) + } + + } + + #[test] + fn test_amd() -> Result<(), CpuError> { + let pgm = vec!( ezop(2, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.arr.insert(1338, vec![0,0,0,0]); + c.reg = [0, 1338, 1, 1336, 0, 0, 0, 0]; + c.run(&mut NoConsole{})?; + let exp = [0, 1338, 1, 1336, + 0, 0, 0, 0]; + assert_eq!(c.reg, exp); + if let Some(arr) = c.arr.get(&1338){ + assert_eq!(arr,&vec![0,1336,0,0] ); + Ok(()) + } else { + Err(CpuError::InvalidArray) + } + } + + #[test] + fn test_amd_noarr() -> Result<(), String> { + let pgm = vec!( ezop(2, 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::InvalidArray) => Ok(()), + Err(_) => Err(String::from("Invalid error")), + Ok(_) => Err(String::from("Expected err got ok")) + } + + } + + #[test] + fn test_amd_nooff() -> Result<(), String> { + let pgm = vec!( ezop(2, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 1338, 3, 0, 0, 0, 0, 0]; + c.arr.insert(1338, vec![0]); + match c.run(&mut NoConsole{}) { + Err(CpuError::ArrayOutOfBounds) => Ok(()), + Err(_) => Err(String::from("Invalid error")), + Ok(_) => Err(String::from("Expected err got ok")) + } + } + + #[test] + fn test_add() -> Result<(), CpuError> { + let pgm = vec!( ezop(3, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 1337, 1, 0, 0, 0, 0]; + c.run(&mut NoConsole{})?; + let exp = [0, 1338, 1337, 1, 0, 0, 0, 0]; + assert_eq!(c.reg, exp); + Ok(()) + } + + #[test] + fn test_add_ovf() -> Result<(), CpuError> { + let pgm = vec!( ezop(3, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 1337, 0xffffffff, 0, 0, 0, 0]; + c.run(&mut NoConsole{})?; + let exp = [0, 1336, 1337, 0xffffffff, 0, 0, 0, 0]; + assert_eq!(c.reg, exp); + Ok(()) + } + + #[test] + fn test_mul() -> Result<(), CpuError> { + let pgm = vec!( ezop(4, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 1337, 2, 0, 0, 0, 0]; + c.run(&mut NoConsole{})?; + let exp = [0, 2674, 1337, 2, 0, 0, 0, 0]; + assert_eq!(c.reg, exp); + Ok(()) + } + + #[test] + fn test_mul_ovf() -> Result<(), CpuError> { + let pgm = vec!( ezop(4, 1, 2, 3) ); + let mut c = Cpu::new(pgm); + c.reg = [0, 0, 2, 0xffffffff, 0, 0, 0, 0]; + c.run(&mut NoConsole{})?; + let exp = [0, 0xfffffffe, 2, 0xffffffff, 0, 0, 0, 0]; + assert_eq!(c.reg, exp); + Ok(()) + } } \ No newline at end of file