blob: 84031b82381c89241720007d5986c7c29925f936 [file]
// Copyright 2025 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
use super::Instr;
use crate::riscv::{
FUNCT3_BRANCH_EQ, FUNCT3_BRANCH_NE, FUNCT3_LOAD_W, FUNCT3_OP_ADDI, FUNCT3_OP_ANDI,
FUNCT3_OP_SLI, FUNCT3_STORE_W, FUNCT10_ADD, FUNCT10_AND, FUNCT10_OR, FUNCT10_SRAI,
FUNCT10_SRLI, FUNCT10_SUB, FUNCT10_XOR, Instr32B, Instr32I, Instr32IS, Instr32J, Instr32R,
Instr32S, Instr32U, Opcode, Reg,
};
const OP_MASK_5: u16 = 0xe003;
const OP_MASK_6: u16 = 0xf003;
const OP_MASK_7: u16 = 0xec03;
const OP_MASK_9: u16 = 0xfc63;
macro_rules! static_assert {
($expression:expr) => {
const _: () = assert!($expression);
};
}
/// Decodes a 16-bit RV32IMC compressed instruction `instr` into a 32-bit RV32IM instruction.
///
pub fn decompress_instr(instr: u16) -> Option<Instr> {
match instr & OP_MASK_5 {
rv16::CJ::OP_CODE => {
static_assert!(rv16::CJ::OP_MASK == OP_MASK_5);
let instr = rv16::CJ::from_bits(instr);
let mut result = Instr32J::from_bits(0);
result.set_opcode(Opcode::JAL);
result.set_imm(instr.imm().into());
result.set_rd(Reg::X0);
return Some(Instr(result.into_bits()));
}
rv16::CJal::OP_CODE => {
static_assert!(rv16::CJal::OP_MASK == OP_MASK_5);
let instr = rv16::CJal::from_bits(instr);
let mut result = Instr32J(0);
result.set_opcode(Opcode::JAL);
result.set_imm(i32::from(instr.imm()));
result.set_rd(Reg::X1Ra);
return Some(Instr(result.into_bits()));
}
rv16::CLw::OP_CODE => {
static_assert!(rv16::CLw::OP_MASK == OP_MASK_5);
let instr = rv16::CLw::from_bits(instr);
let mut result = Instr32I::from_bits(0);
result.set_opcode(Opcode::LOAD);
result.set_funct3(FUNCT3_LOAD_W);
result.set_uimm(instr.uimm().into());
result.set_rs1(instr.rs1());
result.set_rd(instr.rd());
return Some(Instr(result.into_bits()));
}
rv16::CSw::OP_CODE => {
static_assert!(rv16::CSw::OP_MASK == OP_MASK_5);
let instr = rv16::CSw::from_bits(instr);
let mut result = Instr32S::from_bits(0);
result.set_opcode(Opcode::STORE);
result.set_funct3(FUNCT3_STORE_W);
result.set_uimm(instr.uimm().into());
result.set_rs1(instr.rs1());
result.set_rs2(instr.rs2());
return Some(Instr(result.into_bits()));
}
rv16::CLwsp::OP_CODE => {
static_assert!(rv16::CLwsp::OP_MASK == OP_MASK_5);
let instr = rv16::CLwsp::from_bits(instr);
if instr.rd() != Reg::X0 {
let mut result = Instr32I::from_bits(0);
result.set_opcode(Opcode::LOAD);
result.set_funct3(FUNCT3_LOAD_W);
result.set_uimm(instr.uimm().into());
result.set_rs1(Reg::X2Sp);
result.set_rd(instr.rd());
return Some(Instr(result.into_bits()));
}
}
rv16::CSwsp::OP_CODE => {
static_assert!(rv16::CSwsp::OP_MASK == OP_MASK_5);
let instr = rv16::CSwsp::from_bits(instr);
let mut result = Instr32S::from_bits(0);
result.set_opcode(Opcode::STORE);
result.set_funct3(FUNCT3_STORE_W);
result.set_uimm(instr.uimm().into());
result.set_rs1(Reg::X2Sp);
result.set_rs2(instr.rs2());
return Some(Instr(result.into_bits()));
}
rv16::CAddi::OP_CODE => {
static_assert!(rv16::CAddi::OP_MASK == OP_MASK_5);
let instr = rv16::CAddi::from_bits(instr);
let mut result = Instr32I::from_bits(0);
result.set_opcode(Opcode::OP_IMM);
result.set_funct3(FUNCT3_OP_ADDI);
result.set_imm(instr.nzimm().into());
result.set_rs1(instr.rs1rd());
result.set_rd(instr.rs1rd());
return Some(Instr(result.into_bits()));
}
rv16::CAddi4spn::OP_CODE => {
static_assert!(rv16::CAddi4spn::OP_MASK == OP_MASK_5);
let instr = rv16::CAddi4spn::from_bits(instr);
if instr.nzuimm() != 0 {
let mut result = Instr32I::from_bits(0);
result.set_opcode(Opcode::OP_IMM);
result.set_funct3(FUNCT3_OP_ADDI);
result.set_imm(instr.nzuimm().into());
result.set_rs1(Reg::X2Sp);
result.set_rd(instr.rd());
return Some(Instr(result.into_bits()));
}
}
rv16::CLi::OP_CODE => {
static_assert!(rv16::CLui::OP_MASK == OP_MASK_5);
let instr = rv16::CLi::from_bits(instr);
let mut result = Instr32I::from_bits(0);
result.set_opcode(Opcode::OP_IMM);
result.set_funct3(FUNCT3_OP_ADDI);
result.set_imm(instr.nzimm());
result.set_rs1(Reg::X0);
result.set_rd(instr.rd());
return Some(Instr(result.into_bits()));
}
rv16::CLui::OP_CODE => {
static_assert!(rv16::CLui::OP_MASK == OP_MASK_5);
let instr = rv16::CLui::from_bits(instr);
if instr.nzimm() != 0 {
if instr.rd() == Reg::X2Sp {
static_assert!(rv16::CAddi16sp::OP_MASK == OP_MASK_5);
static_assert!(rv16::CAddi16sp::OP_CODE == rv16::CLui::OP_CODE);
let instr = rv16::CAddi16sp::from_bits(instr.into_bits());
let mut result = Instr32I::from_bits(0);
result.set_opcode(Opcode::OP_IMM);
result.set_funct3(FUNCT3_OP_ADDI);
result.set_imm(instr.nzimm());
result.set_rs1(Reg::X2Sp);
result.set_rd(Reg::X2Sp);
return Some(Instr(result.into_bits()));
} else {
let mut result = Instr32U::from_bits(0);
result.set_opcode(Opcode::LUI);
result.set_imm(instr.nzimm() >> 12);
result.set_rd(instr.rd());
return Some(Instr(result.into_bits()));
}
}
}
rv16::CBeqz::OP_CODE => {
static_assert!(rv16::CBeqz::OP_MASK == OP_MASK_5);
let instr = rv16::CBeqz::from_bits(instr);
let mut result = Instr32B::from_bits(0);
result.set_opcode(Opcode::BRANCH);
result.set_funct3(FUNCT3_BRANCH_EQ);
result.set_imm(i32::from(instr.offset()));
result.set_rs1(instr.rs1());
result.set_rs2(Reg::X0);
return Some(Instr(result.into_bits()));
}
rv16::CBnez::OP_CODE => {
static_assert!(rv16::CBnez::OP_MASK == OP_MASK_5);
let instr = rv16::CBnez::from_bits(instr);
let mut result = Instr32B::from_bits(0);
result.set_opcode(Opcode::BRANCH);
result.set_funct3(FUNCT3_BRANCH_NE);
result.set_imm(i32::from(instr.offset()));
result.set_rs1(instr.rs1());
result.set_rs2(Reg::X0);
return Some(Instr(result.into_bits()));
}
rv16::CSlli::OP_CODE => {
static_assert!(rv16::CSlli::OP_MASK == OP_MASK_5);
let instr = rv16::CSlli::from_bits(instr);
let mut result = Instr32I::from_bits(0);
// For RV32C, code points with shamt[5] == 1 are reserved
if instr.shamt() & 0x20 == 0 {
result.set_opcode(Opcode::OP_IMM);
result.set_funct3(FUNCT3_OP_SLI);
result.set_uimm(instr.shamt().into());
result.set_rs1(instr.rs1rd());
result.set_rd(instr.rs1rd());
return Some(Instr(result.into_bits()));
}
}
_ => {}
}
match instr & OP_MASK_6 {
rv16::CMv::OP_CODE => {
static_assert!(rv16::CMv::OP_MASK == OP_MASK_6);
let instr = rv16::CMv::from_bits(instr);
if instr.rs2() == Reg::X0 {
let instr = rv16::CJr::from_bits(instr.into_bits());
let mut result = Instr32I::from_bits(0);
result.set_opcode(Opcode::JALR);
result.set_funct3(0);
result.set_imm(0);
result.set_rs1(instr.rs1());
result.set_rd(Reg::X0);
return Some(Instr(result.into_bits()));
} else {
let mut result = Instr32R::from_bits(0);
result.set_opcode(Opcode::OP);
result.set_funct10(FUNCT10_ADD);
result.set_rs1(Reg::X0);
result.set_rs2(instr.rs2());
result.set_rd(instr.rd());
return Some(Instr(result.into_bits()));
}
}
rv16::CAdd::OP_CODE => {
static_assert!(rv16::CAdd::OP_MASK == OP_MASK_6);
let instr = rv16::CAdd::from_bits(instr);
if instr.rs1rd() == Reg::X0 && instr.rs2() == Reg::X0 {
// EBREAK
return Some(Instr(0x100073));
}
if instr.rs2() == Reg::X0 {
let instr = rv16::CJalr::from_bits(instr.into_bits());
let mut result = Instr32I::from_bits(0);
result.set_opcode(Opcode::JALR);
result.set_funct3(0);
result.set_imm(0);
result.set_rs1(instr.rs1());
result.set_rd(Reg::X1Ra);
return Some(Instr(result.into_bits()));
} else {
let mut result = Instr32R::from_bits(0);
result.set_opcode(Opcode::OP);
result.set_funct10(FUNCT10_ADD);
result.set_rs1(instr.rs1rd());
result.set_rs2(instr.rs2());
result.set_rd(instr.rs1rd());
return Some(Instr(result.into_bits()));
}
}
_ => {}
}
match instr & OP_MASK_7 {
rv16::CSrli::OP_CODE => {
static_assert!(rv16::CSrli::OP_MASK == OP_MASK_7);
let instr = rv16::CSrli::from_bits(instr);
// For RV32C, code points with shamt[5] == 1 are reserved
if instr.shamt() & 0x20 == 0 {
let mut result = Instr32IS::from_bits(0);
result.set_opcode(Opcode::OP_IMM);
result.set_funct10(FUNCT10_SRLI);
result.set_uimm(instr.shamt());
result.set_rs1(instr.rs1rd());
result.set_rd(instr.rs1rd());
return Some(Instr(result.into_bits()));
}
}
rv16::CSrai::OP_CODE => {
static_assert!(rv16::CSrai::OP_MASK == OP_MASK_7);
let instr = rv16::CSrai::from_bits(instr);
// For RV32C, code points with shamt[5] == 1 are reserved
if instr.shamt() & 0x20 == 0 {
let mut result = Instr32IS::from_bits(0);
result.set_opcode(Opcode::OP_IMM);
result.set_funct10(FUNCT10_SRAI);
result.set_uimm(instr.shamt());
result.set_rs1(instr.rs1rd());
result.set_rd(instr.rs1rd());
return Some(Instr(result.into_bits()));
}
}
rv16::CAndi::OP_CODE => {
static_assert!(rv16::CAndi::OP_MASK == OP_MASK_7);
let instr = rv16::CAndi::from_bits(instr);
let mut result = Instr32I::from_bits(0);
result.set_opcode(Opcode::OP_IMM);
result.set_funct3(FUNCT3_OP_ANDI);
result.set_imm(instr.imm().into());
result.set_rs1(instr.rs1rd());
result.set_rd(instr.rs1rd());
return Some(Instr(result.into_bits()));
}
_ => {}
}
match instr & OP_MASK_9 {
rv16::CAnd::OP_CODE => {
static_assert!(rv16::CAnd::OP_MASK == OP_MASK_9);
let instr = rv16::CAnd::from_bits(instr);
let mut result = Instr32R::from_bits(0);
result.set_opcode(Opcode::OP);
result.set_funct10(FUNCT10_AND);
result.set_rs1(instr.rs1rd());
result.set_rs2(instr.rs2());
result.set_rd(instr.rs1rd());
return Some(Instr(result.into_bits()));
}
rv16::COr::OP_CODE => {
static_assert!(rv16::COr::OP_MASK == OP_MASK_9);
let instr = rv16::COr::from_bits(instr);
let mut result = Instr32R::from_bits(0);
result.set_opcode(Opcode::OP);
result.set_funct10(FUNCT10_OR);
result.set_rs1(instr.rs1rd());
result.set_rs2(instr.rs2());
result.set_rd(instr.rs1rd());
return Some(Instr(result.into_bits()));
}
rv16::CXor::OP_CODE => {
static_assert!(rv16::CXor::OP_MASK == OP_MASK_9);
let instr = rv16::CXor::from_bits(instr);
let mut result = Instr32R::from_bits(0);
result.set_opcode(Opcode::OP);
result.set_funct10(FUNCT10_XOR);
result.set_rs1(instr.rs1rd());
result.set_rs2(instr.rs2());
result.set_rd(instr.rs1rd());
return Some(Instr(result.into_bits()));
}
rv16::CSub::OP_CODE => {
static_assert!(rv16::CSub::OP_MASK == OP_MASK_9);
let instr = rv16::CSub::from_bits(instr);
let mut result = Instr32R::from_bits(0);
result.set_opcode(Opcode::OP);
result.set_funct10(FUNCT10_SUB);
result.set_rs1(instr.rs1rd());
result.set_rs2(instr.rs2());
result.set_rd(instr.rs1rd());
return Some(Instr(result.into_bits()));
}
_ => {}
}
None
}
mod rv16 {
use bitfield_struct::bitfield;
use pw_cast::try_cast;
use crate::riscv::{Reg, sign_extend_i16, sign_extend_i32};
const fn unwrap_or_0(val: Option<u16>) -> u16 {
match val {
Some(val) => val,
None => 0,
}
}
const fn unwrap_or_0_32(val: Option<u32>) -> u32 {
match val {
Some(val) => val,
None => 0,
}
}
const fn bit_range(val: u16, msb: u32, lsb: u32) -> u16 {
assert!(msb < 16 && lsb < 16);
(val >> lsb) & (unwrap_or_0(1_u16.checked_shl(msb + 1 - lsb)) - 1)
}
const fn set_bit_range(result: &mut u16, msb: u32, lsb: u32, val: u16) {
assert!(msb < 16 && lsb < 16);
let mask = unwrap_or_0(1_u16.checked_shl(msb + 1 - lsb)) - 1;
let val = val & mask;
*result = (*result & !(mask << lsb)) | (val << lsb);
}
const fn set_bit_range_32(result: &mut u32, msb: u32, lsb: u32, val: u32) {
assert!(msb < 32 && lsb < 32);
let mask = unwrap_or_0_32(1_u32.checked_shl(msb + 1 - lsb)) - 1;
let val = val & mask;
*result = (*result & !(mask << lsb)) | (val << lsb);
}
/// RISCV C.LWSP instruction
#[bitfield(u16)]
pub struct CLwsp {
#[bits(7)]
__: (),
#[bits(5)]
pub rd: Reg,
#[bits(4)]
__: (),
}
impl CLwsp {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0x4002;
pub fn uimm(&self) -> u16 {
let mut result = 0;
set_bit_range(&mut result, 5, 5, bit_range(self.0, 12, 12));
set_bit_range(&mut result, 4, 2, bit_range(self.0, 6, 4));
set_bit_range(&mut result, 7, 6, bit_range(self.0, 3, 2));
result
}
}
/// RISCV C.SWSP instruction
#[bitfield(u16)]
pub struct CSwsp {
#[bits(2)]
__: (),
#[bits(5)]
pub rs2: Reg,
#[bits(9)]
__: (),
}
impl CSwsp {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0xc002;
pub fn uimm(&self) -> u16 {
let mut result = 0;
set_bit_range(&mut result, 5, 2, bit_range(self.0, 12, 9));
set_bit_range(&mut result, 7, 6, bit_range(self.0, 8, 7));
result
}
}
/// RISCV C.LW instruction
#[bitfield(u16)]
pub struct CLw {
#[bits(16)]
__: (),
}
impl CLw {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0x4000;
pub const fn rs1(&self) -> Reg {
Reg::from_bits(try_cast!(bit_range(self.0, 9, 7) + 8 => u8).unwrap())
}
pub const fn rd(&self) -> Reg {
Reg::from_bits(try_cast!(bit_range(self.0, 4, 2) + 8 => u8).unwrap())
}
pub const fn uimm(&self) -> u16 {
let mut result = 0;
set_bit_range(&mut result, 5, 3, bit_range(self.0, 12, 10));
set_bit_range(&mut result, 2, 2, bit_range(self.0, 6, 6));
set_bit_range(&mut result, 6, 6, bit_range(self.0, 5, 5));
result
}
}
/// RISCV C.SW instruction
#[bitfield(u16)]
pub struct CSw {
#[bits(16)]
__: (),
}
impl CSw {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0xc000;
pub const fn rs1(&self) -> Reg {
Reg::from_bits(try_cast!(bit_range(self.0, 9, 7) + 8 => u8).unwrap())
}
pub const fn rs2(&self) -> Reg {
Reg::from_bits(try_cast!(bit_range(self.0, 4, 2) + 8 => u8).unwrap())
}
pub const fn uimm(&self) -> u16 {
let mut result = 0;
set_bit_range(&mut result, 5, 3, bit_range(self.0, 12, 10));
set_bit_range(&mut result, 2, 2, bit_range(self.0, 6, 6));
set_bit_range(&mut result, 6, 6, bit_range(self.0, 5, 5));
result
}
}
/// RISCV C.J instruction
#[bitfield(u16)]
pub struct CJ {
#[bits(16)]
__: (),
}
impl CJ {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0xa001;
pub const fn imm(&self) -> i16 {
let mut result = 0u16;
set_bit_range(&mut result, 11, 11, bit_range(self.0, 12, 12));
set_bit_range(&mut result, 4, 4, bit_range(self.0, 11, 11));
set_bit_range(&mut result, 9, 8, bit_range(self.0, 10, 9));
set_bit_range(&mut result, 10, 10, bit_range(self.0, 8, 8));
set_bit_range(&mut result, 6, 6, bit_range(self.0, 7, 7));
set_bit_range(&mut result, 7, 7, bit_range(self.0, 6, 6));
set_bit_range(&mut result, 3, 1, bit_range(self.0, 5, 3));
set_bit_range(&mut result, 5, 5, bit_range(self.0, 2, 2));
sign_extend_i16(result, 11)
}
}
/// RISCV C.JAL instruction
#[bitfield(u16)]
pub struct CJal {
#[bits(16)]
__: (),
}
impl CJal {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0x2001;
pub const fn imm(&self) -> i16 {
CJ(self.0).imm()
}
}
/// RISCV C.ADDI instruction
#[bitfield(u16)]
pub struct CAddi {
#[bits(16)]
__: (),
}
impl CAddi {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0x0001;
pub const fn nzimm(&self) -> i16 {
let mut result = 0u16;
set_bit_range(&mut result, 5, 5, bit_range(self.0, 12, 12));
set_bit_range(&mut result, 4, 0, bit_range(self.0, 6, 2));
sign_extend_i16(result, 5)
}
pub const fn rs1rd(&self) -> Reg {
Reg::from_bits(try_cast!(bit_range(self.0, 11, 7) => u8).unwrap())
}
}
/// RISCV C.ADDI4SPN instruction
#[bitfield(u16)]
pub struct CAddi4spn {
#[bits(16)]
__: (),
}
impl CAddi4spn {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0x0000;
pub const fn nzuimm(&self) -> u16 {
let mut result = 0u16;
set_bit_range(&mut result, 5, 4, bit_range(self.0, 12, 11));
set_bit_range(&mut result, 9, 6, bit_range(self.0, 10, 7));
set_bit_range(&mut result, 2, 2, bit_range(self.0, 6, 6));
set_bit_range(&mut result, 3, 3, bit_range(self.0, 5, 5));
result
}
pub fn rd(&self) -> Reg {
Reg::from_bits(try_cast!(bit_range(self.0, 4, 2) => u8).unwrap() + 8)
}
}
/// RISCV C.ADDI4SPN instruction
#[bitfield(u16)]
pub struct CAddi16sp {
#[bits(16)]
__: (),
}
impl CAddi16sp {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
#[allow(dead_code)]
pub const OP_CODE: u16 = 0x6001;
pub fn nzimm(&self) -> i32 {
let mut result = 0_u32;
set_bit_range_32(&mut result, 9, 9, u32::from(bit_range(self.0, 12, 12)));
set_bit_range_32(&mut result, 4, 4, u32::from(bit_range(self.0, 6, 6)));
set_bit_range_32(&mut result, 6, 6, u32::from(bit_range(self.0, 5, 5)));
set_bit_range_32(&mut result, 8, 7, u32::from(bit_range(self.0, 4, 3)));
set_bit_range_32(&mut result, 5, 5, u32::from(bit_range(self.0, 2, 2)));
sign_extend_i32(result, 9)
}
}
/// RISCV C.LI instruction
#[bitfield(u16)]
pub struct CLi {
#[bits(16)]
__: (),
}
impl CLi {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0x4001;
pub const fn nzimm(&self) -> i32 {
let mut result = 0u32;
set_bit_range_32(&mut result, 5, 5, bit_range(self.0, 12, 12) as u32);
set_bit_range_32(&mut result, 4, 0, bit_range(self.0, 6, 2) as u32);
sign_extend_i32(result, 5)
}
pub const fn rd(&self) -> Reg {
Reg::from_bits(try_cast!(bit_range(self.0, 11, 7) => u8).unwrap())
}
}
/// RISCV C.LUI instruction
#[bitfield(u16)]
pub struct CLui {
#[bits(16)]
__: (),
}
impl CLui {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0x6001;
pub const fn nzimm(&self) -> i32 {
let mut d = 0u32;
set_bit_range_32(&mut d, 5, 5, bit_range(self.0, 12, 12) as u32);
set_bit_range_32(&mut d, 4, 0, bit_range(self.0, 6, 2) as u32);
let mut result = 0u32;
set_bit_range_32(&mut result, 17, 17, bit_range(self.0, 12, 12) as u32);
set_bit_range_32(&mut result, 16, 12, bit_range(self.0, 6, 2) as u32);
sign_extend_i32(result, 17)
}
pub const fn rd(&self) -> Reg {
Reg::from_bits(try_cast!(bit_range(self.0, 11, 7) => u8).unwrap())
}
}
/// RISCV C.BEQZ instruction
#[bitfield(u16)]
pub struct CBeqz {
#[bits(16)]
__: (),
}
impl CBeqz {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0xc001;
pub const fn offset(&self) -> i16 {
let mut result = 0u16;
set_bit_range(&mut result, 8, 8, bit_range(self.0, 12, 12));
set_bit_range(&mut result, 4, 3, bit_range(self.0, 11, 10));
set_bit_range(&mut result, 7, 6, bit_range(self.0, 6, 5));
set_bit_range(&mut result, 2, 1, bit_range(self.0, 4, 3));
set_bit_range(&mut result, 5, 5, bit_range(self.0, 2, 2));
sign_extend_i16(result, 8)
}
pub const fn rs1(&self) -> Reg {
Reg::from_bits(try_cast!(bit_range(self.0, 9, 7) => u8).unwrap() + 8)
}
}
/// RISCV C.BNEZ instruction
#[bitfield(u16)]
pub struct CBnez {
#[bits(16)]
__: (),
}
impl CBnez {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0xe001;
pub const fn offset(&self) -> i16 {
CBeqz(self.0).offset()
}
pub const fn rs1(&self) -> Reg {
CBeqz(self.0).rs1()
}
}
/// RISCV C.BNEZ instruction
#[bitfield(u16)]
pub struct CSlli {
#[bits(7)]
__: (),
#[bits(5)]
pub rs1rd: Reg,
#[bits(4)]
__: (),
}
impl CSlli {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xe003;
pub const OP_CODE: u16 = 0x0002;
pub const fn shamt(&self) -> u16 {
let mut result = 0u16;
set_bit_range(&mut result, 5, 5, bit_range(self.0, 12, 12));
set_bit_range(&mut result, 4, 0, bit_range(self.0, 6, 2));
result
}
}
/// RISCV C.MV instruction
#[bitfield(u16)]
pub struct CMv {
#[bits(2)]
__: (),
#[bits(5)]
pub rs2: Reg,
#[bits(5)]
pub rd: Reg,
#[bits(4)]
__: (),
}
impl CMv {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xf003;
pub const OP_CODE: u16 = 0x8002;
}
/// RISCV C.ADD instruction
#[bitfield(u16)]
pub struct CAdd {
#[bits(2)]
__: (),
#[bits(5)]
pub rs2: Reg,
#[bits(5)]
pub rs1rd: Reg,
#[bits(4)]
__: (),
}
impl CAdd {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xf003;
pub const OP_CODE: u16 = 0x9002;
}
/// RISCV C.JALR instruction
#[bitfield(u16)]
pub struct CJalr {
#[bits(2)]
__: (),
#[bits(5)]
pub rs2: Reg,
#[bits(5)]
pub rs1: Reg,
#[bits(4)]
__: (),
}
impl CJalr {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xf07f;
#[allow(dead_code)]
pub const OP_CODE: u16 = 0x9002;
}
/// RISCV C.JR instruction
#[bitfield(u16)]
pub struct CJr {
#[bits(2)]
__: (),
#[bits(5)]
pub rs2: Reg,
#[bits(5)]
pub rs1: Reg,
#[bits(4)]
__: (),
}
impl CJr {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xf07f;
#[allow(dead_code)]
pub const OP_CODE: u16 = 0x8002;
}
/// RISCV C.SRLI instruction
#[bitfield(u16)]
pub struct CSrli {
#[bits(16)]
__: (),
}
impl CSrli {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xec03;
pub const OP_CODE: u16 = 0x8001;
pub const fn shamt(&self) -> u32 {
let mut result = 0;
set_bit_range_32(&mut result, 5, 5, bit_range(self.0, 12, 12) as u32);
set_bit_range_32(&mut result, 4, 0, bit_range(self.0, 6, 2) as u32);
result
}
pub const fn rs1rd(&self) -> Reg {
Reg::from_bits(try_cast!(bit_range(self.0, 9, 7) => u8).unwrap() + 8)
}
}
/// RISCV C.SRAI instruction
#[bitfield(u16)]
pub struct CSrai {
#[bits(16)]
__: (),
}
impl CSrai {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xec03;
pub const OP_CODE: u16 = 0x8401;
pub const fn shamt(&self) -> u32 {
CSrli(self.0).shamt()
}
pub const fn rs1rd(&self) -> Reg {
CSrli(self.0).rs1rd()
}
}
/// RISCV C.ANDI instruction
#[bitfield(u16)]
pub struct CAndi {
#[bits(16)]
__: (),
}
impl CAndi {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xec03;
pub const OP_CODE: u16 = 0x8801;
pub const fn imm(&self) -> i16 {
let mut result = 0;
set_bit_range(&mut result, 5, 5, bit_range(self.0, 12, 12));
set_bit_range(&mut result, 4, 0, bit_range(self.0, 6, 2));
sign_extend_i16(result, 5)
}
pub const fn rs1rd(&self) -> Reg {
CSrli(self.0).rs1rd()
}
}
/// RISCV C.AND instruction
#[bitfield(u16)]
pub struct CAnd {
#[bits(16)]
__: (),
}
impl CAnd {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xfc63;
pub const OP_CODE: u16 = 0x8c61;
pub const fn rs1rd(&self) -> Reg {
Reg::from_bits(try_cast!(bit_range(self.0, 9, 7) => u8).unwrap() + 8)
}
pub const fn rs2(&self) -> Reg {
Reg::from_bits(try_cast!(bit_range(self.0, 4, 2) => u8).unwrap() + 8)
}
}
#[bitfield(u16)]
/// RISCV C.OR instruction
pub struct COr {
#[bits(16)]
__: (),
}
impl COr {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xfc63;
pub const OP_CODE: u16 = 0x8c41;
pub const fn rs1rd(&self) -> Reg {
CAnd(self.0).rs1rd()
}
pub const fn rs2(&self) -> Reg {
CAnd(self.0).rs2()
}
}
/// RISCV C.XOR instruction
#[bitfield(u16)]
pub struct CXor {
#[bits(16)]
__: (),
}
impl CXor {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xfc63;
pub const OP_CODE: u16 = 0x8c21;
pub const fn rs1rd(&self) -> Reg {
CAnd(self.0).rs1rd()
}
pub const fn rs2(&self) -> Reg {
CAnd(self.0).rs2()
}
}
/// RISCV C.SUB instruction
#[bitfield(u16)]
pub struct CSub {
#[bits(16)]
__: (),
}
impl CSub {
#[allow(dead_code)]
pub const OP_MASK: u16 = 0xfc63;
pub const OP_CODE: u16 = 0x8c01;
pub const fn rs1rd(&self) -> Reg {
CAnd(self.0).rs1rd()
}
pub const fn rs2(&self) -> Reg {
CAnd(self.0).rs2()
}
}
#[cfg(test)]
mod test {
use super::bit_range;
use crate::riscv::compression::rv16::set_bit_range;
#[test]
fn test_bit_range() {
assert_eq!(bit_range(0x56fa, 3, 0), 0xa);
assert_eq!(bit_range(0x56fa, 7, 4), 0xf);
assert_eq!(bit_range(0x56fa, 11, 8), 0x6);
assert_eq!(bit_range(0x56fa, 15, 12), 0x5);
assert_eq!(bit_range(0x56fa, 2, 1), 0x1);
assert_eq!(bit_range(0x56fa, 3, 2), 0x2);
assert_eq!(bit_range(0x56fa, 15, 0), 0x56fa);
}
#[test]
fn test_set_bit_range() {
let mut result = 0_u16;
set_bit_range(&mut result, 2, 0, 0xf);
assert_eq!(result, 0x7);
set_bit_range(&mut result, 1, 0, 0x0);
assert_eq!(result, 0x4);
set_bit_range(&mut result, 3, 1, 0x3);
assert_eq!(result, 0x6);
set_bit_range(&mut result, 12, 4, 0x5ba);
assert_eq!(result, 0x1ba6);
set_bit_range(&mut result, 15, 0, 0xba5e);
assert_eq!(result, 0xba5e);
set_bit_range(&mut result, 15, 0, 0);
assert_eq!(result, 0x0);
set_bit_range(&mut result, 15, 0, 0xffff);
assert_eq!(result, 0xffff);
}
}
}