Skip to main content

ab_riscv_primitives/instructions/
zvbc.rs

1//! Zvbc 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 Zvbc vector carryless multiplication instruction.
27///
28/// All use the OP-V major opcode (0b101_0111). Encoding spaces:
29///
30/// - `vclmul.[vv,vx]`:  funct6=0b001100, OPMVV/OPMVX; `vm` controls masking (0=masked, 1=unmasked)
31/// - `vclmulh.[vv,vx]`: funct6=0b001101, OPMVV/OPMVX; `vm` controls masking
32///
33/// Both instructions compute a carryless (GF(2)) polynomial product of two SEW-wide elements.
34/// `vclmul` produces the lower SEW bits of the 2*SEW-bit result; `vclmulh` produces the upper
35/// SEW bits. Together they implement full-width carry-less multiplication, as required for
36/// GCM/GHASH (`vclmulh` gives the reduction term) and for CRC computation.
37///
38/// For the `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 ZvbcInstruction<Reg> {
47    // vclmul: lower SEW bits of the carry-less 2*SEW product
48    /// `vclmul.vv vd, vs2, vs1, vm`
49    VclmulVv  { vd: VReg, vs2: VReg, vs1: VReg, vm: bool },
50    /// `vclmul.vx vd, vs2, rs1, vm`
51    VclmulVx  { vd: VReg, vs2: VReg, rs1: Reg, vm: bool },
52    // vclmulh: upper SEW bits of the carry-less 2*SEW product
53    /// `vclmulh.vv vd, vs2, vs1, vm`
54    VclmulhVv { vd: VReg, vs2: VReg, vs1: VReg, vm: bool },
55    /// `vclmulh.vx vd, vs2, rs1, vm`
56    VclmulhVx { vd: VReg, vs2: VReg, rs1: Reg, vm: bool },
57}
58
59#[instruction]
60const impl<Reg> Instruction for ZvbcInstruction<Reg>
61where
62    Reg: [const] Register,
63{
64    type Reg = Reg;
65
66    #[inline(always)]
67    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
68    fn try_decode(instruction: u32) -> Option<Self> {
69        let opcode = (instruction & 0b111_1111) as u8;
70        if opcode != 0b101_0111 {
71            None?;
72        }
73        let vd_bits = ((instruction >> 7) & 0x1f) as u8;
74        let funct3 = ((instruction >> 12) & 0b111) as u8;
75        let vs1_bits = ((instruction >> 15) & 0x1f) as u8;
76        let vs2_bits = ((instruction >> 20) & 0x1f) as u8;
77        // vm=1 means unmasked, vm=0 means masked by v0
78        let vm = ((instruction >> 25) & 1) as u8 == 1;
79        let funct6 = ((instruction >> 26) & 0b11_1111) as u8;
80        let vd = VReg::from_bits(vd_bits)?;
81        let vs2 = VReg::from_bits(vs2_bits)?;
82        match funct3 {
83            // OPMVV: vclmul.vv, vclmulh.vv
84            0b010 => {
85                let vs1 = VReg::from_bits(vs1_bits)?;
86                match funct6 {
87                    0b00_1100 => Some(Self::VclmulVv { vd, vs2, vs1, vm }),
88                    0b00_1101 => Some(Self::VclmulhVv { vd, vs2, vs1, vm }),
89                    _ => None,
90                }
91            }
92            // OPMVX: vclmul.vx, vclmulh.vx
93            0b110 => {
94                let rs1 = Reg::from_bits(vs1_bits)?;
95                match funct6 {
96                    0b00_1100 => Some(Self::VclmulVx { vd, vs2, rs1, vm }),
97                    0b00_1101 => Some(Self::VclmulhVx { vd, vs2, rs1, vm }),
98                    _ => None,
99                }
100            }
101            _ => None,
102        }
103    }
104
105    #[inline(always)]
106    fn alignment() -> u8 {
107        align_of::<u32>() as u8
108    }
109
110    #[inline(always)]
111    fn size(&self) -> u8 {
112        size_of::<u32>() as u8
113    }
114}
115
116#[instruction]
117impl<Reg> fmt::Display for ZvbcInstruction<Reg>
118where
119    Reg: fmt::Display + Copy,
120{
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        #[rustfmt::skip]
123        match self {
124            Self::VclmulVv  { vd, vs2, vs1, vm } => write!(f, "vclmul.vv {vd}, {vs2}, {vs1}{}", mask_suffix(vm)),
125            Self::VclmulVx  { vd, vs2, rs1, vm } => write!(f, "vclmul.vx {vd}, {vs2}, {rs1}{}", mask_suffix(vm)),
126            Self::VclmulhVv { vd, vs2, vs1, vm } => write!(f, "vclmulh.vv {vd}, {vs2}, {vs1}{}", mask_suffix(vm)),
127            Self::VclmulhVx { vd, vs2, rs1, vm } => write!(f, "vclmulh.vx {vd}, {vs2}, {rs1}{}", mask_suffix(vm)),
128        }
129    }
130}
131
132/// Format mask suffix for display
133#[inline(always)]
134fn mask_suffix(vm: &bool) -> &'static str {
135    if *vm { "" } else { ", v0.t" }
136}