ops
This commit is contained in:
parent
65598cf86e
commit
1ea7908fca
275
src/cpu.rs
275
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<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(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user