Compare commits

...

2 Commits

Author SHA1 Message Date
Richard
1ea7908fca ops 2025-08-28 19:34:25 +02:00
Richard
65598cf86e cmov 2025-08-26 10:50:05 +02:00

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)]
@ -33,6 +48,14 @@ impl Cpu {
}
}
fn gr(&self, r: u8) -> u32{
self.reg[r as usize]
}
fn sr(&mut self, r: u8, v:u32) {
self.reg[r as usize] = v
}
fn ins(&self) -> Result<Instruction,CpuError> {
if self.finger as usize >= self.arr[&0].len() {
return Err(CpuError::ProgramEnd);
@ -75,14 +98,76 @@ impl Cpu {
}
fn handle_ortho(&mut self, i:SpecialInstruction) -> Result<(), CpuError>{
self.reg[i.a as usize] = i.v as u32;
self.sr(i.a, i.v);
Ok(())
}
fn handle_cmov(&mut self, i:NormalInstruction) -> Result<(), CpuError>{
if self.gr(i.c) > 0 {
let v = self.gr(i.b);
self.sr(i.a, v);
}
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);
//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)
}
}
@ -95,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{
@ -108,17 +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<(), CpuError> {
let pgm = vec!( ezop(0, 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, 1337, 1337, 1, 0, 0, 0, 0];
assert_eq!(c.reg, exp);
Ok(())
}
#[test]
fn test_cmov_neg() -> Result<(), CpuError> {
let pgm = vec!( ezop(0, 1, 2, 3) );
let mut c = Cpu::new(pgm);
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(())
}
}