use super::riscv_instr_info::RiscVOpcode;
use super::riscv_register_info::{FPR_BASE, GPR_BASE};
use crate::codegen::{MachineFunction, MachineInstr, MachineOperand};
const OP_LUI: u32 = 0b0110111;
const OP_AUIPC: u32 = 0b0010111;
const OP_JAL: u32 = 0b1101111;
const OP_JALR: u32 = 0b1100111;
const OP_BRANCH: u32 = 0b1100011;
const OP_LOAD: u32 = 0b0000011;
const OP_STORE: u32 = 0b0100011;
const OP_ALUI: u32 = 0b0010011;
const OP_ALU: u32 = 0b0110011;
const OP_FENCE: u32 = 0b0001111;
const OP_SYSTEM: u32 = 0b1110011;
const OP_ALUIW: u32 = 0b0011011;
const OP_ALUW: u32 = 0b0111011;
const OP_MISC_MEM: u32 = 0b0001111;
const F3_BEQ: u32 = 0b000;
const F3_BNE: u32 = 0b001;
const F3_BLT: u32 = 0b100;
const F3_BGE: u32 = 0b101;
const F3_BLTU: u32 = 0b110;
const F3_BGEU: u32 = 0b111;
const F3_LB: u32 = 0b000;
const F3_LH: u32 = 0b001;
const F3_LW: u32 = 0b010;
const F3_LBU: u32 = 0b100;
const F3_LHU: u32 = 0b101;
const F3_LD: u32 = 0b011;
const F3_LWU: u32 = 0b110;
const F3_SB: u32 = 0b000;
const F3_SH: u32 = 0b001;
const F3_SW: u32 = 0b010;
const F3_SD: u32 = 0b011;
const F3_ADDI: u32 = 0b000;
const F3_SLTI: u32 = 0b010;
const F3_SLTIU: u32 = 0b011;
const F3_XORI: u32 = 0b100;
const F3_ORI: u32 = 0b110;
const F3_ANDI: u32 = 0b111;
const F3_SLLI: u32 = 0b001;
const F3_SRLI_SRAI: u32 = 0b101;
const F3_ADD_SUB: u32 = 0b000;
const F3_SLL: u32 = 0b001;
const F3_SLT: u32 = 0b010;
const F3_SLTU: u32 = 0b011;
const F3_XOR: u32 = 0b100;
const F3_SRL_SRA: u32 = 0b101;
const F3_OR: u32 = 0b110;
const F3_AND: u32 = 0b111;
const F3_MUL: u32 = 0b000;
const F3_MULH: u32 = 0b001;
const F3_MULHSU: u32 = 0b010;
const F3_MULHU: u32 = 0b011;
const F3_DIV: u32 = 0b100;
const F3_DIVU: u32 = 0b101;
const F3_REM: u32 = 0b110;
const F3_REMU: u32 = 0b111;
const F7_BASE: u32 = 0b0000000;
const F7_ALT: u32 = 0b0100000;
const F7_MUL: u32 = 0b0000001;
const F7_DIV: u32 = 0b0000001;
const F3_PRIV: u32 = 0b000;
const F3_FENCE: u32 = 0b000;
const F3_FENCE_I: u32 = 0b001;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum InstrFormat {
R,
I,
S,
B,
U,
J,
IShift,
None,
}
pub struct RiscVMCEncoder {
pub is_64bit: bool,
pub output: Vec<u8>,
}
impl RiscVMCEncoder {
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_le_bytes(word)
}
pub fn encode_r_type(
funct7: u32,
rs2: u32,
rs1: u32,
funct3: u32,
rd: u32,
opcode: u32,
) -> u32 {
(funct7 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode
}
pub fn encode_i_type(imm12: i32, rs1: u32, funct3: u32, rd: u32, opcode: u32) -> u32 {
let imm = (imm12 as u32) & 0xFFF;
(imm << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode
}
pub fn encode_s_type(imm12: i32, rs2: u32, rs1: u32, funct3: u32, opcode: u32) -> u32 {
let imm = (imm12 as u32) & 0xFFF;
let imm_11_5 = (imm >> 5) & 0x7F;
let imm_4_0 = imm & 0x1F;
(imm_11_5 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (imm_4_0 << 7) | opcode
}
pub fn encode_b_type(offset: i32, rs2: u32, rs1: u32, funct3: u32, opcode: u32) -> u32 {
let off = (offset as u32) & 0x1FFE;
let imm_12 = (off >> 12) & 0x1;
let imm_11 = (off >> 11) & 0x1;
let imm_10_5 = (off >> 5) & 0x3F;
let imm_4_1 = (off >> 1) & 0xF;
(imm_12 << 31)
| (imm_10_5 << 25)
| (rs2 << 20)
| (rs1 << 15)
| (funct3 << 12)
| (imm_4_1 << 8)
| (imm_11 << 7)
| opcode
}
pub fn encode_u_type(imm20: i32, rd: u32, opcode: u32) -> u32 {
let imm = (imm20 as u32) & 0xFFFFF000;
imm | (rd << 7) | opcode
}
pub fn encode_j_type(offset: i32, rd: u32, opcode: u32) -> u32 {
let off = (offset as u32) & 0x1FFFFE;
let imm_20 = (off >> 20) & 0x1;
let imm_10_1 = (off >> 1) & 0x3FF;
let imm_11 = (off >> 11) & 0x1;
let imm_19_12 = (off >> 12) & 0xFF;
(imm_20 << 31) | (imm_10_1 << 21) | (imm_11 << 20) | (imm_19_12 << 12) | (rd << 7) | opcode
}
pub fn get_register_field(reg_id: u16) -> u8 {
if reg_id >= GPR_BASE && reg_id < GPR_BASE + 32 {
(reg_id - GPR_BASE) as u8
} else if reg_id >= FPR_BASE && reg_id < FPR_BASE + 32 {
(reg_id - FPR_BASE) as u8
} else {
0 }
}
pub fn encode_add(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_r_type(F7_BASE, rs2, rs1, F3_ADD_SUB, rd, OP_ALU)
}
pub fn encode_sub(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_r_type(F7_ALT, rs2, rs1, F3_ADD_SUB, rd, OP_ALU)
}
pub fn encode_and(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_r_type(F7_BASE, rs2, rs1, F3_AND, rd, OP_ALU)
}
pub fn encode_or(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_r_type(F7_BASE, rs2, rs1, F3_OR, rd, OP_ALU)
}
pub fn encode_xor(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_r_type(F7_BASE, rs2, rs1, F3_XOR, rd, OP_ALU)
}
pub fn encode_sll(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_r_type(F7_BASE, rs2, rs1, F3_SLL, rd, OP_ALU)
}
pub fn encode_srl(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_r_type(F7_BASE, rs2, rs1, F3_SRL_SRA, rd, OP_ALU)
}
pub fn encode_sra(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_r_type(F7_ALT, rs2, rs1, F3_SRL_SRA, rd, OP_ALU)
}
pub fn encode_addi(rd: u32, rs1: u32, imm: i32) -> u32 {
Self::encode_i_type(imm, rs1, F3_ADDI, rd, OP_ALUI)
}
pub fn encode_andi(rd: u32, rs1: u32, imm: i32) -> u32 {
Self::encode_i_type(imm, rs1, F3_ANDI, rd, OP_ALUI)
}
pub fn encode_ori(rd: u32, rs1: u32, imm: i32) -> u32 {
Self::encode_i_type(imm, rs1, F3_ORI, rd, OP_ALUI)
}
pub fn encode_xori(rd: u32, rs1: u32, imm: i32) -> u32 {
Self::encode_i_type(imm, rs1, F3_XORI, rd, OP_ALUI)
}
pub fn encode_slli(rd: u32, rs1: u32, shamt: u32, is_64bit: bool) -> u32 {
let mask = if is_64bit { 0x3F } else { 0x1F };
let imm = shamt & mask;
Self::encode_r_type(F7_BASE, imm, rs1, F3_SLLI, rd, OP_ALUI)
}
pub fn encode_srli(rd: u32, rs1: u32, shamt: u32, is_64bit: bool) -> u32 {
let mask = if is_64bit { 0x3F } else { 0x1F };
let imm = shamt & mask;
Self::encode_r_type(F7_BASE, imm, rs1, F3_SRLI_SRAI, rd, OP_ALUI)
}
pub fn encode_srai(rd: u32, rs1: u32, shamt: u32, is_64bit: bool) -> u32 {
let mask = if is_64bit { 0x3F } else { 0x1F };
let imm = shamt & mask;
Self::encode_r_type(F7_ALT, imm, rs1, F3_SRLI_SRAI, rd, OP_ALUI)
}
pub fn encode_lw(rd: u32, rs1: u32, offset: i32) -> u32 {
Self::encode_i_type(offset, rs1, F3_LW, rd, OP_LOAD)
}
pub fn encode_ld(rd: u32, rs1: u32, offset: i32) -> u32 {
Self::encode_i_type(offset, rs1, F3_LD, rd, OP_LOAD)
}
pub fn encode_lb(rd: u32, rs1: u32, offset: i32) -> u32 {
Self::encode_i_type(offset, rs1, F3_LB, rd, OP_LOAD)
}
pub fn encode_lbu(rd: u32, rs1: u32, offset: i32) -> u32 {
Self::encode_i_type(offset, rs1, F3_LBU, rd, OP_LOAD)
}
pub fn encode_lh(rd: u32, rs1: u32, offset: i32) -> u32 {
Self::encode_i_type(offset, rs1, F3_LH, rd, OP_LOAD)
}
pub fn encode_lhu(rd: u32, rs1: u32, offset: i32) -> u32 {
Self::encode_i_type(offset, rs1, F3_LHU, rd, OP_LOAD)
}
pub fn encode_sw(rs2: u32, rs1: u32, offset: i32) -> u32 {
Self::encode_s_type(offset, rs2, rs1, F3_SW, OP_STORE)
}
pub fn encode_sd(rs2: u32, rs1: u32, offset: i32) -> u32 {
Self::encode_s_type(offset, rs2, rs1, F3_SD, OP_STORE)
}
pub fn encode_sb(rs2: u32, rs1: u32, offset: i32) -> u32 {
Self::encode_s_type(offset, rs2, rs1, F3_SB, OP_STORE)
}
pub fn encode_sh(rs2: u32, rs1: u32, offset: i32) -> u32 {
Self::encode_s_type(offset, rs2, rs1, F3_SH, OP_STORE)
}
pub fn encode_beq(rs1: u32, rs2: u32, offset: i32) -> u32 {
Self::encode_b_type(offset, rs2, rs1, F3_BEQ, OP_BRANCH)
}
pub fn encode_bne(rs1: u32, rs2: u32, offset: i32) -> u32 {
Self::encode_b_type(offset, rs2, rs1, F3_BNE, OP_BRANCH)
}
pub fn encode_blt(rs1: u32, rs2: u32, offset: i32) -> u32 {
Self::encode_b_type(offset, rs2, rs1, F3_BLT, OP_BRANCH)
}
pub fn encode_bge(rs1: u32, rs2: u32, offset: i32) -> u32 {
Self::encode_b_type(offset, rs2, rs1, F3_BGE, OP_BRANCH)
}
pub fn encode_bltu(rs1: u32, rs2: u32, offset: i32) -> u32 {
Self::encode_b_type(offset, rs2, rs1, F3_BLTU, OP_BRANCH)
}
pub fn encode_bgeu(rs1: u32, rs2: u32, offset: i32) -> u32 {
Self::encode_b_type(offset, rs2, rs1, F3_BGEU, OP_BRANCH)
}
pub fn encode_jal(rd: u32, offset: i32) -> u32 {
Self::encode_j_type(offset, rd, OP_JAL)
}
pub fn encode_jalr(rd: u32, rs1: u32, offset: i32) -> u32 {
Self::encode_i_type(offset, rs1, 0, rd, OP_JALR)
}
pub fn encode_lui(rd: u32, imm: i32) -> u32 {
Self::encode_u_type(imm, rd, OP_LUI)
}
pub fn encode_auipc(rd: u32, imm: i32) -> u32 {
Self::encode_u_type(imm, rd, OP_AUIPC)
}
pub fn encode_ecall() -> u32 {
Self::encode_i_type(0, 0, F3_PRIV, 0, OP_SYSTEM)
}
pub fn encode_ebreak() -> u32 {
Self::encode_i_type(1, 0, F3_PRIV, 0, OP_SYSTEM)
}
pub fn encode_fence(pred: u32, succ: u32) -> u32 {
let imm = ((pred & 0xF) << 4) | (succ & 0xF);
Self::encode_i_type(imm as i32, 0, F3_FENCE, 0, OP_FENCE)
}
pub fn encode_fence_i() -> u32 {
Self::encode_i_type(0, 0, F3_FENCE_I, 0, OP_MISC_MEM)
}
fn encode_by_opcode(&self, mi: &MachineInstr) -> u32 {
let op = mi.opcode;
let rd = self.extract_rd(mi);
let rs1 = self.extract_rs1(mi);
let rs2 = self.extract_rs2(mi);
let imm2 = self.extract_imm(mi, 2);
let imm1 = self.extract_imm(mi, 1);
if op == RiscVOpcode::ADD as u32 {
return Self::encode_add(rd, rs1, rs2);
}
if op == RiscVOpcode::SUB as u32 {
return Self::encode_sub(rd, rs1, rs2);
}
if op == RiscVOpcode::AND as u32 {
return Self::encode_and(rd, rs1, rs2);
}
if op == RiscVOpcode::OR as u32 {
return Self::encode_or(rd, rs1, rs2);
}
if op == RiscVOpcode::XOR as u32 {
return Self::encode_xor(rd, rs1, rs2);
}
if op == RiscVOpcode::SLL as u32 {
return Self::encode_sll(rd, rs1, rs2);
}
if op == RiscVOpcode::SRL as u32 {
return Self::encode_srl(rd, rs1, rs2);
}
if op == RiscVOpcode::SRA as u32 {
return Self::encode_sra(rd, rs1, rs2);
}
if op == RiscVOpcode::ADDI as u32 {
return Self::encode_addi(rd, rs1, imm2);
}
if op == RiscVOpcode::ANDI as u32 {
return Self::encode_andi(rd, rs1, imm2);
}
if op == RiscVOpcode::ORI as u32 {
return Self::encode_ori(rd, rs1, imm2);
}
if op == RiscVOpcode::XORI as u32 {
return Self::encode_xori(rd, rs1, imm2);
}
if op == RiscVOpcode::SLLI as u32 {
return Self::encode_slli(rd, rs1, imm2 as u32, self.is_64bit);
}
if op == RiscVOpcode::SRLI as u32 {
return Self::encode_srli(rd, rs1, imm2 as u32, self.is_64bit);
}
if op == RiscVOpcode::SRAI as u32 {
return Self::encode_srai(rd, rs1, imm2 as u32, self.is_64bit);
}
if op == RiscVOpcode::LW as u32 {
return Self::encode_lw(rd, rs1, imm2);
}
if op == RiscVOpcode::LD as u32 {
return Self::encode_ld(rd, rs1, imm2);
}
if op == RiscVOpcode::LB as u32 {
return Self::encode_lb(rd, rs1, imm2);
}
if op == RiscVOpcode::LBU as u32 {
return Self::encode_lbu(rd, rs1, imm2);
}
if op == RiscVOpcode::LH as u32 {
return Self::encode_lh(rd, rs1, imm2);
}
if op == RiscVOpcode::LHU as u32 {
return Self::encode_lhu(rd, rs1, imm2);
}
if op == RiscVOpcode::SW as u32 {
return Self::encode_sw(rd, rs1, imm2);
}
if op == RiscVOpcode::SD as u32 {
return Self::encode_sd(rd, rs1, imm2);
}
if op == RiscVOpcode::SB as u32 {
return Self::encode_sb(rd, rs1, imm2);
}
if op == RiscVOpcode::SH as u32 {
return Self::encode_sh(rd, rs1, imm2);
}
if op == RiscVOpcode::BEQ as u32 {
return Self::encode_beq(rs1, rs2, imm2);
}
if op == RiscVOpcode::BNE as u32 {
return Self::encode_bne(rs1, rs2, imm2);
}
if op == RiscVOpcode::BLT as u32 {
return Self::encode_blt(rs1, rs2, imm2);
}
if op == RiscVOpcode::BGE as u32 {
return Self::encode_bge(rs1, rs2, imm2);
}
if op == RiscVOpcode::BLTU as u32 {
return Self::encode_bltu(rs1, rs2, imm2);
}
if op == RiscVOpcode::BGEU as u32 {
return Self::encode_bgeu(rs1, rs2, imm2);
}
if op == RiscVOpcode::JAL as u32 {
return Self::encode_jal(rd, imm1);
}
if op == RiscVOpcode::JALR as u32 {
return Self::encode_jalr(rd, rs1, imm2);
}
if op == RiscVOpcode::LUI as u32 {
return Self::encode_lui(rd, imm1);
}
if op == RiscVOpcode::AUIPC as u32 {
return Self::encode_auipc(rd, imm1);
}
if op == RiscVOpcode::ECALL as u32 {
return Self::encode_ecall();
}
if op == RiscVOpcode::EBREAK as u32 {
return Self::encode_ebreak();
}
if op == RiscVOpcode::FENCE as u32 {
let pred = self.extract_imm(mi, 0) as u32;
let succ = self.extract_imm(mi, 1) as u32;
return Self::encode_fence(pred, succ);
}
if op == RiscVOpcode::FENCE_I as u32 {
return Self::encode_fence_i();
}
if op == RiscVOpcode::NOP as u32 {
return Self::encode_addi(0, 0, 0); }
if op == RiscVOpcode::MV as u32 {
return Self::encode_addi(rd, rs1, 0); }
0
}
fn extract_rd(&self, mi: &MachineInstr) -> u32 {
mi.operands
.first()
.and_then(|op| get_reg_field(op))
.unwrap_or(0) as u32
}
fn extract_rs1(&self, mi: &MachineInstr) -> u32 {
mi.operands
.get(1)
.and_then(|op| get_reg_field(op))
.unwrap_or(0) as u32
}
fn extract_rs2(&self, mi: &MachineInstr) -> u32 {
mi.operands
.get(2)
.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(RiscVMCEncoder::get_register_field(*vr as u16)),
MachineOperand::PhysReg(pr) => Some(RiscVMCEncoder::get_register_field(*pr as u16)),
_ => None,
}
}
pub fn u32_to_le_bytes(word: u32) -> Vec<u8> {
vec![
(word & 0xFF) as u8,
((word >> 8) & 0xFF) as u8,
((word >> 16) & 0xFF) as u8,
((word >> 24) & 0xFF) as u8,
]
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RvcQuadrant {
C0, C1, C2, }
impl RvcQuadrant {
pub fn from_bits(bits: u8) -> Option<Self> {
match bits & 0x3 {
0 => Some(RvcQuadrant::C0),
1 => Some(RvcQuadrant::C1),
2 => Some(RvcQuadrant::C2),
_ => None, }
}
}
pub struct RvcEncoder;
impl RvcEncoder {
pub fn encode_c_addi4spn(rd_prime: u8, nzuimm: u16) -> Option<u16> {
if nzuimm == 0 || nzuimm > 1020 || nzuimm % 4 != 0 {
return None;
}
let funct3: u16 = 0b000;
let uimm = nzuimm;
let imm_5_4 = ((uimm >> 4) & 0x3) as u16;
let imm_9_6 = ((uimm >> 6) & 0xF) as u16;
let imm_2 = ((uimm >> 2) & 0x1) as u16;
let imm_3 = ((uimm >> 3) & 0x1) as u16;
let op: u16 = 0b00;
Some(
(funct3 << 13)
| (imm_5_4 << 11)
| (imm_9_6 << 7)
| (imm_2 << 6)
| (imm_3 << 5)
| ((rd_prime as u16 & 0x7) << 2)
| op,
)
}
pub fn encode_c_lw(rd_prime: u8, rs1_prime: u8, uimm: u8) -> u16 {
let funct3: u16 = 0b010;
let imm_5_3 = ((uimm >> 3) & 0x7) as u16;
let imm_2 = ((uimm >> 2) & 0x1) as u16;
let imm_6 = ((uimm >> 6) & 0x1) as u16;
let op: u16 = 0b00;
(funct3 << 13)
| (imm_5_3 << 10)
| ((rs1_prime as u16 & 0x7) << 7)
| (imm_2 << 6)
| (imm_6 << 5)
| ((rd_prime as u16 & 0x7) << 2)
| op
}
pub fn encode_c_sw(rs2_prime: u8, rs1_prime: u8, uimm: u8) -> u16 {
let funct3: u16 = 0b110;
let imm_5_3 = ((uimm >> 3) & 0x7) as u16;
let imm_2 = ((uimm >> 2) & 0x1) as u16;
let imm_6 = ((uimm >> 6) & 0x1) as u16;
let op: u16 = 0b00;
(funct3 << 13)
| (imm_5_3 << 10)
| ((rs1_prime as u16 & 0x7) << 7)
| (imm_2 << 6)
| (imm_6 << 5)
| ((rs2_prime as u16 & 0x7) << 2)
| op
}
pub fn encode_c_addi(rd: u8, imm: i8) -> u16 {
let funct3: u16 = 0b000;
let op: u16 = 0b01;
let imm_u = imm as u8;
let imm_5 = ((imm_u >> 5) & 0x1) as u16;
let imm_4_0 = (imm_u & 0x1F) as u16;
(funct3 << 13) | (imm_5 << 12) | ((rd as u16 & 0x1F) << 7) | (imm_4_0 << 2) | op
}
pub fn encode_c_li(rd: u8, imm: i8) -> u16 {
Self::encode_c_addi(rd, imm) }
pub fn encode_c_lui(rd: u8, imm: i32) -> Option<u16> {
if rd == 0 || rd == 2 || imm == 0 {
return None;
}
let funct3: u16 = 0b011;
let op: u16 = 0b01;
let imm_17 = ((imm >> 17) & 0x1) as u16;
let imm_16_12 = ((imm >> 12) & 0x1F) as u16;
Some((funct3 << 13) | (imm_17 << 12) | ((rd as u16 & 0x1F) << 7) | (imm_16_12 << 2) | op)
}
pub fn encode_c_slli(rd: u8, shamt: u8) -> Option<u16> {
if shamt == 0 || shamt > 31 {
return None;
}
let funct3: u16 = 0b000;
let op: u16 = 0b10;
let imm_5 = ((shamt >> 5) & 0x1) as u16;
let imm_4_0 = (shamt & 0x1F) as u16;
Some((funct3 << 13) | (imm_5 << 12) | ((rd as u16 & 0x1F) << 7) | (imm_4_0 << 2) | op)
}
pub fn encode_c_j(offset: i16) -> Option<u16> {
if offset < -2048 || offset > 2046 {
return None;
}
let funct3: u16 = 0b101;
let op: u16 = 0b01;
let off = offset as u16;
let imm_11 = (off >> 11) & 0x1;
let imm_4 = (off >> 4) & 0x1;
let imm_9_8 = (off >> 8) & 0x3;
let imm_10 = (off >> 10) & 0x1;
let imm_6 = (off >> 6) & 0x1;
let imm_7 = (off >> 7) & 0x1;
let imm_3_1 = (off >> 1) & 0x7;
let imm_5 = (off >> 5) & 0x1;
Some(
(funct3 << 13)
| (imm_11 << 12)
| (imm_4 << 11)
| (imm_9_8 << 9)
| (imm_10 << 8)
| (imm_6 << 7)
| (imm_7 << 6)
| (imm_3_1 << 3)
| (imm_5 << 2)
| op,
)
}
pub fn encode_c_beqz(rs1_prime: u8, offset: i16) -> Option<u16> {
if offset < -256 || offset > 254 {
return None;
}
let funct3: u16 = 0b110;
let op: u16 = 0b01;
let off = offset as u16;
let imm_8 = (off >> 8) & 0x1;
let imm_4_3 = (off >> 3) & 0x3;
let imm_7_6 = (off >> 6) & 0x3;
let imm_2_1 = (off >> 1) & 0x3;
let imm_5 = (off >> 5) & 0x1;
Some(
(funct3 << 13)
| (imm_8 << 12)
| (imm_4_3 << 10)
| ((rs1_prime as u16 & 0x7) << 7)
| (imm_7_6 << 5)
| (imm_2_1 << 3)
| (imm_5 << 2)
| op,
)
}
pub fn encode_c_bnez(rs1_prime: u8, offset: i16) -> Option<u16> {
if offset < -256 || offset > 254 {
return None;
}
let funct3: u16 = 0b111;
let op: u16 = 0b01;
let off = offset as u16;
let imm_8 = (off >> 8) & 0x1;
let imm_4_3 = (off >> 3) & 0x3;
let imm_7_6 = (off >> 6) & 0x3;
let imm_2_1 = (off >> 1) & 0x3;
let imm_5 = (off >> 5) & 0x1;
Some(
(funct3 << 13)
| (imm_8 << 12)
| (imm_4_3 << 10)
| ((rs1_prime as u16 & 0x7) << 7)
| (imm_7_6 << 5)
| (imm_2_1 << 3)
| (imm_5 << 2)
| op,
)
}
pub fn encode_c_mv(rd: u8, rs2: u8) -> Option<u16> {
if rd == 0 || rs2 == 0 {
return None;
}
let funct4: u16 = 0b1000;
let op: u16 = 0b10;
Some((funct4 << 12) | ((rd as u16 & 0x1F) << 7) | ((rs2 as u16 & 0x1F) << 2) | op)
}
pub fn encode_c_add(rd: u8, rs2: u8) -> Option<u16> {
if rd == 0 || rs2 == 0 {
return None;
}
let funct4: u16 = 0b1001;
let op: u16 = 0b10;
Some((funct4 << 12) | ((rd as u16 & 0x1F) << 7) | ((rs2 as u16 & 0x1F) << 2) | op)
}
pub fn encode_c_jr(rs1: u8) -> Option<u16> {
if rs1 == 0 {
return None;
}
let funct4: u16 = 0b1000;
let op: u16 = 0b10;
Some((funct4 << 12) | ((rs1 as u16 & 0x1F) << 7) | op)
}
pub fn encode_c_jalr(rs1: u8) -> Option<u16> {
if rs1 == 0 {
return None;
}
let funct4: u16 = 0b1001;
let op: u16 = 0b10;
Some((funct4 << 12) | ((rs1 as u16 & 0x1F) << 7) | (1 << 2) | op)
}
pub fn encode_c_lwsp(rd: u8, uimm: u8) -> Option<u16> {
if rd == 0 {
return None;
}
let funct3: u16 = 0b010;
let op: u16 = 0b10;
let imm_5 = ((uimm >> 5) & 0x1) as u16;
let imm_4_2 = ((uimm >> 2) & 0x7) as u16;
let imm_7_6 = ((uimm >> 6) & 0x3) as u16;
Some(
(funct3 << 13)
| (imm_5 << 12)
| ((rd as u16 & 0x1F) << 7)
| (imm_4_2 << 4)
| (imm_7_6 << 2)
| op,
)
}
pub fn encode_c_swsp(rs2: u8, uimm: u8) -> u16 {
let funct3: u16 = 0b110;
let op: u16 = 0b10;
let imm_5_2 = ((uimm >> 2) & 0xF) as u16;
let imm_7_6 = ((uimm >> 6) & 0x3) as u16;
(funct3 << 13)
| (imm_5_2 << 9)
| ((rs2 as u16 & 0x1F) << 2)
| (imm_7_6 << 7) | op
}
pub fn to_le_bytes(insn: u16) -> Vec<u8> {
vec![(insn & 0xFF) as u8, ((insn >> 8) & 0xFF) as u8]
}
}
pub struct PseudoExpander {
pub is_64bit: bool,
}
#[derive(Debug, Clone)]
pub struct ExpandedInstr {
pub opcode: u32,
pub rd: u32,
pub rs1: u32,
pub rs2: u32,
pub imm: i64,
}
impl PseudoExpander {
pub fn new(is_64bit: bool) -> Self {
Self { is_64bit }
}
pub fn expand_li(&self, rd: u32, imm: i64) -> Vec<ExpandedInstr> {
let imm32 = imm as i32;
let mut result = Vec::new();
if imm32 >= -2048 && imm32 <= 2047 {
result.push(ExpandedInstr {
opcode: RiscVOpcode::ADDI as u32,
rd,
rs1: 0, rs2: 0,
imm: imm32 as i64,
});
} else {
let upper = (imm32 as u32).wrapping_add(0x800) & 0xFFFFF000;
let lower = imm32.wrapping_sub(upper as i32);
result.push(ExpandedInstr {
opcode: RiscVOpcode::LUI as u32,
rd,
rs1: 0,
rs2: 0,
imm: upper as i64,
});
if lower != 0 {
result.push(ExpandedInstr {
opcode: RiscVOpcode::ADDI as u32,
rd,
rs1: rd,
rs2: 0,
imm: lower as i64,
});
}
}
result
}
pub fn expand_la(&self, rd: u32, _imm: i64) -> Vec<ExpandedInstr> {
vec![
ExpandedInstr {
opcode: RiscVOpcode::AUIPC as u32,
rd,
rs1: 0,
rs2: 0,
imm: 0, },
ExpandedInstr {
opcode: RiscVOpcode::ADDI as u32,
rd,
rs1: rd,
rs2: 0,
imm: 0,
},
]
}
pub fn expand_call(&self, _imm: i64) -> Vec<ExpandedInstr> {
let ra = 1;
vec![
ExpandedInstr {
opcode: RiscVOpcode::AUIPC as u32,
rd: ra,
rs1: 0,
rs2: 0,
imm: 0, },
ExpandedInstr {
opcode: RiscVOpcode::JALR as u32,
rd: ra,
rs1: ra,
rs2: 0,
imm: 0,
},
]
}
pub fn expand_tail(&self, _imm: i64) -> Vec<ExpandedInstr> {
let t1 = 6;
vec![
ExpandedInstr {
opcode: RiscVOpcode::AUIPC as u32,
rd: t1,
rs1: 0,
rs2: 0,
imm: 0,
},
ExpandedInstr {
opcode: RiscVOpcode::JALR as u32,
rd: 0, rs1: t1,
rs2: 0,
imm: 0,
},
]
}
pub fn expand_mv(&self, rd: u32, rs: u32) -> Vec<ExpandedInstr> {
vec![ExpandedInstr {
opcode: RiscVOpcode::ADDI as u32,
rd,
rs1: rs,
rs2: 0,
imm: 0,
}]
}
pub fn expand_not(&self, rd: u32, rs: u32) -> Vec<ExpandedInstr> {
vec![ExpandedInstr {
opcode: RiscVOpcode::XORI as u32,
rd,
rs1: rs,
rs2: 0,
imm: -1,
}]
}
pub fn expand_neg(&self, rd: u32, rs: u32) -> Vec<ExpandedInstr> {
vec![ExpandedInstr {
opcode: RiscVOpcode::SUB as u32,
rd,
rs1: 0,
rs2: rs,
imm: 0,
}]
}
pub fn expand_seqz(&self, rd: u32, rs: u32) -> Vec<ExpandedInstr> {
vec![ExpandedInstr {
opcode: RiscVOpcode::SLTIU as u32,
rd,
rs1: rs,
rs2: 0,
imm: 1,
}]
}
pub fn expand_snez(&self, rd: u32, rs: u32) -> Vec<ExpandedInstr> {
vec![ExpandedInstr {
opcode: RiscVOpcode::SLTU as u32,
rd,
rs1: 0,
rs2: rs,
imm: 0,
}]
}
pub fn is_pseudo(opcode: u32) -> bool {
matches!(
RiscVOpcode::from_u32(opcode),
Some(RiscVOpcode::LI)
| Some(RiscVOpcode::LA)
| Some(RiscVOpcode::CALL)
| Some(RiscVOpcode::TAIL)
| Some(RiscVOpcode::MV)
| Some(RiscVOpcode::NOT)
| Some(RiscVOpcode::NEG)
| Some(RiscVOpcode::SEQZ)
| Some(RiscVOpcode::SNEZ)
)
}
pub fn expand(&self, opcode: u32, rd: u32, rs1: u32, rs2: u32, imm: i64) -> Vec<ExpandedInstr> {
match RiscVOpcode::from_u32(opcode) {
Some(RiscVOpcode::LI) => self.expand_li(rd, imm),
Some(RiscVOpcode::LA) => self.expand_la(rd, imm),
Some(RiscVOpcode::CALL) => self.expand_call(imm),
Some(RiscVOpcode::TAIL) => self.expand_tail(imm),
Some(RiscVOpcode::MV) => self.expand_mv(rd, rs1),
Some(RiscVOpcode::NOT) => self.expand_not(rd, rs1),
Some(RiscVOpcode::NEG) => self.expand_neg(rd, rs1),
Some(RiscVOpcode::SEQZ) => self.expand_seqz(rd, rs1),
Some(RiscVOpcode::SNEZ) => self.expand_snez(rd, rs1),
_ => vec![],
}
}
}
impl RiscVOpcode {
fn from_u32(v: u32) -> Option<RiscVOpcode> {
match v {
n if n == RiscVOpcode::LI as u32 => Some(RiscVOpcode::LI),
n if n == RiscVOpcode::LA as u32 => Some(RiscVOpcode::LA),
n if n == RiscVOpcode::CALL as u32 => Some(RiscVOpcode::CALL),
n if n == RiscVOpcode::TAIL as u32 => Some(RiscVOpcode::TAIL),
n if n == RiscVOpcode::MV as u32 => Some(RiscVOpcode::MV),
n if n == RiscVOpcode::NOT as u32 => Some(RiscVOpcode::NOT),
n if n == RiscVOpcode::NEG as u32 => Some(RiscVOpcode::NEG),
n if n == RiscVOpcode::SEQZ as u32 => Some(RiscVOpcode::SEQZ),
n if n == RiscVOpcode::SNEZ as u32 => Some(RiscVOpcode::SNEZ),
_ => None,
}
}
}
pub struct ImmediateValidator;
impl ImmediateValidator {
pub fn is_valid_i_imm(imm: i32) -> bool {
imm >= -2048 && imm <= 2047
}
pub fn is_valid_s_imm(imm: i32) -> bool {
Self::is_valid_i_imm(imm)
}
pub fn is_valid_b_imm(imm: i32) -> bool {
imm >= -4096 && imm <= 4094 && (imm & 1) == 0
}
pub fn is_valid_u_imm(imm: i32) -> bool {
(imm as u32) & 0xFFF == 0
}
pub fn is_valid_j_imm(imm: i32) -> bool {
imm >= -1_048_576 && imm <= 1_048_574 && (imm & 1) == 0
}
pub fn is_valid_shamt_rv32(shamt: u32) -> bool {
shamt <= 31
}
pub fn is_valid_shamt_rv64(shamt: u32) -> bool {
shamt <= 63
}
pub fn is_valid_csr(csr: u32) -> bool {
csr <= 0xFFF
}
pub fn validate_imm_error(imm: i32, format: InstrFormat) -> Option<String> {
match format {
InstrFormat::I | InstrFormat::IShift if !Self::is_valid_i_imm(imm) => Some(format!(
"I-type immediate {} out of range [-2048, 2047]",
imm
)),
InstrFormat::S if !Self::is_valid_s_imm(imm) => Some(format!(
"S-type immediate {} out of range [-2048, 2047]",
imm
)),
InstrFormat::B if !Self::is_valid_b_imm(imm) => Some(format!(
"B-type immediate {} out of range [-4096, 4094] or unaligned",
imm
)),
InstrFormat::U if !Self::is_valid_u_imm(imm) => {
Some(format!("U-type immediate {} low 12 bits must be zero", imm))
}
InstrFormat::J if !Self::is_valid_j_imm(imm) => Some(format!(
"J-type immediate {} out of range [-1048576, 1048574] or unaligned",
imm
)),
_ => None,
}
}
}
pub struct AtomicEncoder;
impl AtomicEncoder {
const OP_AMO: u32 = 0b0101111;
pub fn encode_lr_w(rd: u32, rs1: u32, aq: bool, rl: bool) -> u32 {
let funct5: u32 = 0b00010;
let aq_bit = if aq { 1 } else { 0 };
let rl_bit = if rl { 1 } else { 0 };
(funct5 << 27)
| (aq_bit << 26)
| (rl_bit << 25)
| (rs1 << 15)
| (0b010 << 12) | (rd << 7)
| Self::OP_AMO
}
pub fn encode_sc_w(rd: u32, rs1: u32, rs2: u32, aq: bool, rl: bool) -> u32 {
let funct5: u32 = 0b00011;
let aq_bit = if aq { 1 } else { 0 };
let rl_bit = if rl { 1 } else { 0 };
(funct5 << 27)
| (aq_bit << 26)
| (rl_bit << 25)
| (rs2 << 20)
| (rs1 << 15)
| (0b010 << 12)
| (rd << 7)
| Self::OP_AMO
}
pub fn encode_lr_d(rd: u32, rs1: u32, aq: bool, rl: bool) -> u32 {
let funct5: u32 = 0b00010;
let aq_bit = if aq { 1 } else { 0 };
let rl_bit = if rl { 1 } else { 0 };
(funct5 << 27)
| (aq_bit << 26)
| (rl_bit << 25)
| (rs1 << 15)
| (0b011 << 12) | (rd << 7)
| Self::OP_AMO
}
pub fn encode_sc_d(rd: u32, rs1: u32, rs2: u32, aq: bool, rl: bool) -> u32 {
let funct5: u32 = 0b00011;
let aq_bit = if aq { 1 } else { 0 };
let rl_bit = if rl { 1 } else { 0 };
(funct5 << 27)
| (aq_bit << 26)
| (rl_bit << 25)
| (rs2 << 20)
| (rs1 << 15)
| (0b011 << 12)
| (rd << 7)
| Self::OP_AMO
}
pub fn encode_amoswap_w(rd: u32, rs1: u32, rs2: u32, aq: bool, rl: bool) -> u32 {
Self::encode_amo(0b00001, rd, rs1, rs2, aq, rl, false)
}
pub fn encode_amoadd_w(rd: u32, rs1: u32, rs2: u32, aq: bool, rl: bool) -> u32 {
Self::encode_amo(0b00000, rd, rs1, rs2, aq, rl, false)
}
pub fn encode_amoxor_w(rd: u32, rs1: u32, rs2: u32, aq: bool, rl: bool) -> u32 {
Self::encode_amo(0b00100, rd, rs1, rs2, aq, rl, false)
}
pub fn encode_amoand_w(rd: u32, rs1: u32, rs2: u32, aq: bool, rl: bool) -> u32 {
Self::encode_amo(0b01100, rd, rs1, rs2, aq, rl, false)
}
pub fn encode_amoor_w(rd: u32, rs1: u32, rs2: u32, aq: bool, rl: bool) -> u32 {
Self::encode_amo(0b01000, rd, rs1, rs2, aq, rl, false)
}
pub fn encode_amomin_w(rd: u32, rs1: u32, rs2: u32, aq: bool, rl: bool) -> u32 {
Self::encode_amo(0b10000, rd, rs1, rs2, aq, rl, false)
}
pub fn encode_amomax_w(rd: u32, rs1: u32, rs2: u32, aq: bool, rl: bool) -> u32 {
Self::encode_amo(0b10100, rd, rs1, rs2, aq, rl, false)
}
fn encode_amo(
funct5: u32,
rd: u32,
rs1: u32,
rs2: u32,
aq: bool,
rl: bool,
is_64bit: bool,
) -> u32 {
let aq_bit = if aq { 1 } else { 0 };
let rl_bit = if rl { 1 } else { 0 };
let funct3 = if is_64bit { 0b011 } else { 0b010 };
(funct5 << 27)
| (aq_bit << 26)
| (rl_bit << 25)
| (rs2 << 20)
| (rs1 << 15)
| (funct3 << 12)
| (rd << 7)
| Self::OP_AMO
}
}
pub struct FpEncoder;
impl FpEncoder {
const OP_FP: u32 = 0b1010011;
const OP_FP_LOAD: u32 = 0b0000111;
const OP_FP_STORE: u32 = 0b0100111;
const OP_FMADD: u32 = 0b1000011;
const OP_FMSUB: u32 = 0b1000111;
const OP_FNMSUB: u32 = 0b1001011;
const OP_FNMADD: u32 = 0b1001111;
pub const RM_RNE: u32 = 0b000; pub const RM_RTZ: u32 = 0b001; pub const RM_RDN: u32 = 0b010; pub const RM_RUP: u32 = 0b011; pub const RM_RMM: u32 = 0b100; pub const RM_DYN: u32 = 0b111;
pub fn encode_fadd_s(rd: u32, rs1: u32, rs2: u32, rm: u32) -> u32 {
Self::encode_fp_r_type(0b0000000, rs2, rs1, rm, rd, Self::OP_FP, 0b00)
}
pub fn encode_fsub_s(rd: u32, rs1: u32, rs2: u32, rm: u32) -> u32 {
Self::encode_fp_r_type(0b0000100, rs2, rs1, rm, rd, Self::OP_FP, 0b00)
}
pub fn encode_fmul_s(rd: u32, rs1: u32, rs2: u32, rm: u32) -> u32 {
Self::encode_fp_r_type(0b0001000, rs2, rs1, rm, rd, Self::OP_FP, 0b00)
}
pub fn encode_fdiv_s(rd: u32, rs1: u32, rs2: u32, rm: u32) -> u32 {
Self::encode_fp_r_type(0b0001100, rs2, rs1, rm, rd, Self::OP_FP, 0b00)
}
pub fn encode_fsqrt_s(rd: u32, rs1: u32, rm: u32) -> u32 {
Self::encode_fp_r_type(0b0101100, 0, rs1, rm, rd, Self::OP_FP, 0b00)
}
pub fn encode_fadd_d(rd: u32, rs1: u32, rs2: u32, rm: u32) -> u32 {
Self::encode_fp_r_type(0b0000001, rs2, rs1, rm, rd, Self::OP_FP, 0b01)
}
pub fn encode_fsub_d(rd: u32, rs1: u32, rs2: u32, rm: u32) -> u32 {
Self::encode_fp_r_type(0b0000101, rs2, rs1, rm, rd, Self::OP_FP, 0b01)
}
pub fn encode_fmul_d(rd: u32, rs1: u32, rs2: u32, rm: u32) -> u32 {
Self::encode_fp_r_type(0b0001001, rs2, rs1, rm, rd, Self::OP_FP, 0b01)
}
pub fn encode_fdiv_d(rd: u32, rs1: u32, rs2: u32, rm: u32) -> u32 {
Self::encode_fp_r_type(0b0001101, rs2, rs1, rm, rd, Self::OP_FP, 0b01)
}
pub fn encode_fsqrt_d(rd: u32, rs1: u32, rm: u32) -> u32 {
Self::encode_fp_r_type(0b0101101, 0, rs1, rm, rd, Self::OP_FP, 0b01)
}
fn encode_fp_r_type(
funct7: u32,
rs2: u32,
rs1: u32,
funct3: u32, rd: u32,
opcode: u32,
fmt: u32, ) -> u32 {
(funct7 << 25)
| (rs2 << 20)
| (rs1 << 15)
| (funct3 << 12)
| (rd << 7)
| (fmt << 25) | opcode
}
pub fn encode_flw(rd: u32, rs1: u32, offset: i32) -> u32 {
RiscVMCEncoder::encode_i_type(offset, rs1, 0b010, rd, Self::OP_FP_LOAD)
}
pub fn encode_fsw(rs2: u32, rs1: u32, offset: i32) -> u32 {
RiscVMCEncoder::encode_s_type(offset, rs2, rs1, 0b010, Self::OP_FP_STORE)
}
pub fn encode_fld(rd: u32, rs1: u32, offset: i32) -> u32 {
RiscVMCEncoder::encode_i_type(offset, rs1, 0b011, rd, Self::OP_FP_LOAD)
}
pub fn encode_fsd(rs2: u32, rs1: u32, offset: i32) -> u32 {
RiscVMCEncoder::encode_s_type(offset, rs2, rs1, 0b011, Self::OP_FP_STORE)
}
pub fn encode_fcvt_w_s(rd: u32, rs1: u32, rm: u32) -> u32 {
Self::encode_fp_r_type(0b1100000, 0b00000, rs1, rm, rd, Self::OP_FP, 0b00)
}
pub fn encode_fcvt_s_w(rd: u32, rs1: u32, rm: u32) -> u32 {
Self::encode_fp_r_type(0b1101000, 0b00000, rs1, rm, rd, Self::OP_FP, 0b00)
}
pub fn encode_fmadd_s(rd: u32, rs1: u32, rs2: u32, rs3: u32, rm: u32) -> u32 {
(rs3 << 27)
| (0b00 << 25)
| (rs2 << 20)
| (rs1 << 15)
| (rm << 12)
| (rd << 7)
| Self::OP_FMADD
}
pub fn encode_fmsub_s(rd: u32, rs1: u32, rs2: u32, rs3: u32, rm: u32) -> u32 {
(rs3 << 27)
| (0b00 << 25)
| (rs2 << 20)
| (rs1 << 15)
| (rm << 12)
| (rd << 7)
| Self::OP_FMSUB
}
pub fn encode_feq_s(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_fp_r_type(0b1010000, rs2, rs1, 0b010, rd, Self::OP_FP, 0b00)
}
pub fn encode_flt_s(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_fp_r_type(0b1010000, rs2, rs1, 0b001, rd, Self::OP_FP, 0b00)
}
pub fn encode_fle_s(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_fp_r_type(0b1010000, rs2, rs1, 0b000, rd, Self::OP_FP, 0b00)
}
pub fn encode_fsgnj_s(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_fp_r_type(0b0010000, rs2, rs1, 0b000, rd, Self::OP_FP, 0b00)
}
pub fn encode_fsgnjn_s(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_fp_r_type(0b0010000, rs2, rs1, 0b001, rd, Self::OP_FP, 0b00)
}
pub fn encode_fsgnjx_s(rd: u32, rs1: u32, rs2: u32) -> u32 {
Self::encode_fp_r_type(0b0010000, rs2, rs1, 0b010, rd, Self::OP_FP, 0b00)
}
pub fn encode_fmv_x_w(rd: u32, rs1: u32) -> u32 {
Self::encode_fp_r_type(0b1110000, 0b00000, rs1, 0b000, rd, Self::OP_FP, 0b00)
}
pub fn encode_fmv_w_x(rd: u32, rs1: u32) -> u32 {
Self::encode_fp_r_type(0b1111000, 0b00000, rs1, 0b000, rd, Self::OP_FP, 0b00)
}
}
pub struct VectorEncoder;
impl VectorEncoder {
const OP_V: u32 = 0b1010111;
pub fn encode_vsetvli(rd: u32, rs1: u32, vtypei: u32) -> u32 {
(vtypei << 20) | (rs1 << 15) | (0b111 << 12) | (rd << 7) | Self::OP_V
}
pub fn encode_vadd_vv(vd: u32, vs1: u32, vs2: u32, masked: bool) -> u32 {
let vm = if masked { 0 } else { 1 }; let funct6: u32 = 0b000000;
(funct6 << 26)
| (vm << 25)
| (vs2 << 20)
| (vs1 << 15)
| (0b000 << 12)
| (vd << 7)
| Self::OP_V
}
pub fn encode_vadd_vx(vd: u32, vs1: u32, rs1: u32, masked: bool) -> u32 {
let vm = if masked { 0 } else { 1 };
let funct6: u32 = 0b000000;
(funct6 << 26)
| (vm << 25)
| (rs1 << 20) | (vs1 << 15)
| (0b100 << 12) | (vd << 7)
| Self::OP_V
}
pub fn encode_vadd_vi(vd: u32, vs1: u32, simm5: u32, masked: bool) -> u32 {
let vm = if masked { 0 } else { 1 };
let funct6: u32 = 0b000000;
(funct6 << 26)
| (vm << 25)
| ((simm5 & 0x1F) << 20)
| (vs1 << 15)
| (0b011 << 12)
| (vd << 7)
| Self::OP_V
}
pub fn encode_vmul_vv(vd: u32, vs1: u32, vs2: u32, masked: bool) -> u32 {
let vm = if masked { 0 } else { 1 };
let funct6: u32 = 0b100101;
(funct6 << 26)
| (vm << 25)
| (vs2 << 20)
| (vs1 << 15)
| (0b010 << 12)
| (vd << 7)
| Self::OP_V
}
pub fn encode_vle32_v(vd: u32, rs1: u32, masked: bool) -> u32 {
let vm = if masked { 0 } else { 1 };
let funct3: u32 = 0b000; let width: u32 = 0b110; (width << 29)
| (vm << 25)
| (0b00000 << 20) | (rs1 << 15)
| (funct3 << 12)
| (vd << 7)
| 0b0000111 }
pub fn encode_vse32_v(vs3: u32, rs1: u32, masked: bool) -> u32 {
let vm = if masked { 0 } else { 1 };
let funct3: u32 = 0b000;
let width: u32 = 0b110;
(width << 29)
| (vm << 25)
| (0b00000 << 20)
| (rs1 << 15)
| (funct3 << 12)
| (vs3 << 7)
| 0b0100111 }
pub fn encode_vmv_v_v(vd: u32, vs1: u32) -> u32 {
let funct6: u32 = 0b010111;
(funct6 << 26)
| (1 << 25)
| (0 << 20)
| (vs1 << 15)
| (0b000 << 12)
| (vd << 7)
| Self::OP_V
}
pub fn encode_vmv_v_x(vd: u32, rs1: u32) -> u32 {
let funct6: u32 = 0b010111;
(funct6 << 26)
| (1 << 25)
| (rs1 << 20)
| (0 << 15)
| (0b100 << 12)
| (vd << 7)
| Self::OP_V
}
pub fn encode_vmv_v_i(vd: u32, simm5: u32) -> u32 {
let funct6: u32 = 0b010111;
(funct6 << 26)
| (1 << 25)
| ((simm5 & 0x1F) << 20)
| (0 << 15)
| (0b011 << 12)
| (vd << 7)
| Self::OP_V
}
pub fn encode_vmerge_vvm(vd: u32, vs1: u32, vs2: u32) -> u32 {
let funct6: u32 = 0b010111;
(funct6 << 26)
| (0 << 25)
| (vs2 << 20)
| (vs1 << 15)
| (0b000 << 12)
| (vd << 7)
| Self::OP_V
}
pub fn encode_vmseq_vv(vd: u32, vs1: u32, vs2: u32, masked: bool) -> u32 {
let vm = if masked { 0 } else { 1 };
let funct6: u32 = 0b011000;
(funct6 << 26)
| (vm << 25)
| (vs2 << 20)
| (vs1 << 15)
| (0b000 << 12)
| (vd << 7)
| Self::OP_V
}
pub fn encode_vfadd_vv(vd: u32, vs1: u32, vs2: u32, masked: bool) -> u32 {
let vm = if masked { 0 } else { 1 };
let funct6: u32 = 0b001000;
(funct6 << 26)
| (vm << 25)
| (vs2 << 20)
| (vs1 << 15)
| (0b001 << 12)
| (vd << 7)
| Self::OP_V
}
pub fn encode_vfmul_vv(vd: u32, vs1: u32, vs2: u32, masked: bool) -> u32 {
let vm = if masked { 0 } else { 1 };
let funct6: u32 = 0b100100;
(funct6 << 26)
| (vm << 25)
| (vs2 << 20)
| (vs1 << 15)
| (0b001 << 12)
| (vd << 7)
| Self::OP_V
}
pub fn encode_vredsum_vs(vd: u32, vs1: u32, vs2: u32) -> u32 {
let funct6: u32 = 0b000000;
(funct6 << 26)
| (1 << 25)
| (vs2 << 20)
| (vs1 << 15)
| (0b010 << 12)
| (vd << 7)
| Self::OP_V
}
}
impl RiscVMCEncoder {
pub fn encode_compressed_insn(&self, insn: u16) -> Vec<u8> {
RvcEncoder::to_le_bytes(insn)
}
pub fn encode_with_expansion(
&mut self,
opcode: u32,
rd: u32,
rs1: u32,
rs2: u32,
imm: i64,
) -> Vec<u8> {
if PseudoExpander::is_pseudo(opcode) {
let expander = PseudoExpander::new(self.is_64bit);
let expanded = expander.expand(opcode, rd, rs1, rs2, imm);
let mut bytes = Vec::new();
for instr in expanded {
let word = match RiscVOpcode::from_u32(instr.opcode) {
Some(RiscVOpcode::LUI) => Self::encode_lui(instr.rd, instr.imm as i32),
Some(RiscVOpcode::AUIPC) => Self::encode_auipc(instr.rd, instr.imm as i32),
Some(RiscVOpcode::ADDI) => {
Self::encode_addi(instr.rd, instr.rs1, instr.imm as i32)
}
Some(RiscVOpcode::JALR) => {
Self::encode_jalr(instr.rd, instr.rs1, instr.imm as i32)
}
Some(RiscVOpcode::XORI) => {
Self::encode_xori(instr.rd, instr.rs1, instr.imm as i32)
}
Some(RiscVOpcode::SUB) => Self::encode_sub(instr.rd, instr.rs1, instr.rs2),
Some(RiscVOpcode::SLTIU) => Self::encode_i_type(
instr.imm as i32,
instr.rs1,
F3_SLTIU,
instr.rd,
OP_ALUI,
),
Some(RiscVOpcode::SLTU) => Self::encode_r_type(
F7_BASE, instr.rs2, instr.rs1, F3_SLTU, instr.rd, OP_ALU,
),
_ => 0,
};
bytes.extend_from_slice(&u32_to_le_bytes(word));
}
self.output.extend_from_slice(&bytes);
bytes
} else {
let mi = self.make_mi(opcode, rd, rs1, rs2, imm);
self.encode_instruction(&mi)
}
}
fn make_mi(&self, opcode: u32, rd: u32, rs1: u32, rs2: u32, imm: i64) -> MachineInstr {
let mut mi = MachineInstr::new(opcode);
if rd != 0 || opcode != 0 {
mi.push_reg(rd);
}
if rs1 != 0 {
mi.push_reg(rs1);
}
if rs2 != 0 {
mi.push_reg(rs2);
}
mi.push_imm(imm);
mi
}
}
#[cfg(test)]
mod tests {
use super::*;
fn mi_r(opcode: u32, rd: u16, rs1: u16, rs2: u16) -> MachineInstr {
let mut mi = MachineInstr::new(opcode);
mi.push_reg(rd as u32);
mi.push_reg(rs1 as u32);
mi.push_reg(rs2 as u32);
mi
}
fn mi_i(opcode: u32, rd: u16, rs1: u16, imm: i32) -> MachineInstr {
let mut mi = MachineInstr::new(opcode);
mi.push_reg(rd as u32);
mi.push_reg(rs1 as u32);
mi.push_imm(imm as i64);
mi
}
fn mi_u(opcode: u32, rd: u16, imm: i32) -> MachineInstr {
let mut mi = MachineInstr::new(opcode);
mi.push_reg(rd as u32);
mi.push_imm(imm as i64);
mi
}
#[test]
fn test_encode_r_type_add() {
let word = RiscVMCEncoder::encode_add(5, 10, 11);
assert_eq!(word & 0x7F, OP_ALU);
assert_eq!((word >> 7) & 0x1F, 5); assert_eq!((word >> 12) & 0x7, F3_ADD_SUB);
assert_eq!((word >> 15) & 0x1F, 10); assert_eq!((word >> 20) & 0x1F, 11); assert_eq!((word >> 25) & 0x7F, F7_BASE);
}
#[test]
fn test_encode_sub() {
let word = RiscVMCEncoder::encode_sub(8, 15, 20);
assert_eq!(word & 0x7F, OP_ALU);
assert_eq!((word >> 12) & 0x7, F3_ADD_SUB);
assert_eq!((word >> 25) & 0x7F, F7_ALT);
assert_eq!((word >> 7) & 0x1F, 8);
assert_eq!((word >> 15) & 0x1F, 15);
assert_eq!((word >> 20) & 0x1F, 20);
}
#[test]
fn test_encode_i_type_addi() {
let word = RiscVMCEncoder::encode_addi(5, 10, 42);
assert_eq!(word & 0x7F, OP_ALUI);
assert_eq!((word >> 7) & 0x1F, 5);
assert_eq!((word >> 12) & 0x7, F3_ADDI);
assert_eq!((word >> 15) & 0x1F, 10);
assert_eq!((word >> 20) & 0xFFF, 42);
}
#[test]
fn test_encode_andi() {
let word = RiscVMCEncoder::encode_andi(5, 10, 0xFF);
assert_eq!(word & 0x7F, OP_ALUI);
assert_eq!((word >> 12) & 0x7, F3_ANDI);
}
#[test]
fn test_encode_ori() {
let word = RiscVMCEncoder::encode_ori(5, 10, 0xFF);
assert_eq!(word & 0x7F, OP_ALUI);
assert_eq!((word >> 12) & 0x7, F3_ORI);
}
#[test]
fn test_encode_xori() {
let word = RiscVMCEncoder::encode_xori(5, 10, -1);
assert_eq!(word & 0x7F, OP_ALUI);
assert_eq!((word >> 12) & 0x7, F3_XORI);
}
#[test]
fn test_encode_slli() {
let word = RiscVMCEncoder::encode_slli(5, 10, 3, false);
assert_eq!(word & 0x7F, OP_ALUI);
assert_eq!((word >> 12) & 0x7, F3_SLLI);
assert_eq!((word >> 7) & 0x1F, 5);
assert_eq!((word >> 15) & 0x1F, 10);
}
#[test]
fn test_encode_srli() {
let word = RiscVMCEncoder::encode_srli(5, 10, 2, false);
assert_eq!(word & 0x7F, OP_ALUI);
assert_eq!((word >> 12) & 0x7, F3_SRLI_SRAI);
assert_eq!((word >> 25) & 0x7F, F7_BASE);
}
#[test]
fn test_encode_srai() {
let word = RiscVMCEncoder::encode_srai(5, 10, 4, false);
assert_eq!(word & 0x7F, OP_ALUI);
assert_eq!((word >> 12) & 0x7, F3_SRLI_SRAI);
assert_eq!((word >> 25) & 0x7F, F7_ALT);
}
#[test]
fn test_encode_s_type_sw() {
let word = RiscVMCEncoder::encode_sw(11, 10, 8);
assert_eq!(word & 0x7F, OP_STORE);
assert_eq!((word >> 12) & 0x7, F3_SW);
assert_eq!((word >> 15) & 0x1F, 10); assert_eq!((word >> 20) & 0x1F, 11); assert_eq!((word >> 7) & 0x1F, 8 & 0x1F); assert_eq!((word >> 25) & 0x7F, (8 >> 5) & 0x7F); }
#[test]
fn test_encode_b_type_beq() {
let word = RiscVMCEncoder::encode_beq(10, 11, 16);
assert_eq!(word & 0x7F, OP_BRANCH);
assert_eq!((word >> 12) & 0x7, F3_BEQ);
assert_eq!((word >> 15) & 0x1F, 10);
assert_eq!((word >> 20) & 0x1F, 11);
}
#[test]
fn test_encode_bne() {
let word = RiscVMCEncoder::encode_bne(10, 11, -8);
assert_eq!(word & 0x7F, OP_BRANCH);
assert_eq!((word >> 12) & 0x7, F3_BNE);
}
#[test]
fn test_encode_u_type_lui() {
let word = RiscVMCEncoder::encode_lui(5, 0x12345000u32 as i32);
assert_eq!(word & 0x7F, OP_LUI);
assert_eq!((word >> 7) & 0x1F, 5);
assert_eq!((word >> 12) & 0xFFFFF, 0x12345);
}
#[test]
fn test_encode_auipc() {
let word = RiscVMCEncoder::encode_auipc(3, 0xABCDE000u32 as i32);
assert_eq!(word & 0x7F, OP_AUIPC);
assert_eq!((word >> 7) & 0x1F, 3);
}
#[test]
fn test_encode_j_type_jal() {
let word = RiscVMCEncoder::encode_jal(1, 256);
assert_eq!(word & 0x7F, OP_JAL);
assert_eq!((word >> 7) & 0x1F, 1); }
#[test]
fn test_encode_jalr() {
let word = RiscVMCEncoder::encode_jalr(1, 5, 0);
assert_eq!(word & 0x7F, OP_JALR);
assert_eq!((word >> 7) & 0x1F, 1);
assert_eq!((word >> 15) & 0x1F, 5);
}
#[test]
fn test_get_register_field_gpr() {
assert_eq!(RiscVMCEncoder::get_register_field(3000), 0);
assert_eq!(RiscVMCEncoder::get_register_field(3001), 1);
assert_eq!(RiscVMCEncoder::get_register_field(3031), 31);
}
#[test]
fn test_get_register_field_fpr() {
assert_eq!(RiscVMCEncoder::get_register_field(3050), 0);
assert_eq!(RiscVMCEncoder::get_register_field(3051), 1);
assert_eq!(RiscVMCEncoder::get_register_field(3081), 31);
}
#[test]
fn test_encode_ecall() {
let word = RiscVMCEncoder::encode_ecall();
assert_eq!(word & 0x7F, OP_SYSTEM);
assert_eq!((word >> 12) & 0x7, F3_PRIV);
assert_eq!((word >> 20) & 0xFFF, 0);
}
#[test]
fn test_encode_ebreak() {
let word = RiscVMCEncoder::encode_ebreak();
assert_eq!(word & 0x7F, OP_SYSTEM);
assert_eq!((word >> 20) & 0xFFF, 1);
}
#[test]
fn test_encode_fence() {
let word = RiscVMCEncoder::encode_fence(0b0011, 0b0011);
assert_eq!(word & 0x7F, OP_FENCE);
assert_eq!((word >> 12) & 0x7, F3_FENCE);
}
#[test]
fn test_u32_to_le_bytes() {
let bytes = u32_to_le_bytes(0x12345678);
assert_eq!(bytes, vec![0x78, 0x56, 0x34, 0x12]);
}
#[test]
fn test_encode_function_integration() {
let mut enc = RiscVMCEncoder::new(false);
let word = RiscVMCEncoder::encode_add(5, 10, 11);
let bytes = u32_to_le_bytes(word);
assert_eq!(bytes.len(), 4);
let decoded = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
assert_eq!(decoded & 0x7F, OP_ALU);
}
#[test]
fn test_rvc_encode_c_li() {
let insn = RvcEncoder::encode_c_li(5, 21);
assert_eq!((insn >> 13) & 0x7, 0b010);
assert_eq!((insn >> 7) & 0x1F, 5);
assert_eq!((insn >> 2) & 0x1F, 21);
assert_eq!(insn & 0x3, 0b01);
}
#[test]
fn test_rvc_encode_c_mv() {
let insn = RvcEncoder::encode_c_mv(5, 10).unwrap();
assert_eq!((insn >> 12) & 0xF, 0b1000);
assert_eq!((insn >> 7) & 0x1F, 5);
assert_eq!((insn >> 2) & 0x1F, 10);
assert_eq!(insn & 0x3, 0b10);
}
#[test]
fn test_rvc_encode_c_mv_rd0() {
assert!(RvcEncoder::encode_c_mv(0, 10).is_none());
}
#[test]
fn test_rvc_encode_c_add() {
let insn = RvcEncoder::encode_c_add(5, 10).unwrap();
assert_eq!((insn >> 12) & 0xF, 0b1001);
assert_eq!((insn >> 7) & 0x1F, 5);
assert_eq!((insn >> 2) & 0x1F, 10);
}
#[test]
fn test_rvc_encode_c_jr() {
let insn = RvcEncoder::encode_c_jr(5).unwrap();
assert_eq!((insn >> 12) & 0xF, 0b1000);
assert_eq!((insn >> 7) & 0x1F, 5);
assert_eq!(insn & 0x3F, 0b10); }
#[test]
fn test_rvc_encode_c_beqz() {
let insn = RvcEncoder::encode_c_beqz(2, 32).unwrap();
assert_eq!((insn >> 13) & 0x7, 0b110);
assert_eq!((insn >> 7) & 0x7, 2);
assert_eq!(insn & 0x3, 0b01);
}
#[test]
fn test_rvc_encode_c_bnez() {
let insn = RvcEncoder::encode_c_bnez(3, -64).unwrap();
assert_eq!((insn >> 13) & 0x7, 0b111);
assert_eq!((insn >> 7) & 0x7, 3);
}
#[test]
fn test_rvc_encode_c_j() {
let insn = RvcEncoder::encode_c_j(256).unwrap();
assert_eq!((insn >> 13) & 0x7, 0b101);
assert_eq!(insn & 0x3, 0b01);
}
#[test]
fn test_rvc_encode_c_slli() {
let insn = RvcEncoder::encode_c_slli(5, 3).unwrap();
assert_eq!((insn >> 13) & 0x7, 0b000);
assert_eq!((insn >> 7) & 0x1F, 5);
assert_eq!(insn & 0x3, 0b10);
}
#[test]
fn test_rvc_encode_c_lui() {
let insn = RvcEncoder::encode_c_lui(5, 0x20000).unwrap();
assert_eq!((insn >> 13) & 0x7, 0b011);
assert_eq!((insn >> 7) & 0x1F, 5);
}
#[test]
fn test_rvc_encode_c_lwsp() {
let insn = RvcEncoder::encode_c_lwsp(5, 32).unwrap();
assert_eq!((insn >> 13) & 0x7, 0b010);
assert_eq!((insn >> 7) & 0x1F, 5);
assert_eq!(insn & 0x3, 0b10);
}
#[test]
fn test_rvc_encode_c_swsp() {
let insn = RvcEncoder::encode_c_swsp(10, 64);
assert_eq!((insn >> 13) & 0x7, 0b110);
assert_eq!((insn >> 2) & 0x1F, 10);
assert_eq!(insn & 0x3, 0b10);
}
#[test]
fn test_pseudo_expand_li_small() {
let expander = PseudoExpander::new(false);
let result = expander.expand_li(5, 42);
assert_eq!(result.len(), 1);
assert_eq!(result[0].opcode, RiscVOpcode::ADDI as u32);
assert_eq!(result[0].rd, 5);
assert_eq!(result[0].rs1, 0); assert_eq!(result[0].imm, 42);
}
#[test]
fn test_pseudo_expand_li_large() {
let expander = PseudoExpander::new(false);
let result = expander.expand_li(5, 0x12345);
assert_eq!(result.len(), 2);
assert_eq!(result[0].opcode, RiscVOpcode::LUI as u32);
assert_eq!(result[1].opcode, RiscVOpcode::ADDI as u32);
}
#[test]
fn test_pseudo_expand_mv() {
let expander = PseudoExpander::new(false);
let result = expander.expand_mv(5, 10);
assert_eq!(result.len(), 1);
assert_eq!(result[0].opcode, RiscVOpcode::ADDI as u32);
assert_eq!(result[0].rd, 5);
assert_eq!(result[0].rs1, 10);
assert_eq!(result[0].imm, 0);
}
#[test]
fn test_pseudo_expand_not() {
let expander = PseudoExpander::new(false);
let result = expander.expand_not(5, 10);
assert_eq!(result[0].opcode, RiscVOpcode::XORI as u32);
assert_eq!(result[0].imm, -1);
}
#[test]
fn test_pseudo_expand_neg() {
let expander = PseudoExpander::new(false);
let result = expander.expand_neg(5, 10);
assert_eq!(result[0].opcode, RiscVOpcode::SUB as u32);
assert_eq!(result[0].rs1, 0);
assert_eq!(result[0].rs2, 10);
}
#[test]
fn test_pseudo_expand_seqz() {
let expander = PseudoExpander::new(false);
let result = expander.expand_seqz(5, 10);
assert_eq!(result[0].opcode, RiscVOpcode::SLTIU as u32);
assert_eq!(result[0].imm, 1);
}
#[test]
fn test_pseudo_expand_snez() {
let expander = PseudoExpander::new(false);
let result = expander.expand_snez(5, 10);
assert_eq!(result[0].opcode, RiscVOpcode::SLTU as u32);
}
#[test]
fn test_pseudo_expand_call() {
let expander = PseudoExpander::new(false);
let result = expander.expand_call(0x1000);
assert_eq!(result.len(), 2);
assert_eq!(result[0].opcode, RiscVOpcode::AUIPC as u32);
assert_eq!(result[1].opcode, RiscVOpcode::JALR as u32);
}
#[test]
fn test_pseudo_expand_tail() {
let expander = PseudoExpander::new(false);
let result = expander.expand_tail(0x1000);
assert_eq!(result.len(), 2);
assert_eq!(result[0].opcode, RiscVOpcode::AUIPC as u32);
assert_eq!(result[1].opcode, RiscVOpcode::JALR as u32);
}
#[test]
fn test_pseudo_is_pseudo() {
assert!(PseudoExpander::is_pseudo(RiscVOpcode::LI as u32));
assert!(PseudoExpander::is_pseudo(RiscVOpcode::LA as u32));
assert!(PseudoExpander::is_pseudo(RiscVOpcode::CALL as u32));
assert!(PseudoExpander::is_pseudo(RiscVOpcode::MV as u32));
assert!(!PseudoExpander::is_pseudo(RiscVOpcode::ADD as u32));
}
#[test]
fn test_immediate_validation_i_type() {
assert!(ImmediateValidator::is_valid_i_imm(0));
assert!(ImmediateValidator::is_valid_i_imm(2047));
assert!(ImmediateValidator::is_valid_i_imm(-2048));
assert!(!ImmediateValidator::is_valid_i_imm(2048));
assert!(!ImmediateValidator::is_valid_i_imm(-2049));
}
#[test]
fn test_immediate_validation_b_type() {
assert!(ImmediateValidator::is_valid_b_imm(0));
assert!(ImmediateValidator::is_valid_b_imm(4094));
assert!(ImmediateValidator::is_valid_b_imm(-4096));
assert!(!ImmediateValidator::is_valid_b_imm(4096));
assert!(!ImmediateValidator::is_valid_b_imm(1)); }
#[test]
fn test_immediate_validation_u_type() {
assert!(ImmediateValidator::is_valid_u_imm(0x1000));
assert!(ImmediateValidator::is_valid_u_imm(-4096)); assert!(!ImmediateValidator::is_valid_u_imm(1));
}
#[test]
fn test_immediate_validation_j_type() {
assert!(ImmediateValidator::is_valid_j_imm(0));
assert!(ImmediateValidator::is_valid_j_imm(1048574));
assert!(ImmediateValidator::is_valid_j_imm(-1048576));
assert!(!ImmediateValidator::is_valid_j_imm(1048576));
assert!(!ImmediateValidator::is_valid_j_imm(1)); }
#[test]
fn test_immediate_validation_shamt() {
assert!(ImmediateValidator::is_valid_shamt_rv32(0));
assert!(ImmediateValidator::is_valid_shamt_rv32(31));
assert!(!ImmediateValidator::is_valid_shamt_rv32(32));
assert!(ImmediateValidator::is_valid_shamt_rv64(63));
assert!(!ImmediateValidator::is_valid_shamt_rv64(64));
}
#[test]
fn test_atomic_encode_lr_w() {
let word = AtomicEncoder::encode_lr_w(5, 10, false, false);
assert_eq!(word & 0x7F, 0b0101111);
assert_eq!((word >> 7) & 0x1F, 5);
assert_eq!((word >> 15) & 0x1F, 10);
}
#[test]
fn test_atomic_encode_sc_w() {
let word = AtomicEncoder::encode_sc_w(5, 10, 11, true, true);
assert_eq!(word & 0x7F, 0b0101111);
assert_eq!((word >> 26) & 0x1, 1); assert_eq!((word >> 25) & 0x1, 1); }
#[test]
fn test_atomic_encode_amoswap_w() {
let word = AtomicEncoder::encode_amoswap_w(5, 10, 11, false, false);
assert_eq!(word & 0x7F, 0b0101111);
assert_eq!((word >> 27) & 0x1F, 0b00001); }
#[test]
fn test_atomic_encode_amoadd_w() {
let word = AtomicEncoder::encode_amoadd_w(5, 10, 11, false, false);
assert_eq!((word >> 27) & 0x1F, 0b00000);
}
#[test]
fn test_fp_encode_fadd_s() {
let word = FpEncoder::encode_fadd_s(5, 10, 11, FpEncoder::RM_RNE);
assert_eq!(word & 0x7F, 0b1010011);
assert_eq!((word >> 12) & 0x7, 0b000); }
#[test]
fn test_fp_encode_fadd_d() {
let word = FpEncoder::encode_fadd_d(5, 10, 11, FpEncoder::RM_RTZ);
assert_eq!(word & 0x7F, 0b1010011);
assert_eq!((word >> 12) & 0x7, 0b001); }
#[test]
fn test_fp_encode_fsqrt_s() {
let word = FpEncoder::encode_fsqrt_s(5, 10, FpEncoder::RM_RDN);
assert_eq!(word & 0x7F, 0b1010011);
assert_eq!((word >> 12) & 0x7, 0b010);
}
#[test]
fn test_fp_encode_flw() {
let word = FpEncoder::encode_flw(5, 10, 8);
assert_eq!(word & 0x7F, 0b0000111);
assert_eq!((word >> 7) & 0x1F, 5);
assert_eq!((word >> 15) & 0x1F, 10);
}
#[test]
fn test_fp_encode_fsw() {
let word = FpEncoder::encode_fsw(11, 10, 8);
assert_eq!(word & 0x7F, 0b0100111);
}
#[test]
fn test_fp_encode_fmadd_s() {
let word = FpEncoder::encode_fmadd_s(5, 10, 11, 12, FpEncoder::RM_RNE);
assert_eq!(word & 0x7F, 0b1000011);
assert_eq!((word >> 27) & 0x1F, 12); }
#[test]
fn test_fp_encode_fmsub_s() {
let word = FpEncoder::encode_fmsub_s(5, 10, 11, 12, FpEncoder::RM_RNE);
assert_eq!(word & 0x7F, 0b1000111);
}
#[test]
fn test_fp_encode_fmv_x_w() {
let word = FpEncoder::encode_fmv_x_w(5, 10);
assert_eq!(word & 0x7F, 0b1010011);
assert_eq!((word >> 25) & 0x7F, 0b1110000);
}
#[test]
fn test_fp_encode_fmv_w_x() {
let word = FpEncoder::encode_fmv_w_x(5, 10);
assert_eq!(word & 0x7F, 0b1010011);
assert_eq!((word >> 25) & 0x7F, 0b1111000);
}
#[test]
fn test_vector_encode_vadd_vv() {
let word = VectorEncoder::encode_vadd_vv(5, 10, 11, true);
assert_eq!(word & 0x7F, 0b1010111);
assert_eq!((word >> 26) & 0x3F, 0b000000); }
#[test]
fn test_vector_encode_vadd_vx() {
let word = VectorEncoder::encode_vadd_vx(5, 10, 11, false);
assert_eq!(word & 0x7F, 0b1010111);
assert_eq!((word >> 25) & 0x1, 1); }
#[test]
fn test_vector_encode_vmul_vv() {
let word = VectorEncoder::encode_vmul_vv(5, 10, 11, false);
assert_eq!(word & 0x7F, 0b1010111);
assert_eq!((word >> 26) & 0x3F, 0b100101);
}
#[test]
fn test_vector_encode_vle32_v() {
let word = VectorEncoder::encode_vle32_v(5, 10, false);
assert_eq!(word & 0x7F, 0b0000111); }
#[test]
fn test_vector_encode_vse32_v() {
let word = VectorEncoder::encode_vse32_v(5, 10, false);
assert_eq!(word & 0x7F, 0b0100111); }
#[test]
fn test_vector_encode_vmv_v_v() {
let word = VectorEncoder::encode_vmv_v_v(5, 10);
assert_eq!(word & 0x7F, 0b1010111);
assert_eq!((word >> 26) & 0x3F, 0b010111);
}
#[test]
fn test_vector_encode_vfadd_vv() {
let word = VectorEncoder::encode_vfadd_vv(5, 10, 11, true);
assert_eq!(word & 0x7F, 0b1010111);
assert_eq!((word >> 26) & 0x3F, 0b001000);
}
#[test]
fn test_vector_encode_vfmul_vv() {
let word = VectorEncoder::encode_vfmul_vv(5, 10, 11, false);
assert_eq!(word & 0x7F, 0b1010111);
assert_eq!((word >> 26) & 0x3F, 0b100100);
}
#[test]
fn test_vector_encode_vmseq_vv() {
let word = VectorEncoder::encode_vmseq_vv(5, 10, 11, false);
assert_eq!(word & 0x7F, 0b1010111);
assert_eq!((word >> 26) & 0x3F, 0b011000);
}
}