feat: complete assembler implementation, minus some instructions
This commit is contained in:
parent
961725d9d7
commit
5db045990c
|
@ -1,6 +1,7 @@
|
|||
use std::fs;
|
||||
use std::env;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
|
||||
use std::collections::{HashMap, BTreeMap, VecDeque};
|
||||
|
||||
|
@ -22,7 +23,7 @@ fn parse_number(string: &str) -> u16 {
|
|||
string.parse::<u16>().unwrap()
|
||||
}
|
||||
|
||||
fn stack_bit(token: &String) -> Result<u16, String> {
|
||||
fn stack_bit(token: &str) -> Result<u16, String> {
|
||||
let c = token.as_bytes()[0] as char;
|
||||
match c {
|
||||
'r' => Ok(0),
|
||||
|
@ -31,29 +32,31 @@ fn stack_bit(token: &String) -> Result<u16, String> {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_unary_math_format<'a>(tokens: &Vec<String>, opcode: u16, signed: bool) -> Result<u16, String> {
|
||||
assert_argument_count!(tokens, 4);
|
||||
// e.g. not r t
|
||||
fn parse_unary_op(tokens: &Vec<&str>, opcode: u16, signed: bool) -> Result<u16, String> {
|
||||
assert_argument_count!(tokens, 3);
|
||||
|
||||
let src = stack_bit(&tokens[1])?;
|
||||
let dest = stack_bit(&tokens[2])?;
|
||||
let src = stack_bit(tokens[1])?;
|
||||
let dest = stack_bit(tokens[2])?;
|
||||
|
||||
Ok(opcode<<11 & src<<9 & dest<<8 & (signed as u16)<<7)
|
||||
}
|
||||
|
||||
fn parse_binary_math_format<'a>(tokens: &Vec<String>, opcode: u16, signed: bool) -> Result<u16, String> {
|
||||
// e.g. add r r t
|
||||
fn parse_binary_op(tokens: &Vec<&str>, opcode: u16, signed: bool) -> Result<u16, String> {
|
||||
assert_argument_count!(tokens, 4);
|
||||
|
||||
let left = stack_bit(&tokens[1])?;
|
||||
let right = stack_bit(&tokens[2])?;
|
||||
let dest = stack_bit(&tokens[3])?;
|
||||
let left = stack_bit(tokens[1])?;
|
||||
let right = stack_bit(tokens[2])?;
|
||||
let dest = stack_bit(tokens[3])?;
|
||||
|
||||
Ok(opcode<<11 & left<<10 & right<<9 & dest<<8 & (signed as u16)<<7)
|
||||
Ok(opcode<<11 | left<<10 | right<<9 | dest<<8 | (signed as u16)<<7)
|
||||
}
|
||||
|
||||
fn parse_push(tokens: &Vec<String>, opcode: u16, signed: bool) -> Result<u16, String> {
|
||||
fn parse_push(tokens: &Vec<&str>, opcode: u16, signed: bool) -> Result<u16, String> {
|
||||
assert_argument_count!(tokens, 3);
|
||||
|
||||
let dest = stack_bit(&tokens[1])?;
|
||||
let dest = stack_bit(tokens[1])?;
|
||||
let signed_immediate = tokens[2].parse::<i16>()
|
||||
.map_err(|_| format!("Cannot parse number: {t}", t=tokens[2]))?;
|
||||
|
||||
|
@ -66,7 +69,33 @@ fn parse_push(tokens: &Vec<String>, opcode: u16, signed: bool) -> Result<u16, St
|
|||
return Err("Cannot push number larger than 511 due to bit width limitations".to_owned());
|
||||
}
|
||||
|
||||
Ok(opcode<<11 & dest<<10 & (signed as u16) << 9 & immediate)
|
||||
Ok(opcode<<11 | dest<<10 | (signed as u16) << 9 | immediate)
|
||||
}
|
||||
|
||||
// e.g. sow t -2 3
|
||||
fn parse_forestry_op(tokens: &Vec<&str>, opcode: u16) -> Result<u16, String> {
|
||||
assert_argument_count!(tokens, 4);
|
||||
|
||||
let stack = stack_bit(tokens[1])?;
|
||||
let relative_x = tokens[2].parse::<i16>()
|
||||
.map_err(|_| format!("Cannot parse number: {t}", t=tokens[2]))?;
|
||||
|
||||
let relative_y = tokens[3].parse::<i16>()
|
||||
.map_err(|_| format!("Cannot parse number: {t}", t=tokens[2]))?;
|
||||
|
||||
if relative_x > 15 || relative_x < -16 {
|
||||
Err(format!("Cannot reach cell at {relative_x} along the X-axis; trees may only access cells in the range of -16 to 15"))
|
||||
} else if relative_y > 15 || relative_y < -16 {
|
||||
Err(format!("Cannot reach cell at {relative_y} along the Y-axis; trees may only access cells in the range of -16 to 15"))
|
||||
} else {
|
||||
Ok(opcode<<11 | stack<<10 | (relative_x as u16)<<5 | (relative_y as u16))
|
||||
}
|
||||
}
|
||||
|
||||
// Take a Vec<u8> and a u16, push two corresponding u8s
|
||||
fn push_u16(vec: &mut Vec<u8>, value: u16) {
|
||||
vec.push(((value & 0b11111111_00000000) >> 8) as u8);
|
||||
vec.push((value & 0b00000000_11111111) as u8);
|
||||
}
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
|
@ -90,6 +119,7 @@ fn main() -> io::Result<()> {
|
|||
let mut current_rule_name: String = String::from("");
|
||||
let mut current_rule: Rule = VecDeque::new();
|
||||
|
||||
let mut line_number = 1;
|
||||
for source_line in source_code.lines() {
|
||||
let tokens: Vec<&str> = source_line
|
||||
.split_whitespace()
|
||||
|
@ -102,7 +132,6 @@ fn main() -> io::Result<()> {
|
|||
if reading_land_values {
|
||||
if tokens.len() < 3 {
|
||||
reading_land_values = false;
|
||||
break;
|
||||
} else {
|
||||
let (value, x_pos, y_pos) = (tokens[0].parse::<u16>(), tokens[1].parse::<u16>(), tokens[2].parse::<u16>());
|
||||
match (value, x_pos, y_pos) {
|
||||
|
@ -125,14 +154,46 @@ fn main() -> io::Result<()> {
|
|||
rules.insert(current_rule_name, new_rule);
|
||||
}
|
||||
|
||||
reading_rule = true;
|
||||
current_rule_name = String::from(&tokens[0][1..]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if reading_rule {
|
||||
let parse_instruction_result = match tokens[0] {
|
||||
"add" => Ok(1),
|
||||
"and" => parse_binary_op(&tokens, 0b00001, false),
|
||||
"nand" => parse_binary_op(&tokens, 0b00010, false),
|
||||
"or" => parse_binary_op(&tokens, 0b00011, false),
|
||||
"nor" => parse_binary_op(&tokens, 0b00100, false),
|
||||
"xor" => parse_binary_op(&tokens, 0b00101, false),
|
||||
|
||||
"add" => parse_binary_op(&tokens, 0b00110, false),
|
||||
"mult" => parse_binary_op(&tokens, 0b00111, false),
|
||||
"div" => parse_binary_op(&tokens, 0b01000, false),
|
||||
|
||||
"slt" => parse_binary_op(&tokens, 0b01001, false),
|
||||
"not" => parse_unary_op(&tokens, 0b01010, false),
|
||||
"sll" => parse_binary_op(&tokens, 0b01011, false),
|
||||
"srl" => parse_binary_op(&tokens, 0b01100, false),
|
||||
|
||||
"push" => parse_push(&tokens, 0b01101, false),
|
||||
|
||||
"sow" => parse_forestry_op(&tokens, 0b10101),
|
||||
"reap" => parse_forestry_op(&tokens, 0b10110),
|
||||
"plant" => parse_forestry_op(&tokens, 0b10111),
|
||||
"replant" => parse_forestry_op(&tokens, 0b11000),
|
||||
"yield" => Ok(0b11001_0_00000_00000),
|
||||
"compost" => Ok(0b11010_0_00000_00000),
|
||||
|
||||
_ => Err(format!("Unknown instruction: {token}", token=tokens[0])),
|
||||
};
|
||||
|
||||
let instruction = match parse_instruction_result {
|
||||
Ok(ins) => ins,
|
||||
Err(msg) => panic!("Error on line {line_number}:\n\n{source_line}\n\n{msg}"),
|
||||
};
|
||||
|
||||
current_rule.push_back(instruction);
|
||||
}
|
||||
|
||||
match tokens[0] {
|
||||
|
@ -143,11 +204,51 @@ fn main() -> io::Result<()> {
|
|||
"land" => reading_land_values = true,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
line_number += 1;
|
||||
}
|
||||
|
||||
// Save the last rule
|
||||
rules.insert(current_rule_name, current_rule);
|
||||
|
||||
println!("Original stack size: {}", original_stack_size);
|
||||
println!("Land dimensions: {}x{}", land.width, land.height);
|
||||
println!("Seed tree position: ({}, {})", seed_cell_position.0, seed_cell_position.1);
|
||||
|
||||
let mut rom_bytes: Vec<u8> = Vec::new();
|
||||
|
||||
push_u16(&mut rom_bytes, original_stack_size);
|
||||
push_u16(&mut rom_bytes, land.width);
|
||||
push_u16(&mut rom_bytes, land.height);
|
||||
push_u16(&mut rom_bytes, seed_cell_position.0);
|
||||
push_u16(&mut rom_bytes, seed_cell_position.1);
|
||||
|
||||
push_u16(&mut rom_bytes, land.map.len() as u16);
|
||||
for position in land.map.keys() {
|
||||
push_u16(&mut rom_bytes, *land.map.get(position).unwrap());
|
||||
push_u16(&mut rom_bytes, position.0);
|
||||
push_u16(&mut rom_bytes, position.1);
|
||||
}
|
||||
|
||||
push_u16(&mut rom_bytes, 0b0);
|
||||
|
||||
for rule in rules.values() {
|
||||
for instruction in rule {
|
||||
push_u16(&mut rom_bytes, *instruction);
|
||||
}
|
||||
|
||||
push_u16(&mut rom_bytes, 0b0);
|
||||
}
|
||||
|
||||
for byte_index in 0..rom_bytes.len() {
|
||||
print!("{:08b}", rom_bytes[byte_index]);
|
||||
if byte_index % 2 != 0 {
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
let mut output_file = fs::File::create("a.out")?;
|
||||
output_file.write_all(rom_bytes.as_slice())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue