Browse Source

instructions implemented, no debugging yet

master
Michael Preisach 8 years ago
parent
commit
0504a13d9e
  1. 439
      src/main.rs

439
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<u16> = 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<u16>,
mem: Vec<u16>,
reg: Vec<u16>,
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<u16>) {
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 <a> <b>: set register <a> to the value of <b>
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 <a>: push <a> 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 <a>: remove the top element from the stack and write it into <a>; 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 <a> <b> <c>: set <a> to 1 if <b> is equal to <c>; 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 <a> <b> <c>: set <a> to 1 if <b> is greater than <c>; 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 <a>: jump to <a>
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 <a> <b>: if <a> is nonzero, jump to <b>
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 <a> <b>: if <a> is zero, jump to <b>
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 <a> <b> <c>: compute result in alu with <a> = <b> op <c>
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 <a> <b>: stores 15-bit bitwise inverse of <b> in <a>
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 <a> <b>: read memory at address <b> and write it to <a>
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 <a> <b>: write the value from <b> into memory at address <a>
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 <a>: write the address of the next instruction to the stack and jump to <a>
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 <a>: write the character represented by ascii code <a> 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 <a>: read a character from the terminal and write its ascii code to <a>; 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<u16> {
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<u16, &'static str> {
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<u16, &'static str> {
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 inc(&mut self) {
self.value += 1;
}
fn get_second_byte(&self) -> u8 {
((self.value >> 8) & 0x7F) as u8
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nop_out_halt() {
let mut cpu = Cpu::new();
let program: Vec<u16> = 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())
}
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);
assert!(result.is_ok());
}
}

Loading…
Cancel
Save