Add State Generator
This commit is contained in:
@@ -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],
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
45
src/main.rs
45
src/main.rs
@@ -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")
|
||||
}
|
||||
None => {
|
||||
println!("No input file was provided");
|
||||
return;
|
||||
}
|
||||
};
|
||||
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);
|
||||
}
|
||||
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
src/simulate.rs
Normal file
209
src/simulate.rs
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user