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) {
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,
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),
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),
Msp430Opcode::CLR => self.encode_emulated_clr(mi),
Msp430Opcode::NOP => 0x4303, Msp430Opcode::BR => self.encode_jump(0x3C00, mi),
Msp430Opcode::RET => 0x4130, Msp430Opcode::TST => self.encode_single_op(0x9000, mi),
_ => 0x4303, }
}
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; base | (offset & 0x03FF)
}
fn encode_emulated_clr(&self, mi: &MachineInstr) -> u16 {
let reg = Self::get_reg(mi, 0);
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,
}
}