llvm-native-core 0.1.9

LLVM-native core semantic engine — IR, CodeGen, X86 MC, Clang frontend pipeline
//! MSP430 MC Encoder — instruction encoding for TI MSP430.
//!
//! Encodes MSP430 instructions into little-endian byte sequences.
//! Instructions are variable-length: 16-bit (2 bytes), 32-bit (4 bytes),
//! or 48-bit (6 bytes) for MSP430X extensions.
//!
//! # Instruction Formats
//!
//! ```text
//! Single-operand (16-bit):
//!   opcode(9) | B/W(1) | As(2) | register(4)
//!
//! Double-operand (16-bit):
//!   opcode(4) | source(6) | Ad(1) | B/W(1) | As(2) | register(4)
//!
//! Jump (16-bit):
//!   opcode(6) | condition(3) | offset(10)
//! ```

use super::msp430_instr_info::Msp430Opcode;
use crate::codegen::{MachineFunction, MachineInstr, MachineOperand};

fn u16_to_le_bytes(word: u16) -> Vec<u8> {
    word.to_le_bytes().to_vec()
}

pub struct Msp430MCEncoder {
    pub output: Vec<u8>,
}

impl Msp430MCEncoder {
    pub fn new() -> Self {
        Self {
            output: Vec::with_capacity(256),
        }
    }

    pub fn encode_instruction(&mut self, mi: &MachineInstr) -> Vec<u8> {
        let bytes = self.instruction_to_bytes(mi);
        self.output.extend_from_slice(&bytes);
        bytes
    }

    pub fn encode_function(&mut self, mf: &MachineFunction) -> Vec<u8> {
        for block in &mf.blocks {
            for instr in &block.instructions {
                self.encode_instruction(instr);
            }
        }
        std::mem::take(&mut self.output)
    }

    fn instruction_to_bytes(&self, mi: &MachineInstr) -> Vec<u8> {
        let word = self.encode_by_opcode(mi);
        u16_to_le_bytes(word)
    }

    fn encode_by_opcode(&self, mi: &MachineInstr) -> u16 {
        match get_msp430_opcode(mi.opcode) {
            // Single-operand
            Msp430Opcode::RRC => self.encode_single_op(0x1000, mi),
            Msp430Opcode::SWPB => self.encode_single_op(0x1080, mi),
            Msp430Opcode::RRA => self.encode_single_op(0x1100, mi),
            Msp430Opcode::SXT => self.encode_single_op(0x1180, mi),
            Msp430Opcode::PUSH => self.encode_single_op(0x1200, mi),
            Msp430Opcode::CALL => self.encode_single_op(0x1280, mi),
            Msp430Opcode::RETI => 0x1300,

            // Double-operand
            Msp430Opcode::MOV => self.encode_double_op(0x4000, mi),
            Msp430Opcode::ADD => self.encode_double_op(0x5000, mi),
            Msp430Opcode::ADDC => self.encode_double_op(0x6000, mi),
            Msp430Opcode::SUBC => self.encode_double_op(0x7000, mi),
            Msp430Opcode::SUB => self.encode_double_op(0x8000, mi),
            Msp430Opcode::CMP => self.encode_double_op(0x9000, mi),
            Msp430Opcode::DADD => self.encode_double_op(0xA000, mi),
            Msp430Opcode::BIT => self.encode_double_op(0xB000, mi),
            Msp430Opcode::BIC => self.encode_double_op(0xC000, mi),
            Msp430Opcode::BIS => self.encode_double_op(0xD000, mi),
            Msp430Opcode::XOR => self.encode_double_op(0xE000, mi),
            Msp430Opcode::AND => self.encode_double_op(0xF000, mi),

            // Jumps
            Msp430Opcode::JNE => self.encode_jump(0x2000, mi),
            Msp430Opcode::JEQ => self.encode_jump(0x2400, mi),
            Msp430Opcode::JNC => self.encode_jump(0x2800, mi),
            Msp430Opcode::JC => self.encode_jump(0x2C00, mi),
            Msp430Opcode::JN => self.encode_jump(0x3000, mi),
            Msp430Opcode::JGE => self.encode_jump(0x3400, mi),
            Msp430Opcode::JL => self.encode_jump(0x3800, mi),
            Msp430Opcode::JMP => self.encode_jump(0x3C00, mi),

            // Emulated
            Msp430Opcode::CLR => self.encode_emulated_clr(mi),
            Msp430Opcode::NOP => 0x4303, // MOV #0, R3 (NOP via CG)
            Msp430Opcode::BR => self.encode_jump(0x3C00, mi),
            Msp430Opcode::RET => 0x4130, // MOV @SP+, PC
            Msp430Opcode::TST => self.encode_single_op(0x9000, mi),

            _ => 0x4303, // NOP
        }
    }

