Compare commits
2 Commits
f74be7dbbf
...
1ea7908fca
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1ea7908fca | ||
![]() |
65598cf86e |
274
src/cpu.rs
274
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)]
|
||||
@ -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(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user