From 03a55b4d85b64b6b666ec5687f04d602d002681a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20B=C3=B6ving?= Date: Sat, 28 Nov 2020 18:55:14 +0100 Subject: [PATCH] binary ggeneration as well --- examples/add_number.asm | 3 ++ src/asm.rs | 83 ++++++++++++++++++++++++++++++++++++++ src/generate.rs | 88 +++++++++++++++++++++++++++++++++++++++++ src/main.rs | 4 +- 4 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 examples/add_number.asm diff --git a/examples/add_number.asm b/examples/add_number.asm new file mode 100644 index 0000000..8423db8 --- /dev/null +++ b/examples/add_number.asm @@ -0,0 +1,3 @@ +LDA #1 +ADD #3 +STA (8) diff --git a/src/asm.rs b/src/asm.rs index 4f6cf56..ecda5ce 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -48,3 +48,86 @@ pub enum ArgumentInstruction { ADD(Argument), SUB(Argument), } + +pub struct BinaryInstruction { + pub opcode: u8, + pub argument: u8, +} + +impl<'a> Into for NoArgumentInstruction { + fn into(self) -> BinaryInstruction { + match self { + NoArgumentInstruction::NOP => BinaryInstruction { + opcode: 0, + argument: 0, + }, + } + } +} + +impl<'a> Into for MemoryLocationInstruction { + fn into(self) -> BinaryInstruction { + match self { + MemoryLocationInstruction::STA(arg) => BinaryInstruction { + opcode: 3, + argument: arg, + }, + } + } +} + +impl<'a> Into 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 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, + }, + }, + } + } +} diff --git a/src/generate.rs b/src/generate.rs index 8b13789..2e54049 100644 --- a/src/generate.rs +++ b/src/generate.rs @@ -1 +1,89 @@ +use crate::asm::*; +use std::collections::HashMap; +use std::fmt; +pub struct Program { + data_memory: [u8; 16], + 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) -> 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); + } + } + }, + }; + + program_memory[c] = binary_instruction.opcode; + data_memory[c] = binary_instruction.argument; + } + + Program { + data_memory, + program_memory, + } +} + +fn insert_label<'a>(hashmap: &mut HashMap<&'a str, u8>, label: &Option>) { + if let Some(label) = label { + hashmap.insert(label.name, label.location); + } +} diff --git a/src/main.rs b/src/main.rs index c38b89f..79e7de6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ mod asm; mod generate; mod parse; +use generate::generate_binary; use parse::{parse_asm, AsmParser}; fn main() { @@ -28,5 +29,6 @@ fn main() { let instructions = parse_asm( AsmParser::parse(parse::Rule::program, &file_content).unwrap_or_else(|e| panic!("{}", e)), ); - println!("{:#?}", instructions); + let binary = generate_binary(instructions); + println!("{}", binary); }