use super::mips_instr_info::MipsOpcode;
use super::mips_register_info::{MIPS_FPR_BASE, MIPS_GPR_BASE};
use crate::codegen::{MachineFunction, MachineInstr, MachineOperand};
const OP_SPECIAL: u32 = 0x00; const OP_REGIMM: u32 = 0x01; const OP_J: u32 = 0x02;
const OP_JAL: u32 = 0x03;
const OP_BEQ: u32 = 0x04;
const OP_BNE: u32 = 0x05;
const OP_BLEZ: u32 = 0x06;
const OP_BGTZ: u32 = 0x07;
const OP_ADDI: u32 = 0x08;
const OP_ADDIU: u32 = 0x09;
const OP_SLTI: u32 = 0x0A;
const OP_SLTIU: u32 = 0x0B;
const OP_ANDI: u32 = 0x0C;
const OP_ORI: u32 = 0x0D;
const OP_XORI: u32 = 0x0E;
const OP_LUI: u32 = 0x0F;
const OP_COP0: u32 = 0x10; const OP_COP1: u32 = 0x11; const OP_COP2: u32 = 0x12;
const OP_BEQL: u32 = 0x14;
const OP_BNEL: u32 = 0x15;
const OP_BLEZL: u32 = 0x16;
const OP_BGTZL: u32 = 0x17;
const OP_DADDI: u32 = 0x18;
const OP_DADDIU: u32 = 0x19;
const OP_LDL: u32 = 0x1A;
const OP_LDR: u32 = 0x1B;
const OP_SPECIAL2: u32 = 0x1C;
const OP_LB: u32 = 0x20;
const OP_LH: u32 = 0x21;
const OP_LWL: u32 = 0x22;
const OP_LW: u32 = 0x23;
const OP_LBU: u32 = 0x24;
const OP_LHU: u32 = 0x25;
const OP_LWR: u32 = 0x26;
const OP_LWU: u32 = 0x27;
const OP_SB: u32 = 0x28;
const OP_SH: u32 = 0x29;
const OP_SWL: u32 = 0x2A;
const OP_SW: u32 = 0x2B;
const OP_SDL: u32 = 0x2C;
const OP_SDR: u32 = 0x2D;
const OP_SWR: u32 = 0x2E;
const OP_CACHE: u32 = 0x2F;
const OP_LL: u32 = 0x30;
const OP_LWC1: u32 = 0x31;
const OP_LLD: u32 = 0x34;
const OP_LDC1: u32 = 0x35;
const OP_LD: u32 = 0x37;
const OP_SC: u32 = 0x38;
const OP_SWC1: u32 = 0x39;
const OP_SCD: u32 = 0x3C;
const OP_SDC1: u32 = 0x3D;
const OP_SD: u32 = 0x3F;
const F_SLL: u32 = 0x00;
const F_MOVCI: u32 = 0x01;
const F_SRL: u32 = 0x02;
const F_SRA: u32 = 0x03;
const F_SLLV: u32 = 0x04;
const F_SRLV: u32 = 0x06;
const F_SRAV: u32 = 0x07;
const F_JR: u32 = 0x08;
const F_JALR: u32 = 0x09;
const F_MFHI: u32 = 0x10;
const F_MTHI: u32 = 0x11;
const F_MFLO: u32 = 0x12;
const F_MTLO: u32 = 0x13;
const F_DSLLV: u32 = 0x14;
const F_DSRLV: u32 = 0x16;
const F_DSRAV: u32 = 0x17;
const F_MULT: u32 = 0x18;
const F_MULTU: u32 = 0x19;
const F_DIV: u32 = 0x1A;
const F_DIVU: u32 = 0x1B;
const F_DMULT: u32 = 0x1C;
const F_DMULTU: u32 = 0x1D;
const F_DDIV: u32 = 0x1E;
const F_DDIVU: u32 = 0x1F;
const F_ADD: u32 = 0x20;
const F_ADDU: u32 = 0x21;
const F_SUB: u32 = 0x22;
const F_SUBU: u32 = 0x23;
const F_AND: u32 = 0x24;
const F_OR: u32 = 0x25;
const F_XOR: u32 = 0x26;
const F_NOR: u32 = 0x27;
const F_SLT: u32 = 0x2A;
const F_SLTU: u32 = 0x2B;
const F_DADD: u32 = 0x2C;
const F_DADDU: u32 = 0x2D;
const F_DSUB: u32 = 0x2E;
const F_DSUBU: u32 = 0x2F;
const F_TGE: u32 = 0x30;
const F_TGEU: u32 = 0x31;
const F_TLT: u32 = 0x32;
const F_TLTU: u32 = 0x33;
const F_TEQ: u32 = 0x34;
const F_TNE: u32 = 0x36;
const F_DSLL: u32 = 0x38;
const F_DSRL: u32 = 0x3A;
const F_DSRA: u32 = 0x3B;
const F_DSLL32: u32 = 0x3C;
const F_DSRL32: u32 = 0x3E;
const F_DSRA32: u32 = 0x3F;
const FMT_S: u32 = 0x10; const FMT_D: u32 = 0x11; const FMT_W: u32 = 0x14;
const FF_ADD: u32 = 0x00;
const FF_SUB: u32 = 0x01;
const FF_MUL: u32 = 0x02;
const FF_DIV: u32 = 0x03;
const FF_SQRT: u32 = 0x04;
const FF_ABS: u32 = 0x05;
const FF_MOV: u32 = 0x06;
const FF_NEG: u32 = 0x07;
const FF_C_EQ: u32 = 0x32;
const FF_C_LT: u32 = 0x3C;
const FF_C_LE: u32 = 0x3E;
const FF_CVT_S: u32 = 0x20;
const FF_CVT_D: u32 = 0x21;
const FF_CVT_W: u32 = 0x24;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum InstrFormat {
R,
I,
J,
FpuR,
FpuCmp,
None,
}
pub struct MipsMCEncoder {
pub is_64bit: bool,
pub output: Vec<u8>,
}
impl MipsMCEncoder {
pub fn new(is_64bit: bool) -> Self {
Self {
is_64bit,
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);
u32_to_be_bytes(word)
}
pub fn encode_r_type(opcode: u32, rs: u32, rt: u32, rd: u32, shamt: u32, funct: u32) -> u32 {
(opcode << 26) | (rs << 21) | (rt << 16) | (rd << 11) | (shamt << 6) | funct
}
pub fn encode_i_type(opcode: u32, rs: u32, rt: u32, immediate: i32) -> u32 {
let imm = (immediate as u32) & 0xFFFF;
(opcode << 26) | (rs << 21) | (rt << 16) | imm
}
pub fn encode_j_type(opcode: u32, address: u32) -> u32 {
(opcode << 26) | (address & 0x3FFFFFF)
}
pub fn encode_fpu_r(fmt: u32, ft: u32, fs: u32, fd: u32, funct: u32) -> u32 {
(OP_COP1 << 26) | (fmt << 21) | (ft << 16) | (fs << 11) | (fd << 6) | funct
}
pub fn get_register_field(reg_id: u16) -> u8 {
if reg_id >= MIPS_GPR_BASE && reg_id < MIPS_GPR_BASE + 32 {
(reg_id - MIPS_GPR_BASE) as u8
} else if reg_id >= MIPS_FPR_BASE && reg_id < MIPS_FPR_BASE + 32 {
(reg_id - MIPS_FPR_BASE) as u8
} else {
0
}
}
pub fn encode_add(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_ADD)
}
pub fn encode_addu(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_ADDU)
}
pub fn encode_sub(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_SUB)
}
pub fn encode_subu(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_SUBU)
}
pub fn encode_and(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_AND)
}
pub fn encode_or(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_OR)
}
pub fn encode_xor(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_XOR)
}
pub fn encode_nor(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_NOR)
}
pub fn encode_slt(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_SLT)
}
pub fn encode_sltu(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_SLTU)
}
pub fn encode_sll(rd: u32, rt: u32, shamt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, 0, rt, rd, shamt & 0x1F, F_SLL)
}
pub fn encode_srl(rd: u32, rt: u32, shamt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, 0, rt, rd, shamt & 0x1F, F_SRL)
}
pub fn encode_sra(rd: u32, rt: u32, shamt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, 0, rt, rd, shamt & 0x1F, F_SRA)
}
pub fn encode_sllv(rd: u32, rt: u32, rs: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_SLLV)
}
pub fn encode_srlv(rd: u32, rt: u32, rs: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_SRLV)
}
pub fn encode_srav(rd: u32, rt: u32, rs: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_SRAV)
}
pub fn encode_mult(rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, 0, 0, F_MULT)
}
pub fn encode_multu(rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, 0, 0, F_MULTU)
}
pub fn encode_div(rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, 0, 0, F_DIV)
}
pub fn encode_divu(rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, 0, 0, F_DIVU)
}
pub fn encode_mfhi(rd: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, 0, 0, rd, 0, F_MFHI)
}
pub fn encode_mflo(rd: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, 0, 0, rd, 0, F_MFLO)
}
pub fn encode_mthi(rs: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, 0, 0, 0, F_MTHI)
}
pub fn encode_mtlo(rs: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, 0, 0, 0, F_MTLO)
}
pub fn encode_jr(rs: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, 0, 0, 0, F_JR)
}
pub fn encode_jalr(rd: u32, rs: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, 0, rd, 0, F_JALR)
}
pub fn encode_addi(rt: u32, rs: u32, imm: i32) -> u32 {
Self::encode_i_type(OP_ADDI, rs, rt, imm)
}
pub fn encode_addiu(rt: u32, rs: u32, imm: i32) -> u32 {
Self::encode_i_type(OP_ADDIU, rs, rt, imm)
}
pub fn encode_andi(rt: u32, rs: u32, imm: i32) -> u32 {
Self::encode_i_type(OP_ANDI, rs, rt, imm)
}
pub fn encode_ori(rt: u32, rs: u32, imm: i32) -> u32 {
Self::encode_i_type(OP_ORI, rs, rt, imm)
}
pub fn encode_xori(rt: u32, rs: u32, imm: i32) -> u32 {
Self::encode_i_type(OP_XORI, rs, rt, imm)
}
pub fn encode_slti(rt: u32, rs: u32, imm: i32) -> u32 {
Self::encode_i_type(OP_SLTI, rs, rt, imm)
}
pub fn encode_sltiu(rt: u32, rs: u32, imm: i32) -> u32 {
Self::encode_i_type(OP_SLTIU, rs, rt, imm)
}
pub fn encode_lui(rt: u32, imm: i32) -> u32 {
Self::encode_i_type(OP_LUI, 0, rt, imm)
}
pub fn encode_lw(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_LW, rs, rt, offset)
}
pub fn encode_lh(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_LH, rs, rt, offset)
}
pub fn encode_lhu(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_LHU, rs, rt, offset)
}
pub fn encode_lb(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_LB, rs, rt, offset)
}
pub fn encode_lbu(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_LBU, rs, rt, offset)
}
pub fn encode_ld(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_LD, rs, rt, offset)
}
pub fn encode_lwc1(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_LWC1, rs, rt, offset)
}
pub fn encode_ldc1(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_LDC1, rs, rt, offset)
}
pub fn encode_sw(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_SW, rs, rt, offset)
}
pub fn encode_sh(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_SH, rs, rt, offset)
}
pub fn encode_sb(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_SB, rs, rt, offset)
}
pub fn encode_sd(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_SD, rs, rt, offset)
}
pub fn encode_swc1(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_SWC1, rs, rt, offset)
}
pub fn encode_sdc1(rt: u32, rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_SDC1, rs, rt, offset)
}
pub fn encode_beq(rs: u32, rt: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_BEQ, rs, rt, offset)
}
pub fn encode_bne(rs: u32, rt: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_BNE, rs, rt, offset)
}
pub fn encode_blez(rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_BLEZ, rs, 0, offset)
}
pub fn encode_bgtz(rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_BGTZ, rs, 0, offset)
}
pub fn encode_bltz(rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_REGIMM, rs, 0, offset)
}
pub fn encode_bgez(rs: u32, offset: i32) -> u32 {
Self::encode_i_type(OP_REGIMM, rs, 1, offset)
}
pub fn encode_j(address: u32) -> u32 {
Self::encode_j_type(OP_J, address)
}
pub fn encode_jal(address: u32) -> u32 {
Self::encode_j_type(OP_JAL, address)
}
pub fn encode_add_s(fd: u32, fs: u32, ft: u32) -> u32 {
Self::encode_fpu_r(FMT_S, ft, fs, fd, FF_ADD)
}
pub fn encode_sub_s(fd: u32, fs: u32, ft: u32) -> u32 {
Self::encode_fpu_r(FMT_S, ft, fs, fd, FF_SUB)
}
pub fn encode_mul_s(fd: u32, fs: u32, ft: u32) -> u32 {
Self::encode_fpu_r(FMT_S, ft, fs, fd, FF_MUL)
}
pub fn encode_div_s(fd: u32, fs: u32, ft: u32) -> u32 {
Self::encode_fpu_r(FMT_S, ft, fs, fd, FF_DIV)
}
pub fn encode_mov_s(fd: u32, fs: u32) -> u32 {
Self::encode_fpu_r(FMT_S, 0, fs, fd, FF_MOV)
}
pub fn encode_neg_s(fd: u32, fs: u32) -> u32 {
Self::encode_fpu_r(FMT_S, 0, fs, fd, FF_NEG)
}
pub fn encode_abs_s(fd: u32, fs: u32) -> u32 {
Self::encode_fpu_r(FMT_S, 0, fs, fd, FF_ABS)
}
pub fn encode_add_d(fd: u32, fs: u32, ft: u32) -> u32 {
Self::encode_fpu_r(FMT_D, ft, fs, fd, FF_ADD)
}
pub fn encode_sub_d(fd: u32, fs: u32, ft: u32) -> u32 {
Self::encode_fpu_r(FMT_D, ft, fs, fd, FF_SUB)
}
pub fn encode_mul_d(fd: u32, fs: u32, ft: u32) -> u32 {
Self::encode_fpu_r(FMT_D, ft, fs, fd, FF_MUL)
}
pub fn encode_div_d(fd: u32, fs: u32, ft: u32) -> u32 {
Self::encode_fpu_r(FMT_D, ft, fs, fd, FF_DIV)
}
pub fn encode_dadd(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_DADD)
}
pub fn encode_daddu(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_DADDU)
}
pub fn encode_dsub(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_DSUB)
}
pub fn encode_dsubu(rd: u32, rs: u32, rt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, rs, rt, rd, 0, F_DSUBU)
}
pub fn encode_daddiu(rt: u32, rs: u32, imm: i32) -> u32 {
Self::encode_i_type(OP_DADDIU, rs, rt, imm)
}
pub fn encode_dsll(rd: u32, rt: u32, shamt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, 0, rt, rd, shamt & 0x1F, F_DSLL)
}
pub fn encode_dsrl(rd: u32, rt: u32, shamt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, 0, rt, rd, shamt & 0x1F, F_DSRL)
}
pub fn encode_dsra(rd: u32, rt: u32, shamt: u32) -> u32 {
Self::encode_r_type(OP_SPECIAL, 0, rt, rd, shamt & 0x1F, F_DSRA)
}
fn encode_by_opcode(&self, mi: &MachineInstr) -> u32 {
let op = mi.opcode;
let rd = self.extract_reg(mi, 0);
let rs = self.extract_reg(mi, 1);
let rt = self.extract_reg(mi, 2);
let imm2 = self.extract_imm(mi, 2);
let imm1 = self.extract_imm(mi, 1);
if op == MipsOpcode::ADD as u32 {
return Self::encode_add(rd, rs, rt);
}
if op == MipsOpcode::ADDU as u32 {
return Self::encode_addu(rd, rs, rt);
}
if op == MipsOpcode::SUB as u32 {
return Self::encode_sub(rd, rs, rt);
}
if op == MipsOpcode::SUBU as u32 {
return Self::encode_subu(rd, rs, rt);
}
if op == MipsOpcode::AND as u32 {
return Self::encode_and(rd, rs, rt);
}
if op == MipsOpcode::OR as u32 {
return Self::encode_or(rd, rs, rt);
}
if op == MipsOpcode::XOR as u32 {
return Self::encode_xor(rd, rs, rt);
}
if op == MipsOpcode::NOR as u32 {
return Self::encode_nor(rd, rs, rt);
}
if op == MipsOpcode::SLT as u32 {
return Self::encode_slt(rd, rs, rt);
}
if op == MipsOpcode::SLTU as u32 {
return Self::encode_sltu(rd, rs, rt);
}
if op == MipsOpcode::SLL as u32 {
return Self::encode_sll(rd, rs, imm2 as u32);
}
if op == MipsOpcode::SRL as u32 {
return Self::encode_srl(rd, rs, imm2 as u32);
}
if op == MipsOpcode::SRA as u32 {
return Self::encode_sra(rd, rs, imm2 as u32);
}
if op == MipsOpcode::SLLV as u32 {
return Self::encode_sllv(rd, rs, rt);
}
if op == MipsOpcode::SRLV as u32 {
return Self::encode_srlv(rd, rs, rt);
}
if op == MipsOpcode::SRAV as u32 {
return Self::encode_srav(rd, rs, rt);
}
if op == MipsOpcode::MULT as u32 {
return Self::encode_mult(rs, rt);
}
if op == MipsOpcode::MULTU as u32 {
return Self::encode_multu(rs, rt);
}
if op == MipsOpcode::DIV as u32 {
return Self::encode_div(rs, rt);
}
if op == MipsOpcode::DIVU as u32 {
return Self::encode_divu(rs, rt);
}
if op == MipsOpcode::MFHI as u32 {
return Self::encode_mfhi(rd);
}
if op == MipsOpcode::MFLO as u32 {
return Self::encode_mflo(rd);
}
if op == MipsOpcode::MTHI as u32 {
return Self::encode_mthi(rs);
}
if op == MipsOpcode::MTLO as u32 {
return Self::encode_mtlo(rs);
}
if op == MipsOpcode::JR as u32 {
return Self::encode_jr(rs);
}
if op == MipsOpcode::JALR as u32 {
return Self::encode_jalr(rd, rs);
}
if op == MipsOpcode::ADDI as u32 {
return Self::encode_addi(rd, rs, imm2);
}
if op == MipsOpcode::ADDIU as u32 {
return Self::encode_addiu(rd, rs, imm2);
}
if op == MipsOpcode::ANDI as u32 {
return Self::encode_andi(rd, rs, imm2);
}
if op == MipsOpcode::ORI as u32 {
return Self::encode_ori(rd, rs, imm2);
}
if op == MipsOpcode::XORI as u32 {
return Self::encode_xori(rd, rs, imm2);
}
if op == MipsOpcode::SLTI as u32 {
return Self::encode_slti(rd, rs, imm2);
}
if op == MipsOpcode::SLTIU as u32 {
return Self::encode_sltiu(rd, rs, imm2);
}
if op == MipsOpcode::LUI as u32 {
return Self::encode_lui(rd, imm2);
}
if op == MipsOpcode::LW as u32 {
return Self::encode_lw(rd, rs, imm2);
}
if op == MipsOpcode::LH as u32 {
return Self::encode_lh(rd, rs, imm2);
}
if op == MipsOpcode::LHU as u32 {
return Self::encode_lhu(rd, rs, imm2);
}
if op == MipsOpcode::LB as u32 {
return Self::encode_lb(rd, rs, imm2);
}
if op == MipsOpcode::LBU as u32 {
return Self::encode_lbu(rd, rs, imm2);
}
if op == MipsOpcode::LWC1 as u32 {
return Self::encode_lwc1(rd, rs, imm2);
}
if op == MipsOpcode::LDC1 as u32 {
return Self::encode_ldc1(rd, rs, imm2);
}
if op == MipsOpcode::SW as u32 {
return Self::encode_sw(rd, rs, imm2);
}
if op == MipsOpcode::SH as u32 {
return Self::encode_sh(rd, rs, imm2);
}
if op == MipsOpcode::SB as u32 {
return Self::encode_sb(rd, rs, imm2);
}
if op == MipsOpcode::SWC1 as u32 {
return Self::encode_swc1(rd, rs, imm2);
}
if op == MipsOpcode::SDC1 as u32 {
return Self::encode_sdc1(rd, rs, imm2);
}
if op == MipsOpcode::BEQ as u32 {
return Self::encode_beq(rs, rt, imm2);
}
if op == MipsOpcode::BNE as u32 {
return Self::encode_bne(rs, rt, imm2);
}
if op == MipsOpcode::BLEZ as u32 {
return Self::encode_blez(rs, imm2);
}
if op == MipsOpcode::BGTZ as u32 {
return Self::encode_bgtz(rs, imm2);
}
if op == MipsOpcode::BLTZ as u32 {
return Self::encode_bltz(rs, imm2);
}
if op == MipsOpcode::BGEZ as u32 {
return Self::encode_bgez(rs, imm2);
}
if op == MipsOpcode::J as u32 {
return Self::encode_j(imm1 as u32);
}
if op == MipsOpcode::JAL as u32 {
return Self::encode_jal(imm1 as u32);
}
if op == MipsOpcode::ADD_S as u32 {
return Self::encode_add_s(rd, rs, rt);
}
if op == MipsOpcode::SUB_S as u32 {
return Self::encode_sub_s(rd, rs, rt);
}
if op == MipsOpcode::MUL_S as u32 {
return Self::encode_mul_s(rd, rs, rt);
}
if op == MipsOpcode::DIV_S as u32 {
return Self::encode_div_s(rd, rs, rt);
}
if op == MipsOpcode::MOV_S as u32 {
return Self::encode_mov_s(rd, rs);
}
if op == MipsOpcode::NEG_S as u32 {
return Self::encode_neg_s(rd, rs);
}
if op == MipsOpcode::ABS_S as u32 {
return Self::encode_abs_s(rd, rs);
}
if op == MipsOpcode::ADD_D as u32 {
return Self::encode_add_d(rd, rs, rt);
}
if op == MipsOpcode::SUB_D as u32 {
return Self::encode_sub_d(rd, rs, rt);
}
if op == MipsOpcode::MUL_D as u32 {
return Self::encode_mul_d(rd, rs, rt);
}
if op == MipsOpcode::DIV_D as u32 {
return Self::encode_div_d(rd, rs, rt);
}
if op == MipsOpcode::DADD as u32 {
return Self::encode_dadd(rd, rs, rt);
}
if op == MipsOpcode::DADDU as u32 {
return Self::encode_daddu(rd, rs, rt);
}
if op == MipsOpcode::DSUB as u32 {
return Self::encode_dsub(rd, rs, rt);
}
if op == MipsOpcode::DSUBU as u32 {
return Self::encode_dsubu(rd, rs, rt);
}
if op == MipsOpcode::DADDIU as u32 {
return Self::encode_daddiu(rd, rs, imm2);
}
if op == MipsOpcode::DSLL as u32 {
return Self::encode_dsll(rd, rs, imm2 as u32);
}
if op == MipsOpcode::DSRL as u32 {
return Self::encode_dsrl(rd, rs, imm2 as u32);
}
if op == MipsOpcode::DSRA as u32 {
return Self::encode_dsra(rd, rs, imm2 as u32);
}
if op == MipsOpcode::LD as u32 {
return Self::encode_ld(rd, rs, imm2);
}
if op == MipsOpcode::SD as u32 {
return Self::encode_sd(rd, rs, imm2);
}
if op == MipsOpcode::NOP as u32 {
return Self::encode_sll(0, 0, 0);
}
if op == MipsOpcode::MOVE as u32 {
return Self::encode_addu(rd, rs, 0);
}
if op == MipsOpcode::LI as u32 {
return Self::encode_addiu(rd, 0, imm2);
}
if op == MipsOpcode::SYSCALL as u32 {
return Self::encode_r_type(OP_SPECIAL, 0, 0, 0, 0, 0x0C);
}
if op == MipsOpcode::BREAK as u32 {
return Self::encode_r_type(OP_SPECIAL, 0, 0, 0, 0, 0x0D);
}
if op == MipsOpcode::SYNC as u32 {
return Self::encode_r_type(OP_SPECIAL, 0, 0, 0, 0, 0x0F);
}
if op == MipsOpcode::ERET as u32 {
return Self::encode_r_type(OP_COP0, 0, 0, 0, 0, 0x18);
}
0
}
fn extract_reg(&self, mi: &MachineInstr, idx: usize) -> u32 {
mi.operands
.get(idx)
.and_then(|op| get_reg_field(op))
.unwrap_or(0) as u32
}
fn extract_imm(&self, mi: &MachineInstr, idx: usize) -> i32 {
mi.operands
.get(idx)
.and_then(|op| match op {
MachineOperand::Imm(v) => Some(*v as i32),
_ => None,
})
.unwrap_or(0)
}
}
fn get_reg_field(op: &MachineOperand) -> Option<u8> {
match op {
MachineOperand::Reg(vr) => Some(MipsMCEncoder::get_register_field(*vr as u16)),
MachineOperand::PhysReg(pr) => Some(MipsMCEncoder::get_register_field(*pr as u16)),
_ => None,
}
}
pub fn u32_to_be_bytes(word: u32) -> Vec<u8> {
vec![
((word >> 24) & 0xFF) as u8,
((word >> 16) & 0xFF) as u8,
((word >> 8) & 0xFF) as u8,
(word & 0xFF) as u8,
]
}
#[cfg(test)]
mod tests {
use super::*;
use crate::codegen::*;
fn mi_r(opcode: u32, rd: u16, rs: u16, rt: u16) -> MachineInstr {
let mut mi = MachineInstr::new(opcode);
mi.push_reg(rd as u32);
mi.push_reg(rs as u32);
mi.push_reg(rt as u32);
mi
}
fn mi_i(opcode: u32, rt: u16, rs: u16, imm: i32) -> MachineInstr {
let mut mi = MachineInstr::new(opcode);
mi.push_reg(rt as u32);
mi.push_reg(rs as u32);
mi.push_imm(imm as i64);
mi
}
fn be_bytes_to_u32(bytes: &[u8]) -> u32 {
((bytes[0] as u32) << 24)
| ((bytes[1] as u32) << 16)
| ((bytes[2] as u32) << 8)
| (bytes[3] as u32)
}
#[test]
fn test_encode_add() {
let word = MipsMCEncoder::encode_add(2, 4, 5); assert_eq!(word, 0x00851020); }
#[test]
fn test_encode_sub() {
let word = MipsMCEncoder::encode_sub(3, 4, 5);
assert_eq!(word, 0x00851822);
}
#[test]
fn test_encode_and() {
let word = MipsMCEncoder::encode_and(2, 4, 5);
assert_eq!(word, 0x00851024);
}
#[test]
fn test_encode_addi() {
let word = MipsMCEncoder::encode_addi(8, 9, 10);
assert_eq!(word, 0x2128000A);
}
#[test]
fn test_encode_lw() {
let word = MipsMCEncoder::encode_lw(2, 29, 0); assert_eq!(word, 0x8FA20000);
}
#[test]
fn test_encode_sw() {
let word = MipsMCEncoder::encode_sw(31, 29, 28); assert_eq!(word, 0xAFBF001C);
}
#[test]
fn test_encode_beq() {
let word = MipsMCEncoder::encode_beq(4, 5, 12);
let expected = (OP_BEQ << 26) | (4 << 21) | (5 << 16) | 12;
assert_eq!(word, expected);
}
#[test]
fn test_encode_bne() {
let word = MipsMCEncoder::encode_bne(4, 5, 8);
let expected = (OP_BNE << 26) | (4 << 21) | (5 << 16) | 8;
assert_eq!(word, expected);
}
#[test]
fn test_encode_j() {
let word = MipsMCEncoder::encode_j(0x400000 >> 2);
assert_eq!(word, (OP_J << 26) | (0x100000));
}
#[test]
fn test_encode_jal() {
let word = MipsMCEncoder::encode_jal(0x100000);
assert_eq!(word, (OP_JAL << 26) | 0x100000);
}
#[test]
fn test_encode_jr() {
let word = MipsMCEncoder::encode_jr(31); assert_eq!(word, 0x03E00008);
}
#[test]
fn test_encode_lui() {
let word = MipsMCEncoder::encode_lui(2, 0x1234);
assert_eq!(word, 0x3C021234);
}
#[test]
fn test_encode_mfhi() {
let word = MipsMCEncoder::encode_mfhi(2);
assert_eq!(word, 0x00001010);
}
#[test]
fn test_encode_mflo() {
let word = MipsMCEncoder::encode_mflo(2);
assert_eq!(word, 0x00001012);
}
#[test]
fn test_encode_nop() {
let word = MipsMCEncoder::encode_sll(0, 0, 0);
assert_eq!(word, 0x00000000);
}
#[test]
fn test_encode_sll() {
let word = MipsMCEncoder::encode_sll(2, 3, 4);
assert_eq!(word, 0x00031100);
}
#[test]
fn test_encode_add_s() {
let word = MipsMCEncoder::encode_add_s(0, 1, 2);
assert_eq!(word, 0x46020800);
}
#[test]
fn test_encode_add_d() {
let word = MipsMCEncoder::encode_add_d(0, 1, 2);
assert_eq!(word, 0x46220800);
}
#[test]
fn test_u32_to_be_bytes() {
let bytes = u32_to_be_bytes(0x12345678);
assert_eq!(bytes, vec![0x12, 0x34, 0x56, 0x78]);
}
#[test]
fn test_get_register_field() {
assert_eq!(MipsMCEncoder::get_register_field(4000), 0); assert_eq!(MipsMCEncoder::get_register_field(4031), 31); assert_eq!(MipsMCEncoder::get_register_field(4050), 0); assert_eq!(MipsMCEncoder::get_register_field(4081), 31); }
#[test]
fn test_encode_instruction_r_type() {
let mut encoder = MipsMCEncoder::new(false);
let mi = mi_r(MipsOpcode::ADD as u32, 4002, 4004, 4005);
let bytes = encoder.encode_instruction(&mi);
assert_eq!(bytes.len(), 4);
let word = be_bytes_to_u32(&bytes);
assert_eq!(word, 0x00851020);
}
#[test]
fn test_encode_instruction_i_type() {
let mut encoder = MipsMCEncoder::new(false);
let mi = mi_i(MipsOpcode::LW as u32, 4002, 4029, 0);
let bytes = encoder.encode_instruction(&mi);
assert_eq!(bytes.len(), 4);
let word = be_bytes_to_u32(&bytes);
assert_eq!(word, 0x8FA20000);
}
#[test]
fn test_encode_function() {
let mut encoder = MipsMCEncoder::new(false);
let mut mf = MachineFunction::new("test");
let mut bb = MachineBasicBlock {
name: "entry".into(),
instructions: Vec::new(),
successors: Vec::new(),
};
let mi1 = mi_r(MipsOpcode::ADD as u32, 4002, 4004, 4005);
bb.instructions.push(mi1);
let mi2 = mi_r(MipsOpcode::JR as u32, 4031, 0, 0);
bb.instructions.push(mi2);
mf.push_block(bb);
let bytes = encoder.encode_function(&mf);
assert_eq!(bytes.len(), 8);
}
#[test]
fn test_mips64_encoding() {
let mut encoder = MipsMCEncoder::new(true);
let mi = mi_r(MipsOpcode::DADD as u32, 4002, 4004, 4005);
let bytes = encoder.encode_instruction(&mi);
assert_eq!(bytes.len(), 4);
}
}