Restructuring into multiple crates and projects
This commit is contained in:
12
hm-asm-simulator/Cargo.toml
Normal file
12
hm-asm-simulator/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "hm-asm-simulator"
|
||||
version = "0.1.0"
|
||||
authors = ["Henrik Boeving <boeving@hm.edu>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
pest = "2.0"
|
||||
pest_derive = "2.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
30
hm-asm-simulator/src/asm.pest
Normal file
30
hm-asm-simulator/src/asm.pest
Normal file
@@ -0,0 +1,30 @@
|
||||
program = _{ SOI ~ "\n"* ~ (stmt ~ "\n"+) * ~ stmt? ~ EOI }
|
||||
|
||||
|
||||
stmt = { ((label ~ ":")? ~ instruction)}
|
||||
|
||||
|
||||
instruction = {
|
||||
no_arg_instruction |
|
||||
arg_instruction ~ argument |
|
||||
jump_instruction ~ jump_argument |
|
||||
memory_location_instruction ~ memory_location |
|
||||
constant_arg_instruction ~ digit_literal
|
||||
}
|
||||
|
||||
memory_location_instruction = {"STA"}
|
||||
constant_arg_instruction = {"BRZ" | "BRC" | "BRN"}
|
||||
jump_instruction = {"JMP"}
|
||||
arg_instruction = {"LDA" | "ADD" | "SUB"}
|
||||
no_arg_instruction = { "NOP" }
|
||||
|
||||
jump_argument = { jump_location | label | memory_location }
|
||||
argument = { memory_location | digit_literal }
|
||||
memory_location = { "(" ~ ASCII_HEX_DIGIT ~")" }
|
||||
digit_literal = {"#" ~ ASCII_HEX_DIGIT}
|
||||
jump_location = { '0'..'9' | 'a'..'f' }
|
||||
|
||||
label = { ASCII_ALPHA_UPPER+ }
|
||||
|
||||
WHITESPACE = _{ " " | "\t" }
|
||||
COMMENT = _{"//" ~ (!"\n" ~ ANY)* }
|
||||
134
hm-asm-simulator/src/asm.rs
Normal file
134
hm-asm-simulator/src/asm.rs
Normal file
@@ -0,0 +1,134 @@
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Argument {
|
||||
MemoryLocation(u8),
|
||||
Constant(u8),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Label<'a> {
|
||||
pub name: &'a str,
|
||||
pub location: u8,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum JumpArgument<'a> {
|
||||
Location(u8),
|
||||
Label(&'a str),
|
||||
MemoryLocation(u8),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Instruction<'a> {
|
||||
NoArgumentInstruction(NoArgumentInstruction, Option<Label<'a>>),
|
||||
MemoryLocationInstruction(MemoryLocationInstruction, Option<Label<'a>>),
|
||||
ConstantArgumentInstruction(ConstantArgumentInstruction, Option<Label<'a>>),
|
||||
ArgumentInstruction(ArgumentInstruction, Option<Label<'a>>),
|
||||
Jump(JumpArgument<'a>, Option<Label<'a>>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum NoArgumentInstruction {
|
||||
NOP,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum MemoryLocationInstruction {
|
||||
STA(u8),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ConstantArgumentInstruction {
|
||||
BRZ(u8),
|
||||
BRC(u8),
|
||||
BRN(u8),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ArgumentInstruction {
|
||||
LDA(Argument),
|
||||
ADD(Argument),
|
||||
SUB(Argument),
|
||||
}
|
||||
|
||||
pub struct BinaryInstruction {
|
||||
pub opcode: u8,
|
||||
pub argument: u8,
|
||||
}
|
||||
|
||||
impl<'a> Into<BinaryInstruction> for NoArgumentInstruction {
|
||||
fn into(self) -> BinaryInstruction {
|
||||
match self {
|
||||
NoArgumentInstruction::NOP => BinaryInstruction {
|
||||
opcode: 0,
|
||||
argument: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Into<BinaryInstruction> for MemoryLocationInstruction {
|
||||
fn into(self) -> BinaryInstruction {
|
||||
match self {
|
||||
MemoryLocationInstruction::STA(arg) => BinaryInstruction {
|
||||
opcode: 3,
|
||||
argument: arg,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Into<BinaryInstruction> for ConstantArgumentInstruction {
|
||||
fn into(self) -> BinaryInstruction {
|
||||
match self {
|
||||
ConstantArgumentInstruction::BRZ(arg) => BinaryInstruction {
|
||||
opcode: 9,
|
||||
argument: arg,
|
||||
},
|
||||
ConstantArgumentInstruction::BRC(arg) => BinaryInstruction {
|
||||
opcode: 10,
|
||||
argument: arg,
|
||||
},
|
||||
ConstantArgumentInstruction::BRN(arg) => BinaryInstruction {
|
||||
opcode: 11,
|
||||
argument: arg,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Into<BinaryInstruction> for ArgumentInstruction {
|
||||
fn into(self) -> BinaryInstruction {
|
||||
match self {
|
||||
ArgumentInstruction::LDA(arg) => match arg {
|
||||
Argument::MemoryLocation(arg) => BinaryInstruction {
|
||||
opcode: 2,
|
||||
argument: arg,
|
||||
},
|
||||
Argument::Constant(arg) => BinaryInstruction {
|
||||
opcode: 1,
|
||||
argument: arg,
|
||||
},
|
||||
},
|
||||
ArgumentInstruction::ADD(arg) => match arg {
|
||||
Argument::MemoryLocation(arg) => BinaryInstruction {
|
||||
opcode: 5,
|
||||
argument: arg,
|
||||
},
|
||||
Argument::Constant(arg) => BinaryInstruction {
|
||||
opcode: 4,
|
||||
argument: arg,
|
||||
},
|
||||
},
|
||||
ArgumentInstruction::SUB(arg) => match arg {
|
||||
Argument::MemoryLocation(arg) => BinaryInstruction {
|
||||
opcode: 7,
|
||||
argument: arg,
|
||||
},
|
||||
Argument::Constant(arg) => BinaryInstruction {
|
||||
opcode: 6,
|
||||
argument: arg,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
98
hm-asm-simulator/src/generate.rs
Normal file
98
hm-asm-simulator/src/generate.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
use crate::asm::*;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Program {
|
||||
pub data_memory: [u8; 16],
|
||||
pub program_memory: [u8; 16],
|
||||
}
|
||||
|
||||
impl fmt::Display for Program {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(f, "Data Memory:")?;
|
||||
for chunk in self.data_memory.chunks(4) {
|
||||
writeln!(
|
||||
f,
|
||||
"{:x} {:x} {:x} {:x}",
|
||||
chunk[0], chunk[1], chunk[2], chunk[3]
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(f, "Program Memory:")?;
|
||||
for chunk in self.program_memory.chunks(4) {
|
||||
writeln!(
|
||||
f,
|
||||
"{:x} {:x} {:x} {:x}",
|
||||
chunk[0], chunk[1], chunk[2], chunk[3]
|
||||
)?;
|
||||
}
|
||||
writeln!(f, "And that's your program!")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_binary(instructions: Vec<Instruction>) -> Program {
|
||||
let mut labels: HashMap<&str, u8> = HashMap::new();
|
||||
let mut data_memory: [u8; 16] = [0; 16];
|
||||
let mut program_memory: [u8; 16] = [0; 16];
|
||||
|
||||
// collect all labels
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (c, instruction) in instructions.iter().enumerate() {
|
||||
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
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
program_memory[c] = binary_instruction.opcode;
|
||||
data_memory[c] = binary_instruction.argument;
|
||||
}
|
||||
|
||||
Program {
|
||||
data_memory,
|
||||
program_memory,
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
7
hm-asm-simulator/src/lib.rs
Normal file
7
hm-asm-simulator/src/lib.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
#[macro_use]
|
||||
extern crate pest_derive;
|
||||
|
||||
pub mod generate;
|
||||
pub mod asm;
|
||||
pub mod parse;
|
||||
pub mod simulate;
|
||||
180
hm-asm-simulator/src/parse.rs
Normal file
180
hm-asm-simulator/src/parse.rs
Normal file
@@ -0,0 +1,180 @@
|
||||
use crate::asm::*;
|
||||
use pest::iterators::{Pair, Pairs};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[grammar = "asm.pest"]
|
||||
pub struct AsmParser;
|
||||
|
||||
pub fn parse_asm<'a>(pairs: Pairs<'a, Rule>) -> Vec<Instruction<'a>> {
|
||||
let mut instruction = Vec::new();
|
||||
let mut instruction_counter = 0;
|
||||
for stmnt in pairs {
|
||||
if let Rule::stmt = stmnt.as_rule() {
|
||||
let mut stmnt = stmnt.into_inner();
|
||||
let first = stmnt.next();
|
||||
let second = stmnt.next();
|
||||
|
||||
// Second can only be Some if we have a label, thus second must be the
|
||||
// instruction if that is the case.
|
||||
if second.is_some() {
|
||||
instruction.push(parse_instruction(
|
||||
second.unwrap(),
|
||||
first,
|
||||
instruction_counter,
|
||||
));
|
||||
} else {
|
||||
instruction.push(parse_instruction(first.unwrap(), None, instruction_counter));
|
||||
}
|
||||
|
||||
instruction_counter += 1;
|
||||
}
|
||||
|
||||
if instruction_counter > 16 {
|
||||
panic!("This program contains more than 16 instructions, that is impossible on this processor");
|
||||
}
|
||||
}
|
||||
instruction
|
||||
}
|
||||
|
||||
fn parse_instruction<'a>(
|
||||
instruction: Pair<'a, Rule>,
|
||||
label: Option<Pair<'a, Rule>>,
|
||||
instruction_counter: u8,
|
||||
) -> Instruction<'a> {
|
||||
let label = label.map(|l| parse_label(l, instruction_counter));
|
||||
let mut instruction = instruction.into_inner();
|
||||
let mnemonic = instruction.next().unwrap();
|
||||
|
||||
match mnemonic.as_rule() {
|
||||
Rule::no_arg_instruction => parse_no_arg_instruction(mnemonic, label),
|
||||
Rule::arg_instruction => {
|
||||
parse_arg_instruction(mnemonic, instruction.next().unwrap(), label)
|
||||
}
|
||||
Rule::jump_instruction => {
|
||||
parse_jump_instruction(mnemonic, instruction.next().unwrap(), label)
|
||||
}
|
||||
Rule::memory_location_instruction => {
|
||||
parse_memory_location_instruction(mnemonic, instruction.next().unwrap(), label)
|
||||
}
|
||||
Rule::constant_arg_instruction => {
|
||||
parse_constant_arg_instruction(mnemonic, instruction.next().unwrap(), label)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_no_arg_instruction<'a>(
|
||||
instruction: Pair<'a, Rule>,
|
||||
label: Option<Label<'a>>,
|
||||
) -> Instruction<'a> {
|
||||
match instruction.as_str() {
|
||||
"NOP" => Instruction::NoArgumentInstruction(NoArgumentInstruction::NOP, label),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_arg_instruction<'a>(
|
||||
instruction: Pair<'a, Rule>,
|
||||
arg: Pair<'a, Rule>,
|
||||
label: Option<Label<'a>>,
|
||||
) -> Instruction<'a> {
|
||||
let arg = parse_argument(arg);
|
||||
match instruction.as_str() {
|
||||
"LDA" => Instruction::ArgumentInstruction(ArgumentInstruction::LDA(arg), label),
|
||||
"ADD" => Instruction::ArgumentInstruction(ArgumentInstruction::ADD(arg), label),
|
||||
"SUB" => Instruction::ArgumentInstruction(ArgumentInstruction::SUB(arg), label),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_jump_instruction<'a>(
|
||||
instruction: Pair<'a, Rule>,
|
||||
arg: Pair<'a, Rule>,
|
||||
label: Option<Label<'a>>,
|
||||
) -> Instruction<'a> {
|
||||
let arg = parse_jump_argument(arg);
|
||||
match instruction.as_str() {
|
||||
"JMP" => Instruction::Jump(arg, label),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_memory_location_instruction<'a>(
|
||||
instruction: Pair<'a, Rule>,
|
||||
arg: Pair<'a, Rule>,
|
||||
label: Option<Label<'a>>,
|
||||
) -> Instruction<'a> {
|
||||
let arg_string = arg.as_str();
|
||||
let arg_value = u8::from_str_radix(&arg_string[1..arg_string.len() - 1], 16).unwrap();
|
||||
match instruction.as_str() {
|
||||
"STA" => {
|
||||
Instruction::MemoryLocationInstruction(MemoryLocationInstruction::STA(arg_value), label)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_constant_arg_instruction<'a>(
|
||||
instruction: Pair<'a, Rule>,
|
||||
arg: Pair<'a, Rule>,
|
||||
label: Option<Label<'a>>,
|
||||
) -> Instruction<'a> {
|
||||
let arg_value = u8::from_str_radix(&arg.as_str()[1..], 16).unwrap();
|
||||
match instruction.as_str() {
|
||||
"BRZ" => Instruction::ConstantArgumentInstruction(
|
||||
ConstantArgumentInstruction::BRZ(arg_value),
|
||||
label,
|
||||
),
|
||||
"BRC" => Instruction::ConstantArgumentInstruction(
|
||||
ConstantArgumentInstruction::BRC(arg_value),
|
||||
label,
|
||||
),
|
||||
"BRN" => Instruction::ConstantArgumentInstruction(
|
||||
ConstantArgumentInstruction::BRN(arg_value),
|
||||
label,
|
||||
),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_argument<'a>(argument: Pair<'a, Rule>) -> Argument {
|
||||
let argument = argument.into_inner().next().unwrap();
|
||||
match argument.as_rule() {
|
||||
Rule::memory_location => {
|
||||
let arg_string = argument.as_str();
|
||||
let arg_value = u8::from_str_radix(&arg_string[1..arg_string.len() - 1], 16).unwrap();
|
||||
Argument::MemoryLocation(arg_value)
|
||||
}
|
||||
Rule::digit_literal => {
|
||||
let arg_value = u8::from_str_radix(&argument.as_str()[1..], 16).unwrap();
|
||||
Argument::Constant(arg_value)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_label<'a>(label: Pair<'a, Rule>, instruction_counter: u8) -> Label<'a> {
|
||||
match label.as_rule() {
|
||||
Rule::label => Label {
|
||||
name: label.as_str(),
|
||||
location: instruction_counter,
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_jump_argument<'a>(arg: Pair<'a, Rule>) -> JumpArgument<'a> {
|
||||
let arg = arg.into_inner().next().unwrap();
|
||||
match arg.as_rule() {
|
||||
Rule::label => JumpArgument::Label(arg.as_str()),
|
||||
Rule::jump_location => {
|
||||
JumpArgument::Location(u8::from_str_radix(arg.as_str(), 16).unwrap())
|
||||
},
|
||||
Rule::memory_location => {
|
||||
let arg_string = arg.as_str();
|
||||
let arg_value = u8::from_str_radix(&arg_string[1..arg_string.len() - 1], 16).unwrap();
|
||||
JumpArgument::MemoryLocation(arg_value)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
275
hm-asm-simulator/src/simulate.rs
Normal file
275
hm-asm-simulator/src/simulate.rs
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user