prepare for upload

master
Griffiths Lott 3 years ago
commit a1ff7a1480
  1. 1
      .gitignore
  2. BIN
      cardiac_problem
  3. 3928
      output.txt
  4. 94
      src/lib.rs
  5. 150
      src/lib_verbose_documentation.rs
  6. 56
      src/main.rs

1
.gitignore vendored

@ -0,0 +1 @@
*.exe

Binary file not shown.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,94 @@
pub mod cardiac {
pub struct Memory {
pub memory: [[i8;2]; 32]
}
pub struct ProcessCounter {
pub pid: usize
}
pub struct Accumulator {
pub value: i8
}
pub struct CPU {
pub mem: Memory,
pub acc: Accumulator,
pub pc: ProcessCounter
}
impl CPU {
fn decoder(&mut self, mem_loc: usize) {
let opcode = self.mem.memory[mem_loc][0];
let address = self.mem.memory[mem_loc][1] as usize;
self.pc.pid += 1;
match opcode {
1 => { self.acc.value = self.mem.memory[address][1] as i8},
2 => { self.acc.value += self.mem.memory[address][1] as i8},
3 => {
if self.acc.value < 0 {
self.pc.pid = address;
}
}
5 => { println!("OUTPUT: {:?}", self.mem.memory[address][1]) }
6 => { self.mem.memory[address][1] = self.acc.value }
7 => { self.acc.value -= self.mem.memory[address][1] as i8}
8 => {
self.pc.pid = address;
}
9 => {
self.pc.pid = 0;
println!("\n\n\n PROGRAM COMPLETE");
self.print_varibles();
panic!("Program Halted");
}
0 => (),
_ => println!("Instuction set not defined...")
}
}
pub fn run(mut self) {
let mut cycle_counter = 0;
loop {
println!("Current State: ");
self.print_varibles();
println!("\nInstruction: {:?}", self.mem.memory[self.pc.pid]);
self.decoder(self.pc.pid);
println!("New State: ");
self.print_varibles();
cycle_counter += 1;
println!("Cycles: {:?}", cycle_counter);
println!("\n\n");
}
}
pub fn step(mut self, steps: u8){
for _i in 0..steps {
println!("Current State: ");
self.print_varibles();
println!("\nInstruction: {:?}", self.mem.memory[self.pc.pid]);
self.decoder(self.pc.pid);
println!("New State: ");
self.print_varibles();
println!("\n\n");
}
}
fn print_state(&self){
println!("Process Counter: {:?}", self.pc.pid);
println!("Accumulator: {:?}", self.acc.value);
println!("Memory: {:?}", self.mem.memory);
}
fn print_varibles(&self){
println!("Process Counter: {:?}", self.pc.pid);
println!("Accumulator: {:?}", self.acc.value);
println!("w: {:?} | x: {:?} | y: {:?} | z: {:?}", self.mem.memory[4],self.mem.memory[5],self.mem.memory[6],self.mem.memory[7]);
}
}
}

