This commit is contained in:
Richard 2025-08-28 19:34:25 +02:00
parent 65598cf86e
commit 1ea7908fca

View File

@ -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<u8>;
fn write(&mut self, c: u8);
}
struct NoConsole;
impl Console for NoConsole {
fn read(&self) -> Option<u8> {
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(())
}
}