Skip to main content

ab_riscv_primitives/instructions/zvbb/
zvkb.rs

1//! Zvkb extension
2
3#[cfg(test)]
4mod tests;
5
6use crate::instructions::Instruction;
7use crate::instructions::v::zvexx::ZveXxInstruction;
8use crate::instructions::v::zvexx::arith::ZveXxArithInstruction;
9use crate::instructions::v::zvexx::carry::ZveXxCarryInstruction;
10use crate::instructions::v::zvexx::config::ZveXxConfigInstruction;
11use crate::instructions::v::zvexx::fixed_point::ZveXxFixedPointInstruction;
12use crate::instructions::v::zvexx::load::{LoadStoreNreg, Nf, SegVmNf, ZveXxLoadInstruction};
13use crate::instructions::v::zvexx::mask::ZveXxMaskInstruction;
14use crate::instructions::v::zvexx::muldiv::ZveXxMulDivInstruction;
15use crate::instructions::v::zvexx::perm::ZveXxPermInstruction;
16use crate::instructions::v::zvexx::reduction::ZveXxReductionInstruction;
17use crate::instructions::v::zvexx::store::ZveXxStoreInstruction;
18use crate::instructions::v::zvexx::widen_narrow::ZveXxWidenNarrowInstruction;
19use crate::instructions::v::{Eew, V};
20use crate::instructions::zicsr::ZicsrInstruction;
21use crate::registers::general_purpose::Register;
22use crate::registers::vector::VReg;
23use ab_riscv_macros::instruction;
24use core::fmt;
25
26/// RISC-V Zvkb vector cryptography bit-manipulation instruction.
27///
28/// All use the OP-V major opcode (0b101_0111). Encoding spaces:
29///
30/// - `vandn.[vv,vx]`: funct6=0b000001, OPIVV/OPIVX; `vm` controls masking (0=masked, 1=unmasked)
31/// - `vbrev8.v`:      funct6=0b010010, OPMVV, vs1=0b01000; `vm` controls masking
32/// - `vrev8.v`:       funct6=0b010010, OPMVV, vs1=0b01001; `vm` controls masking
33/// - `vrol.[vv,vx]`:  funct6=0b010101, OPIVV/OPIVX; `vm` controls masking
34/// - `vror.[vv,vx]`:  funct6=0b010100, OPIVV/OPIVX; `vm` controls masking
35/// - `vror.vi`:       funct6=0b010100, OPIVI; 5-bit unsigned immediate in bits\[19:15] (0-31);
36///   bit\[25] is the standard `vm` field, independent of the immediate
37///
38/// For instructions with a `vm` field: `vm=true` means unmasked (process all body elements);
39/// `vm=false` means masked by v0 (skip elements where v0\[i]=0, leaving them undisturbed).
40#[instruction(
41    inherit = [ZveXxInstruction],
42)]
43#[derive(Debug, Clone, Copy)]
44#[derive_const(PartialEq, Eq)]
45#[rustfmt::skip]
46pub enum ZvkbInstruction<Reg> {
47    // vandn: vd[i] = ~vs1[i] & vs2[i]  (or ~rs1 & vs2[i])
48    // Essential for the Chi step of the Keccak permutation (SHA-3).
49
50    /// `vandn.vv vd, vs2, vs1, vm`
51    VandnVv { vd: VReg, vs2: VReg, vs1: VReg, vm: bool },
52    /// `vandn.vx vd, vs2, rs1, vm`
53    VandnVx { vd: VReg, vs2: VReg, rs1: Reg, vm: bool },
54
55    // vbrev8: reverse bits within each byte of each SEW-wide element
56
57    /// `vbrev8.v vd, vs2, vm`
58    Vbrev8V { vd: VReg, vs2: VReg, vm: bool },
59
60    // vrev8: reverse bytes within each SEW-wide element
61
62    /// `vrev8.v vd, vs2, vm`
63    Vrev8V  { vd: VReg, vs2: VReg, vm: bool },
64
65    // vrol: rotate left; no immediate form (use vror.vi with negated immediate instead)
66
67    /// `vrol.vv vd, vs2, vs1, vm`
68    VrolVv  { vd: VReg, vs2: VReg, vs1: VReg, vm: bool },
69    /// `vrol.vx vd, vs2, rs1, vm`
70    VrolVx  { vd: VReg, vs2: VReg, rs1: Reg, vm: bool },
71
72    // vror: rotate right
73    // vror.vi has a 5-bit unsigned immediate in vs1[19:15]; bit[25] is the standard `vm`
74    // mask-control bit
75
76    /// `vror.vv vd, vs2, vs1, vm`
77    VrorVv  { vd: VReg, vs2: VReg, vs1: VReg, vm: bool },
78    /// `vror.vx vd, vs2, rs1, vm`
79    VrorVx  { vd: VReg, vs2: VReg, rs1: Reg, vm: bool },
80    /// `vror.vi vd, vs2, uimm, vm` - `uimm` is 5-bit unsigned (0..=31); `vm` is the
81    /// standard mask-control bit at bit\[25], orthogonal to the immediate.
82    VrorVi  { vd: VReg, vs2: VReg, uimm: u8, vm: bool },
83}
84
85#[instruction]
86const impl<Reg> Instruction for ZvkbInstruction<Reg>
87where
88    Reg: [const] Register,
89{
90    type Reg = Reg;
91
92    #[inline(always)]
93    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
94    fn try_decode(instruction: u32) -> Option<Self> {
95        let opcode = (instruction & 0b111_1111) as u8;
96
97        if opcode != 0b101_0111 {
98            None?;
99        }
100
101        let vd_bits = ((instruction >> 7) & 0x1f) as u8;
102        let funct3 = ((instruction >> 12) & 0b111) as u8;
103        let vs1_bits = ((instruction >> 15) & 0x1f) as u8;
104        let vs2_bits = ((instruction >> 20) & 0x1f) as u8;
105        // vm=1 means unmasked, vm=0 means masked by v0
106        let vm = ((instruction >> 25) & 1) as u8 == 1;
107        let funct6 = ((instruction >> 26) & 0b11_1111) as u8;
108
109        let vd = VReg::from_bits(vd_bits)?;
110        let vs2 = VReg::from_bits(vs2_bits)?;
111
112        match funct3 {
113            // OPIVV: vandn.vv, vrol.vv, vror.vv
114            0b000 => {
115                let vs1 = VReg::from_bits(vs1_bits)?;
116                match funct6 {
117                    0b00_0001 => Some(Self::VandnVv { vd, vs2, vs1, vm }),
118                    0b01_0100 => Some(Self::VrorVv { vd, vs2, vs1, vm }),
119                    0b01_0101 => Some(Self::VrolVv { vd, vs2, vs1, vm }),
120                    _ => None,
121                }
122            }
123            // OPIVX: vandn.vx, vrol.vx, vror.vx
124            0b100 => {
125                let rs1 = Reg::from_bits(vs1_bits)?;
126                match funct6 {
127                    0b00_0001 => Some(Self::VandnVx { vd, vs2, rs1, vm }),
128                    0b01_0100 => Some(Self::VrorVx { vd, vs2, rs1, vm }),
129                    0b01_0101 => Some(Self::VrolVx { vd, vs2, rs1, vm }),
130                    _ => None,
131                }
132            }
133            // OPIVI: vror.vi only - 5-bit unsigned immediate in vs1[19:15]; bit[25] is the standard
134            // vm mask-control bit
135            0b011 => {
136                if funct6 != 0b01_0100 {
137                    None?;
138                }
139                // vm_bit here is imm[5]; reconstruct 6-bit unsigned immediate
140                // uimm is 5-bit (0-31); bit[25] is a standard vm field, not imm[5]
141                let uimm = vs1_bits;
142                Some(Self::VrorVi { vd, vs2, uimm, vm })
143            }
144            // OPMVV: vbrev8.v and vrev8.v - unary, vs1 encodes the sub-operation
145            // funct6=0b010010 (VXUNARY0 sub-space); sub-opcodes 0b01000/0b01001 belong
146            // to Zvkb; other sub-opcodes in this space (vzext, vsext) are not claimed here
147            0b010 => {
148                if funct6 != 0b01_0010 {
149                    None?;
150                }
151                match vs1_bits {
152                    0b01000 => Some(Self::Vbrev8V { vd, vs2, vm }),
153                    0b01001 => Some(Self::Vrev8V { vd, vs2, vm }),
154                    _ => None,
155                }
156            }
157            _ => None,
158        }
159    }
160
161    #[inline(always)]
162    fn alignment() -> u8 {
163        align_of::<u32>() as u8
164    }
165
166    #[inline(always)]
167    fn size(&self) -> u8 {
168        size_of::<u32>() as u8
169    }
170}
171
172#[instruction]
173impl<Reg> fmt::Display for ZvkbInstruction<Reg>
174where
175    Reg: fmt::Display + Copy,
176{
177    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178        #[rustfmt::skip]
179        match self {
180            Self::VandnVv { vd, vs2, vs1, vm }  => write!(f, "vandn.vv {vd}, {vs2}, {vs1}{}", mask_suffix(vm)),
181            Self::VandnVx { vd, vs2, rs1, vm }  => write!(f, "vandn.vx {vd}, {vs2}, {rs1}{}", mask_suffix(vm)),
182            Self::Vbrev8V { vd, vs2, vm }       => write!(f, "vbrev8.v {vd}, {vs2}{}", mask_suffix(vm)),
183            Self::Vrev8V  { vd, vs2, vm }       => write!(f, "vrev8.v {vd}, {vs2}{}", mask_suffix(vm)),
184            Self::VrolVv  { vd, vs2, vs1, vm }  => write!(f, "vrol.vv {vd}, {vs2}, {vs1}{}", mask_suffix(vm)),
185            Self::VrolVx  { vd, vs2, rs1, vm }  => write!(f, "vrol.vx {vd}, {vs2}, {rs1}{}", mask_suffix(vm)),
186            Self::VrorVv  { vd, vs2, vs1, vm }  => write!(f, "vror.vv {vd}, {vs2}, {vs1}{}", mask_suffix(vm)),
187            Self::VrorVx  { vd, vs2, rs1, vm }  => write!(f, "vror.vx {vd}, {vs2}, {rs1}{}", mask_suffix(vm)),
188            Self::VrorVi  { vd, vs2, uimm, vm } => write!(f, "vror.vi {vd}, {vs2}, {uimm}{}", mask_suffix(vm)),
189        }
190    }
191}
192
193/// Format mask suffix for display
194#[inline(always)]
195fn mask_suffix(vm: &bool) -> &'static str {
196    if *vm { "" } else { ", v0.t" }
197}