    fn encode_single_op(&self, base: u16, mi: &MachineInstr) -> u16 {
        let reg = Self::get_reg(mi, 0);
        base | (reg & 0x0F)
    }

    fn encode_double_op(&self, base: u16, mi: &MachineInstr) -> u16 {
        let src = Self::get_reg(mi, 0);
        let dst = Self::get_reg(mi, 1);
        base | (src << 8) | (dst & 0x0F)
    }

    fn encode_jump(&self, base: u16, _mi: &MachineInstr) -> u16 {
        let offset: u16 = 0; // Would be computed from target
        base | (offset & 0x03FF)
    }

    fn encode_emulated_clr(&self, mi: &MachineInstr) -> u16 {
        let reg = Self::get_reg(mi, 0);
        // CLR reg = MOV #0, reg
        0x4300 | (reg & 0x0F)
    }

    fn get_reg(mi: &MachineInstr, index: usize) -> u16 {
        mi.operands
            .get(index)
            .map(|op| match op {
                MachineOperand::Reg(vr) => (*vr & 0xF) as u16,
                MachineOperand::PhysReg(pr) => (*pr & 0xF) as u16,
                _ => 0,
            })
            .unwrap_or(0)
    }
}

fn get_msp430_opcode(opcode: u32) -> Msp430Opcode {
    match opcode {
        0 => Msp430Opcode::RRC,
        1 => Msp430Opcode::SWPB,
        2 => Msp430Opcode::RRA,
        3 => Msp430Opcode::SXT,
        4 => Msp430Opcode::PUSH,
        5 => Msp430Opcode::POP,
        6 => Msp430Opcode::CALL,
        7 => Msp430Opcode::RETI,
        10 => Msp430Opcode::MOV,
        11 => Msp430Opcode::ADD,
        12 => Msp430Opcode::ADDC,
        13 => Msp430Opcode::SUBC,
        14 => Msp430Opcode::SUB,
        15 => Msp430Opcode::CMP,
        16 => Msp430Opcode::DADD,
        17 => Msp430Opcode::BIT,
        18 => Msp430Opcode::BIC,
        19 => Msp430Opcode::BIS,
        20 => Msp430Opcode::XOR,
        21 => Msp430Opcode::AND,
        30 => Msp430Opcode::JNE,
        31 => Msp430Opcode::JEQ,
        32 => Msp430Opcode::JNC,
        33 => Msp430Opcode::JC,
        34 => Msp430Opcode::JN,
        35 => Msp430Opcode::JGE,
        36 => Msp430Opcode::JL,
        37 => Msp430Opcode::JMP,
        40 => Msp430Opcode::CLR,
        48 => Msp430Opcode::NOP,
        49 => Msp430Opcode::BR,
        50 => Msp430Opcode::RET,
        51 => Msp430Opcode::TST,
        52 => Msp430Opcode::INV,
        60 => Msp430Opcode::MOVA,
        61 => Msp430Opcode::CMPA,
        62 => Msp430Opcode::ADDA,
        63 => Msp430Opcode::SUBA,
        64 => Msp430Opcode::BRA,
        65 => Msp430Opcode::RETA,
        66 => Msp430Opcode::PUSHM,
        67 => Msp430Opcode::POPM,
        68 => Msp430Opcode::CALLA,
        _ => Msp430Opcode::NOP,
    }
}