add support for optional optimization, shorter bit operations and register pointer offsets
This commit is contained in:
parent
36a8432411
commit
4647b9fe63
|
@ -2,7 +2,7 @@ WHITESPACE = _{ " " | "\t" | "\n" | "\r" | "\x0B" | "\x0C" | "\xA0" | SPACE_SEPA
|
||||||
COMMENT = _{ ";" ~ (!"\n" ~ ANY)* }
|
COMMENT = _{ ";" ~ (!"\n" ~ ANY)* }
|
||||||
|
|
||||||
assembly = {
|
assembly = {
|
||||||
SOI ~ (origin | include_bin_optional | include_bin | data | constant | label | instruction)* ~ EOI
|
SOI ~ (origin | include_bin_optional | include_bin | data | constant | label | instruction | opt)* ~ EOI
|
||||||
}
|
}
|
||||||
|
|
||||||
origin = {
|
origin = {
|
||||||
|
@ -12,6 +12,13 @@ origin = {
|
||||||
origin_padding = { "org.pad" ~ operand_value }
|
origin_padding = { "org.pad" ~ operand_value }
|
||||||
origin_no_padding = { "org" ~ operand_value }
|
origin_no_padding = { "org" ~ operand_value }
|
||||||
|
|
||||||
|
opton = { "opton" }
|
||||||
|
optoff = { "optoff" }
|
||||||
|
opt = {
|
||||||
|
opton |
|
||||||
|
optoff
|
||||||
|
}
|
||||||
|
|
||||||
include_bin = { "#include_bin" ~ immediate_str }
|
include_bin = { "#include_bin" ~ immediate_str }
|
||||||
include_bin_optional = { "#include_bin_optional" ~ immediate_str }
|
include_bin_optional = { "#include_bin_optional" ~ immediate_str }
|
||||||
|
|
||||||
|
@ -48,7 +55,9 @@ operand = {
|
||||||
operand_value
|
operand_value
|
||||||
}
|
}
|
||||||
operand_value_ptr = {
|
operand_value_ptr = {
|
||||||
|
register ~ "+" ~ operand_value |
|
||||||
operand_value
|
operand_value
|
||||||
|
|
||||||
}
|
}
|
||||||
operand_value = {
|
operand_value = {
|
||||||
register |
|
register |
|
||||||
|
|
347
src/main.rs
347
src/main.rs
|
@ -247,32 +247,41 @@ enum LabelKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
enum AstNode {
|
struct OperationZero {
|
||||||
OperationZero {
|
|
||||||
size: Size,
|
size: Size,
|
||||||
condition: Condition,
|
condition: Condition,
|
||||||
instruction: InstructionZero,
|
instruction: InstructionZero,
|
||||||
},
|
}
|
||||||
OperationOne {
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
struct OperationOne {
|
||||||
size: Size,
|
size: Size,
|
||||||
condition: Condition,
|
condition: Condition,
|
||||||
instruction: InstructionOne,
|
instruction: InstructionOne,
|
||||||
operand: Box<AstNode>,
|
operand: Box<AstNode>,
|
||||||
},
|
}
|
||||||
OperationIncDec {
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
struct OperationIncDec {
|
||||||
size: Size,
|
size: Size,
|
||||||
condition: Condition,
|
condition: Condition,
|
||||||
instruction: InstructionIncDec,
|
instruction: InstructionIncDec,
|
||||||
lhs: Box<AstNode>,
|
lhs: Box<AstNode>,
|
||||||
rhs: Box<AstNode>,
|
rhs: Box<AstNode>,
|
||||||
},
|
}
|
||||||
OperationTwo {
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
struct OperationTwo {
|
||||||
size: Size,
|
size: Size,
|
||||||
condition: Condition,
|
condition: Condition,
|
||||||
instruction: InstructionTwo,
|
instruction: InstructionTwo,
|
||||||
lhs: Box<AstNode>,
|
lhs: Box<AstNode>,
|
||||||
rhs: Box<AstNode>,
|
rhs: Box<AstNode>,
|
||||||
},
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
enum AstNode {
|
||||||
|
OperationZero(OperationZero) ,
|
||||||
|
OperationOne (OperationOne),
|
||||||
|
OperationIncDec(OperationIncDec) ,
|
||||||
|
OperationTwo (OperationTwo),
|
||||||
|
|
||||||
Immediate8(u8),
|
Immediate8(u8),
|
||||||
Immediate16(u16),
|
Immediate16(u16),
|
||||||
|
@ -280,6 +289,7 @@ enum AstNode {
|
||||||
Register(u8),
|
Register(u8),
|
||||||
ImmediatePointer(u32),
|
ImmediatePointer(u32),
|
||||||
RegisterPointer(u8),
|
RegisterPointer(u8),
|
||||||
|
RegisterPointerOffset(u8, u8),
|
||||||
|
|
||||||
Constant {
|
Constant {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -314,6 +324,7 @@ enum AstNode {
|
||||||
|
|
||||||
Origin(u32),
|
Origin(u32),
|
||||||
OriginPadded(u32),
|
OriginPadded(u32),
|
||||||
|
Optimize(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_address_table(m: &HashMap<String, (u32, bool)>) -> String {
|
fn format_address_table(m: &HashMap<String, (u32, bool)>) -> String {
|
||||||
|
@ -364,7 +375,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Parsing file...");
|
println!("Parsing file...");
|
||||||
let ast = match parse(&input_file) {
|
let mut ast = match parse(&input_file) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(x) => {
|
Err(x) => {
|
||||||
println!("{:#?}", x);
|
println!("{:#?}", x);
|
||||||
|
@ -376,7 +387,9 @@ fn main() {
|
||||||
let mut current_address: u32 = 0;
|
let mut current_address: u32 = 0;
|
||||||
|
|
||||||
println!("Assembling...");
|
println!("Assembling...");
|
||||||
for node in ast {
|
let mut optimize = false;
|
||||||
|
for mut node in ast {
|
||||||
|
node = optimize_node(node, &mut optimize);
|
||||||
if let AstNode::LabelDefine {name, ..} = node {
|
if let AstNode::LabelDefine {name, ..} = node {
|
||||||
let mut address_table = LABEL_ADDRESSES.lock().unwrap();
|
let mut address_table = LABEL_ADDRESSES.lock().unwrap();
|
||||||
if let Some(_) = address_table.get(&name) {
|
if let Some(_) = address_table.get(&name) {
|
||||||
|
@ -404,6 +417,8 @@ fn main() {
|
||||||
} else if let AstNode::IncludedBinary(binary_vec) = node {
|
} else if let AstNode::IncludedBinary(binary_vec) = node {
|
||||||
current_address += binary_vec.len() as u32;
|
current_address += binary_vec.len() as u32;
|
||||||
instructions.push(binary_vec.into());
|
instructions.push(binary_vec.into());
|
||||||
|
} else if let AstNode::Optimize(_) = node {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
let instruction = assemble_node(node);
|
let instruction = assemble_node(node);
|
||||||
instruction.set_address(current_address);
|
instruction.set_address(current_address);
|
||||||
|
@ -563,7 +578,6 @@ fn parse(source: &str) -> Result<Vec<AstNode>, Error<Rule>> {
|
||||||
|
|
||||||
fn build_ast_from_expression(pair: pest::iterators::Pair<Rule>) -> AstNode {
|
fn build_ast_from_expression(pair: pest::iterators::Pair<Rule>) -> AstNode {
|
||||||
//println!("{:#?}\n\n", pair); // debug
|
//println!("{:#?}\n\n", pair); // debug
|
||||||
|
|
||||||
let pair_rule = pair.as_rule();
|
let pair_rule = pair.as_rule();
|
||||||
let mut inner_pair = pair.into_inner();
|
let mut inner_pair = pair.into_inner();
|
||||||
*CURRENT_CONDITION.lock().unwrap() = Condition::Always;
|
*CURRENT_CONDITION.lock().unwrap() = Condition::Always;
|
||||||
|
@ -586,6 +600,7 @@ fn build_ast_from_expression(pair: pest::iterators::Pair<Rule>) -> AstNode {
|
||||||
Rule::constant => parse_constant(inner_pair),
|
Rule::constant => parse_constant(inner_pair),
|
||||||
Rule::label => parse_label(inner_pair.next().unwrap(), inner_pair.next()),
|
Rule::label => parse_label(inner_pair.next().unwrap(), inner_pair.next()),
|
||||||
Rule::data => parse_data(inner_pair.next().unwrap()),
|
Rule::data => parse_data(inner_pair.next().unwrap()),
|
||||||
|
Rule::opt => parse_opt(inner_pair.next().unwrap()),
|
||||||
Rule::origin => parse_origin(inner_pair.next().unwrap()),
|
Rule::origin => parse_origin(inner_pair.next().unwrap()),
|
||||||
Rule::include_bin => include_binary_file(inner_pair.next().unwrap(), false),
|
Rule::include_bin => include_binary_file(inner_pair.next().unwrap(), false),
|
||||||
Rule::include_bin_optional => include_binary_file(inner_pair.next().unwrap(), true),
|
Rule::include_bin_optional => include_binary_file(inner_pair.next().unwrap(), true),
|
||||||
|
@ -686,7 +701,13 @@ fn parse_data(pair: pest::iterators::Pair<Rule>) -> AstNode {
|
||||||
_ => panic!("Unsupported data: {}", pair.as_str()),
|
_ => panic!("Unsupported data: {}", pair.as_str()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn parse_opt(rule: pest::iterators::Pair<Rule>) -> AstNode {
|
||||||
|
match rule.as_str() {
|
||||||
|
"opton"=>AstNode::Optimize(true),
|
||||||
|
"optoff"=>AstNode::Optimize(false),
|
||||||
|
_ => panic!("Unknown optimize flag {}", rule.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
fn parse_origin(pair: pest::iterators::Pair<Rule>) -> AstNode {
|
fn parse_origin(pair: pest::iterators::Pair<Rule>) -> AstNode {
|
||||||
//println!("{:#?}", pair);
|
//println!("{:#?}", pair);
|
||||||
match pair.as_rule() {
|
match pair.as_rule() {
|
||||||
|
@ -825,45 +846,67 @@ fn immediate_to_astnode(immediate: u32, size: Size, is_pointer: bool) -> AstNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_operand(mut pair: pest::iterators::Pair<Rule>, is_pointer: bool) -> AstNode {
|
fn parse_immediate(pair: pest::iterators::Pair<Rule>) -> u32 {
|
||||||
//println!("parse_operand: {:#?}", pair); // debug
|
|
||||||
let size = *CURRENT_SIZE.lock().unwrap();
|
|
||||||
if is_pointer {
|
|
||||||
// skip past the operand_value_ptr pair and look at its operand_value rule
|
|
||||||
pair = pair.into_inner().next().unwrap();
|
|
||||||
}
|
|
||||||
match pair.as_rule() {
|
match pair.as_rule() {
|
||||||
Rule::operand_value => {
|
|
||||||
let mut inner_pair = pair.into_inner();
|
|
||||||
let operand_value_pair = inner_pair.next().unwrap();
|
|
||||||
match operand_value_pair.as_rule() {
|
|
||||||
Rule::immediate_bin => {
|
Rule::immediate_bin => {
|
||||||
let body_bin_str = operand_value_pair.into_inner().next().unwrap().as_str();
|
let body_bin_str = pair.into_inner().next().unwrap().as_str();
|
||||||
let immediate = u32::from_str_radix(&remove_underscores(body_bin_str), 2).unwrap();
|
u32::from_str_radix(&remove_underscores(body_bin_str), 2).unwrap()
|
||||||
immediate_to_astnode(immediate, size, is_pointer)
|
|
||||||
}
|
}
|
||||||
Rule::immediate_hex => {
|
Rule::immediate_hex => {
|
||||||
let body_hex_str = operand_value_pair.into_inner().next().unwrap().as_str();
|
let body_hex_str = pair.into_inner().next().unwrap().as_str();
|
||||||
let immediate = u32::from_str_radix(&remove_underscores(body_hex_str), 16).unwrap();
|
u32::from_str_radix(&remove_underscores(body_hex_str), 16).unwrap()
|
||||||
immediate_to_astnode(immediate, size, is_pointer)
|
|
||||||
}
|
}
|
||||||
Rule::immediate_dec => {
|
Rule::immediate_dec => {
|
||||||
let dec_str = operand_value_pair.as_span().as_str();
|
let dec_str = pair.as_span().as_str();
|
||||||
let immediate = remove_underscores(dec_str).parse::<u32>().unwrap();
|
remove_underscores(dec_str).parse::<u32>().unwrap()
|
||||||
immediate_to_astnode(immediate, size, is_pointer)
|
|
||||||
}
|
}
|
||||||
Rule::immediate_char => {
|
Rule::immediate_char => {
|
||||||
let body_char_str = operand_value_pair.into_inner().next().unwrap().as_str();
|
let body_char_str = pair.into_inner().next().unwrap().as_str();
|
||||||
let immediate = body_char_str.chars().nth(0).unwrap() as u8 as u32;
|
body_char_str.chars().nth(0).unwrap() as u8 as u32
|
||||||
immediate_to_astnode(immediate, size, is_pointer)
|
|
||||||
}
|
}
|
||||||
Rule::register => {
|
_=> {
|
||||||
let register_num_pair = operand_value_pair.into_inner().next().unwrap();
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_register(pair: pest::iterators::Pair<Rule>) -> u8 {
|
||||||
|
let register_num_pair = pair.into_inner().next().unwrap();
|
||||||
let register_num = if register_num_pair.as_str() == "sp" { 32 }
|
let register_num = if register_num_pair.as_str() == "sp" { 32 }
|
||||||
else if register_num_pair.as_str() == "esp" { 33 }
|
else if register_num_pair.as_str() == "esp" { 33 }
|
||||||
else if register_num_pair.as_str() == "fp" { 34 }
|
else if register_num_pair.as_str() == "fp" { 34 }
|
||||||
else { register_num_pair.as_str().parse::<u8>().unwrap() };
|
else { register_num_pair.as_str().parse::<u8>().unwrap() };
|
||||||
if register_num > 34 { panic!("register number out of range"); }
|
if register_num > 34 { panic!("register number out of range"); }
|
||||||
|
register_num
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_operand(mut pair: pest::iterators::Pair<Rule>, is_pointer: bool) -> AstNode {
|
||||||
|
//println!("parse_operand: {:#?}", pair); // debug
|
||||||
|
// dbg!(&pair);
|
||||||
|
let size = *CURRENT_SIZE.lock().unwrap();
|
||||||
|
let pointer_offset =
|
||||||
|
if is_pointer {
|
||||||
|
// skip past the operand_value_ptr pair and look at its operand_value rule
|
||||||
|
let mut pairs = pair.into_inner();
|
||||||
|
pair = pairs.next().unwrap();
|
||||||
|
pairs.next()
|
||||||
|
// pair = pair.into_inner().next().unwrap();
|
||||||
|
}else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
match pair.as_rule() {
|
||||||
|
Rule::operand_value => {
|
||||||
|
let mut inner_pair = pair.into_inner();
|
||||||
|
let operand_value_pair = inner_pair.next().unwrap();
|
||||||
|
match operand_value_pair.as_rule() {
|
||||||
|
Rule::immediate_bin|
|
||||||
|
Rule::immediate_char|
|
||||||
|
Rule::immediate_dec|
|
||||||
|
Rule::immediate_hex => {
|
||||||
|
immediate_to_astnode(parse_immediate(operand_value_pair), size, is_pointer)
|
||||||
|
}
|
||||||
|
Rule::register => {
|
||||||
|
let register_num = parse_register(operand_value_pair);
|
||||||
if is_pointer {
|
if is_pointer {
|
||||||
AstNode::RegisterPointer(register_num)
|
AstNode::RegisterPointer(register_num)
|
||||||
} else {
|
} else {
|
||||||
|
@ -887,12 +930,25 @@ fn parse_operand(mut pair: pest::iterators::Pair<Rule>, is_pointer: bool) -> Ast
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Rule::register => {
|
||||||
|
let register_num = parse_register(pair);
|
||||||
|
let offset = if let Some(offset_pair) = pointer_offset {
|
||||||
|
parse_immediate(offset_pair.into_inner().next().unwrap())
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
if offset == 0 {
|
||||||
|
AstNode::RegisterPointer(register_num)
|
||||||
|
} else {
|
||||||
|
AstNode::RegisterPointerOffset(register_num, offset as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_instruction_zero(pair: pest::iterators::Pair<Rule>, size: Size, condition: Condition) -> AstNode {
|
fn parse_instruction_zero(pair: pest::iterators::Pair<Rule>, size: Size, condition: Condition) -> AstNode {
|
||||||
AstNode::OperationZero {
|
AstNode::OperationZero ( OperationZero {
|
||||||
size: size,
|
size: size,
|
||||||
condition: condition,
|
condition: condition,
|
||||||
instruction: match pair.as_str() {
|
instruction: match pair.as_str() {
|
||||||
|
@ -906,12 +962,12 @@ fn parse_instruction_zero(pair: pest::iterators::Pair<Rule>, size: Size, conditi
|
||||||
"mse" => InstructionZero::Mse,
|
"mse" => InstructionZero::Mse,
|
||||||
"mcl" => InstructionZero::Mcl,
|
"mcl" => InstructionZero::Mcl,
|
||||||
_ => panic!("Unsupported conditional instruction (zero): {}", pair.as_str()),
|
_ => panic!("Unsupported conditional instruction (zero): {}", pair.as_str()),
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_instruction_one(pair: pest::iterators::Pair<Rule>, mut operand: AstNode, size: Size, condition: Condition) -> AstNode {
|
fn parse_instruction_one(pair: pest::iterators::Pair<Rule>, mut operand: AstNode, size: Size, condition: Condition) -> AstNode {
|
||||||
AstNode::OperationOne {
|
AstNode::OperationOne ( OperationOne {
|
||||||
size: size,
|
size: size,
|
||||||
condition: condition,
|
condition: condition,
|
||||||
instruction: match pair.as_str() {
|
instruction: match pair.as_str() {
|
||||||
|
@ -956,12 +1012,12 @@ fn parse_instruction_one(pair: pest::iterators::Pair<Rule>, mut operand: AstNode
|
||||||
"flp" => InstructionOne::Flp,
|
"flp" => InstructionOne::Flp,
|
||||||
_ => panic!("Unsupported conditional instruction (one): {}", pair.as_str()),
|
_ => panic!("Unsupported conditional instruction (one): {}", pair.as_str()),
|
||||||
},
|
},
|
||||||
operand: Box::new(operand),
|
operand: Box::new(operand)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_instruction_incdec(pair: pest::iterators::Pair<Rule>, lhs: AstNode, rhs: AstNode, size: Size, condition: Condition) -> AstNode {
|
fn parse_instruction_incdec(pair: pest::iterators::Pair<Rule>, lhs: AstNode, rhs: AstNode, size: Size, condition: Condition) -> AstNode {
|
||||||
AstNode::OperationIncDec {
|
AstNode::OperationIncDec ( OperationIncDec {
|
||||||
size: size,
|
size: size,
|
||||||
condition: condition,
|
condition: condition,
|
||||||
instruction: match pair.as_str() {
|
instruction: match pair.as_str() {
|
||||||
|
@ -971,12 +1027,25 @@ fn parse_instruction_incdec(pair: pest::iterators::Pair<Rule>, lhs: AstNode, rhs
|
||||||
},
|
},
|
||||||
lhs: Box::new(lhs),
|
lhs: Box::new(lhs),
|
||||||
rhs: Box::new(rhs),
|
rhs: Box::new(rhs),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn parse_instruction_two(pair: pest::iterators::Pair<Rule>, mut lhs: AstNode, mut rhs: AstNode, size: Size, condition: Condition) -> AstNode {
|
fn parse_instruction_two(pair: pest::iterators::Pair<Rule>, mut lhs: AstNode, mut rhs: AstNode, size: Size, condition: Condition) -> AstNode {
|
||||||
AstNode::OperationTwo {
|
match pair.as_str() {
|
||||||
|
"sla" |
|
||||||
|
"sra" |
|
||||||
|
"srl" |
|
||||||
|
"rol" |
|
||||||
|
"ror" |
|
||||||
|
"bse" |
|
||||||
|
"bcl" |
|
||||||
|
"bts" => if let Some(value) = node_value(&rhs) {
|
||||||
|
rhs = AstNode::Immediate8(value as u8);
|
||||||
|
}
|
||||||
|
_=>()
|
||||||
|
}
|
||||||
|
AstNode::OperationTwo ( OperationTwo {
|
||||||
size: size,
|
size: size,
|
||||||
condition: condition,
|
condition: condition,
|
||||||
instruction: match pair.as_str() {
|
instruction: match pair.as_str() {
|
||||||
|
@ -1025,7 +1094,7 @@ fn parse_instruction_two(pair: pest::iterators::Pair<Rule>, mut lhs: AstNode, mu
|
||||||
},
|
},
|
||||||
lhs: Box::new(lhs),
|
lhs: Box::new(lhs),
|
||||||
rhs: Box::new(rhs),
|
rhs: Box::new(rhs),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assemble_node(node: AstNode) -> AssembledInstruction {
|
fn assemble_node(node: AstNode) -> AssembledInstruction {
|
||||||
|
@ -1060,12 +1129,14 @@ fn assemble_node(node: AstNode) -> AssembledInstruction {
|
||||||
|
|
||||||
let mut instruction_data: Vec<u8> = Vec::new();
|
let mut instruction_data: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
instruction_data.push(condition_source_destination_to_byte(&node));
|
let condition_source_destination = condition_source_destination_to_byte(&node);
|
||||||
|
instruction_data.push(condition_source_destination);
|
||||||
instruction_data.push(instruction_to_byte(&node));
|
instruction_data.push(instruction_to_byte(&node));
|
||||||
|
|
||||||
let mut instruction: AssembledInstruction = instruction_data.into();
|
let mut instruction: AssembledInstruction = instruction_data.into();
|
||||||
|
|
||||||
node_to_immediate_values(&node, &mut instruction);
|
//0x80 bit determines if we need to write the pointer offsets or not
|
||||||
|
node_to_immediate_values(&node, &mut instruction, condition_source_destination & 0x80 != 0);
|
||||||
|
|
||||||
instruction
|
instruction
|
||||||
}
|
}
|
||||||
|
@ -1090,7 +1161,7 @@ fn size_to_byte(size: Size) -> u8 {
|
||||||
|
|
||||||
fn instruction_to_byte(node: &AstNode) -> u8 {
|
fn instruction_to_byte(node: &AstNode) -> u8 {
|
||||||
match *node {
|
match *node {
|
||||||
AstNode::OperationZero {size, instruction, ..} => {
|
AstNode::OperationZero (OperationZero{size, instruction, ..}) => {
|
||||||
match instruction {
|
match instruction {
|
||||||
InstructionZero::Nop => 0x00 | size_to_byte(size),
|
InstructionZero::Nop => 0x00 | size_to_byte(size),
|
||||||
InstructionZero::Halt => 0x10 | size_to_byte(size),
|
InstructionZero::Halt => 0x10 | size_to_byte(size),
|
||||||
|
@ -1103,7 +1174,7 @@ fn instruction_to_byte(node: &AstNode) -> u8 {
|
||||||
InstructionZero::Mcl => 0x1D | size_to_byte(size),
|
InstructionZero::Mcl => 0x1D | size_to_byte(size),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstNode::OperationOne {size, instruction, ..} => {
|
AstNode::OperationOne (OperationOne{size, instruction, ..}) => {
|
||||||
match instruction {
|
match instruction {
|
||||||
InstructionOne::Not => 0x33 | size_to_byte(size),
|
InstructionOne::Not => 0x33 | size_to_byte(size),
|
||||||
InstructionOne::Jmp => 0x08 | size_to_byte(size),
|
InstructionOne::Jmp => 0x08 | size_to_byte(size),
|
||||||
|
@ -1119,13 +1190,13 @@ fn instruction_to_byte(node: &AstNode) -> u8 {
|
||||||
InstructionOne::Flp => 0x3D | size_to_byte(size),
|
InstructionOne::Flp => 0x3D | size_to_byte(size),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstNode::OperationIncDec {size, instruction, ..} => {
|
AstNode::OperationIncDec (OperationIncDec{size, instruction, ..}) => {
|
||||||
match instruction {
|
match instruction {
|
||||||
InstructionIncDec::Inc => 0x11 | size_to_byte(size),
|
InstructionIncDec::Inc => 0x11 | size_to_byte(size),
|
||||||
InstructionIncDec::Dec => 0x31 | size_to_byte(size),
|
InstructionIncDec::Dec => 0x31 | size_to_byte(size),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstNode::OperationTwo {size, instruction, ..} => {
|
AstNode::OperationTwo (OperationTwo{size, instruction, ..}) => {
|
||||||
match instruction {
|
match instruction {
|
||||||
InstructionTwo::Add => 0x01 | size_to_byte(size),
|
InstructionTwo::Add => 0x01 | size_to_byte(size),
|
||||||
InstructionTwo::Sub => 0x21 | size_to_byte(size),
|
InstructionTwo::Sub => 0x21 | size_to_byte(size),
|
||||||
|
@ -1172,29 +1243,32 @@ fn condition_to_bits(condition: &Condition) -> u8 {
|
||||||
|
|
||||||
fn condition_source_destination_to_byte(node: &AstNode) -> u8 {
|
fn condition_source_destination_to_byte(node: &AstNode) -> u8 {
|
||||||
let source: u8 = match node {
|
let source: u8 = match node {
|
||||||
AstNode::OperationZero {..} => 0x00,
|
AstNode::OperationZero (_) => 0x00,
|
||||||
AstNode::OperationOne {operand, ..} => {
|
AstNode::OperationOne (OperationOne{operand, ..}) => {
|
||||||
match operand.as_ref() {
|
match operand.as_ref() {
|
||||||
AstNode::Register(_) => 0x00,
|
AstNode::Register(_) => 0x00,
|
||||||
AstNode::RegisterPointer(_) => 0x01,
|
AstNode::RegisterPointer(_) => 0x01,
|
||||||
|
AstNode::RegisterPointerOffset(_, _) => 0x81,
|
||||||
AstNode::Immediate8(_) | AstNode::Immediate16(_) | AstNode::Immediate32(_) | AstNode::LabelOperand {..} => 0x02,
|
AstNode::Immediate8(_) | AstNode::Immediate16(_) | AstNode::Immediate32(_) | AstNode::LabelOperand {..} => 0x02,
|
||||||
AstNode::ImmediatePointer(_) | AstNode::LabelOperandPointer {..} => 0x03,
|
AstNode::ImmediatePointer(_) | AstNode::LabelOperandPointer {..} => 0x03,
|
||||||
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstNode::OperationIncDec {lhs, ..} => {
|
AstNode::OperationIncDec (OperationIncDec{lhs, ..}) => {
|
||||||
match lhs.as_ref() {
|
match lhs.as_ref() {
|
||||||
AstNode::Register(_) => 0x00,
|
AstNode::Register(_) => 0x00,
|
||||||
AstNode::RegisterPointer(_) => 0x01,
|
AstNode::RegisterPointer(_) => 0x01,
|
||||||
|
AstNode::RegisterPointerOffset(_, _) => 0x81,
|
||||||
AstNode::Immediate8(_) | AstNode::Immediate16(_) | AstNode::Immediate32(_) | AstNode::LabelOperand {..} => 0x02,
|
AstNode::Immediate8(_) | AstNode::Immediate16(_) | AstNode::Immediate32(_) | AstNode::LabelOperand {..} => 0x02,
|
||||||
AstNode::ImmediatePointer(_) | AstNode::LabelOperandPointer {..} => 0x03,
|
AstNode::ImmediatePointer(_) | AstNode::LabelOperandPointer {..} => 0x03,
|
||||||
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstNode::OperationTwo {rhs, ..} => {
|
AstNode::OperationTwo (OperationTwo{rhs, ..}) => {
|
||||||
match rhs.as_ref() {
|
match rhs.as_ref() {
|
||||||
AstNode::Register(_) => 0x00,
|
AstNode::Register(_) => 0x00,
|
||||||
AstNode::RegisterPointer(_) => 0x01,
|
AstNode::RegisterPointer(_) => 0x01,
|
||||||
|
AstNode::RegisterPointerOffset(_, _) => 0x81,
|
||||||
AstNode::Immediate8(_) | AstNode::Immediate16(_) | AstNode::Immediate32(_) | AstNode::LabelOperand {..} => 0x02,
|
AstNode::Immediate8(_) | AstNode::Immediate16(_) | AstNode::Immediate32(_) | AstNode::LabelOperand {..} => 0x02,
|
||||||
AstNode::ImmediatePointer(_) | AstNode::LabelOperandPointer {..} => 0x03,
|
AstNode::ImmediatePointer(_) | AstNode::LabelOperandPointer {..} => 0x03,
|
||||||
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
||||||
|
@ -1203,18 +1277,19 @@ fn condition_source_destination_to_byte(node: &AstNode) -> u8 {
|
||||||
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
||||||
};
|
};
|
||||||
let destination: u8 = match node {
|
let destination: u8 = match node {
|
||||||
AstNode::OperationZero {..} => 0x00,
|
AstNode::OperationZero(_) => 0x00,
|
||||||
AstNode::OperationOne {..} => 0x00,
|
AstNode::OperationOne (_)=> 0x00,
|
||||||
AstNode::OperationIncDec { rhs, ..} => {
|
AstNode::OperationIncDec (OperationIncDec{ rhs, ..}) => {
|
||||||
match rhs.as_ref() {
|
match rhs.as_ref() {
|
||||||
AstNode::Immediate8(n) => *n << 2,
|
AstNode::Immediate8(n) => *n << 2,
|
||||||
_ => panic!(""),
|
_ => panic!(""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstNode::OperationTwo {lhs, ..} => {
|
AstNode::OperationTwo (OperationTwo{lhs, ..}) => {
|
||||||
match lhs.as_ref() {
|
match lhs.as_ref() {
|
||||||
AstNode::Register(_) => 0x00,
|
AstNode::Register(_) => 0x00,
|
||||||
AstNode::RegisterPointer(_) => 0x04,
|
AstNode::RegisterPointer(_) => 0x04,
|
||||||
|
AstNode::RegisterPointerOffset(_, _) => 0x84,
|
||||||
AstNode::Immediate8(_) | AstNode::Immediate16(_) | AstNode::Immediate32(_) | AstNode::LabelOperand {..} => 0x08,
|
AstNode::Immediate8(_) | AstNode::Immediate16(_) | AstNode::Immediate32(_) | AstNode::LabelOperand {..} => 0x08,
|
||||||
AstNode::ImmediatePointer(_) | AstNode::LabelOperandPointer {..} => 0x0C,
|
AstNode::ImmediatePointer(_) | AstNode::LabelOperandPointer {..} => 0x0C,
|
||||||
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
||||||
|
@ -1223,10 +1298,10 @@ fn condition_source_destination_to_byte(node: &AstNode) -> u8 {
|
||||||
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
||||||
};
|
};
|
||||||
let condition: u8 = match node {
|
let condition: u8 = match node {
|
||||||
AstNode::OperationZero {condition, ..} => condition_to_bits(condition),
|
AstNode::OperationZero (OperationZero{condition, ..}) => condition_to_bits(condition),
|
||||||
AstNode::OperationOne {condition, ..} => condition_to_bits(condition),
|
AstNode::OperationOne (OperationOne{condition, ..}) => condition_to_bits(condition),
|
||||||
AstNode::OperationIncDec {condition, ..} => condition_to_bits(condition),
|
AstNode::OperationIncDec (OperationIncDec{condition, ..}) => condition_to_bits(condition),
|
||||||
AstNode::OperationTwo {condition, ..} => condition_to_bits(condition),
|
AstNode::OperationTwo (OperationTwo{condition, ..}) => condition_to_bits(condition),
|
||||||
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
||||||
};
|
};
|
||||||
condition | source | destination
|
condition | source | destination
|
||||||
|
@ -1257,11 +1332,23 @@ fn generate_backpatch_immediate(name: &String, size: Size, instruction: &Assembl
|
||||||
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){
|
|
||||||
|
fn operand_to_immediate_value(instruction: &AssembledInstruction, node: &AstNode, pointer_offset: bool){
|
||||||
let mut vec = instruction.borrow_mut();
|
let mut vec = instruction.borrow_mut();
|
||||||
match *node {
|
match *node {
|
||||||
AstNode::Register (register) => vec.push(register),
|
AstNode::Register (register) => vec.push(register),
|
||||||
AstNode::RegisterPointer(register) => vec.push(register),
|
AstNode::RegisterPointer(register) => {
|
||||||
|
vec.push(register);
|
||||||
|
if pointer_offset {
|
||||||
|
vec.push(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AstNode::RegisterPointerOffset(register, offset) => {
|
||||||
|
vec.push(register);
|
||||||
|
if pointer_offset {
|
||||||
|
vec.push(offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AstNode::Immediate8 (immediate) => vec.push(immediate),
|
AstNode::Immediate8 (immediate) => vec.push(immediate),
|
||||||
AstNode::Immediate16 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()),
|
AstNode::Immediate16 (immediate) => vec.extend_from_slice(&immediate.to_le_bytes()),
|
||||||
|
@ -1279,21 +1366,22 @@ fn operand_to_immediate_value(instruction: &AssembledInstruction, node: &AstNode
|
||||||
|
|
||||||
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_to_immediate_values(node: &AstNode, instruction: &AssembledInstruction) {
|
fn node_to_immediate_values(node: &AstNode, instruction: &AssembledInstruction, pointer_offset: bool) {
|
||||||
{
|
{
|
||||||
match node {
|
match node {
|
||||||
AstNode::OperationZero {..} => {}
|
AstNode::OperationZero {..} => {}
|
||||||
|
|
||||||
AstNode::OperationOne {operand, ..} =>
|
AstNode::OperationOne (OperationOne{operand, ..}) =>
|
||||||
operand_to_immediate_value(instruction, operand.as_ref()),
|
operand_to_immediate_value(instruction, operand.as_ref(), pointer_offset),
|
||||||
|
|
||||||
AstNode::OperationIncDec {lhs, ..} =>
|
AstNode::OperationIncDec (OperationIncDec{lhs, ..}) =>
|
||||||
operand_to_immediate_value(instruction, lhs.as_ref()),
|
operand_to_immediate_value(instruction, lhs.as_ref(), pointer_offset),
|
||||||
|
|
||||||
AstNode::OperationTwo {rhs, ..} =>
|
AstNode::OperationTwo (OperationTwo{rhs, ..}) =>
|
||||||
operand_to_immediate_value(instruction, rhs.as_ref()),
|
operand_to_immediate_value(instruction, rhs.as_ref(), pointer_offset),
|
||||||
|
|
||||||
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
||||||
}
|
}
|
||||||
|
@ -1304,9 +1392,116 @@ fn node_to_immediate_values(node: &AstNode, instruction: &AssembledInstruction)
|
||||||
AstNode::OperationOne {..} => {}
|
AstNode::OperationOne {..} => {}
|
||||||
AstNode::OperationIncDec {..} => {}
|
AstNode::OperationIncDec {..} => {}
|
||||||
|
|
||||||
AstNode::OperationTwo {lhs, ..} =>
|
AstNode::OperationTwo (OperationTwo{lhs, ..}) =>
|
||||||
operand_to_immediate_value(instruction, lhs.as_ref()),
|
operand_to_immediate_value(instruction, lhs.as_ref(), pointer_offset),
|
||||||
|
|
||||||
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
_ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn node_value(node: &AstNode) -> Option<u32> {
|
||||||
|
match *node {
|
||||||
|
AstNode::Immediate16(n) => Some(n as u32),
|
||||||
|
AstNode::Immediate32(n) => Some(n as u32),
|
||||||
|
AstNode::Immediate8(n) => Some(n as u32),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn optimize_node(node: AstNode, enabled: &mut bool) -> AstNode {
|
||||||
|
if let AstNode::Optimize(value) = node {
|
||||||
|
*enabled = value;
|
||||||
|
}
|
||||||
|
if *enabled {
|
||||||
|
match node {
|
||||||
|
AstNode::OperationTwo(mut n) => {
|
||||||
|
let v = node_value(&n.rhs);
|
||||||
|
if let Some(v) = v {
|
||||||
|
match n.instruction {
|
||||||
|
InstructionTwo::Add => {
|
||||||
|
match v {
|
||||||
|
1 => return AstNode::OperationIncDec(OperationIncDec { size: n.size, condition: n.condition, instruction: InstructionIncDec::Inc, lhs: n.lhs, rhs: Box::new(AstNode::Immediate8(0)) }),
|
||||||
|
2 => return AstNode::OperationIncDec(OperationIncDec { size: n.size, condition: n.condition, instruction: InstructionIncDec::Inc, lhs: n.lhs, rhs: Box::new(AstNode::Immediate8(1)) }),
|
||||||
|
4 => return AstNode::OperationIncDec(OperationIncDec { size: n.size, condition: n.condition, instruction: InstructionIncDec::Inc, lhs: n.lhs, rhs: Box::new(AstNode::Immediate8(2)) }),
|
||||||
|
8 => return AstNode::OperationIncDec(OperationIncDec { size: n.size, condition: n.condition, instruction: InstructionIncDec::Inc, lhs: n.lhs, rhs: Box::new(AstNode::Immediate8(3)) }),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
InstructionTwo::Sub => {
|
||||||
|
match v {
|
||||||
|
1 => return AstNode::OperationIncDec(OperationIncDec { size: n.size, condition: n.condition, instruction: InstructionIncDec::Dec, lhs: n.lhs, rhs: Box::new(AstNode::Immediate8(0)) }),
|
||||||
|
2 => return AstNode::OperationIncDec(OperationIncDec { size: n.size, condition: n.condition, instruction: InstructionIncDec::Dec, lhs: n.lhs, rhs: Box::new(AstNode::Immediate8(1)) }),
|
||||||
|
4 => return AstNode::OperationIncDec(OperationIncDec { size: n.size, condition: n.condition, instruction: InstructionIncDec::Dec, lhs: n.lhs, rhs: Box::new(AstNode::Immediate8(2)) }),
|
||||||
|
8 => return AstNode::OperationIncDec(OperationIncDec { size: n.size, condition: n.condition, instruction: InstructionIncDec::Dec, lhs: n.lhs, rhs: Box::new(AstNode::Immediate8(3)) }),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
InstructionTwo::Mov => {
|
||||||
|
if let Size::Word = n.size {
|
||||||
|
if let AstNode::Register(_) = *n.lhs {
|
||||||
|
if v <= 0xff {
|
||||||
|
n.size = Size::Byte;
|
||||||
|
n.instruction = InstructionTwo::Movz;
|
||||||
|
n.rhs = Box::new(AstNode::Immediate8(v as u8));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if v <= 0xffff {
|
||||||
|
n.size = Size::Half;
|
||||||
|
n.instruction = InstructionTwo::Movz;
|
||||||
|
n.rhs = Box::new(AstNode::Immediate16(v as u16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
InstructionTwo::Mul => {
|
||||||
|
if let Size::Word = n.size {
|
||||||
|
if v.is_power_of_two() {
|
||||||
|
n.instruction = InstructionTwo::Sla;
|
||||||
|
n.rhs = Box::new(AstNode::Immediate8(v.trailing_zeros() as u8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
InstructionTwo::Idiv => {
|
||||||
|
if let Size::Word = n.size {
|
||||||
|
if v.is_power_of_two() {
|
||||||
|
n.instruction = InstructionTwo::Sra;
|
||||||
|
n.rhs = Box::new(AstNode::Immediate8(v.trailing_zeros() as u8));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
InstructionTwo::Div => {
|
||||||
|
if let Size::Word = n.size {
|
||||||
|
if v.is_power_of_two() {
|
||||||
|
n.instruction = InstructionTwo::Srl;
|
||||||
|
n.rhs = Box::new(AstNode::Immediate8(v.trailing_zeros() as u8));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// InstructionTwo::Sla
|
||||||
|
// | InstructionTwo::Srl | InstructionTwo::Sra
|
||||||
|
// | InstructionTwo::Bcl | InstructionTwo::Bse
|
||||||
|
// | InstructionTwo::Bts
|
||||||
|
// | InstructionTwo::Ror | InstructionTwo::Rol
|
||||||
|
// => {
|
||||||
|
// n.rhs = Box::new(AstNode::Immediate8(v as u8));
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode::OperationTwo(n)
|
||||||
|
}
|
||||||
|
_=> node
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user