Skip to content

Commit

Permalink
Merge pull request #1 from CramMK/main
Browse files Browse the repository at this point in the history
Add State Generator
  • Loading branch information
hargoniX authored Nov 28, 2020
2 parents 03a55b4 + 57b4c0e commit 3e0777c
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 15 deletions.
4 changes: 2 additions & 2 deletions src/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashMap;
use std::fmt;

pub struct Program {
data_memory: [u8; 16],
pub data_memory: [u8; 16],
program_memory: [u8; 16],
}

Expand Down Expand Up @@ -82,7 +82,7 @@ pub fn generate_binary(instructions: Vec<Instruction>) -> Program {
}
}

fn insert_label<'a>(hashmap: &mut HashMap<&'a str, u8>, label: &Option<Label<'a>>) {
pub fn insert_label<'a>(hashmap: &mut HashMap<&'a str, u8>, label: &Option<Label<'a>>) {
if let Some(label) = label {
hashmap.insert(label.name, label.location);
}
Expand Down
41 changes: 28 additions & 13 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,41 @@ use pest::Parser;
mod asm;
mod generate;
mod parse;
mod simulate;

use generate::generate_binary;
use parse::{parse_asm, AsmParser};

fn main() {
let file_name = env::args().nth(1);
let sub_cmd = env::args().nth(1);
let file_name = env::args().nth(2);
let steps = env::args().nth(3);

let file_content = match file_name {
Some(file_name) => {
fs::read_to_string(file_name).expect("Could not read the provided asm file")
if let Some(sub_cmd) = sub_cmd {
let file_content = match file_name {
Some(file_name) => {
fs::read_to_string(file_name).expect("Could not read the provided asm file")
}
None => {
println!("No input file was provided");
return;
}
};

let instructions = parse_asm(
AsmParser::parse(parse::Rule::program, &file_content).unwrap_or_else(|e| panic!("{}", e)),
);

if sub_cmd == "generate" {
let binary = generate_binary(instructions);
println!("{}", binary);
}
None => {
println!("No input file was provided");
return;
else if sub_cmd == "simulate" {
if let Some(steps) = steps {
let states = simulate::simulate(instructions, steps.parse::<usize>().unwrap());
println!("{:#?}", states);
}
}
};
}

let instructions = parse_asm(
AsmParser::parse(parse::Rule::program, &file_content).unwrap_or_else(|e| panic!("{}", e)),
);
let binary = generate_binary(instructions);
println!("{}", binary);
}
209 changes: 209 additions & 0 deletions src/simulate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
use crate::generate::insert_label;
use crate::asm::*;
use crate::generate::generate_binary;

use std::collections::HashMap;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct StateRegister {
carry: bool,
zero: bool,
negative: bool
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct OpcodeInfo {
addr: u8,
content: u8
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct State {
step: usize,
clk: bool,
pc: u8,
addr_bus: u8,
data_bus: u8,
ir: u8, // instruction register
dr: u8, // data register
akku: u8,
sr: StateRegister,
opcode_info: Option<OpcodeInfo>
}

pub fn simulate<'a>(instructions: Vec<Instruction<'a>>, max_steps: usize) -> Vec<State> {
let mut data_memory = generate_binary(instructions.clone()).data_memory;

let mut labels: HashMap<&str, u8> = HashMap::new();

let mut states: Vec<State> = Vec::new();
let mut step: usize = 0;
let mut clk: bool = false;
let mut pc: u8 = 0;
let mut addr_bus: u8 = 0;
let mut data_bus: u8 = 0;
let mut ir : u8 = 0;
let mut dr : u8 = 0;
let mut akku : u8 = 0;
let mut sr: StateRegister = StateRegister {
carry: false,
zero: false,
negative: false
};

for instruction in instructions.iter() {
match instruction {
Instruction::NoArgumentInstruction(_, label)
| Instruction::MemoryLocationInstruction(_, label)
| Instruction::ConstantArgumentInstruction(_, label)
| Instruction::ArgumentInstruction(_, label)
| Instruction::Jump(_, label) => {
insert_label(&mut labels, label);
}
}
}

let mut next_pc = 0;
let mut next_akku = 0;
let mut next_data_mem_addr = 0;
let mut next_data_mem_val = 0;
let mut first_iter = true;
loop {
pc = next_pc;
akku = next_akku;
if !first_iter {
data_memory[next_data_mem_addr] = next_data_mem_val;
}
let instruction = instructions[pc as usize];

let binary_instruction: BinaryInstruction = match instruction {
Instruction::NoArgumentInstruction(instruction, _) => instruction.into(),
Instruction::MemoryLocationInstruction(instruction, _) => instruction.into(),
Instruction::ConstantArgumentInstruction(instruction, _) => instruction.into(),
Instruction::ArgumentInstruction(instruction, _) => instruction.into(),
Instruction::Jump(argument, _) => match argument {
JumpArgument::Location(arg) => BinaryInstruction {
opcode: 8,
argument: arg,
},
JumpArgument::Label(arg) => {
if let Some(address) = labels.get(arg) {
BinaryInstruction {
opcode: 8,
argument: *address,
}
} else {
panic!("Tried to JMP to label: {}, which does not exist", arg);
}
}
},
};

clk = false;
addr_bus = pc;
data_bus = data_memory[pc as usize];
let opcode_info = match instruction {
Instruction::MemoryLocationInstruction(instruction, _) => {
match instruction {
MemoryLocationInstruction::STA(location) => Some(OpcodeInfo{addr: location, content: data_memory[location as usize]}),
}
},
Instruction::ArgumentInstruction(instruction, _) => {
match instruction {
ArgumentInstruction::ADD(argument) | ArgumentInstruction::SUB(argument) | ArgumentInstruction::LDA(argument) => match argument {
Argument::MemoryLocation(location) => Some(OpcodeInfo{addr: location, content: data_memory[location as usize]}),
_ => None
}
}
}
_ => None
};
states.push(State{
step,
clk,
pc,
addr_bus,
data_bus,
ir,
dr,
akku,
sr,
opcode_info
});

clk = true;
dr = binary_instruction.argument;
ir = binary_instruction.opcode;

match instruction {
Instruction::NoArgumentInstruction(instruction, _) => match instruction {
NoArgumentInstruction::NOP => {}
},
Instruction::ConstantArgumentInstruction(instruction, _) => match instruction {
ConstantArgumentInstruction::BRC(arg) if sr.carry => next_pc = pc + arg,
ConstantArgumentInstruction::BRN(arg) if sr.negative => next_pc = pc + arg,
ConstantArgumentInstruction::BRZ(arg) if sr.zero => next_pc = pc + arg,
_ => {}
},
Instruction::Jump(arg, _) => match arg {
JumpArgument::Label(label) => {
next_pc = *labels.get(label).unwrap();
addr_bus = next_pc;
},
JumpArgument::Location(location) => {
next_pc = location;
addr_bus = next_pc;
},
},
Instruction::MemoryLocationInstruction(arg, _) => match arg {
MemoryLocationInstruction::STA(arg) => {
next_data_mem_addr = arg as usize;
next_data_mem_val = akku;
}
},
Instruction::ArgumentInstruction(instruction, _) => match instruction {
ArgumentInstruction::LDA(arg) => match arg {
Argument::MemoryLocation(location) => next_akku = data_memory[location as usize],
Argument::Constant(val) => next_akku = val
},
ArgumentInstruction::ADD(arg) => match arg {
Argument::MemoryLocation(location) => next_akku = akku + data_memory[location as usize],
Argument::Constant(val) => next_akku = akku + val
},
ArgumentInstruction::SUB(arg) => match arg {
Argument::MemoryLocation(location) => next_akku = akku - data_memory[location as usize],
Argument::Constant(val) => next_akku = akku - val
}
}
}

if next_pc == pc {
next_pc = pc + 1;
}

states.push(State{
step,
clk,
pc,
addr_bus,
data_bus,
ir,
dr,
akku,
sr,
opcode_info
});

sr.carry = (akku & (1<<4)) != 0;
sr.zero = akku == 0 || akku == (1<<4);
sr.negative = (akku & (1<<3)) != 0;

step += 1;
first_iter = false;
if step == max_steps {
break;
}
}

return states;
}

0 comments on commit 3e0777c

Please sign in to comment.