From 226a0f1aff6f3559a470aa7b2178202ce687ba15 Mon Sep 17 00:00:00 2001 From: jn Date: Thu, 2 Feb 2023 02:30:36 +0100 Subject: [PATCH 1/7] Use println!("...") instead of print!("...\n") And also use exit without module path. --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index ecbcce4..4b60971 100644 --- a/src/main.rs +++ b/src/main.rs @@ -355,8 +355,8 @@ fn main() { let ast = match parse(&input_file) { Ok(x) => x, Err(x) => { - print!("{:#?}\n", x); - std::process::exit(1); + println!("{:#?}", x); + exit(1); }, }; From b23f2b4315b869dc8dd7a1fb7ed9873885604113 Mon Sep 17 00:00:00 2001 From: jn Date: Thu, 2 Feb 2023 03:05:38 +0100 Subject: [PATCH 2/7] Eliminate non-determinism due to use of HashMap --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4b60971..6a21afa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ extern crate pest_derive; use pest::error::Error; use pest::Parser; use core::panic; -use std::collections::HashMap; +use std::collections::{HashMap, BTreeMap}; use std::env; use std::fs::{canonicalize, read, read_to_string, File}; use std::fmt::Debug; @@ -28,7 +28,7 @@ lazy_static! { static ref SOURCE_PATH: Mutex = Mutex::new(PathBuf::new()); static ref CURRENT_SIZE: Mutex = Mutex::new(Size::Word); static ref CURRENT_CONDITION: Mutex = Mutex::new(Condition::Always); - static ref LABEL_TARGETS: Mutex>> = Mutex::new(HashMap::new()); + static ref LABEL_TARGETS: Mutex>> = Mutex::new(BTreeMap::new()); static ref LABEL_ADDRESSES: Mutex> = Mutex::new(HashMap::new()); static ref RELOC_ADDRESSES: Mutex> = Mutex::new(Vec::new()); } From 7371aed79ff806e5befae323d5c0a9a13a4db31d Mon Sep 17 00:00:00 2001 From: jn Date: Thu, 2 Feb 2023 01:48:55 +0100 Subject: [PATCH 3/7] Allow specifying immediates as target (right-hand side) operands --- src/main.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.rs b/src/main.rs index 6a21afa..7865e46 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1148,6 +1148,7 @@ fn condition_source_destination_to_byte(node: &AstNode) -> u8 { match lhs.as_ref() { AstNode::Register(_) => 0x00, AstNode::RegisterPointer(_) => 0x04, + AstNode::Immediate8(_) | AstNode::Immediate16(_) | AstNode::Immediate32(_) | AstNode::LabelOperand {..} => 0x08, AstNode::ImmediatePointer(_) | AstNode::LabelOperandPointer {..} => 0x0C, _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node), } @@ -1286,6 +1287,9 @@ fn node_to_immediate_values(node: &AstNode, instruction: &AssembledInstruction) AstNode::Register (register) => vec.push(register), AstNode::RegisterPointer(register) => vec.push(register), + AstNode::Immediate8 (immediate) => vec.push(immediate), + AstNode::Immediate16 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), + AstNode::Immediate32 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), AstNode::ImmediatePointer(immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), AstNode::LabelOperand {ref name, ref size, is_relative} => { From fc1008cc10a6cb7db04272596a909cc6b533b2c3 Mon Sep 17 00:00:00 2001 From: jn Date: Thu, 2 Feb 2023 01:49:36 +0100 Subject: [PATCH 4/7] Deduplicate operand to immediate conversion --- src/main.rs | 100 ++++++++++++++++------------------------------------ 1 file changed, 30 insertions(+), 70 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7865e46..49b6695 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1219,91 +1219,51 @@ fn generate_backpatch_immediate(name: &String, size: &Size, instruction: &Assemb targets.push(BackpatchTarget::new(instruction, index, *size, is_relative)); } +fn operand_to_immediate_value(instruction: &AssembledInstruction, node: &AstNode){ + let mut vec = instruction.borrow_mut(); + match *node { + AstNode::Register (register) => vec.push(register), + AstNode::RegisterPointer(register) => vec.push(register), + + AstNode::Immediate8 (immediate) => vec.push(immediate), + AstNode::Immediate16 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), + AstNode::Immediate32 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), + AstNode::ImmediatePointer(immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), + + AstNode::LabelOperand {ref name, ref size, is_relative} => { + std::mem::drop(vec); + generate_backpatch_immediate(name, size, instruction, is_relative); + } + AstNode::LabelOperandPointer {ref name, is_relative} => { + std::mem::drop(vec); + generate_backpatch_immediate(name, &Size::Word, instruction, is_relative); + } + + _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node), + } +} + fn node_to_immediate_values(node: &AstNode, instruction: &AssembledInstruction) { { - let mut vec = instruction.borrow_mut(); - match node { AstNode::OperationZero {..} => {} - AstNode::OperationOne {operand, ..} => { - match *operand.as_ref() { - AstNode::Register (register) => vec.push(register), - AstNode::RegisterPointer(register) => vec.push(register), + AstNode::OperationOne {operand, ..} => + operand_to_immediate_value(instruction, operand.as_ref()), - AstNode::Immediate8 (immediate) => vec.push(immediate), - AstNode::Immediate16 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), - AstNode::Immediate32 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), - AstNode::ImmediatePointer(immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), - - AstNode::LabelOperand {ref name, ref size, is_relative} => { - std::mem::drop(vec); - generate_backpatch_immediate(name, size, instruction, is_relative); - } - AstNode::LabelOperandPointer {ref name, is_relative} => { - std::mem::drop(vec); - generate_backpatch_immediate(name, &Size::Word, instruction, is_relative); - } - - _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node), - } - } - - AstNode::OperationTwo {rhs, ..} => { - match *rhs.as_ref() { - AstNode::Register (register) => vec.push(register), - AstNode::RegisterPointer(register) => vec.push(register), - - AstNode::Immediate8 (immediate) => vec.push(immediate), - AstNode::Immediate16 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), - AstNode::Immediate32 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), - AstNode::ImmediatePointer(immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), - - AstNode::LabelOperand {ref name, ref size, is_relative} => { - std::mem::drop(vec); - generate_backpatch_immediate(name, size, instruction, is_relative); - } - AstNode::LabelOperandPointer {ref name, is_relative} => { - std::mem::drop(vec); - generate_backpatch_immediate(name, &Size::Word, instruction, is_relative); - } - - _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node), - } - } + AstNode::OperationTwo {rhs, ..} => + operand_to_immediate_value(instruction, rhs.as_ref()), _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node), } } - let mut vec = instruction.borrow_mut(); - match node { AstNode::OperationZero {..} => {} AstNode::OperationOne {..} => {} - AstNode::OperationTwo {lhs, ..} => { - match *lhs.as_ref() { - AstNode::Register (register) => vec.push(register), - AstNode::RegisterPointer(register) => vec.push(register), - - AstNode::Immediate8 (immediate) => vec.push(immediate), - AstNode::Immediate16 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), - AstNode::Immediate32 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), - AstNode::ImmediatePointer(immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), - - AstNode::LabelOperand {ref name, ref size, is_relative} => { - std::mem::drop(vec); - generate_backpatch_immediate(name, size, instruction, is_relative); - } - AstNode::LabelOperandPointer {ref name, is_relative} => { - std::mem::drop(vec); - generate_backpatch_immediate(name, &Size::Word, instruction, is_relative); - } - - _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node), - } - } + AstNode::OperationTwo {lhs, ..} => + operand_to_immediate_value(instruction, lhs.as_ref()), _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node), }; From b2212bfa246650680cc89c42847adf2d69993446 Mon Sep 17 00:00:00 2001 From: jn Date: Thu, 2 Feb 2023 02:06:22 +0100 Subject: [PATCH 5/7] Deduplicate condition to bits conversion --- src/main.rs | 48 +++++++++++++++--------------------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/src/main.rs b/src/main.rs index 49b6695..cebb5df 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1118,6 +1118,18 @@ fn instruction_to_byte(node: &AstNode) -> u8 { } } +fn condition_to_bits(condition: &Condition) -> u8 { + match condition { + Condition::Always => 0x00, + Condition::Zero => 0x10, + Condition::NotZero => 0x20, + Condition::Carry => 0x30, + Condition::NotCarry => 0x40, + Condition::GreaterThan => 0x50, + Condition::LessThanEqualTo => 0x60, + } +} + fn condition_source_destination_to_byte(node: &AstNode) -> u8 { let source: u8 = match node { AstNode::OperationZero {..} => 0x00, @@ -1156,39 +1168,9 @@ fn condition_source_destination_to_byte(node: &AstNode) -> u8 { _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node), }; let condition: u8 = match node { - AstNode::OperationZero {condition, ..} => { - match condition { - Condition::Always => 0x00, - Condition::Zero => 0x10, - Condition::NotZero => 0x20, - Condition::Carry => 0x30, - Condition::NotCarry => 0x40, - Condition::GreaterThan => 0x50, - Condition::LessThanEqualTo => 0x60, - } - } - AstNode::OperationOne {condition, ..} => { - match condition { - Condition::Always => 0x00, - Condition::Zero => 0x10, - Condition::NotZero => 0x20, - Condition::Carry => 0x30, - Condition::NotCarry => 0x40, - Condition::GreaterThan => 0x50, - Condition::LessThanEqualTo => 0x60, - } - } - AstNode::OperationTwo {condition, ..} => { - match condition { - Condition::Always => 0x00, - Condition::Zero => 0x10, - Condition::NotZero => 0x20, - Condition::Carry => 0x30, - Condition::NotCarry => 0x40, - Condition::GreaterThan => 0x50, - Condition::LessThanEqualTo => 0x60, - } - } + AstNode::OperationZero {condition, ..} => condition_to_bits(condition), + AstNode::OperationOne {condition, ..} => condition_to_bits(condition), + AstNode::OperationTwo {condition, ..} => condition_to_bits(condition), _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node), }; condition | source | destination From da654a216ba4621144bee1e66de0171d01c97bcb Mon Sep 17 00:00:00 2001 From: jn Date: Thu, 2 Feb 2023 02:10:52 +0100 Subject: [PATCH 6/7] Deduplicate immediate to AstNode conversion --- src/main.rs | 52 ++++++++++++++++------------------------------------ 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/src/main.rs b/src/main.rs index cebb5df..288b24c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -770,6 +770,18 @@ fn remove_underscores(input: &str) -> String { String::from_iter(input.chars().filter(|c| *c != '_')) } +fn immediate_to_astnode(immediate: u32, size: Size, is_pointer: bool) -> AstNode { + if is_pointer { + AstNode::ImmediatePointer(immediate) + } else { + match size { + Size::Byte => AstNode::Immediate8(immediate as u8), + Size::Half => AstNode::Immediate16(immediate as u16), + Size::Word => AstNode::Immediate32(immediate), + } + } +} + fn parse_operand(mut pair: pest::iterators::Pair, is_pointer: bool) -> AstNode { //println!("parse_operand: {:#?}", pair); // debug let size = *CURRENT_SIZE.lock().unwrap(); @@ -785,54 +797,22 @@ fn parse_operand(mut pair: pest::iterators::Pair, is_pointer: bool) -> Ast Rule::immediate_bin => { let body_bin_str = operand_value_pair.into_inner().next().unwrap().as_str(); let immediate = u32::from_str_radix(&remove_underscores(body_bin_str), 2).unwrap(); - if is_pointer { - AstNode::ImmediatePointer(immediate) - } else { - match size { - Size::Byte => AstNode::Immediate8(immediate as u8), - Size::Half => AstNode::Immediate16(immediate as u16), - Size::Word => AstNode::Immediate32(immediate), - } - } + immediate_to_astnode(immediate, size, is_pointer) } Rule::immediate_hex => { let body_hex_str = operand_value_pair.into_inner().next().unwrap().as_str(); let immediate = u32::from_str_radix(&remove_underscores(body_hex_str), 16).unwrap(); - if is_pointer { - AstNode::ImmediatePointer(immediate) - } else { - match size { - Size::Byte => AstNode::Immediate8(immediate as u8), - Size::Half => AstNode::Immediate16(immediate as u16), - Size::Word => AstNode::Immediate32(immediate), - } - } + immediate_to_astnode(immediate, size, is_pointer) } Rule::immediate_dec => { let body_dec_str = operand_value_pair.into_inner().next().unwrap().as_str(); let immediate = remove_underscores(body_dec_str).parse::().unwrap(); - if is_pointer { - AstNode::ImmediatePointer(immediate) - } else { - match size { - Size::Byte => AstNode::Immediate8(immediate as u8), - Size::Half => AstNode::Immediate16(immediate as u16), - Size::Word => AstNode::Immediate32(immediate), - } - } + immediate_to_astnode(immediate, size, is_pointer) } Rule::immediate_char => { let body_char_str = operand_value_pair.into_inner().next().unwrap().as_str(); let immediate = body_char_str.chars().nth(0).unwrap() as u8 as u32; - if is_pointer { - AstNode::ImmediatePointer(immediate) - } else { - match size { - Size::Byte => AstNode::Immediate8(immediate as u8), - Size::Half => AstNode::Immediate16(immediate as u16), - Size::Word => AstNode::Immediate32(immediate), - } - } + immediate_to_astnode(immediate, size, is_pointer) } Rule::register => { let register_num_pair = operand_value_pair.into_inner().next().unwrap(); From bb81c2df697ba18c565e9c04336b07aba2f82df3 Mon Sep 17 00:00:00 2001 From: jn Date: Thu, 2 Feb 2023 02:21:57 +0100 Subject: [PATCH 7/7] Don't pass Size by reference It's a small value type. --- src/main.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index 288b24c..31418ea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -996,7 +996,7 @@ fn assemble_node(node: AstNode) -> AssembledInstruction { // label is used on its own, not as an operand: // LabelOperand was previously only checked as part of operands let instruction = AssembledInstruction::new(); - generate_backpatch_immediate(&name, &size, &instruction, is_relative); + generate_backpatch_immediate(&name, size, &instruction, is_relative); return instruction; }, _ => {} @@ -1024,7 +1024,7 @@ fn assemble_node(node: AstNode) -> AssembledInstruction { // vec // } -fn size_to_byte(size: &Size) -> u8 { +fn size_to_byte(size: Size) -> u8 { match size { Size::Byte => 0b00000000, Size::Half => 0b01000000, @@ -1033,7 +1033,7 @@ fn size_to_byte(size: &Size) -> u8 { } fn instruction_to_byte(node: &AstNode) -> u8 { - match node { + match *node { AstNode::OperationZero {size, instruction, ..} => { match instruction { InstructionZero::Nop => 0x00 | size_to_byte(size), @@ -1156,7 +1156,7 @@ fn condition_source_destination_to_byte(node: &AstNode) -> u8 { condition | source | destination } -fn generate_backpatch_immediate(name: &String, size: &Size, instruction: &AssembledInstruction, is_relative: bool) { +fn generate_backpatch_immediate(name: &String, size: Size, instruction: &AssembledInstruction, is_relative: bool) { let index = instruction.borrow().len(); { let mut vec = instruction.borrow_mut(); @@ -1178,7 +1178,7 @@ fn generate_backpatch_immediate(name: &String, size: &Size, instruction: &Assemb table.get_mut(name).unwrap() } }; - targets.push(BackpatchTarget::new(instruction, index, *size, is_relative)); + targets.push(BackpatchTarget::new(instruction, index, size, is_relative)); } fn operand_to_immediate_value(instruction: &AssembledInstruction, node: &AstNode){ @@ -1192,13 +1192,13 @@ fn operand_to_immediate_value(instruction: &AssembledInstruction, node: &AstNode AstNode::Immediate32 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), AstNode::ImmediatePointer(immediate) => vec.extend_from_slice(&immediate.to_le_bytes()), - AstNode::LabelOperand {ref name, ref size, is_relative} => { + AstNode::LabelOperand {ref name, size, is_relative} => { std::mem::drop(vec); generate_backpatch_immediate(name, size, instruction, is_relative); } AstNode::LabelOperandPointer {ref name, is_relative} => { std::mem::drop(vec); - generate_backpatch_immediate(name, &Size::Word, instruction, is_relative); + generate_backpatch_immediate(name, Size::Word, instruction, is_relative); } _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),