Skip to main content

ab_riscv_primitives/instructions/rv64/zk/
zbkb.rs

1//! RV64 Zbkb extension
2
3#[cfg(test)]
4mod tests;
5
6use crate::hart::HartConfig;
7use crate::instructions::rv64::b::zbb::Rv64ZbbZbkbSharedInstruction;
8use crate::instructions::utils::Shamt;
9use crate::instructions::{ImplementedExtension, Instruction, IsaExtension};
10use crate::registers::general_purpose::Register;
11use ab_riscv_macros::instruction;
12use core::fmt;
13
14/// RISC-V RV64 Zbkb instruction (Bit-manipulation for Cryptography)
15#[instruction(inherit = [Rv64ZbbZbkbSharedInstruction])]
16#[derive(Debug, Clone, Copy)]
17#[derive_const(PartialEq, Eq)]
18#[rustfmt::skip]
19pub enum Rv64ZbkbInstruction<Hart>
20where
21    Hart: HartConfig,
22{
23    /// Pack low 32 bits of `rs1` and `rs2` into `rd`
24    Pack { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
25    /// Pack low 8 bits of `rs1` and `rs2` into `rd` bytes `0` and `1`
26    Packh { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
27    /// Pack low 16 bits of `rs1` and `rs2` into lower 32 bits of `rd`, sign-extend
28    Packw { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg },
29    /// Reverse bits in each byte of `rs1`
30    Brev8 { rd: Hart::Reg, rs1: Hart::Reg },
31}
32
33#[instruction]
34const impl<Reg, Hart> Instruction for Rv64ZbkbInstruction<Hart>
35where
36    Reg: [const] Register<Type = u64>,
37    Hart: [const] HartConfig<Reg = Reg>,
38{
39    const OWN_ISA_EXTENSIONS: &'static [IsaExtension] = &[IsaExtension::new("zbkb", 1, 0)];
40
41    const ALIGNMENT: u8 = align_of::<u32>() as u8;
42
43    type Hart = Hart;
44
45    #[inline(always)]
46    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
47    fn try_decode(instruction: u32) -> Option<Self> {
48        let opcode = (instruction & 0b111_1111) as u8;
49        let rd_bits = ((instruction >> 7) & 0x1f) as u8;
50        let funct3 = ((instruction >> 12) & 0b111) as u8;
51        let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
52        let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
53        let funct7 = ((instruction >> 25) & 0b111_1111) as u8;
54        let funct12 = ((instruction >> 20) & 0xfff) as u16;
55
56        match opcode {
57            // OP-IMM (I-type): brev8
58            0b001_0011 => {
59                let rd = Reg::from_bits(rd_bits)?;
60                let rs1 = Reg::from_bits(rs1_bits)?;
61                match funct3 {
62                    // brev8: funct12 = 0b0110_1000_0111 = 0x687
63                    0b101 if funct12 == 0b0110_1000_0111 => Some(Self::Brev8 { rd, rs1 }),
64                    _ => None,
65                }
66            }
67            // OP (R-type): pack, packh
68            0b011_0011 => {
69                let rd = Reg::from_bits(rd_bits)?;
70                let rs1 = Reg::from_bits(rs1_bits)?;
71                let rs2 = Reg::from_bits(rs2_bits)?;
72                match (funct3, funct7) {
73                    // pack: funct3=100, funct7=000_0100
74                    (0b100, 0b000_0100) => Some(Self::Pack { rd, rs1, rs2 }),
75                    // packh: funct3=111, funct7=000_0100
76                    (0b111, 0b000_0100) => Some(Self::Packh { rd, rs1, rs2 }),
77                    _ => None,
78                }
79            }
80            // OP-32 (R-type): packw
81            0b011_1011 => {
82                let rd = Reg::from_bits(rd_bits)?;
83                let rs1 = Reg::from_bits(rs1_bits)?;
84                let rs2 = Reg::from_bits(rs2_bits)?;
85                match (funct3, funct7) {
86                    // packw: funct3=100, funct7=000_0100
87                    (0b100, 0b000_0100) => {
88                        // NOTE: `packw rd, rs1, x0` has exactly the same encoding and semantics
89                        // as Zbb's `zext.h`, which is cheaper to execute, so it is decoded as
90                        // `zext.h` when it is present in the instruction set, regardless of the
91                        // order in which extensions are inherited. The macro replaces `Self::Zexth`
92                        // with `None?` in instruction sets without it, which makes this a regular
93                        // `packw`.
94                        let zexth = if rs2_bits == 0 {
95                            try { Self::Zexth { rd, rs1 } }
96                        } else {
97                            None
98                        };
99                        if zexth.is_some() {
100                            zexth
101                        } else {
102                            Some(Self::Packw { rd, rs1, rs2 })
103                        }
104                    }
105                    _ => None,
106                }
107            }
108            _ => None,
109        }
110    }
111
112    #[inline(always)]
113    fn size(&self) -> u8 {
114        size_of::<u32>() as u8
115    }
116}
117
118#[instruction]
119impl<Reg, Hart> fmt::Display for Rv64ZbkbInstruction<Hart>
120where
121    Reg: fmt::Display + Copy,
122    Hart: HartConfig<Reg = Reg>,
123{
124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125        match self {
126            Self::Pack { rd, rs1, rs2 } => write!(f, "pack {rd}, {rs1}, {rs2}"),
127            Self::Packh { rd, rs1, rs2 } => write!(f, "packh {rd}, {rs1}, {rs2}"),
128            Self::Packw { rd, rs1, rs2 } => write!(f, "packw {rd}, {rs1}, {rs2}"),
129            Self::Brev8 { rd, rs1 } => write!(f, "brev8 {rd}, {rs1}"),
130        }
131    }
132}