From 0504a13d9ec10dc8657cc4d50d61298661deee85 Mon Sep 17 00:00:00 2001 From: Michael Preisach Date: Tue, 22 May 2018 17:50:59 +0200 Subject: [PATCH] instructions implemented, no debugging yet --- src/main.rs | 441 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 420 insertions(+), 21 deletions(-) diff --git a/src/main.rs b/src/main.rs index 09980a0..f0ae0d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,33 +1,382 @@ -use std::prelude; +use std::fmt; use std::ops::*; +const debug: bool = true; + fn main() { - println!("Hello World!"); - let mut s = Vec::new(); - s.push(9); - println!("{}",s.pop().unwrap()); + let mut cpu = Cpu::new(); + let program:Vec = vec![9,32768,32769,'a' as u16,19,32768]; + cpu.write_program(program); + let mut result = cpu.execute(); + if result.is_ok() { + println!("Execution successful!"); + } else { + println!("Err: {}", result.err().unwrap()) + } } -struct Cpu { +pub struct Cpu { stack: Vec, mem: Vec, reg: Vec, pc: Number, + alu: Alu, +} + +impl fmt::Debug for Cpu { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Cpu {{ pc = {}, ", self.pc.value)?; + write!(f, "reg = ")?; + for i in 0 .. 7 { + write!(f, "[{}]: {}, ", i, self.reg[i]); + } + write!(f, "stack = ")?; + for i in 0 .. self.stack.len() { + write!(f, "[{}]: {}, ", i, self.stack[i])?; + } + for i in 0 .. self.mem.len() { + write!(f, "[{}]: {}, ", i, self.mem[i])?; + } + write!(f, "}}")?; + Ok(()) + } } impl Cpu { - fn new() -> Cpu { + pub fn new() -> Cpu { Cpu { stack: Vec::new(), - mem: Vec::with_capacity(32768), - reg: Vec::with_capacity(8), + mem: vec![0; 32768], + reg: vec![0; 8], pc: Number::new(), + alu: Alu::new(), + } + } + + pub fn write_program(&mut self, prog: Vec) { + self.pc.value = 0; + for i in prog { + self.mem[self.pc.value as usize] = i; + self.pc.inc(); + } + self.pc.value = 0; + } + + pub fn execute(&mut self) -> Result<&'static str, &'static str>{ + let mut running = true; + let mut err = 0; + if self.mem.is_empty() { + running = false; + err = 2; + } + while running { + match self.read(self.pc.value).unwrap() { + 0 => { //halt: stop execution and terminate the program + if debug { + println!("{}: halt", self.pc); + } + running = false; + }, + 1 => { //set : set register to the value of + if debug { + println!("{}: set {} {}", self.pc, self.mem[(self.pc.value + 1) as usize], self.mem[(self.pc.value + 2) as usize]); + } + self.pc.inc(); + let reg = self.mem[(self.pc.value) as usize]; + self.pc.inc(); + let val = self.read(self.pc.value).unwrap(); + self.write(reg + 32768, val); + self.pc.inc(); + }, + 2 => { //push : push onto the stack + if debug { + println!("{}: push {}", self.pc, self.mem[(self.pc.value + 1) as usize]); + } + self.pc.inc(); + let val = self.read(self.pc.value).unwrap(); + self.stack.push(val); + self.pc.inc(); + }, + 3 => { //pop : remove the top element from the stack and write it into ; empty stack = error + if debug { + println!("{}: pop {}", self.pc, self.mem[(self.pc.value + 1) as usize]); + } + self.pc.inc(); + match self.stack.pop() { + None => { + running = false; + err = 1; + }, + Some(i) => { + let addr = self.read(self.pc.value).unwrap(); + self.write(addr, i); + self.pc.inc(); + }, + } + }, + 4 => { //eq : set to 1 if is equal to ; set it to 0 otherwise + if debug { + println!("{}: eq {} {} {}", self.pc, self.mem[(self.pc.value + 1) as usize], self.mem[(self.pc.value + 2) as usize], self.mem[(self.pc.value + 3) as usize]); + } + self.pc.inc(); + let resaddr = self.read(self.pc.value).unwrap(); + self.pc.inc(); + self.alu.a.value = self.read(self.pc.value).unwrap(); + self.pc.inc(); + self.alu.b.value = self.read(self.pc.value).unwrap(); + self.alu.op = 0; //alu eq + self.alu.execute(); + let result = self.alu.c.value; + self.write(resaddr, result); + self.pc.inc(); + }, + 5 => { //gt : set to 1 if is greater than ; set it to 0 otherwise + if debug { + println!("{}: gt {} {} {}", self.pc, self.mem[(self.pc.value + 1) as usize], self.mem[(self.pc.value + 2) as usize], self.mem[(self.pc.value + 3) as usize]); + } + self.pc.inc(); + let resaddr = self.read(self.pc.value).unwrap(); + self.pc.inc(); + self.alu.a.value = self.read(self.pc.value).unwrap(); + self.pc.inc(); + self.alu.b.value = self.read(self.pc.value).unwrap(); + self.alu.op = 1; //alu gt + self.alu.execute(); + let result = self.alu.c.value; + self.write(resaddr, result); + self.pc.inc(); + }, + 6 => { //jmp : jump to + if debug { + println!("{}: jmp {}", self.pc, self.mem[(self.pc.value + 1) as usize]); + } + self.pc.inc(); + let target = self.read(self.pc.value).unwrap(); + self.jump(target); + }, + 7 => { //jt : if is nonzero, jump to + if debug { + println!("{}: jt {} {}", self.pc, self.mem[(self.pc.value + 1) as usize], self.mem[(self.pc.value + 2) as usize]); + } + self.pc.inc(); + self.alu.a.value = self.read(self.pc.value).unwrap(); + self.alu.b.value = 0; + self.alu.op = 0; //alu op: eq + self.alu.execute(); + self.pc.inc(); + let target = self.read(self.pc.value).unwrap(); + match self.alu.c.value { + 0 => {self.jump(target);}, + _ => {self.pc.inc();}, + } + }, + 8 => { //jf : if is zero, jump to + if debug { + println!("{}: jf {} {}", self.pc, self.mem[(self.pc.value + 1) as usize], self.mem[(self.pc.value + 2) as usize]); + } + self.pc.inc(); + self.alu.a.value = self.read(self.pc.value).unwrap(); + self.alu.b.value = 0; + self.alu.op = 0; //alu op: eq + self.alu.execute(); + self.pc.inc(); + let target = self.read(self.pc.value).unwrap(); + match self.alu.c.value { + 0 => {self.pc.inc();}, + _ => {self.jump(target);}, + } + }, + 9...13 => { //aluop : compute result in alu with = op + if debug { + println!("{}: aluop {} {} {}", self.pc, self.mem[(self.pc.value + 1) as usize], self.mem[(self.pc.value + 2) as usize], self.mem[(self.pc.value + 3) as usize]); + } + self.alu.op = self.read(self.pc.value).unwrap() - 7; //alu ops: 2...6 + self.pc.inc(); + let resaddr = self.read(self.pc.value).unwrap(); + self.pc.inc(); + self.alu.a.value = self.read(self.pc.value).unwrap(); + self.pc.inc(); + self.alu.b.value = self.read(self.pc.value).unwrap(); + self.alu.execute(); + let result = self.alu.c.value; + self.write(resaddr, result); + self.pc.inc(); + }, + 14 => { //not : stores 15-bit bitwise inverse of in + if debug { + println!("{}: not {} {}", self.pc, self.mem[(self.pc.value + 1) as usize], self.mem[(self.pc.value + 2) as usize]); + } + self.pc.inc(); + let resaddr = self.read(self.pc.value).unwrap(); + self.pc.inc(); + self.alu.a.value = self.read(self.pc.value).unwrap(); + self.alu.op = 7; //alu op: not + self.alu.execute(); + let result = self.alu.c.value; + self.write(resaddr, result); + self.pc.inc(); + }, + 15 => { //rmem : read memory at address and write it to + if debug { + println!("{}: rmem {} {}", self.pc, self.mem[(self.pc.value + 1) as usize], self.mem[(self.pc.value + 2) as usize]); + } + self.pc.inc(); + let resaddr = self.read(self.pc.value).unwrap(); + self.pc.inc(); + let result = self.read(self.read(self.pc.value).unwrap()).unwrap(); + self.write(resaddr, result); + self.pc.inc(); + }, + 16 => { //wmem : write the value from into memory at address + if debug { + println!("{}: wmem {} {}", self.pc, self.mem[(self.pc.value + 1) as usize], self.mem[(self.pc.value + 2) as usize]); + } + self.pc.inc(); + let resaddr = self.read(self.pc.value).unwrap(); + self.pc.inc(); + let result = self.read(self.read(self.pc.value).unwrap()).unwrap(); + self.write(resaddr, result); + self.pc.inc(); + }, + 17 => { //call : write the address of the next instruction to the stack and jump to + if debug { + println!("{}: call {}", self.pc, self.mem[(self.pc.value + 1) as usize]); + } + self.pc.inc(); + let target = self.read(self.pc.value).unwrap(); + self.pc.inc(); + self.stack.push(self.pc.value); + self.jump(target); + }, + 18 => { //ret: remove the top element from the stack and jump to it; empty stack = halt + if debug { + println!("{}: ret", self.pc); + } + match self.stack.pop() { + None => { + running = false; + }, + Some(target) => { + self.jump(target); + }, + } + }, + 19 => { //out : write the character represented by ascii code to the terminal + if debug { + println!("{}: out {}", self.pc, self.mem[(self.pc.value + 1) as usize]); + } + self.pc += Number{value: 1}; + let addr = self.read(self.pc.value).unwrap(); + let c:char = self.read(addr).unwrap() as u8 as char; + print!("{}", c); + self.pc += Number{value: 1}; + }, + 20 => { //in : read a character from the terminal and write its ascii code to ; it can be assumed that once input starts, it will continue until a newline is encountered; this means that you can safely read whole lines from the keyboard and trust that they will be fully read + if debug { + println!("{}: in {}", self.pc, self.mem[(self.pc.value + 1) as usize]); + } + running = false; + }, + 21 => { //noop: no operation + if debug { + println!("{}: noop", self.pc); + } + self.pc += Number{value: 1} + }, + _ => { //invalid + if debug { + println!("{}: invalid", self.pc); + } + err = 3; + running = false; + } + } + } + match err { + 0 => Ok("Execution successful"), + 1 => Err("Stack Empty"), + 2 => Err("No Program"), + 3 => Err("Invalid Instruction"), + _ => Err("Unknown Error"), + } + } + + fn read(&self, address: u16) -> Option { + match address { + 0...32767 => Some(self.mem[address as usize]), + 32768...32775 => Some(self.mem[(address -32768) as usize]), + _ => None + } + } + + fn write(&mut self, address: u16, val: u16) -> Result { + match address { + 0...32767 => { + self.mem[address as usize] = val; + Ok(val) + }, + 32768...32775 => { + self.mem[(address - 32768) as usize] = val; + Ok(val) + } + _ => Err("Write: Invalid address") + } + } + + fn jump(&mut self, target: u16) -> Result { + match target { + 0...32767 => { + self.pc.value = target; + Ok(target) + }, + _ => Err("Jump: Invalid address") + } + } +} + +struct Alu { + op: u16, + a: Number, + b: Number, + c: Number, +} + +impl Alu { + fn new() -> Alu { + Alu { + op: 0, + a: Number {value: 0}, + b: Number {value: 0}, + c: Number {value: 0}, + } + } + fn execute(&mut self) { + match self.op { + 0 => self.c = Number { //eq + value: match self.a.value == self.b.value { + true => 1, + false => 0, + } + }, + 1 => self.c = Number { //gt + value: match self.a.value > self.b.value { + true => 1, + false => 0, + } + }, + 2 => self.c = self.a + self.b, //add + 3 => self.c = self.a * self.b, //mult + 4 => self.c = self.a % self.b, //mod + 5 => self.c = self.a & self.b, //and + 6 => self.c = self.a | self.b, //or + 7 => self.c = !self.a, //not + _ => self.c = self.a, //other } } } //15Bit numbers for the ALU -#[derive(Eq, PartialEq, Copy, Clone)] +#[derive(Copy, Clone, Debug)] struct Number { value: u16, } @@ -42,6 +391,13 @@ impl Add for Number { } } +impl AddAssign for Number { + fn add_assign(&mut self, other: Number) { + self.value += other.value; + self.value %= 32768; + } +} + impl Sub for Number { type Output = Number; fn sub(self, other: Number) -> Number { @@ -60,31 +416,74 @@ impl Mul for Number { } } +impl Rem for Number { + type Output = Number; + fn rem(self, other: Number) -> Number { + Number { + value: (self.value % other.value), + } + } +} + +impl BitOr for Number { + type Output = Number; + fn bitor(self, other: Number) -> Number { + Number { + value: (self.value | other.value), + } + } +} + +impl BitAnd for Number { + type Output = Number; + fn bitand(self, other: Number) -> Number { + Number { + value: (self.value & other.value), + } + } +} + impl Not for Number { type Output = Number; fn not(self) -> Number { Number { - value: (!self.value) % 32768, + value: (!self.value) & 0x7FFF, } } } +impl fmt::Display for Number { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.value) + } +} + impl Number { - //little Endian -> + //little Endian -> memory management fn new() -> Number { Number { value: 0, } } - fn get_first_byte(&self) -> u8 { - (self.value & 0xFF) as u8 - } - fn get_second_byte(&self) -> u8 { - ((self.value >> 8) & 0x7F) as u8 + fn inc(&mut self) { + self.value += 1; } - fn set_bytes(&mut self, first: u8, second: u8) { - let mut newval:u16 = (second & 0x7F) as u16; - newval <<= 8; - self.value = newval + (first as u16); +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn nop_out_halt() { + let mut cpu = Cpu::new(); + let program: Vec = vec![21, 21, 19, 5, 0, 'a' as u16]; + cpu.write_program(program); + let mut result = cpu.execute(); + if result.is_ok() { + println!("Execution successful!"); + } else { + println!("Err: {}", result.err().unwrap()) + } + assert!(result.is_ok()); } }