Skip to main content

ab_riscv_interpreter/rv32/b/
zbc.rs

1//! RV32 Zbc extension
2
3#[cfg(test)]
4mod tests;
5pub mod zbc_helpers;
6
7use crate::{ExecutableInstruction, ExecutionError, InterpreterState};
8use ab_riscv_macros::instruction_execution;
9use ab_riscv_primitives::instructions::rv32::b::zbc::Rv32ZbcInstruction;
10use ab_riscv_primitives::registers::general_purpose::Register;
11use core::ops::ControlFlow;
12
13#[instruction_execution]
14impl<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>
15    ExecutableInstruction<
16        InterpreterState<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>,
17        CustomError,
18    > for Rv32ZbcInstruction<Reg>
19where
20    Reg: Register<Type = u32>,
21    [(); Reg::N]:,
22{
23    #[inline(always)]
24    fn execute(
25        self,
26        state: &mut InterpreterState<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>,
27    ) -> Result<ControlFlow<()>, ExecutionError<Reg::Type, CustomError>> {
28        match self {
29            Self::Clmul { rd, rs1, rs2 } => {
30                // Only here to prevent compiler warnings about unused `zbc_helpers` module
31                let () = zbc_helpers::PLACEHOLDER;
32                let a = state.regs.read(rs1);
33                let b = state.regs.read(rs2);
34
35                // TODO: Miri is excluded because corresponding intrinsic is not implemented there
36                let value = cfg_select! {
37                    all(not(miri), target_arch = "riscv32", target_feature = "zbkc") => {
38                        core::arch::riscv32::clmul(a as usize, b as usize) as u32
39                    }
40                    _ => {{
41                        let result = zbc_helpers::clmul_internal(a, b);
42                        result as u32
43                    }}
44                };
45
46                state.regs.write(rd, value);
47            }
48            Self::Clmulh { rd, rs1, rs2 } => {
49                let a = state.regs.read(rs1);
50                let b = state.regs.read(rs2);
51
52                // TODO: Miri is excluded because corresponding intrinsic is not implemented there
53                let value = cfg_select! {
54                    all(not(miri), target_arch = "riscv32", target_feature = "zbkc") => {
55                        core::arch::riscv32::clmulh(a as usize, b as usize) as u32
56                    }
57                    _ => {{
58                        let result = zbc_helpers::clmul_internal(a, b);
59                        (result >> 32) as u32
60                    }}
61                };
62                state.regs.write(rd, value);
63            }
64            Self::Clmulr { rd, rs1, rs2 } => {
65                let a = state.regs.read(rs1);
66                let b = state.regs.read(rs2);
67
68                // TODO: Miri is excluded because corresponding intrinsic is not implemented there
69                let value = cfg_select! {
70                    all(not(miri), target_arch = "riscv32", target_feature = "zbc") => {
71                        core::arch::riscv32::clmulr(a as usize, b as usize) as u32
72                    }
73                    _ => {{
74                        let result = zbc_helpers::clmul_internal(a, b);
75                        (result >> 31) as u32
76                    }}
77                };
78
79                state.regs.write(rd, value);
80            }
81        }
82
83        Ok(ControlFlow::Continue(()))
84    }
85}