pub(crate) mod a;
pub(crate) mod b;
pub(crate) mod c;
pub(crate) mod d;
pub(crate) mod f;
pub(crate) mod h;
pub(crate) mod i;
pub(crate) mod m;
pub(crate) mod pseudo;
pub(crate) mod q;
pub(crate) mod system;
#[cfg(feature = "vector")]
pub(crate) mod v;
#[cfg(feature = "vendor-corev")]
pub(crate) mod xcv;
#[cfg(feature = "vendor-thead")]
pub(crate) mod xthead;
pub(crate) mod zabha;
pub(crate) mod zalasr;
pub(crate) mod zawrs;
pub(crate) mod zcb;
pub(crate) mod zcmp;
pub(crate) mod zfa;
pub(crate) mod zfbfmin;
pub(crate) mod zfh;
pub(crate) mod zicbo;
pub(crate) mod zicond;
pub(crate) mod zilsd;
pub(crate) mod zimop;
pub(crate) mod zk;
use crate::{Extension, Extensions, Isa};
#[cfg_attr(
not(all(feature = "vector", feature = "vendor-thead", feature = "vendor-corev")),
allow(dead_code)
)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum Codec {
Li,
CssSqsp,
CssSdsp,
CssSwsp,
CsSq,
CsSd,
CsSw,
Cs,
CrJr,
CrJalr,
CrMv,
Cr,
ClLq,
ClLd,
ClLw,
ClB,
ClH,
CsB,
CsH,
CuRd,
CmPushPop,
CmMv,
CmJt,
CjJal,
Cj,
Ciw4spn,
CiNone,
CiLui,
CiLi,
CiLqsp,
CiLdsp,
CiLwsp,
Ci16sp,
CiSh6,
Ci,
CbSh6,
CbImm,
Cb,
RF,
RL,
RA,
R4M,
RM,
R,
SB,
S,
ICsr,
ISh7,
ISh6,
ISh5,
I,
Uj,
U,
None,
Illegal,
V,
Vu,
Vu6,
RBs,
Rnum,
VsetVli,
VsetIvli,
IUimm6,
RImm2,
RImm5,
ImmPair6,
ImmPair5,
ImmUpdate,
Pair,
BImm5,
Simm6,
Uimm6,
}
pub(crate) mod fmt {
pub(crate) const NONE: &str = "";
pub(crate) const RS1: &str = "1";
pub(crate) const OFFSET: &str = "o";
pub(crate) const PRED_SUCC: &str = "p,s";
pub(crate) const RS1_RS2: &str = "1,2";
pub(crate) const RD_IMM: &str = "0,i";
pub(crate) const RD_UIMM: &str = "0,u";
pub(crate) const RD_OFFSET: &str = "0,o";
pub(crate) const RD_RS1_RS2: &str = "0,1,2";
pub(crate) const FRD_RS1: &str = "3,1";
pub(crate) const FRD_FRS1: &str = "3,4";
pub(crate) const RD_FRS1: &str = "0,4";
pub(crate) const RD_FRS1_FRS2: &str = "0,4,5";
pub(crate) const FRD_FRS1_FRS2: &str = "3,4,5";
pub(crate) const RM_FRD_FRS1: &str = "3,4r";
pub(crate) const RM_FRD_RS1: &str = "3,1r";
pub(crate) const RM_RD_FRS1: &str = "0,4r";
pub(crate) const RM_FRD_FRS1_FRS2: &str = "3,4,5r";
pub(crate) const RM_FRD_FRS1_FRS2_FRS3: &str = "3,4,5,6r";
pub(crate) const RD_RS1_IMM: &str = "0,1,i";
pub(crate) const RD_RS1_SHAMT: &str = "0,1,>";
pub(crate) const RD_OFFSET_RS1: &str = "0,i(1)";
pub(crate) const FRD_OFFSET_RS1: &str = "3,i(1)";
pub(crate) const RD_CSR_RS1: &str = "0,c,1";
pub(crate) const RD_CSR_ZIMM: &str = "0,c,7";
pub(crate) const RS2_OFFSET_RS1: &str = "2,i(1)";
pub(crate) const FRS2_OFFSET_RS1: &str = "5,i(1)";
pub(crate) const RS1_RS2_OFFSET: &str = "1,2,o";
pub(crate) const RD_RS2_ADDR_RS1: &str = "0,2,(1)";
pub(crate) const RD_ADDR_RS1: &str = "0,(1)";
pub(crate) const RD: &str = "0";
pub(crate) const RD_ZIMM: &str = "0,7";
pub(crate) const RD_RS1: &str = "0,1";
pub(crate) const RD_RS2: &str = "0,2";
pub(crate) const RS1_OFFSET: &str = "1,o";
pub(crate) const RS2_OFFSET: &str = "2,o";
pub(crate) const OFFSET_RS1: &str = "i(1)";
pub(crate) const RD_SHAMT: &str = "0,>";
pub(crate) const RD_CSR: &str = "0,c";
pub(crate) const CSR_RS1: &str = "c,1";
pub(crate) const CSR_ZIMM: &str = "c,7";
pub(crate) const IMM: &str = "i";
pub(crate) const WIDEN_FRD_FRS1: &str = "3,4R";
pub(crate) const WIDEN_FRD_RS1: &str = "3,1R";
pub(crate) const INSN: &str = "l, x";
pub(crate) const RAW: &str = "x";
pub(crate) const ADDR_RS1: &str = "(1)";
pub(crate) const RS2: &str = "2";
pub(crate) const RS2_ADDR_RS1: &str = "2,(1)";
pub(crate) const RD_RS1_RS2_BS: &str = "0,1,2,>";
pub(crate) const RLIST_ADJ: &str = "L,i";
pub(crate) const RLIST_NEG_ADJ: &str = "L,-i";
pub(crate) const UIMM: &str = "u";
pub(crate) const FRD_FLI: &str = "3,F";
pub(crate) const FRD_RS1_RS2: &str = "3,1,2";
pub(crate) const PREFETCH: &str = "P(1)";
}
#[cfg_attr(
not(all(feature = "vector", feature = "vendor-thead", feature = "vendor-corev")),
allow(dead_code)
)]
#[derive(Clone, Copy, Debug)]
pub(crate) enum Constraint {
RdEq(u8),
Rs1Eq(u8),
Rs2Eq(u8),
Rs2EqRs1,
RdEqRs1,
RdOdd,
Rs2Odd,
RdEqRs2,
ImmEq(i32),
ImmMaskEq(i32, i32),
CsrEq(i32),
}
pub(crate) struct Pseudo {
pub(crate) op: &'static Opcode,
pub(crate) when: &'static [Constraint],
}
impl Pseudo {
pub(crate) const fn new(op: &'static Opcode, when: &'static [Constraint]) -> Self {
Pseudo { op, when }
}
}
pub(crate) struct MaskedOpcode {
pub(crate) bits: u32,
pub(crate) mask: u32,
pub(crate) op: Opcode,
}
#[cfg_attr(
not(all(feature = "vector", feature = "vendor-thead", feature = "vendor-corev")),
allow(dead_code)
)]
pub(crate) const fn masked(bits: u32, mask: u32, op: Opcode) -> MaskedOpcode {
MaskedOpcode { bits, mask, op }
}
#[cfg_attr(
not(all(feature = "vector", feature = "vendor-thead", feature = "vendor-corev")),
allow(dead_code)
)]
pub(crate) fn lookup_masked(table: &'static [MaskedOpcode], inst: u64) -> Option<&'static Opcode> {
let inst = inst as u32;
table
.iter()
.find(|e| inst & e.mask == e.bits)
.map(|e| &e.op)
}
pub(crate) struct Opcode {
pub(crate) name: &'static str,
pub(crate) format: &'static str,
pub(crate) requires: &'static [Extension],
pub(crate) extra: &'static Extra,
pub(crate) codec: Codec,
pub(crate) isas: u8,
pub(crate) f_registers: bool,
}
pub(crate) struct Extra {
pub(crate) pseudo: &'static [Pseudo],
pub(crate) decompress: [Option<&'static Opcode>; 3],
pub(crate) illegal_if: &'static [Constraint],
pub(crate) hint_if: &'static [Constraint],
pub(crate) requires_any: &'static [Extension],
}
impl Extra {
pub(crate) const NONE: Extra = Extra {
pseudo: &[],
decompress: [None; 3],
illegal_if: &[],
hint_if: &[],
requires_any: &[],
};
}
impl Opcode {
pub(crate) const fn new(name: &'static str, codec: Codec, format: &'static str) -> Self {
Opcode {
name,
format,
requires: &[],
extra: &Extra::NONE,
codec,
isas: 0b111,
f_registers: false,
}
}
pub(crate) const fn f_registers(self) -> Self {
Opcode {
f_registers: true,
..self
}
}
pub(crate) const fn requires(self, exts: &'static [Extension]) -> Self {
Opcode {
requires: exts,
..self
}
}
pub(crate) const fn rv64(self) -> Self {
Opcode {
isas: 0b110,
..self
}
}
pub(crate) const fn rv32_only(self) -> Self {
Opcode {
isas: 0b001,
..self
}
}
pub(crate) const fn rv64_only(self) -> Self {
Opcode {
isas: 0b010,
..self
}
}
pub(crate) const fn rv128(self) -> Self {
Opcode {
isas: 0b100,
..self
}
}
pub(crate) fn provided_by(&self, exts: Extensions) -> bool {
let has = |e: Extension| exts.contains(e) || exts.contains(e.in_x_registers());
self.requires.iter().all(|&e| has(e))
&& (self.extra.requires_any.is_empty()
|| self.extra.requires_any.iter().any(|&e| has(e)))
}
pub(crate) fn exists_in(&self, isa: Isa, exts: Extensions) -> bool {
self.provided_by(exts)
&& (!exts.contains(Extension::Zfinx) || self.in_x_registers())
&& match self.extra.decompress {
[None, None, None] => self.isas & (1 << isa as u8) != 0,
expansions => expansions[isa as usize].is_some_and(|e| e.exists_in(isa, exts)),
}
}
fn in_x_registers(&self) -> bool {
let fp_operands = self.format.contains(['3', '4', '5', '6']);
!fp_operands
|| (!self.f_registers && self.requires.iter().any(|&e| e.in_x_registers() != e))
}
}
impl PartialEq for Opcode {
fn eq(&self, other: &Self) -> bool {
core::ptr::eq(self, other)
}
}
impl Eq for Opcode {}
impl core::fmt::Debug for Opcode {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(self.name)
}
}
pub(crate) static ILLEGAL: Opcode = Opcode::new(".insn", Codec::Illegal, fmt::INSN);
pub(crate) static RESERVED_PARCEL: Opcode = Opcode::new(".2byte", Codec::Illegal, fmt::RAW);