bquarkz 30acbf5156
dev/prometeuc-improvements (#5)
Co-authored-by: Nilton Constantino <nilton.constantino@visma.com>
Reviewed-on: #5
2026-03-24 13:37:28 +00:00

76 lines
2.4 KiB
Rust

use crate::opcode::OpCode;
use crate::readwrite::*;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub enum Operand {
U32(u32),
I32(i32),
I64(i64),
F64(f64),
Bool(bool),
Label(String),
}
#[derive(Debug, Clone)]
pub enum Asm {
Op(OpCode, Vec<Operand>),
Label(String),
}
pub fn update_pc_by_operand(initial_pc: u32, operands: &Vec<Operand>) -> u32 {
let mut pcp: u32 = initial_pc;
for operand in operands {
match operand {
Operand::U32(_) | Operand::I32(_) | Operand::Label(_) => pcp += 4,
Operand::I64(_) | Operand::F64(_) => pcp += 8,
Operand::Bool(_) => pcp += 1,
}
}
pcp
}
pub fn assemble(instructions: &[Asm]) -> Result<Vec<u8>, String> {
let mut labels = HashMap::new();
let mut current_pc = 0u32;
// First pass: resolve labels
for instr in instructions {
match instr {
Asm::Label(name) => {
labels.insert(name.clone(), current_pc);
}
Asm::Op(_opcode, operands) => {
current_pc += 2; // OpCode is u16 (2 bytes)
current_pc = update_pc_by_operand(current_pc, operands);
}
}
}
// Second pass: generate bytes
let mut rom = Vec::new();
for instr in instructions {
match instr {
Asm::Label(_) => {}
Asm::Op(opcode, operands) => {
write_u16_le(&mut rom, *opcode as u16).map_err(|e| e.to_string())?;
for operand in operands {
match operand {
Operand::U32(v) => write_u32_le(&mut rom, *v).map_err(|e| e.to_string())?,
Operand::I32(v) => write_u32_le(&mut rom, *v as u32).map_err(|e| e.to_string())?,
Operand::I64(v) => write_i64_le(&mut rom, *v).map_err(|e| e.to_string())?,
Operand::F64(v) => write_f64_le(&mut rom, *v).map_err(|e| e.to_string())?,
Operand::Bool(v) => rom.push(if *v { 1 } else { 0 }),
Operand::Label(name) => {
let addr = labels.get(name).ok_or(format!("Undefined label: {}", name))?;
write_u32_le(&mut rom, *addr).map_err(|e| e.to_string())?;
}
}
}
}
}
}
Ok(rom)
}