use crate::expression::ExprType;
use crate::expression::Expression;
use crate::expression::MemOffset;
use crate::generator::Code;
use crate::generator::ResolveType;
use crate::inst::AsmArgs;
use crate::inst::InstType;
use crate::inst::Instructions;
pub fn generate_inst_code(
op: &String,
args: &Vec<Expression>,
code: &mut Code,
) -> Result<(), String> {
if let Some(mut inst) = Instructions::get_code(op) {
let inst_type = Instructions::get_type(op).unwrap();
let expected_args = Instructions::get_args(op).unwrap();
if expected_args.len() != args.len() {
return Err(arg_err(op, &expected_args));
}
for (ex_arg, arg) in expected_args.iter().zip(args.iter()) {
match (ex_arg, arg.get_type()) {
(AsmArgs::Imm, ExprType::NumberLiteral(n)) => {
set_imm(&mut inst, *n, inst_type).unwrap()
}
(AsmArgs::Mem, ExprType::MemAddrLiteral(r, MemOffset::Number(n))) => {
set_mem(&mut inst, *r, *n, inst_type).unwrap()
}
(AsmArgs::RegSrc1, ExprType::RegisterLiteral(r)) => {
set_reg(&mut inst, *r, AsmArgs::RegSrc1).unwrap()
}
(AsmArgs::RegSrc2, ExprType::RegisterLiteral(r)) => {
set_reg(&mut inst, *r, AsmArgs::RegSrc2).unwrap()
}
(AsmArgs::RegDest, ExprType::RegisterLiteral(r)) => {
set_reg(&mut inst, *r, AsmArgs::RegDest).unwrap()
}
(AsmArgs::Imm, ExprType::Symbol(sym)) => {
let resolve_type = get_resolve_type(inst_type);
if let Some(imm) = code.resolve_sym(sym, resolve_type) {
set_imm(&mut inst, imm, inst_type).unwrap()
} else {
return Err(format!("Cannot resolve symbol: `{}`.", sym));
}
}
_ => return Err(arg_err(op, &expected_args)),
}
}
code.append_bytes(u32_to_vecu8(inst))?;
Ok(())
} else {
Err("".to_string())
}
}
fn arg_err(op: &str, expected_args: &Vec<AsmArgs>) -> String {
format!(
"`{}` instruction expects the following arguments: {:?}.",
op, expected_args
)
}
fn get_resolve_type(inst_type: InstType) -> ResolveType {
match inst_type {
InstType::I => ResolveType::Abs,
InstType::J => ResolveType::Rel,
InstType::B => ResolveType::Rel,
_ => panic!(
"Instruction type {:?} should've not entered here.",
inst_type
),
}
}
fn set_mem(
inst_bits: &mut u32,
reg: u32,
mem_offset: i32,
inst_type: InstType,
) -> Result<(), &'static str> {
set_reg(inst_bits, reg, AsmArgs::RegSrc1)?;
set_imm(inst_bits, mem_offset, inst_type)?;
Ok(())
}
fn set_imm(inst_bits: &mut u32, imm: i32, inst_type: InstType) -> Result<(), &'static str> {
let imm = imm as u32;
match inst_type {
InstType::I | InstType::L => *inst_bits |= (imm & 0xFFF) << 20,
InstType::S => {
let imm_11_5 = (imm >> 5) & 0x7F;
let imm_4_0 = imm & 0x1F;
*inst_bits |= (imm_11_5 << 25) + (imm_4_0 << 7);
}
InstType::B => {
let imm_12 = (imm >> 12) & 0x1;
let imm_10_5 = (imm >> 5) & 0x3F;
let imm_4_1 = (imm >> 1) & 0xF;
let imm_11 = (imm >> 11) & 0x1;
*inst_bits |= (imm_12 << 31) + (imm_10_5 << 25) + (imm_4_1 << 8) + (imm_11 << 7);
}
InstType::U => {
let imm_31_12 = (imm >> 12) & 0xFFFFF;
*inst_bits |= imm_31_12 << 12;
}
InstType::J => {
let imm_20 = (imm >> 20) & 0x1;
let imm_10_1 = (imm >> 1) & 0x3FF;
let imm_11 = (imm >> 11) & 0x1;
let imm_19_12 = (imm >> 12) & 0xFF;
*inst_bits |= (imm_20 << 31) + (imm_10_1 << 21) + (imm_11 << 20) + (imm_19_12 << 12);
}
InstType::R => panic!("R-type instruction should've not entered here."),
}
Ok(())
}
fn set_reg(inst_bits: &mut u32, reg: u32, reg_function: AsmArgs) -> Result<(), &'static str> {
match reg_function {
AsmArgs::RegSrc1 => *inst_bits |= reg << 15,
AsmArgs::RegSrc2 => *inst_bits |= reg << 20,
AsmArgs::RegDest => *inst_bits |= reg << 7,
_ => panic!("Only AsmArgs::Reg* should've entered here."),
}
Ok(())
}
fn u32_to_vecu8(value: u32) -> Vec<u8> {
let mut bytes = vec![];
for i in 0..4 {
bytes.push((value >> (8 * i)) as u8)
}
bytes
}