Skip to main content

ab_riscv_primitives/instructions/
zvbb.rs

1//! Zvbb extension
2
3#[cfg(test)]
4mod tests;
5pub mod zvkb;
6
7use crate::instructions::Instruction;
8use crate::instructions::v::Eew;
9use crate::instructions::v::zvexx::arith::ZveXxArithInstruction;
10use crate::instructions::v::zvexx::carry::ZveXxCarryInstruction;
11use crate::instructions::v::zvexx::config::ZveXxConfigInstruction;
12use crate::instructions::v::zvexx::fixed_point::ZveXxFixedPointInstruction;
13use crate::instructions::v::zvexx::load::{LoadStoreNreg, Nf, SegVmNf, ZveXxLoadInstruction};
14use crate::instructions::v::zvexx::mask::ZveXxMaskInstruction;
15use crate::instructions::v::zvexx::muldiv::ZveXxMulDivInstruction;
16use crate::instructions::v::zvexx::perm::ZveXxPermInstruction;
17use crate::instructions::v::zvexx::reduction::ZveXxReductionInstruction;
18use crate::instructions::v::zvexx::store::ZveXxStoreInstruction;
19use crate::instructions::v::zvexx::widen_narrow::ZveXxWidenNarrowInstruction;
20use crate::instructions::zicsr::ZicsrInstruction;
21use crate::instructions::zvbb::zvkb::ZvkbInstruction;
22use crate::registers::general_purpose::Register;
23use crate::registers::vector::VReg;
24use ab_riscv_macros::instruction;
25use core::fmt;
26
27/// RISC-V Zvbb vector bit-manipulation instruction.
28///
29/// Zvbb is a strict superset of Zvkb; this type encodes only the instructions unique to Zvbb.
30/// The Zvkb subset (vandn, vbrev8, vrev8, vrol, vror) is inherited from [`ZvkbInstruction`].
31///
32/// All use the OP-V major opcode (0b101_0111). Encoding spaces:
33///
34/// - `vbrev.v`:       funct6=0b010010, OPMVV, vs1=0b01010; `vm` controls masking
35/// - `vclz.v`:        funct6=0b010010, OPMVV, vs1=0b01100; `vm` controls masking
36/// - `vctz.v`:        funct6=0b010010, OPMVV, vs1=0b01101; `vm` controls masking
37/// - `vcpop.v`:       funct6=0b010010, OPMVV, vs1=0b01110; `vm` controls masking
38/// - `vwsll.[vv,vx]`: funct6=0b110101, OPIVV/OPIVX; `vm` controls masking
39/// - `vwsll.vi`:      funct6=0b110101, OPIVI; 5-bit unsigned immediate in bits\[19:15] (0-31);
40///   bit\[25] is the standard `vm` field, orthogonal to the immediate
41///
42/// The four unary operations share VXUNARY0 (funct6=0b010010, OPMVV); Zvkb claims vs1
43/// sub-opcodes 0b01000 and 0b01001; Zvbb claims 0b01010, 0b01100, 0b01101, and 0b01110.
44/// Sub-opcode 0b01011 is an undefined gap between vbrev and vclz.
45///
46/// Note: `vwsll` funct6 (0b110101) coincides with `vwadd.wv` from the base V extension;
47/// these instructions are mutually exclusive within a combined decoder.
48///
49/// For instructions with a `vm` field: `vm=true` means unmasked (process all body elements);
50/// `vm=false` means masked by v0 (skip elements where v0\[i]=0, leaving them undisturbed).
51#[instruction(
52    inherit = [ZvkbInstruction],
53)]
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55#[rustfmt::skip]
56pub enum ZvbbInstruction<Reg> {
57    // vbrev: bit-reverse within each SEW-wide element (element granularity, unlike vbrev8's byte granularity)
58    /// `vbrev.v vd, vs2, vm`
59    VbrevV  { vd: VReg, vs2: VReg, vm: bool },
60    // vclz: count leading zeros within each SEW-wide element; result in [0, SEW]
61    /// `vclz.v vd, vs2, vm`
62    VclzV   { vd: VReg, vs2: VReg, vm: bool },
63    // vctz: count trailing zeros within each SEW-wide element; result in [0, SEW]
64    /// `vctz.v vd, vs2, vm`
65    VctzV   { vd: VReg, vs2: VReg, vm: bool },
66    // vcpop: population count (number of set bits) within each SEW-wide element
67    /// `vcpop.v vd, vs2, vm`
68    VcpopV  { vd: VReg, vs2: VReg, vm: bool },
69    // vwsll: widening shift left logical; result is 2*SEW wide, both sources are SEW wide
70    /// `vwsll.vv vd, vs2, vs1, vm`
71    VwsllVv { vd: VReg, vs2: VReg, vs1: VReg, vm: bool },
72    /// `vwsll.vx vd, vs2, rs1, vm`
73    VwsllVx { vd: VReg, vs2: VReg, rs1: Reg,  vm: bool },
74    /// `vwsll.vi vd, vs2, uimm, vm` - `uimm` is 5-bit unsigned (0..=31); `vm` is the
75    /// standard mask-control bit at bit\[25], orthogonal to the immediate.
76    VwsllVi { vd: VReg, vs2: VReg, uimm: u8,  vm: bool },
77}
78
79#[instruction]
80impl<Reg> const Instruction for ZvbbInstruction<Reg>
81where
82    Reg: [const] Register,
83{
84    type Reg = Reg;
85
86    #[inline(always)]
87    fn try_decode(instruction: u32) -> Option<Self> {
88        let opcode = (instruction & 0b111_1111) as u8;
89
90        if opcode != 0b101_0111 {
91            None?;
92        }
93
94        let vd_bits = ((instruction >> 7) & 0x1f) as u8;
95        let funct3 = ((instruction >> 12) & 0b111) as u8;
96        let vs1_bits = ((instruction >> 15) & 0x1f) as u8;
97        let vs2_bits = ((instruction >> 20) & 0x1f) as u8;
98        // vm=1 means unmasked, vm=0 means masked by v0
99        let vm = ((instruction >> 25) & 1) as u8 == 1;
100        let funct6 = ((instruction >> 26) & 0b11_1111) as u8;
101
102        let vd = VReg::from_bits(vd_bits)?;
103        let vs2 = VReg::from_bits(vs2_bits)?;
104
105        match funct3 {
106            // OPIVV: vwsll.vv
107            0b000 => {
108                if funct6 != 0b11_0101 {
109                    None?;
110                }
111                let vs1 = VReg::from_bits(vs1_bits)?;
112                Some(Self::VwsllVv { vd, vs2, vs1, vm })
113            }
114            // OPIVX: vwsll.vx
115            0b100 => {
116                if funct6 != 0b11_0101 {
117                    None?;
118                }
119                let rs1 = Reg::from_bits(vs1_bits)?;
120                Some(Self::VwsllVx { vd, vs2, rs1, vm })
121            }
122            // OPIVI: vwsll.vi - standard 5-bit unsigned immediate in bits[19:15]; vm is bit[25]
123            0b011 => {
124                if funct6 != 0b11_0101 {
125                    None?;
126                }
127                let uimm = vs1_bits;
128                Some(Self::VwsllVi { vd, vs2, uimm, vm })
129            }
130            // OPMVV: vbrev.v, vclz.v, vctz.v, vcpop.v
131            // funct6=0b010010 (VXUNARY0 sub-space); Zvkb claims vs1 0b01000/0b01001;
132            // Zvbb claims 0b01010, 0b01100, 0b01101, 0b01110; vs1 0b01011 is an undefined gap
133            0b010 => {
134                if funct6 != 0b01_0010 {
135                    None?;
136                }
137                match vs1_bits {
138                    0b01010 => Some(Self::VbrevV { vd, vs2, vm }),
139                    0b01100 => Some(Self::VclzV { vd, vs2, vm }),
140                    0b01101 => Some(Self::VctzV { vd, vs2, vm }),
141                    0b01110 => Some(Self::VcpopV { vd, vs2, vm }),
142                    _ => None,
143                }
144            }
145            _ => None,
146        }
147    }
148
149    #[inline(always)]
150    fn alignment() -> u8 {
151        align_of::<u32>() as u8
152    }
153
154    #[inline(always)]
155    fn size(&self) -> u8 {
156        size_of::<u32>() as u8
157    }
158}
159
160#[instruction]
161impl<Reg> fmt::Display for ZvbbInstruction<Reg>
162where
163    Reg: fmt::Display + Copy,
164{
165    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166        #[rustfmt::skip]
167        match self {
168            Self::VbrevV  { vd, vs2, vm }        => write!(f, "vbrev.v {vd}, {vs2}{}", mask_suffix(vm)),
169            Self::VclzV   { vd, vs2, vm }        => write!(f, "vclz.v {vd}, {vs2}{}", mask_suffix(vm)),
170            Self::VctzV   { vd, vs2, vm }        => write!(f, "vctz.v {vd}, {vs2}{}", mask_suffix(vm)),
171            Self::VcpopV  { vd, vs2, vm }        => write!(f, "vcpop.v {vd}, {vs2}{}", mask_suffix(vm)),
172            Self::VwsllVv { vd, vs2, vs1, vm }   => write!(f, "vwsll.vv {vd}, {vs2}, {vs1}{}", mask_suffix(vm)),
173            Self::VwsllVx { vd, vs2, rs1, vm }   => write!(f, "vwsll.vx {vd}, {vs2}, {rs1}{}", mask_suffix(vm)),
174            Self::VwsllVi { vd, vs2, uimm, vm }  => write!(f, "vwsll.vi {vd}, {vs2}, {uimm}{}", mask_suffix(vm)),
175        }
176    }
177}
178
179/// Format mask suffix for display
180#[inline(always)]
181fn mask_suffix(vm: &bool) -> &'static str {
182    if *vm { "" } else { ", v0.t" }
183}