asm done with parsing and linking. codegen all that's left

This commit is contained in:
2025-06-18 03:54:39 +01:00
parent 6a0b5c617a
commit 1210b19333
6 changed files with 366 additions and 63 deletions
+189
View File
@@ -0,0 +1,189 @@
use common::prelude::Register;
use crate::{
AssembleError, dsa, expect_token, expect_type,
model::{Node, Opcode, Token, TokenType},
node,
};
pub fn expand_pseudo_ops(
mut nodes: Vec<Node>,
module: u64,
) -> Result<Vec<Node>, AssembleError> {
let mut result = Vec::<Node>::with_capacity(nodes.len());
for node in nodes.iter_mut() {
if let Err(_) = try_expand(node.clone(), &mut result, module) {
result.push(node.clone());
}
}
Ok(result)
}
fn try_expand(
mut node: Node,
result: &mut Vec<Node>,
module: u64,
) -> Result<(), AssembleError> {
match node.opcode() {
Opcode::Push => expand_push(node.clone(), result)?,
Opcode::Pop => expand_pop(node.clone(), result)?,
Opcode::Ldb | Opcode::Ldh | Opcode::Ldw => expand_ldx(node.clone(), result)?,
Opcode::Lwi => expand_lwi(node.clone(), result)?,
Opcode::Resb | Opcode::Resh | Opcode::Resw => expand_resx(node.clone(), result)?,
Opcode::Db | Opcode::Dh | Opcode::Dw => expand_dx(node.clone(), result)?,
_ => result.push(node.clone()),
};
Ok(())
}
fn expand_push(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
let label = current.label();
let reg = expect_type!(current.arg(0).unwrap(), Register)?;
nodes.extend(vec![
node!(label, Opcode::Iadd, reg.clone(), Token::Immediate(4)),
node!(None, Opcode::Stw, reg, Token::Register(Register::Spr)),
]);
Ok(())
}
fn expand_pop(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
let label = current.label();
let reg = expect_type!(current.arg(0).unwrap(), Register)?;
nodes.extend(vec![
node!(label, Opcode::Isub, reg.clone(), Token::Immediate(4)),
node!(None, Opcode::Ldw, reg, Token::Register(Register::Spr)),
]);
Ok(())
}
fn expand_ldx(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
let opcode = current.opcode();
let name = expect_type!(current.arg(0).unwrap(), Symbol)?;
let reg = expect_type!(current.arg(2).unwrap(), Register)?;
nodes.extend(vec![
node!(current.label(), Opcode::Lli, name.clone(), reg.clone()),
node!(None, Opcode::Lui, name.clone(), reg.clone()),
node!(None, opcode, reg.clone(), Token::Immediate(0), reg),
]);
Ok(())
}
fn expand_lwi(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
let reg = expect_type!(current.arg(0).unwrap(), Register)?;
let name = expect_type!(current.arg(1).unwrap(), Symbol)?;
nodes.extend(vec![
node!(current.label(), Opcode::Lli, name.clone(), reg.clone()),
node!(None, Opcode::Lui, name.clone(), reg.clone()),
]);
Ok(())
}
fn expand_resx(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
let region_label = expect_token!(current.arg(0).unwrap(), Symbol)?;
let size = expect_token!(current.arg(1).unwrap(), Immediate)?;
let units_per = match current.opcode() {
Opcode::Resb => 4,
Opcode::Resh => 2,
Opcode::Resw => 1,
_ => unreachable!(),
};
let mut buffer = vec![];
// push the inital node with the label
for _ in 0..size.div_ceil(units_per) {
// push the rest of the nodes
buffer.push(node!(None, Opcode::Data, Token::Immediate(0)));
}
buffer[0].symbol = Some(region_label);
nodes.extend(buffer);
Ok(())
}
fn expand_dx(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
let region_label = expect_token!(current.arg(0).unwrap(), Symbol)?;
let size = match current.opcode() {
Opcode::Db => 4,
Opcode::Dh => 2,
Opcode::Dw => 1,
_ => unreachable!(),
};
let mut buffer = vec![];
let mut args = current.args();
let label = args.remove(0);
for word in process_dx_data(args, size)? {
buffer.push(node!(None, Opcode::Data, Token::Immediate(word)));
}
buffer[0].symbol = Some(region_label);
nodes.extend(buffer);
Ok(())
}
fn process_dx_data(args: Vec<Token>, size: usize) -> Result<Vec<u32>, AssembleError> {
assert!(matches!(size, 1 | 2 | 4));
let mut buffer = Vec::<u8>::new();
// Process each token
for token in args {
match token {
Token::StringLit(s) => {
// Split string into chars and write as bytes
for ch in s.chars() {
// Convert char to bytes (UTF-8 encoding)
let mut char_buf = [0u8; 4];
let char_bytes = ch.encode_utf8(&mut char_buf);
buffer.extend_from_slice(char_bytes.as_bytes());
}
}
Token::Immediate(value) => {
// Split u32 into bytes (little-endian)
buffer.extend_from_slice(&value.to_be_bytes());
}
_ => {
return Err(AssembleError::Generic);
}
}
// Pad buffer to alignment boundary with zeros
let remainder = buffer.len() % size;
if remainder != 0 {
let padding = size - remainder;
buffer.resize(buffer.len() + padding, 0);
}
}
// Convert byte buffer to u32 chunks
// Pad final buffer to u32 boundary if needed
let remainder = buffer.len() % 4;
if remainder != 0 {
let padding = 4 - remainder;
buffer.resize(buffer.len() + padding, 0);
}
// Convert bytes to u32s efficiently using chunks_exact
let result = buffer
.chunks_exact(4)
.map(|chunk| {
// Convert 4 bytes to u32 (little-endian)
u32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]])
})
.collect();
Ok(result)
}