use super::ppc_instr_info::PpcOpcode;
use super::ppc_register_info::{PPC_FPR_BASE, PPC_GPR_BASE, PPC_VR_BASE};
use crate::codegen::{MachineFunction, MachineInstr, MachineOperand};
const OP_TDI: u32 = 0x02;
const OP_TWI: u32 = 0x03;
const OP_MULLI: u32 = 0x07;
const OP_SUBFIC: u32 = 0x08;
const OP_CMPLI: u32 = 0x0A;
const OP_CMPI: u32 = 0x0B;
const OP_ADDIC: u32 = 0x0C;
const OP_ADDICDOT: u32 = 0x0D;
const OP_ADDI: u32 = 0x0E;
const OP_ADDIS: u32 = 0x0F;
const OP_BC: u32 = 0x10;
const OP_SC: u32 = 0x11;
const OP_B: u32 = 0x12;
const OP_MCRF: u32 = 0x13;
const OP_RLWIMI: u32 = 0x14;
const OP_RLWINM: u32 = 0x15;
const OP_RLWNM: u32 = 0x17;
const OP_ORI: u32 = 0x18;
const OP_ORIS: u32 = 0x19;
const OP_XORI: u32 = 0x1A;
const OP_XORIS: u32 = 0x1B;
const OP_ANDIDOT: u32 = 0x1C;
const OP_ANDISDOT: u32 = 0x1D;
const OP_RLDICR: u32 = 0x1E;
const OP_LWZ: u32 = 0x20;
const OP_LWZU: u32 = 0x21;
const OP_LBZ: u32 = 0x22;
const OP_LBZU: u32 = 0x23;
const OP_STW: u32 = 0x24;
const OP_STWU: u32 = 0x25;
const OP_STB: u32 = 0x26;
const OP_STBU: u32 = 0x27;
const OP_LHZ: u32 = 0x28;
const OP_LHZU: u32 = 0x29;
const OP_LHA: u32 = 0x2A;
const OP_LHAU: u32 = 0x2B;
const OP_STH: u32 = 0x2C;
const OP_STHU: u32 = 0x2D;
const OP_LMW: u32 = 0x2E;
const OP_STMW: u32 = 0x2F;
const OP_LFS: u32 = 0x30;
const OP_LFD: u32 = 0x32;
const OP_STFS: u32 = 0x34;
const OP_STFD: u32 = 0x36;
const OP_LD: u32 = 0x3A;
const OP_LDU: u32 = 0x3B;
const OP_LWA: u32 = 0x3A; const OP_STD: u32 = 0x3E;
const OP_STDU: u32 = 0x3F;
const XO_CMP: u32 = 0x000;
const XO_SUBFC: u32 = 0x008;
const XO_ADDC: u32 = 0x00A;
const XO_MULHWU: u32 = 0x00B;
const XO_AND: u32 = 0x01C;
const XO_ANDC: u32 = 0x03C;
const XO_NOR: u32 = 0x07C;
const XO_EQV: u32 = 0x10C;
const XO_XOR: u32 = 0x13C;
const XO_ORC: u32 = 0x15C;
const XO_OR: u32 = 0x1BC;
const XO_NAND: u32 = 0x1DC;
const XO_ADD: u32 = 0x10A;
const XO_SUBF: u32 = 0x028;
const XO_NEG: u32 = 0x068;
const XO_MULLW: u32 = 0x0EB;
const XO_MULLD: u32 = 0x0E9;
const XO_DIVW: u32 = 0x1EB;
const XO_DIVD: u32 = 0x1E9;
const XO_SLW: u32 = 0x018;
const XO_SRW: u32 = 0x218;
const XO_SRAW: u32 = 0x318;
const XO_SLD: u32 = 0x01B;
const XO_SRD: u32 = 0x21B;
const XO_SRAD: u32 = 0x31A;
const XO_CNTLZW: u32 = 0x01A;
const XO_EXTSB: u32 = 0x3BA;
const XO_EXTSH: u32 = 0x39A;
const XO_EXTSW: u32 = 0x3DA;
const XO_MTSPR: u32 = 0x1D3;
const XO_MFSPR: u32 = 0x153;
const XO_MTCRF: u32 = 0x090;
const XO_MFCR: u32 = 0x013;
const XO_RLDICL: u32 = 0x01E;
const XO_BCLR: u32 = 0x010;
const XO_BCCTR: u32 = 0x210;
const XO_BC: u32 = 0x000;
const XO_FCMPU: u32 = 0x000;
const XO_FADD: u32 = 0x015;
const XO_FSUB: u32 = 0x014;
const XO_FMUL: u32 = 0x019;
const XO_FDIV: u32 = 0x012;
const XO_FMADD: u32 = 0x01D;
const XO_FMSUB: u32 = 0x01C;
const XO_FNMADD: u32 = 0x01F;
const XO_FNMSUB: u32 = 0x01E;
const SPR_LR: u32 = 0x008;
const SPR_CTR: u32 = 0x009;
pub struct PpcMCEncoder {
pub is_64bit: bool,
pub output: Vec<u8>,
}
impl PpcMCEncoder {
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_d_form(opcd: u32, rt: u32, ra: u32, d: i32) -> u32 {
let simm = (d as u32) & 0xFFFF;
(opcd << 26) | ((rt & 0x1F) << 21) | ((ra & 0x1F) << 16) | simm
}
pub fn encode_x_form(opcd: u32, rt: u32, ra: u32, rb: u32, xo: u32, rc: u32) -> u32 {
(opcd << 26)
| ((rt & 0x1F) << 21)
| ((ra & 0x1F) << 16)
| ((rb & 0x1F) << 11)
| ((xo & 0x3FF) << 1)
| (rc & 1)
}
pub fn encode_xl_form(opcd: u32, bt: u32, ba: u32, bb: u32, xo: u32, lk: u32) -> u32 {
(opcd << 26)
| ((bt & 0x1F) << 21)
| ((ba & 0x1F) << 16)
| ((bb & 0x1F) << 11)
| ((xo & 0x3FF) << 1)
| (lk & 1)
}
pub fn encode_b_form(opcd: u32, li: i32, aa: u32, lk: u32) -> u32 {
let li_bits = (li as u32) & 0xFFFFFF;
(opcd << 26) | ((li_bits & 0x3FFFFFC) >> 2) | ((aa & 1) << 1) | (lk & 1)
}
pub fn get_register_field(reg_id: u16) -> u8 {
if reg_id >= PPC_GPR_BASE && reg_id < PPC_GPR_BASE + 32 {
(reg_id - PPC_GPR_BASE) as u8
} else if reg_id >= PPC_FPR_BASE && reg_id < PPC_FPR_BASE + 32 {
(reg_id - PPC_FPR_BASE) as u8
} else if reg_id >= PPC_VR_BASE && reg_id < PPC_VR_BASE + 32 {
(reg_id - PPC_VR_BASE) as u8
} else {
0
}
}
pub fn encode_add(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_ADD, 0)
}
pub fn encode_subf(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_SUBF, 0)
}
pub fn encode_mullw(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_MULLW, 0)
}
pub fn encode_mulld(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_MULLD, 0)
}
pub fn encode_divw(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_DIVW, 0)
}
pub fn encode_divd(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_DIVD, 0)
}
pub fn encode_and(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_AND, 0)
}
pub fn encode_or(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_OR, 0)
}
pub fn encode_xor(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_XOR, 0)
}
pub fn encode_nor(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_NOR, 0)
}
pub fn encode_slw(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_SLW, 0)
}
pub fn encode_srw(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_SRW, 0)
}
pub fn encode_sraw(rt: u32, ra: u32, rb: u32) -> u32 {
Self::encode_x_form(0x1F, rt, ra, rb, XO_SRAW, 0)
}
pub fn encode_addi(rt: u32, ra: u32, imm: i32) -> u32 {
Self::encode_d_form(OP_ADDI, rt, ra, imm)
}
pub fn encode_addis(rt: u32, ra: u32, imm: i32) -> u32 {
Self::encode_d_form(OP_ADDIS, rt, ra, imm)
}
pub fn encode_cmpwi(cr: u32, ra: u32, imm: i32) -> u32 {
Self::encode_d_form(OP_CMPI, cr, ra, imm)
}
pub fn encode_lwz(rt: u32, ra: u32, d: i32) -> u32 {
Self::encode_d_form(OP_LWZ, rt, ra, d)
}
pub fn encode_lbz(rt: u32, ra: u32, d: i32) -> u32 {
Self::encode_d_form(OP_LBZ, rt, ra, d)
}
pub fn encode_lhz(rt: u32, ra: u32, d: i32) -> u32 {
Self::encode_d_form(OP_LHZ, rt, ra, d)
}
pub fn encode_lha(rt: u32, ra: u32, d: i32) -> u32 {
Self::encode_d_form(OP_LHA, rt, ra, d)
}
pub fn encode_ld(rt: u32, ra: u32, d: i32) -> u32 {
Self::encode_d_form(OP_LD, rt, ra, d)
}
pub fn encode_stw(rs: u32, ra: u32, d: i32) -> u32 {
Self::encode_d_form(OP_STW, rs, ra, d)
}
pub fn encode_stb(rs: u32, ra: u32, d: i32) -> u32 {
Self::encode_d_form(OP_STB, rs, ra, d)
}
pub fn encode_sth(rs: u32, ra: u32, d: i32) -> u32 {
Self::encode_d_form(OP_STH, rs, ra, d)
}
pub fn encode_std(rs: u32, ra: u32, d: i32) -> u32 {
Self::encode_d_form(OP_STD, rs, ra, d)
}
pub fn encode_b(li: i32) -> u32 {
Self::encode_b_form(OP_B, li, 0, 0)
}
pub fn encode_bl(li: i32) -> u32 {
Self::encode_b_form(OP_B, li, 0, 1)
}
pub fn encode_bc(bo: u32, bi: u32, target: i32) -> u32 {
(OP_BC << 26) | ((bo & 0x1F) << 21) | ((bi & 0x1F) << 16) | ((target as u32) & 0xFFFC)
}
pub fn encode_bclr(bo: u32, bi: u32, lk: u32) -> u32 {
Self::encode_xl_form(0x13, bo, bi, 0, XO_BCLR, lk)
}
pub fn encode_bcctr(bo: u32, bi: u32) -> u32 {
Self::encode_xl_form(0x13, bo, bi, 0, XO_BCCTR, 0)
}
pub fn encode_mfspr(rt: u32, spr: u32) -> u32 {
let spr_encoded = ((spr & 0x1F) << 5) | ((spr >> 5) & 0x1F);
Self::encode_x_form(0x1F, rt, spr_encoded >> 5, spr_encoded & 0x1F, XO_MFSPR, 0)
}
pub fn encode_mtspr(spr: u32, rs: u32) -> u32 {
let spr_encoded = ((spr & 0x1F) << 5) | ((spr >> 5) & 0x1F);
Self::encode_x_form(0x1F, rs, spr_encoded >> 5, spr_encoded & 0x1F, XO_MTSPR, 0)
}
pub fn encode_fadd(ft: u32, fa: u32, fb: u32) -> u32 {
Self::encode_x_form(0x3F, ft, fa, fb, XO_FADD, 0)
}
pub fn encode_fsub(ft: u32, fa: u32, fb: u32) -> u32 {
Self::encode_x_form(0x3F, ft, fa, fb, XO_FSUB, 0)
}
pub fn encode_fmul(ft: u32, fa: u32, fb: u32) -> u32 {
Self::encode_x_form(0x3F, ft, fa, fb, XO_FMUL, 0)
}
fn encode_by_opcode(&self, mi: &MachineInstr) -> u32 {
let op = mi.opcode;
let rd = self.extract_reg(mi, 0);
let ra = self.extract_reg(mi, 1);
let rb = self.extract_reg(mi, 2);
let imm2 = self.extract_imm(mi, 2);
let imm1 = self.extract_imm(mi, 1);
if op == PpcOpcode::ADD as u32 {
return Self::encode_add(rd, ra, rb);
}
if op == PpcOpcode::SUBF as u32 {
return Self::encode_subf(rd, ra, rb);
}
if op == PpcOpcode::MULLW as u32 {
return Self::encode_mullw(rd, ra, rb);
}
if op == PpcOpcode::MULLD as u32 {
return Self::encode_mulld(rd, ra, rb);
}
if op == PpcOpcode::DIVW as u32 {
return Self::encode_divw(rd, ra, rb);
}
if op == PpcOpcode::DIVD as u32 {
return Self::encode_divd(rd, ra, rb);
}
if op == PpcOpcode::AND as u32 {
return Self::encode_and(rd, ra, rb);
}
if op == PpcOpcode::OR as u32 {
return Self::encode_or(rd, ra, rb);
}
if op == PpcOpcode::XOR as u32 {
return Self::encode_xor(rd, ra, rb);
}
if op == PpcOpcode::NOR as u32 {
return Self::encode_nor(rd, ra, rb);
}
if op == PpcOpcode::SLW as u32 {
return Self::encode_slw(rd, ra, rb);
}
if op == PpcOpcode::SRW as u32 {
return Self::encode_srw(rd, ra, rb);
}
if op == PpcOpcode::SRAW as u32 {
return Self::encode_sraw(rd, ra, rb);
}
if op == PpcOpcode::ADDI as u32 {
return Self::encode_addi(rd, ra, imm2);
}
if op == PpcOpcode::LWZ as u32 {
return Self::encode_lwz(rd, ra, imm2);
}
if op == PpcOpcode::LBZ as u32 {
return Self::encode_lbz(rd, ra, imm2);
}
if op == PpcOpcode::LHZ as u32 {
return Self::encode_lhz(rd, ra, imm2);
}
if op == PpcOpcode::LHA as u32 {
return Self::encode_lha(rd, ra, imm2);
}
if op == PpcOpcode::LD as u32 {
return Self::encode_ld(rd, ra, imm2);
}
if op == PpcOpcode::STW as u32 {
return Self::encode_stw(rd, ra, imm2);
}
if op == PpcOpcode::STB as u32 {
return Self::encode_stb(rd, ra, imm2);
}
if op == PpcOpcode::STH as u32 {
return Self::encode_sth(rd, ra, imm2);
}
if op == PpcOpcode::STD as u32 {
return Self::encode_std(rd, ra, imm2);
}
if op == PpcOpcode::B as u32 {
return Self::encode_b(imm1);
}
if op == PpcOpcode::BL as u32 {
return Self::encode_bl(imm1);
}
if op == PpcOpcode::BCLR as u32 {
return Self::encode_bclr(20, 0, 0);
}
if op == PpcOpcode::MTLR as u32 {
return Self::encode_mtspr(SPR_LR, rd);
}
if op == PpcOpcode::MFLR as u32 {
return Self::encode_mfspr(rd, SPR_LR);
}
if op == PpcOpcode::MTCTR as u32 {
return Self::encode_mtspr(SPR_CTR, rd);
}
if op == PpcOpcode::MFCTR as u32 {
return Self::encode_mfspr(rd, SPR_CTR);
}
if op == PpcOpcode::FADD as u32 {
return Self::encode_fadd(rd, ra, rb);
}
if op == PpcOpcode::FSUB as u32 {
return Self::encode_fsub(rd, ra, rb);
}
if op == PpcOpcode::FMUL as u32 {
return Self::encode_fmul(rd, ra, rb);
}
if op == PpcOpcode::MR as u32 {
return Self::encode_or(rd, ra, ra);
}
if op == PpcOpcode::LI as u32 {
return Self::encode_addi(rd, 0, imm2);
}
if op == PpcOpcode::LIS as u32 {
return Self::encode_addis(rd, 0, imm2);
}
if op == PpcOpcode::NOP as u32 {
return Self::encode_x_form(0x18, 0, 0, 0, 0, 0);
}
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(PpcMCEncoder::get_register_field(*vr as u16)),
MachineOperand::PhysReg(pr) => Some(PpcMCEncoder::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,
]
}
pub fn u64_to_be_bytes(word: u64) -> Vec<u8> {
vec![
((word >> 56) & 0xFF) as u8,
((word >> 48) & 0xFF) as u8,
((word >> 40) & 0xFF) as u8,
((word >> 32) & 0xFF) as u8,
((word >> 24) & 0xFF) as u8,
((word >> 16) & 0xFF) as u8,
((word >> 8) & 0xFF) as u8,
(word & 0xFF) as u8,
]
}
pub fn encode_ds_form(opcd: u32, rt: u32, ra: u32, ds: i32, xo: u32) -> u32 {
let ds_field = ((ds as u32) & 0x3FFF);
(opcd << 26) | ((rt & 0x1F) << 21) | ((ra & 0x1F) << 16) | (ds_field << 2) | (xo & 0x3)
}
pub fn encode_xfx_form(opcd: u32, rt: u32, spr: u32, xo: u32, rc: u32) -> u32 {
(opcd << 26)
| ((rt & 0x1F) << 21)
| (((spr >> 5) & 0x1F) << 16)
| (((spr & 0x1F) << 11) as u32)
| ((xo & 0x3FF) << 1)
| (rc & 1)
}
pub fn encode_xfl_form(opcd: u32, bf: u32, bfa: u32, bfb: u32, xo: u32, rc: u32) -> u32 {
(opcd << 26)
| ((bf & 0x7) << 23)
| (1 << 22)
| ((bfa & 0x7) << 18)
| (1 << 17)
| ((bfb & 0x7) << 12)
| ((xo & 0x3FF) << 1)
| (rc & 1)
}
pub fn encode_xs_form(opcd: u32, xt: u32, xa: u32, xb: u32, xo: u32, rc: u32) -> u32 {
(opcd << 26)
| ((xt & 0x1F) << 21)
| ((xa & 0x1F) << 16)
| ((xb & 0x1F) << 11)
| ((xo & 0x3FF) << 1)
| (rc & 1)
}
pub fn encode_xo_form(opcd: u32, xt: u32, xa: u32, xb: u32, xo: u32, sh: u32, rc: u32) -> u32 {
(opcd << 26)
| ((xt & 0x1F) << 21)
| ((xa & 0x1F) << 16)
| ((xb & 0x1F) << 11)
| (((xo >> 1) & 0x1FF) << 2)
| ((sh & 1) << 1)
| (rc & 1)
}
pub fn encode_i_form(opcd: u32, li: i32, aa: u32, lk: u32) -> u32 {
let li_bits = (li as u32) & 0xFFFFFF;
(opcd << 26) | (li_bits & 0xFF_FFFFFC) | ((aa & 1) << 1) | (lk & 1)
}
pub fn encode_sc_form(opcd: u32, lev: u32) -> u32 {
(opcd << 26) | ((lev & 0x7F) << 5) | 0x2
}
pub fn encode_a_form(opcd: u32, frt: u32, fra: u32, frb: u32, frc: u32, xo: u32, rc: u32) -> u32 {
(opcd << 26)
| ((frt & 0x1F) << 21)
| ((fra & 0x1F) << 16)
| ((frb & 0x1F) << 11)
| ((frc & 0x1F) << 6)
| ((xo & 0x1F) << 1)
| (rc & 1)
}
pub fn encode_md_form(
opcd: u32,
rt: u32,
ra: u32,
sh: u32,
mb: u32,
xo: u32,
sh_flag: u32,
rc: u32,
) -> u32 {
(opcd << 26)
| ((rt & 0x1F) << 21)
| ((ra & 0x1F) << 16)
| ((sh & 0x1F) << 11)
| (((sh >> 5) & 1) << 10)
| ((mb & 0x1F) << 6)
| (((mb >> 5) & 1) << 5)
| ((xo & 0x7) << 2)
| ((sh_flag & 1) << 1)
| (rc & 1)
}
pub fn encode_m_form(opcd: u32, rs: u32, ra: u32, sh: u32, mb: u32, me: u32, rc: u32) -> u32 {
(opcd << 26)
| ((rs & 0x1F) << 21)
| ((ra & 0x1F) << 16)
| ((sh & 0x1F) << 11)
| ((mb & 0x1F) << 6)
| ((me & 0x1F) << 1)
| (rc & 1)
}
pub fn encode_mds_form(opcd: u32, rt: u32, ra: u32, ds: i32, xo: u32) -> u32 {
encode_ds_form(opcd, rt, ra, ds, xo)
}
pub fn encode_xx1_form(opcd: u32, xt: u32, xb: u32, xo: u32) -> u32 {
(opcd << 26) | ((xt & 0x1F) << 21) | ((xb & 0x1F) << 11) | ((xo & 0x3FF) << 1)
}
pub fn encode_xx2_form(opcd: u32, xt: u32, xa: u32, xb: u32, xo: u32) -> u32 {
(opcd << 26)
| ((xt & 0x1F) << 21)
| ((xa & 0x1F) << 16)
| ((xb & 0x1F) << 11)
| ((xo & 0x3FF) << 1)
}
pub fn encode_xx3_form(opcd: u32, xt: u32, xa: u32, xb: u32, xc: u32, xo: u32) -> u32 {
(opcd << 26)
| ((xt & 0x1F) << 21)
| ((xa & 0x1F) << 16)
| ((xb & 0x1F) << 11)
| ((xc & 0x1F) << 6)
| ((xo & 0x3FF) << 1)
}
pub fn encode_xx4_form(opcd: u32, xt: u32, xa: u32, xb: u32, xc: u32, xo: u32) -> u32 {
(opcd << 26)
| ((xt & 0x1F) << 21)
| ((xa & 0x1F) << 16)
| ((xb & 0x1F) << 11)
| ((xc & 0x1F) << 6)
| ((xo & 0x1F) << 1)
}
pub const VSX_XX1_OPCD: u32 = 0x3C;
pub const VSX_XX2_OPCD: u32 = 0x3C;
pub const VSX_XX3_OPCD: u32 = 0x3C;
pub const VSX_XX4_OPCD: u32 = 0x3C;
const XO_XSADDSP: u32 = 0x00;
const XO_XSSUBSP: u32 = 0x28;
const XO_XSMULSP: u32 = 0x08;
const XO_XSDIVSP: u32 = 0x18;
const XO_XSADDDP: u32 = 0x20;
const XO_XSSUBDP: u32 = 0x2C;
const XO_XSMULDP: u32 = 0x0C;
const XO_XSDIVDP: u32 = 0x1C;
const XO_XSMADDASP: u32 = 0x04;
const XO_XSMADDMSP: u32 = 0x06;
const XO_XSMSUBASP: u32 = 0x24;
const XO_XSMSUBMSP: u32 = 0x26;
const XO_XSMADDADP: u32 = 0x24;
const XO_XSMADDMDP: u32 = 0x26;
const XO_XSMSUBADP: u32 = 0x04;
const XO_XSMSUBMDP: u32 = 0x06;
const XO_XVADDSP: u32 = 0x100;
const XO_XVSUBSP: u32 = 0x128;
const XO_XVMULSP: u32 = 0x108;
const XO_XVDIVSP: u32 = 0x118;
const XO_XVADDDP: u32 = 0x120;
const XO_XVSUBDP: u32 = 0x12C;
const XO_XVMULDP: u32 = 0x10C;
const XO_XVDIVDP: u32 = 0x11C;
const XO_XVMADDASP: u32 = 0x104;
const XO_XVMADDMSP: u32 = 0x106;
const XO_XVMSUBASP: u32 = 0x124;
const XO_XVMSUBMSP: u32 = 0x126;
const XO_XVMADDMDP: u32 = 0x126;
const XO_XVMSUBADP: u32 = 0x104;
const XO_XVMSUBMDP: u32 = 0x106;
const XO_XXSPLTIB: u32 = 0x168;
impl PpcMCEncoder {
pub fn encode_xsaddsp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx2_form(VSX_XX2_OPCD, xt, xa, xb, XO_XSADDSP)
}
pub fn encode_xssubsp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx2_form(VSX_XX2_OPCD, xt, xa, xb, XO_XSSUBSP)
}
pub fn encode_xsmulsp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx2_form(VSX_XX2_OPCD, xt, xa, xb, XO_XSMULSP)
}
pub fn encode_xsdivsp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx2_form(VSX_XX2_OPCD, xt, xa, xb, XO_XSDIVSP)
}
pub fn encode_xsadddp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx2_form(VSX_XX2_OPCD, xt, xa, xb, XO_XSADDDP)
}
pub fn encode_xssubdp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx2_form(VSX_XX2_OPCD, xt, xa, xb, XO_XSSUBDP)
}
pub fn encode_xsmuldp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx2_form(VSX_XX2_OPCD, xt, xa, xb, XO_XSMULDP)
}
pub fn encode_xsdivdp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx2_form(VSX_XX2_OPCD, xt, xa, xb, XO_XSDIVDP)
}
pub fn encode_xsmaddasp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XSMADDASP)
}
pub fn encode_xsmaddmsp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XSMADDMSP)
}
pub fn encode_xsmsubasp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XSMSUBASP)
}
pub fn encode_xsmsubmsp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XSMSUBMSP)
}
pub fn encode_xsmaddadp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XSMADDADP)
}
pub fn encode_xsmaddmdp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XSMADDMDP)
}
pub fn encode_xsmsubadp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XSMSUBADP)
}
pub fn encode_xsmsubmdp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XSMSUBMDP)
}
pub fn encode_xvaddsp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, 0, XO_XVADDSP)
}
pub fn encode_xvsubsp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, 0, XO_XVSUBSP)
}
pub fn encode_xvmulsp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, 0, XO_XVMULSP)
}
pub fn encode_xvdivsp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, 0, XO_XVDIVSP)
}
pub fn encode_xvadddp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, 0, XO_XVADDDP)
}
pub fn encode_xvsubdp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, 0, XO_XVSUBDP)
}
pub fn encode_xvmuldp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, 0, XO_XVMULDP)
}
pub fn encode_xvdivdp(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, 0, XO_XVDIVDP)
}
pub fn encode_xvmaddasp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XVMADDASP)
}
pub fn encode_xvmaddmsp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XVMADDMSP)
}
pub fn encode_xvmsubasp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XVMSUBASP)
}
pub fn encode_xvmsubmsp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XVMSUBMSP)
}
pub fn encode_xvmaddmdp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XVMADDMDP)
}
pub fn encode_xvmsubadp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XVMSUBADP)
}
pub fn encode_xvmsubmdp(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, XO_XVMSUBMDP)
}
pub fn encode_xxpermdi(xt: u32, xa: u32, xb: u32, dm: u32) -> u32 {
let xo = ((dm & 0x3) << 8) | 0x1; encode_xx2_form(VSX_XX2_OPCD, xt, xa, xb, xo)
}
pub fn encode_xxspltw(xt: u32, xb: u32, uim: u32) -> u32 {
let xo = ((uim & 0x3) << 8) | 0x2A;
encode_xx2_form(VSX_XX2_OPCD, xt, 0, xb, xo)
}
pub fn encode_xxmrghw(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx2_form(VSX_XX2_OPCD, xt, xa, xb, 0x62)
}
pub fn encode_xxmrglw(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx2_form(VSX_XX2_OPCD, xt, xa, xb, 0x262)
}
pub fn encode_xxperm(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, 0x2B)
}
pub fn encode_xxspltib(xt: u32, imm: u8) -> u32 {
let xo = ((imm as u32) << 2) | XO_XXSPLTIB;
encode_xx1_form(VSX_XX1_OPCD, xt, 0, xo)
}
pub fn encode_xxlxor(xt: u32, xa: u32, xb: u32) -> u32 {
encode_xx2_form(VSX_XX2_OPCD, xt, xa, xb, 0x218)
}
pub fn encode_xxsel(xt: u32, xa: u32, xb: u32, xc: u32) -> u32 {
encode_xx3_form(VSX_XX3_OPCD, xt, xa, xb, xc, 0x2F)
}
pub fn encode_lxv(xt: u32, ra: u32, rb: u32) -> u32 {
PpcMCEncoder::encode_x_form(0x1F, xt, ra, rb, 0x318, 0)
}
pub fn encode_stxv(xs: u32, ra: u32, rb: u32) -> u32 {
PpcMCEncoder::encode_x_form(0x1F, xs, ra, rb, 0x398, 0)
}
pub fn encode_lxvl(xt: u32, ra: u32, rb: u32) -> u32 {
PpcMCEncoder::encode_x_form(0x1F, xt, ra, rb, 0x319, 0)
}
pub fn encode_stxvl(xs: u32, ra: u32, rb: u32) -> u32 {
PpcMCEncoder::encode_x_form(0x1F, xs, ra, rb, 0x399, 0)
}
pub fn encode_lxvll(xt: u32, ra: u32, rb: u32) -> u32 {
PpcMCEncoder::encode_x_form(0x1F, xt, ra, rb, 0x31B, 0)
}
pub fn encode_stxvll(xs: u32, ra: u32, rb: u32) -> u32 {
PpcMCEncoder::encode_x_form(0x1F, xs, ra, rb, 0x39B, 0)
}
pub fn encode_lxvdsx(xt: u32, ra: u32, rb: u32) -> u32 {
PpcMCEncoder::encode_x_form(0x1F, xt, ra, rb, 0x352, 0)
}
}
pub fn encode_prefix_word(m_type: u8, r: u8, st1: u16, r2: u8, st0: u16) -> u32 {
((m_type as u32) << 30)
| ((r as u32 & 1) << 20)
| (((st1 as u32) & 0x3FFF) << 6)
| ((r2 as u32 & 1) << 5)
| ((st0 as u32) & 0x1F)
}
pub fn encode_prefixed_instr(prefix_word: u32, suffix_word: u32) -> Vec<u8> {
let mut bytes = u32_to_be_bytes(prefix_word);
bytes.extend_from_slice(&u32_to_be_bytes(suffix_word));
bytes
}
impl PpcMCEncoder {
pub fn encode_pli(rt: u32, imm: i64) -> Vec<u8> {
let si34 = imm as i64;
let r = ((si34 >> 33) & 1) as u8; let st1 = (((si34 >> 16) & 0x3FFFF) as u16); let st0 = ((si34 & 0xFFFF) as u16);
let prefix = encode_prefix_word(0b00, r, st1, 0, st0);
let suffix = PpcMCEncoder::encode_d_form(OP_ADDI, rt, 0, st0 as i32);
encode_prefixed_instr(prefix, suffix)
}
pub fn encode_paddi(rt: u32, ra: u32, imm: i64) -> Vec<u8> {
let si34 = imm as i64;
let r = ((si34 >> 33) & 1) as u8;
let st1 = (((si34 >> 16) & 0x3FFFF) as u16);
let st0 = ((si34 & 0xFFFF) as u16);
let prefix = encode_prefix_word(0b00, r, st1, 0, st0);
let suffix = PpcMCEncoder::encode_d_form(OP_ADDI, rt, ra, st0 as i32);
encode_prefixed_instr(prefix, suffix)
}
pub fn encode_psubi(rt: u32, ra: u32, imm: i64) -> Vec<u8> {
let si34 = -imm;
Self::encode_paddi(rt, ra, si34)
}
pub fn encode_plwz(rt: u32, ra: u32, d: i32) -> Vec<u8> {
let r = ((d as i64 >> 33) & 1) as u8;
let st1 = ((((d as i64) >> 16) & 0x3FFFF) as u16);
let st0 = ((d as u32 & 0xFFFF) as u16);
let prefix = encode_prefix_word(0b10, r, st1, 0, st0);
let suffix = PpcMCEncoder::encode_d_form(OP_LWZ, rt, ra, d & 0xFFFF);
encode_prefixed_instr(prefix, suffix)
}
pub fn encode_pstw(rs: u32, ra: u32, d: i32) -> Vec<u8> {
let r = ((d as i64 >> 33) & 1) as u8;
let st1 = ((((d as i64) >> 16) & 0x3FFFF) as u16);
let st0 = ((d as u32 & 0xFFFF) as u16);
let prefix = encode_prefix_word(0b10, r, st1, 0, st0);
let suffix = PpcMCEncoder::encode_d_form(OP_STW, rs, ra, d & 0xFFFF);
encode_prefixed_instr(prefix, suffix)
}
pub fn encode_pld(rt: u32, ra: u32, d: i32) -> Vec<u8> {
let r = ((d as i64 >> 33) & 1) as u8;
let st1 = ((((d as i64) >> 16) & 0x3FFFF) as u16);
let st0 = ((d as u32 & 0xFFFF) as u16);
let prefix = encode_prefix_word(0b10, r, st1, 0, st0);
let suffix = encode_ds_form(OP_LOAD_58, rt, ra, (d & 0xFFFC), 0);
encode_prefixed_instr(prefix, suffix)
}
pub fn encode_pstd(rs: u32, ra: u32, d: i32) -> Vec<u8> {
let r = ((d as i64 >> 33) & 1) as u8;
let st1 = ((((d as i64) >> 16) & 0x3FFFF) as u16);
let st0 = ((d as u32 & 0xFFFF) as u16);
let prefix = encode_prefix_word(0b10, r, st1, 0, st0);
let suffix = encode_ds_form(OP_STORE_62, rs, ra, (d & 0xFFFC), 0);
encode_prefixed_instr(prefix, suffix)
}
}
const OP_LOAD_58: u32 = 58;
const OP_STORE_62: u32 = 62;
pub fn encode_vle_16bit(opcd5: u8, sub_op: u16) -> u16 {
((opcd5 as u16) << 11) | (sub_op & 0x7FF)
}
pub enum VlePrimaryOpcode {
SeAddi = 0x00, SeAddic = 0x01, SeAddis = 0x02, SeCmpi = 0x03, SeLi = 0x04, SeB = 0x05, SeBc = 0x06, SeLwz = 0x08, SeStw = 0x09, SeLhz = 0x0A, SeSth = 0x0B, SeLbz = 0x0C, SeStb = 0x0D, SeAndi = 0x10, SeOri = 0x11, SeXori = 0x12, SeMr = 0x13, SeRfi = 0x14, }
impl VlePrimaryOpcode {
pub fn to_u8(self) -> u8 {
match self {
VlePrimaryOpcode::SeAddi => 0x00,
VlePrimaryOpcode::SeAddic => 0x01,
VlePrimaryOpcode::SeAddis => 0x02,
VlePrimaryOpcode::SeCmpi => 0x03,
VlePrimaryOpcode::SeLi => 0x04,
VlePrimaryOpcode::SeB => 0x05,
VlePrimaryOpcode::SeBc => 0x06,
VlePrimaryOpcode::SeLwz => 0x08,
VlePrimaryOpcode::SeStw => 0x09,
VlePrimaryOpcode::SeLhz => 0x0A,
VlePrimaryOpcode::SeSth => 0x0B,
VlePrimaryOpcode::SeLbz => 0x0C,
VlePrimaryOpcode::SeStb => 0x0D,
VlePrimaryOpcode::SeAndi => 0x10,
VlePrimaryOpcode::SeOri => 0x11,
VlePrimaryOpcode::SeXori => 0x12,
VlePrimaryOpcode::SeMr => 0x13,
VlePrimaryOpcode::SeRfi => 0x14,
}
}
}
pub const SPE_EVX_OPCD: u32 = 0x04;
pub fn encode_spe_evaddw(rt: u32, ra: u32, rb: u32) -> u32 {
PpcMCEncoder::encode_x_form(SPE_EVX_OPCD, rt, ra, rb, 0x200, 0)
}
pub fn encode_spe_evldd(rt: u32, ra: u32, rb: u32) -> u32 {
PpcMCEncoder::encode_x_form(SPE_EVX_OPCD, rt, ra, rb, 0x201, 0)
}
pub fn encode_spe_evstdd(rs: u32, ra: u32, rb: u32) -> u32 {
PpcMCEncoder::encode_x_form(SPE_EVX_OPCD, rs, ra, rb, 0x221, 0)
}
const OP_DFP: u32 = 0x3B;
pub fn encode_dadd(frt: u32, fra: u32, frb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_DFP, frt, fra, frb, 0x002, 0)
}
pub fn encode_dsub(frt: u32, fra: u32, frb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_DFP, frt, fra, frb, 0x202, 0)
}
pub fn encode_dmul(frt: u32, fra: u32, frb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_DFP, frt, fra, frb, 0x012, 0)
}
pub fn encode_ddiv(frt: u32, fra: u32, frb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_DFP, frt, fra, frb, 0x112, 0)
}
pub fn encode_dcmpu(bf: u32, fra: u32, frb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_DFP, bf, fra, frb, 0x102, 0)
}
const OP_MMA: u32 = 0x1F;
pub fn encode_xxmfacc(xt: u32, acc: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_MMA, xt, acc, 0, 0x332, 0)
}
pub fn encode_xxmtacc(acc: u32, xt: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_MMA, acc, xt, 0, 0x132, 0)
}
pub fn encode_xxsetaccz(acc: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_MMA, acc, 0, 0, 0x332, 0)
}
pub fn encode_xvi4ger(acc: u32, vrt: u32, vrb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_MMA, acc, vrt, vrb, 0x0B0, 0)
}
pub fn encode_xvi8ger(acc: u32, vrt: u32, vrb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_MMA, acc, vrt, vrb, 0x0D0, 0)
}
pub fn encode_xvi16ger(acc: u32, vrt: u32, vrb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_MMA, acc, vrt, vrb, 0x0F0, 0)
}
pub fn encode_xvf32ger(acc: u32, vrt: u32, vrb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_MMA, acc, vrt, vrb, 0x090, 0)
}
pub fn encode_xvf64ger(acc: u32, vrt: u32, vrb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_MMA, acc, vrt, vrb, 0x094, 0)
}
pub fn encode_pmxvi4ger8(acc_a: u32, acc_b: u32, vrt: u32, vrb: u32, vrc: u32, vrd: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_MMA, acc_a, vrt, vrb, 0x0F8, 0)
}
pub fn encode_pmxvi8ger4(acc_a: u32, acc_b: u32, vrt: u32, vrb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_MMA, acc_a, vrt, vrb, 0x0FC, 0)
}
pub fn encode_pmxvf32ger(acc_a: u32, acc_b: u32, vrt: u32, vrb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_MMA, acc_a, vrt, vrb, 0x0E0, 0)
}
pub fn encode_pmxvf64ger(acc_a: u32, acc_b: u32, vrt: u32, vrb: u32) -> u32 {
PpcMCEncoder::encode_x_form(OP_MMA, acc_a, vrt, vrb, 0x0E4, 0)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::codegen::*;
fn mi_r(opcode: u32, rt: u16, ra: u16, rb: u16) -> MachineInstr {
let mut mi = MachineInstr::new(opcode);
mi.push_reg(rt as u32);
mi.push_reg(ra as u32);
mi.push_reg(rb as u32);
mi
}
fn mi_d(opcode: u32, rt: u16, ra: u16, d: i32) -> MachineInstr {
let mut mi = MachineInstr::new(opcode);
mi.push_reg(rt as u32);
mi.push_reg(ra as u32);
mi.push_imm(d as i64);
mi
}
#[test]
fn test_encode_add() {
let word = PpcMCEncoder::encode_add(3, 4, 5);
let expected = (0x1F << 26) | (3 << 21) | (4 << 16) | (5 << 11) | (0x10A << 1);
assert_eq!(word, expected);
}
#[test]
fn test_encode_addi() {
let word = PpcMCEncoder::encode_addi(3, 1, -64);
let expected = (OP_ADDI << 26) | (3 << 21) | (1 << 16) | 0xFFC0;
assert_eq!(word, expected);
}
#[test]
fn test_encode_lwz() {
let word = PpcMCEncoder::encode_lwz(3, 1, 0);
let expected = (OP_LWZ << 26) | (3 << 21) | (1 << 16) | 0;
assert_eq!(word, expected);
}
#[test]
fn test_encode_stw() {
let word = PpcMCEncoder::encode_stw(0, 1, 8);
let expected = (OP_STW << 26) | (0 << 21) | (1 << 16) | 8;
assert_eq!(word, expected);
}
#[test]
fn test_encode_ld() {
let word = PpcMCEncoder::encode_ld(3, 1, 0);
let expected = (OP_LD << 26) | (3 << 21) | (1 << 16) | 0;
assert_eq!(word, expected);
}
#[test]
fn test_encode_std() {
let word = PpcMCEncoder::encode_std(0, 1, 8);
let expected = (OP_STD << 26) | (0 << 21) | (1 << 16) | 8;
assert_eq!(word, expected);
}
#[test]
fn test_encode_b() {
let word = PpcMCEncoder::encode_b(12);
let expected = (OP_B << 26) | 3;
assert_eq!(word, expected);
}
#[test]
fn test_encode_bl() {
let word = PpcMCEncoder::encode_bl(12);
let expected = (OP_B << 26) | 3 | 1;
assert_eq!(word, expected);
}
#[test]
fn test_encode_bclr() {
let word = PpcMCEncoder::encode_bclr(20, 0, 0);
let expected = (0x13 << 26) | (20 << 21) | (0x010 << 1) | 0;
assert_eq!(word, expected);
}
#[test]
fn test_encode_mflr() {
let word = PpcMCEncoder::encode_mfspr(3, SPR_LR);
assert!(word > 0);
}
#[test]
fn test_encode_mtlr() {
let word = PpcMCEncoder::encode_mtspr(SPR_LR, 3);
assert!(word > 0);
}
#[test]
fn test_encode_nop() {
let word = PpcMCEncoder::encode_x_form(0x18, 0, 0, 0, 0, 0);
assert_eq!(word, 0x60000000);
}
#[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!(PpcMCEncoder::get_register_field(5000), 0);
assert_eq!(PpcMCEncoder::get_register_field(5031), 31);
assert_eq!(PpcMCEncoder::get_register_field(5050), 0);
}
#[test]
fn test_encode_instruction() {
let mut encoder = PpcMCEncoder::new(false);
let mi = mi_r(PpcOpcode::ADD as u32, 5003, 5004, 5005);
let bytes = encoder.encode_instruction(&mi);
assert_eq!(bytes.len(), 4);
}
#[test]
fn test_encode_li() {
let word = PpcMCEncoder::encode_addi(3, 0, 42);
let expected = (OP_ADDI << 26) | (3 << 21) | 42;
assert_eq!(word, expected);
}
#[test]
fn test_encode_mr() {
let word = PpcMCEncoder::encode_or(3, 4, 4);
let mr_word = (0x1F << 26) | (3 << 21) | (4 << 16) | (4 << 11) | (XO_OR << 1);
assert_eq!(word, mr_word);
}
#[test]
fn test_encode_fpu() {
let word = PpcMCEncoder::encode_fadd(1, 2, 3);
let expected = (0x3F << 26) | (1 << 21) | (2 << 16) | (3 << 11) | (XO_FADD << 1);
assert_eq!(word, expected);
}
#[test]
fn test_encode_vsx_scalar_add_sp() {
let word = PpcMCEncoder::encode_xsaddsp(5, 1, 2);
let expected = (VSX_XX2_OPCD << 26) | (5 << 21) | (1 << 16) | (2 << 11) | (XO_XSADDSP << 1);
assert_eq!(word, expected);
}
#[test]
fn test_encode_vsx_vector_add_sp() {
let word = PpcMCEncoder::encode_xvaddsp(7, 3, 4);
let expected = (VSX_XX3_OPCD << 26) | (7 << 21) | (3 << 16) | (4 << 11) | (XO_XVADDSP << 1);
assert_eq!(word, expected);
}
#[test]
fn test_encode_lxv() {
let word = PpcMCEncoder::encode_lxv(10, 1, 2);
let expected = PpcMCEncoder::encode_x_form(0x1F, 10, 1, 2, 0x318, 0);
assert_eq!(word, expected);
}
#[test]
fn test_encode_stxv() {
let word = PpcMCEncoder::encode_stxv(10, 1, 2);
let expected = PpcMCEncoder::encode_x_form(0x1F, 10, 1, 2, 0x398, 0);
assert_eq!(word, expected);
}
#[test]
fn test_encode_xvi4ger() {
let word = encode_xvi4ger(0, 5, 6);
let expected = PpcMCEncoder::encode_x_form(OP_MMA, 0, 5, 6, 0x0B0, 0);
assert_eq!(word, expected);
}
#[test]
fn test_encode_dadd() {
let word = encode_dadd(1, 2, 3);
let expected = PpcMCEncoder::encode_x_form(OP_DFP, 1, 2, 3, 0x002, 0);
assert_eq!(word, expected);
}
#[test]
fn test_encode_pli() {
let bytes = PpcMCEncoder::encode_pli(3, 0x1000);
assert_eq!(bytes.len(), 8);
}
#[test]
fn test_encode_paddi() {
let bytes = PpcMCEncoder::encode_paddi(5, 1, 0x20000);
assert_eq!(bytes.len(), 8);
}
#[test]
fn test_prefix_word_encoding() {
let pw = encode_prefix_word(0b00, 0, 0x3FFF, 0, 0x1F);
assert_eq!((pw >> 30) & 0x3, 0);
}
#[test]
fn test_encode_ds_form() {
let word = encode_ds_form(58, 5, 1, 0x100, 0);
let expected = (58u32 << 26) | (5 << 21) | (1 << 16) | (0x100u32 << 2);
assert_eq!(word, expected);
}
#[test]
fn test_encode_xfx_form() {
let spr = ((LR as u32 - PPC_SPECIAL_BASE) << 5);
let word = encode_xfx_form(0x1F, 3, spr, XO_MFSPR, 0);
assert_eq!((word >> 26) & 0x3F, 0x1F);
}
#[test]
fn test_encode_a_form() {
let word = encode_a_form(0x3F, 1, 2, 3, 4, 0x1D, 0);
let expected = (0x3F << 26) | (1 << 21) | (2 << 16) | (3 << 11) | (4 << 6) | (0x1D << 1);
assert_eq!(word, expected);
}
#[test]
fn test_encode_m_form() {
let word = encode_m_form(0x15, 5, 3, 4, 10, 20, 0);
let expected = (0x15 << 26) | (5 << 21) | (3 << 16) | (4 << 11) | (10 << 6) | (20 << 1);
assert_eq!(word, expected);
}
#[test]
fn test_vle_16bit_encoding() {
let insn = encode_vle_16bit(0x04, 0x100);
assert_eq!((insn >> 11) & 0x1F, 0x04);
}
#[test]
fn test_u64_to_be_bytes() {
let bytes = u64_to_be_bytes(0x0102030405060708u64);
assert_eq!(bytes, vec![1, 2, 3, 4, 5, 6, 7, 8]);
}
}