ops
This commit is contained in:
parent
1ea7908fca
commit
35b0b5972f
BIN
data/bootsand.um
Normal file
BIN
data/bootsand.um
Normal file
Binary file not shown.
283
src/cpu.rs
283
src/cpu.rs
@ -3,32 +3,28 @@ use std::vec::Vec;
|
||||
use crate::instruction::{Instruction, NormalInstruction, SpecialInstruction};
|
||||
|
||||
pub trait Console {
|
||||
fn read(&self) -> Option<u8>;
|
||||
fn read(&mut 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,
|
||||
InvalidArray,
|
||||
ArrayOutOfBounds
|
||||
ArrayOutOfBounds,
|
||||
DivideByZero,
|
||||
Halt,
|
||||
LargeAlloc,
|
||||
InvalidOutput
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Cpu {
|
||||
reg: [u32; 8],
|
||||
arr: HashMap<u32, Vec<u32>>,
|
||||
iarr: u32,
|
||||
finger: u32,
|
||||
out: Option<u8>,
|
||||
in_reg: Option<u8>
|
||||
@ -42,6 +38,7 @@ impl Cpu {
|
||||
Cpu {
|
||||
reg: [0;8],
|
||||
arr: arrays,
|
||||
iarr: 1,
|
||||
finger: 0,
|
||||
in_reg: None,
|
||||
out: None
|
||||
@ -159,6 +156,65 @@ impl Cpu {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_div(&mut self, i:NormalInstruction) -> Result<(), CpuError>{
|
||||
let b = self.gr(i.b);
|
||||
let c = self.gr(i.c);
|
||||
if c == 0 {
|
||||
return Err(CpuError::DivideByZero);
|
||||
}
|
||||
let (a, _) = b.overflowing_div(c);
|
||||
self.sr(i.a, a);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_nand(&mut self, i:NormalInstruction) -> Result<(), CpuError>{
|
||||
let b = ! self.gr(i.b);
|
||||
let c = ! self.gr(i.c);
|
||||
let a = b & c;
|
||||
self.sr(i.a, a);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_halt(&mut self, _i:NormalInstruction) -> Result<(), CpuError>{
|
||||
Err(CpuError::Halt)
|
||||
}
|
||||
|
||||
fn handle_alc(&mut self, i:NormalInstruction) -> Result<(), CpuError>{
|
||||
let c = self.gr(i.c) as usize;
|
||||
if c > 1048576 {
|
||||
return Err(CpuError::LargeAlloc);
|
||||
}
|
||||
let aid = self.iarr;
|
||||
self.iarr += 1;
|
||||
let v = vec![0; c];
|
||||
self.arr.insert(aid, v);
|
||||
self.sr(i.b, aid);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_abn(&mut self, i:NormalInstruction) -> Result<(), CpuError>{
|
||||
let c = self.gr(i.c);
|
||||
if c == 0 || ! self.arr.contains_key(&c){
|
||||
return Err(CpuError::InvalidArray);
|
||||
}
|
||||
self.arr.remove(&c);
|
||||
Ok(())
|
||||
}
|
||||
fn handle_out(&mut self, i:NormalInstruction) -> Result<(), CpuError>{
|
||||
let c = self.gr(i.c);
|
||||
if c > 255 {
|
||||
return Err(CpuError::InvalidOutput);
|
||||
}
|
||||
self.out = Some(c as u8);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_inp(&mut self, i:NormalInstruction) -> Result<(), CpuError>{
|
||||
self.sr(i.c, 0xffffffff);
|
||||
self.in_reg = Some(i.c);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn exec(&mut self, instruction: Instruction)-> Result<(), CpuError>{
|
||||
//println!("{:?}", instruction);
|
||||
match instruction {
|
||||
@ -168,6 +224,13 @@ impl Cpu {
|
||||
Instruction::ArrayAmend(i) => self.handle_amd(i),
|
||||
Instruction::Add(i) => self.handle_add(i),
|
||||
Instruction::Multiply(i) => self.handle_mul(i),
|
||||
Instruction::Divide(i) => self.handle_div(i),
|
||||
Instruction::NotAnd(i) => self.handle_nand(i),
|
||||
Instruction::Halt(i) => self.handle_halt(i),
|
||||
Instruction::Allocate(i) => self.handle_alc(i),
|
||||
Instruction::Abandon(i) => self.handle_abn(i),
|
||||
Instruction::Output(i) => self.handle_out(i),
|
||||
Instruction::Input(i) => self.handle_inp(i),
|
||||
_ => Err(CpuError::InvalidInstruction)
|
||||
}
|
||||
}
|
||||
@ -207,6 +270,45 @@ impl Cpu {
|
||||
#[cfg(test)]
|
||||
mod tests{
|
||||
use super::*;
|
||||
struct NoConsole;
|
||||
|
||||
impl Console for NoConsole {
|
||||
fn read(&mut self) -> Option<u8> {
|
||||
None
|
||||
}
|
||||
fn write(&mut self, _c: u8) {}
|
||||
}
|
||||
|
||||
struct BufConsole {
|
||||
inb: Vec<u8>,
|
||||
inptr: usize,
|
||||
outb: Vec<u8>
|
||||
}
|
||||
|
||||
impl BufConsole {
|
||||
fn make() -> BufConsole {
|
||||
BufConsole {
|
||||
inb: vec![],
|
||||
inptr: 0,
|
||||
outb: vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Console for BufConsole {
|
||||
fn read(&mut self) -> Option<u8> {
|
||||
if self.inptr >= self.inb.len() {
|
||||
None
|
||||
} else {
|
||||
let r = self.inb[self.inptr];
|
||||
self.inptr += 1;
|
||||
Some(r)
|
||||
}
|
||||
}
|
||||
fn write(&mut self, c: u8) {
|
||||
self.outb.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
fn ezop(op:u32, a:u32, b:u32, c:u32) -> u32 {
|
||||
match op {
|
||||
@ -317,7 +419,7 @@ mod tests{
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[test]
|
||||
fn test_amd_nooff() -> Result<(), String> {
|
||||
let pgm = vec!( ezop(2, 1, 2, 3) );
|
||||
let mut c = Cpu::new(pgm);
|
||||
@ -373,4 +475,161 @@ mod tests{
|
||||
assert_eq!(c.reg, exp);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_div() -> Result<(), CpuError> {
|
||||
let pgm = vec!( ezop(5, 1, 2, 3) );
|
||||
let mut c = Cpu::new(pgm);
|
||||
c.reg = [0, 0, 2048, 2, 0, 0, 0, 0];
|
||||
c.run(&mut NoConsole{})?;
|
||||
let exp = [0, 1024, 2048, 2, 0, 0, 0, 0];
|
||||
assert_eq!(c.reg, exp);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_div_zero() -> Result<(), String> {
|
||||
let pgm = vec!( ezop(5, 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::DivideByZero) => Ok(()),
|
||||
Err(_) => Err(String::from("Invalid error")),
|
||||
Ok(_) => Err(String::from("Expected err got ok"))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nand() -> Result<(), CpuError> {
|
||||
let pgm = vec!( ezop(6, 1, 2, 3) );
|
||||
let mut c = Cpu::new(pgm);
|
||||
c.reg = [0, 0, 0x5a5a00ff, 0xdede00ff, 0, 0, 0, 0];
|
||||
c.run(&mut NoConsole{})?;
|
||||
let exp = [0, 0x2121ff00, 0x5a5a00ff, 0xdede00ff, 0, 0, 0, 0];
|
||||
assert_eq!(c.reg, exp);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_halt() -> Result<(), String> {
|
||||
let pgm = vec!( ezop(7, 1, 2, 3) );
|
||||
let mut c = Cpu::new(pgm);
|
||||
match c.run(&mut NoConsole{}) {
|
||||
Err(CpuError::Halt) => Ok(()),
|
||||
Err(_) => Err(String::from("Invalid error")),
|
||||
Ok(_) => Err(String::from("Expected err got ok"))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alc_large() -> Result<(), String> {
|
||||
let pgm = vec!( ezop(8, 1, 2, 3) );
|
||||
let mut c = Cpu::new(pgm);
|
||||
c.reg = [0, 1338, 33, 0xffffffff, 0, 0, 0, 0];
|
||||
match c.run(&mut NoConsole{}) {
|
||||
Err(CpuError::LargeAlloc) => Ok(()),
|
||||
Err(_) => Err(String::from("Invalid error")),
|
||||
Ok(_) => Err(String::from("Expected err got ok"))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alc() -> Result<(), CpuError> {
|
||||
let pgm = vec!( ezop(8, 1, 2, 3) );
|
||||
let mut c = Cpu::new(pgm);
|
||||
c.reg = [0, 1338, 33, 5, 0, 0, 0, 0];
|
||||
if let Err(e) = c.run(&mut NoConsole{}) {
|
||||
return Err(e)
|
||||
}
|
||||
let exp = [0, 1338, 1, 5, 0, 0, 0, 0];
|
||||
assert_eq!(c.reg, exp);
|
||||
if let Some(arr) = c.arr.get(&1){
|
||||
assert_eq!(arr,&vec![0,0,0,0,0] );
|
||||
Ok(())
|
||||
} else {
|
||||
Err(CpuError::InvalidArray)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abn() -> Result<(), CpuError> {
|
||||
let pgm = vec!( ezop(9, 1, 2, 3) );
|
||||
let mut c = Cpu::new(pgm);
|
||||
c.arr.insert(1338, vec![0,0,0,0]);
|
||||
c.reg = [0, 0, 0, 1338, 0, 0, 0, 0];
|
||||
c.run(&mut NoConsole{})?;
|
||||
if c.arr.contains_key(&1338) {
|
||||
Err(CpuError::InvalidArray)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abn_zero() -> Result<(), String> {
|
||||
let pgm = vec!( ezop(9, 1, 2, 3) );
|
||||
let mut c = Cpu::new(pgm);
|
||||
c.reg = [0, 0, 0, 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_out() -> Result<(), String> {
|
||||
let pgm = vec!( ezop(10, 1, 2, 3) );
|
||||
let mut c = Cpu::new(pgm);
|
||||
c.reg = [0, 0, 0, 128, 0, 0, 0, 0];
|
||||
let mut cons = BufConsole::make();
|
||||
if let Err(e) = c.run(&mut cons) {
|
||||
return Err(format!("unexpected err {:?}", e));
|
||||
};
|
||||
assert_eq!(cons.outb, vec!(128));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_out_inv() -> Result<(), String> {
|
||||
let pgm = vec!( ezop(10, 1, 2, 3) );
|
||||
let mut c = Cpu::new(pgm);
|
||||
c.reg = [0, 0, 0, 1337, 0, 0, 0, 0];
|
||||
let mut cons = BufConsole::make();
|
||||
match c.run(&mut cons) {
|
||||
Err(CpuError::InvalidOutput) => Ok(()),
|
||||
Ok(_) => Err(format!("unexpected ok")),
|
||||
Err(e) => Err(format!("unexpected err {:?}", e))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inp() -> Result<(), String> {
|
||||
let pgm = vec!( ezop(11, 1, 2, 3) );
|
||||
let mut c = Cpu::new(pgm);
|
||||
c.reg = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
let mut cons = BufConsole::make();
|
||||
cons.inb.push(128);
|
||||
if let Err(e) = c.run(&mut cons) {
|
||||
return Err(format!("unexpected err {:?}", e));
|
||||
};
|
||||
let exp = [0, 0, 0, 128, 0, 0, 0, 0];
|
||||
assert_eq!(c.reg, exp);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inp_fail() -> Result<(), String> {
|
||||
let pgm = vec!( ezop(11, 1, 2, 3) );
|
||||
let mut c = Cpu::new(pgm);
|
||||
c.reg = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
let mut cons = BufConsole::make();
|
||||
if let Err(e) = c.run(&mut cons) {
|
||||
return Err(format!("unexpected err {:?}", e));
|
||||
};
|
||||
let exp = [0, 0, 0, 0xffffffff, 0, 0, 0, 0];
|
||||
assert_eq!(c.reg, exp);
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user