@ -0,0 +1,150 @@
pub mod cardiac { // This is a module that will be imported in the main file
// Seperating this out was just to keep things neater
pub struct Memory {
// This structure represents the memory of the machine
// Its defined as an array of signed 8 bit values
pub memory: [[i8;2]; 32]
}
pub struct ProcessCounter {
// This keeps track of where we are in the instruction set/memory
// usize is used to index the memory, luckily in this program address values
// are always positive or I would have had to deal with a conversion for negatives
pub pid: usize
}
pub struct Accumulator {
// This is the Accumulator, not much to explain
// It only holds an 8 bit signed value so -128 to 127
// Luckily this wasn't a problem for this example
pub value: i8
}
pub struct CPU {
// Here we define a structure to hold all of the pieces together
// This allows us to operate on self without having to make sure we specify
// the correct object
// It also helps with scope and reference issues
pub mem: Memory,
pub acc: Accumulator,
pub pc: ProcessCounter
}
impl CPU {
// This is our implementation for CPU
// This defines all of the methods associated with the CPU struct
fn decoder(&mut self, mem_loc: usize) {
// Decoder reads a memory location and decides what instructions to carry out
// &mut self allows us to change values in the CPU
// mem_loc is an index of a memory location
// in practive mem_loc will be prodivded by the process counter
let opcode = self.mem.memory[mem_loc][0];
// opcode is out operation code. This will be matched to a possible arm
// I didn't implement all the instruction as they were not needed and my time is limited
let address = self.mem.memory[mem_loc][1] as usize;
// address is the index of the memory location mentioned in the current process counter location
self.pc.pid += 1;
// Here we make sure that we will move onto the next instruction in the next cycle
// unless overridden by the instruction
match opcode { // Here we match the opcode to a value on the left of =>
// _ is a wildcard since out matching needs to exhaustive.
1 => { self.acc.value = self.mem.memory[address][1] as i8},
// 1: CLA this sets the Accumulator to the value of the address in the operend
2 => { self.acc.value += self.mem.memory[address][1] as i8},
// 2: ADD this adds the value of the address in the operend to the Accumulator
3 => { // 3: TAC this checks if the Accumulator is negative and if so it sets the process counter
// to the location of the propend
if self.acc.value < 0 {
self.pc.pid = address;
}
}
5 => { println!("OUTPUT: {:?}", self.mem.memory[address][1]) }
// 5: OUT this prints the propend
6 => { self.mem.memory[address][1] = self.acc.value }
// 6: STO this stores the value in the Accumulator to the propend
7 => { self.acc.value -= self.mem.memory[address][1] as i8}
// 7: SUB this subtracts the value of the address in the operend to the Accumulator
8 => { // 8: JMP sets the process counter to the propend
self.pc.pid = address;
}
9 => { // 9: HRS resets the program counter to 0 and halts the program
// The halting is implemented as a panic, but that's fine
self.pc.pid = 0;
println!("\n\n\n PROGRAM COMPLETE");
self.print_varibles();
panic!("Program Halted");
}
0 => (), // This matches the 0 instruction which is passed over
_ => println!("Instuction set not defined...") // This is the catchall to make the match exhaustive
}
}
pub fn run(mut self) {
// This runs the program in it's current state (with program counter wherever it currently is)
let mut cycle_counter = 0;
// This keeps track of how many times we've run through the instructions
loop { // Loop is an infinate loop meaning this program will continue to run until HRS is called
println!("Current State: "); // This is just output printing
self.print_varibles(); // This calls a method that displays the current print_varibles
// It also shows the accum value and the process counter
println!("\nInstruction: {:?}", self.mem.memory[self.pc.pid]);
// This prints the current instruction set based on the process counter
self.decoder(self.pc.pid);
// This runs the decoder on the current memory address specified by the process counter
println!("New State: ");
self.print_varibles();
cycle_counter += 1; // Records the completion of another cycle
println!("Cycles: {:?}", cycle_counter);
println!("\n\n");
}
}
pub fn step(mut self, steps: u8){
// This method was used in debugging.
// It allows us to step through a specified number of instructions
for _i in 0..steps {
println!("Current State: ");
self.print_varibles();
println!("\nInstruction: {:?}", self.mem.memory[self.pc.pid]);
self.decoder(self.pc.pid);
println!("New State: ");
self.print_varibles();
println!("\n\n");
}
}
fn print_state(&self){
// This prints out the entire memory of the machine as well as the accum and process counter
// This was mainly used in debugging
println!("Process Counter: {:?}", self.pc.pid);
println!("Accumulator: {:?}", self.acc.value);
println!("Memory: {:?}", self.mem.memory);
}
fn print_varibles(&self){
// This is less verbose than print_state, we print only varibles instead of the entire memory.
println!("Process Counter: {:?}", self.pc.pid);
println!("Accumulator: {:?}", self.acc.value);
println!("w: {:?} | x: {:?} | y: {:?} | z: {:?}", self.mem.memory[4],self.mem.memory[5],self.mem.memory[6],self.mem.memory[7]);
}
}
}

@ -0,0 +1,56 @@
mod lib;
use lib::cardiac;
// See lib for in-depth documentation
fn main() {
let program = cardiac::CPU {
mem: cardiac::Memory { memory:
[ //op addr
[0,01], // 0
[0,00], // 1
[0,00], // 2
[0,00], // 3
[0,00], // 4 w DATA 0
[0,01], // 5 x DATA 1
[0,00], // 6 y DATA 0
[0,04], // 7 z DATA 4
[0,00], // 8 UNUSED MEMORY
[0,00], // 9 UNUSED MEMORY
[1,04], // 10 start CLA w
[2,05], // 11 ADD X
[2,06], // 12 ADD y
[2,06], // 13 ADD y
[6,04], // 14 STO w
[1,06], // 15 CLA y
[2,05], // 16 ADD x
[6,06], // 17 STO y
[1,07], // 18 CLA z
[7,00], // 19 SUB 00
[6,07], // 20 STO z
[5,04], // 21 OUT w
[3,24], // 22 TAX exit
[8,10], // 23 JUMP start
[9,00], // 24 HRS 00 exit
[0,00], // 25 UNUSED MEMORY
[0,00], // 26 UNUSED MEMORY
[0,00], // 27 UNUSED MEMORY
[0,00], // 28 UNUSED MEMORY
[0,00], // 29 UNUSED MEMORY
[0,00], // 30 UNUSED MEMORY
[0,00] // 31 UNUSED MEMORY
]
},
acc: cardiac::Accumulator { value: 0 },
pc: cardiac::ProcessCounter { pid: 10}
};
// 13 steps is 1 full cycle
//program.step(14);
program.run();
}
Loading…
Cancel
Save