use common::{args, prelude::*}; use crate::{ AssembleError, expect_token, model::{Node, Opcode}, }; pub fn codegen(nodes: Vec) -> Result, AssembleError> { let mut instructions = vec![]; for node in nodes { instructions.push(build_instruction(node)?); } Ok(instructions) } fn build_instruction(node: Node) -> Result { let opcode = node.opcode(); let args = node.args(); match opcode { Opcode::Nop => Ok(Instruction::Nop), Opcode::Mov => { let src = expect_token!(args.first().unwrap(), Register)?; let dest = expect_token!(args.get(1).unwrap(), Register)?; Ok(Instruction::Mov(args!(R, sr1: src, dr: dest))) } Opcode::Movs => { let src = expect_token!(args.first().unwrap(), Register)?; let dest = expect_token!(args.get(1).unwrap(), Register)?; Ok(Instruction::MovSigned(args!(R, sr1: src, dr: dest))) } Opcode::Ldb | Opcode::Ldw | Opcode::Ldh | Opcode::Ldbs | Opcode::Ldhs | Opcode::Stb | Opcode::Stw | Opcode::Sth => { let base = expect_token!(args.first().unwrap(), Register)?; let dest = expect_token!(args.get(1).unwrap(), Register)?; let offset = expect_token!(args.get(2).unwrap(), Immediate)?; let args = args!(I, immediate: offset as u16, r1: base, r2: dest); match opcode { Opcode::Ldb => Ok(Instruction::LoadByte(args)), Opcode::Ldw => Ok(Instruction::LoadWord(args)), Opcode::Ldh => Ok(Instruction::LoadHalfword(args)), Opcode::Ldbs => Ok(Instruction::LoadByteSigned(args)), Opcode::Ldhs => Ok(Instruction::LoadHalfwordSigned(args)), Opcode::Stb => Ok(Instruction::StoreByte(args)), Opcode::Stw => Ok(Instruction::StoreWord(args)), Opcode::Sth => Ok(Instruction::StoreHalfword(args)), _ => unreachable!(), } } Opcode::Lli => { let value = expect_token!(args.first().unwrap(), Immediate)?; let dest = expect_token!(args.get(1).unwrap(), Register)?; let args = args!(I, immediate: value as u16, r1: dest); Ok(Instruction::LoadLowerImmediate(args)) } Opcode::Lui => { let value = expect_token!(args.first().unwrap(), Immediate)? >> 16; let dest = expect_token!(args.get(1).unwrap(), Register)?; let args = args!(I, immediate: value as u16, r1: dest); Ok(Instruction::LoadUpperImmediate(args)) } Opcode::Jmp | Opcode::Jeq | Opcode::Jne | Opcode::Jgt | Opcode::Jge | Opcode::Jlt | Opcode::Jle => { let address = expect_token!(args.first().unwrap(), Immediate)?; let offset = expect_token!(args.get(1).unwrap(), Register)?; let args = args!(I, immediate: address as u16, r1: offset); match opcode { Opcode::Jmp => Ok(Instruction::Jump(args)), Opcode::Jeq => Ok(Instruction::JumpEq(args)), Opcode::Jne => Ok(Instruction::JumpNeq(args)), Opcode::Jgt => Ok(Instruction::JumpGt(args)), Opcode::Jge => Ok(Instruction::JumpGe(args)), Opcode::Jlt => Ok(Instruction::JumpLt(args)), Opcode::Jle => Ok(Instruction::JumpLe(args)), _ => unreachable!(), } } Opcode::Cmp => { let left = expect_token!(args.first().unwrap(), Register)?; let right = expect_token!(args.get(1).unwrap(), Register)?; Ok(Instruction::Compare(args!(R, sr1: left, sr2: right))) } Opcode::Inc => { let reg = expect_token!(args.first().unwrap(), Register)?; Ok(Instruction::Increment(args!(R, sr1: reg))) } Opcode::Dec => { let reg = expect_token!(args.first().unwrap(), Register)?; Ok(Instruction::Decrement(args!(R, sr1: reg))) } Opcode::Shl => { let reg = expect_token!(args.first().unwrap(), Register)?; let amount = expect_token!(args.get(1).unwrap(), Immediate)? as u8; Ok(Instruction::ShiftLeft(args!(R, sr1: reg, shamt: amount))) } Opcode::Shr => { let reg = expect_token!(args.first().unwrap(), Register)?; let amount = expect_token!(args.get(1).unwrap(), Immediate)? as u8; Ok(Instruction::ShiftRight(args!(R, sr1: reg, shamt: amount))) } Opcode::Add | Opcode::Sub | Opcode::And | Opcode::Or | Opcode::Xor | Opcode::Nand | Opcode::Nor | Opcode::Xnor => { let left = expect_token!(args.first().unwrap(), Register)?; let right = expect_token!(args.get(1).unwrap(), Register)?; let dest = expect_token!(args.get(2).unwrap(), Register)?; let args = args!(R, sr1: left, sr2: right, dr: dest); match opcode { Opcode::Add => Ok(Instruction::Add(args)), Opcode::Sub => Ok(Instruction::Sub(args)), Opcode::And => Ok(Instruction::And(args)), Opcode::Or => Ok(Instruction::Or(args)), Opcode::Xor => Ok(Instruction::Xor(args)), Opcode::Nand => Ok(Instruction::Nand(args)), Opcode::Nor => Ok(Instruction::Nor(args)), Opcode::Xnor => Ok(Instruction::Xnor(args)), _ => unreachable!(), } } Opcode::Iadd | Opcode::Isub => { let reg = expect_token!(args.first().unwrap(), Register)?; let immediate = expect_token!(args.get(1).unwrap(), Immediate)? as u16; let dest = expect_token!(args.get(2).unwrap(), Register)?; let args = args!(I, immediate: immediate, r1: reg, r2: dest); match opcode { Opcode::Iadd => Ok(Instruction::AddImmediate(args)), Opcode::Isub => Ok(Instruction::SubImmediate(args)), _ => unreachable!(), } } Opcode::Not => { let reg = expect_token!(args.first().unwrap(), Register)?; let dest = expect_token!(args.get(1).unwrap(), Register)?; Ok(Instruction::Not(args!(R, sr1: reg, dr: dest))) } Opcode::Int => { let code = expect_token!(args.first().unwrap(), Immediate)? as u8; Ok(Instruction::Interrupt(Interrupt::Software(code))) } Opcode::Irt => Ok(Instruction::IntReturn), Opcode::Hlt => Ok(Instruction::Halt), Opcode::Data => { let immediate = expect_token!(args.first().unwrap(), Immediate)?; Ok(Instruction::Data(immediate)) } Opcode::Segment => { let immediate = expect_token!(args.first().unwrap(), Immediate)?; Ok(Instruction::Segment(immediate)) } Opcode::Db | Opcode::Dh | Opcode::Dw | Opcode::Resb | Opcode::Resh | Opcode::Resw | Opcode::Push | Opcode::Pop | Opcode::Lwi | Opcode::Include => todo!(), } }