Restructuring into multiple crates and projects

This commit is contained in:
Henrik Böving
2021-03-05 19:10:18 +01:00
parent 00d0d7aba3
commit d67eda2edc
26 changed files with 6467 additions and 76 deletions

View File

@@ -0,0 +1,275 @@
use crate::generate::insert_label;
use crate::asm::*;
use crate::generate::generate_binary;
use std::collections::HashMap;
use std::fmt;
use serde::Serialize;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize)]
pub struct StateRegister {
pub carry: bool,
pub zero: bool,
pub negative: bool
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize)]
pub struct OpcodeInfo {
pub addr: u8,
pub content: u8
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize)]
pub struct State {
pub step: usize,
pub clk: bool,
pub pc: u8,
pub addr_bus: u8,
pub data_bus: u8,
pub ir: u8, // instruction register
pub dr: u8, // data register
pub akku: u8,
pub sr: StateRegister,
pub opcode_info: Option<OpcodeInfo>
}
impl fmt::Display for State {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "<tr>")?;
writeln!(f, "<td style=\"border: 1px solid #000000; padding: 0mm 1.91mm;\">{}</td>", self.step)?;
writeln!(f, "<td style=\"border: 1px solid #000000; padding: 0mm 1.91mm;\">{}</td>", self.clk as u8)?;
writeln!(f, "<td style=\"border: 1px solid #000000; padding: 0mm 1.91mm;\">{}</td>", self.pc)?;
writeln!(f, "<td style=\"border: 1px solid #000000; padding: 0mm 1.91mm;\">{}</td>", self.addr_bus)?;
writeln!(f, "<td style=\"border: 1px solid #000000; padding: 0mm 1.91mm;\">{}</td>", self.data_bus)?;
writeln!(f, "<td style=\"border: 1px solid #000000; padding: 0mm 1.91mm;\">{}</td>", self.ir)?;
writeln!(f, "<td style=\"border: 1px solid #000000; padding: 0mm 1.91mm;\">{}</td>", self.dr)?;
writeln!(f, "<td style=\"border: 1px solid #000000; padding: 0mm 1.91mm;\">{}</td>", self.akku)?;
writeln!(f, "<td style=\"border: 1px solid #000000; padding: 0mm 1.91mm;\">C: {}, Z: {}, N: {}</td>", self.sr.carry as u8, self.sr.zero as u8, self.sr.negative as u8)?;
if let Some(opcode_info) = self.opcode_info {
writeln!(f, "<td style=\"border: 1px solid #000000; padding: 0mm 1.91mm;\">addr: {}, val: {}</td>", opcode_info.addr, opcode_info.content)?;
} else {
writeln!(f, "<td style=\"border: 1px solid #000000; padding: 0mm 1.91mm;\"></td>")?;
}
writeln!(f, "</tr>")
}
}
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;
let mut pc: u8 = 0;
let mut addr_bus: u8;
let mut data_bus: u8;
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: Option<u8> = None;
let mut next_akku = 0;
let mut next_carry = false;
let mut next_data_mem_addr: Option<usize> = None;
let mut next_data_mem_val: Option<u8> = None;
loop {
if next_akku != akku {
next_carry = (next_akku & (1<<4)) != 0;
}
if let Some(mut next_pc_value) = next_pc {
next_pc_value = next_pc_value % 16;
next_akku = next_akku % 16;
pc = next_pc_value;
next_pc = None;
}
akku = next_akku;
if let Some(addr) = next_data_mem_addr {
data_memory[addr] = next_data_mem_val.unwrap();
next_data_mem_addr = None;
next_data_mem_val = None;
}
let instruction = if pc as usize > instructions.len() - 1 {
Instruction::NoArgumentInstruction(NoArgumentInstruction::NOP, None)
} else {
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);
}
},
JumpArgument::MemoryLocation(address) => {
BinaryInstruction {
opcode: 12,
argument: address
}
}
},
};
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
}
}
},
Instruction::Jump(JumpArgument::MemoryLocation(location), _) => {
Some(OpcodeInfo{
addr: location,
content: data_memory[location as usize]
})
}
_ => None
};
states.push(State{
step,
clk,
pc,
addr_bus,
data_bus,
ir,
dr,
akku,
sr,
opcode_info
});
clk = true;
sr.carry = next_carry;
sr.zero = akku == 0 || akku == (1<<4);
sr.negative = (akku & (1<<3)) != 0;
dr = binary_instruction.argument;
ir = binary_instruction.opcode;
addr_bus = dr;
match instruction {
Instruction::NoArgumentInstruction(instruction, _) => match instruction {
NoArgumentInstruction::NOP => {}
},
Instruction::ConstantArgumentInstruction(instruction, _) => match instruction {
ConstantArgumentInstruction::BRC(arg) if sr.carry => next_pc = Some(pc + arg),
ConstantArgumentInstruction::BRN(arg) if sr.negative => next_pc = Some(pc + arg),
ConstantArgumentInstruction::BRZ(arg) if sr.zero => next_pc = Some(pc + arg),
_ => {}
},
Instruction::Jump(arg, _) => match arg {
JumpArgument::Label(label) => {
next_pc = Some(*labels.get(label).unwrap());
addr_bus = *labels.get(label).unwrap();
},
JumpArgument::Location(location) => {
next_pc = Some(location);
addr_bus = location;
},
JumpArgument::MemoryLocation(location) => {
next_pc = Some(data_memory[location as usize]);
addr_bus = data_memory[location as usize];
}
},
Instruction::MemoryLocationInstruction(arg, _) => match arg {
MemoryLocationInstruction::STA(arg) => {
next_data_mem_addr = Some(arg as usize);
next_data_mem_val = Some(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] ^ 0b1111) + 1,
Argument::Constant(val) => next_akku = akku + (val ^ 0b1111) + 1
}
}
}
data_bus = data_memory[addr_bus as usize];
if let None = next_pc {
next_pc = Some(pc + 1);
}
states.push(State{
step,
clk,
pc,
addr_bus,
data_bus,
ir,
dr,
akku,
sr,
opcode_info
});
step += 1;
if step == max_steps {
break;
}
}
return states;
}