Skip to main content

ab_riscv_interpreter/rv32/
m.rs

1//! RV32 M extension
2
3#[cfg(test)]
4mod tests;
5pub mod zmmul;
6
7use crate::{
8    ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands, ExecutionError,
9    ExecutionResult, FetchInstructionResult, InstructionFetcher, OpaqueThreadedExecutionResult,
10    RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands, ThreadedExecutableInstruction,
11    ThreadedExecutionResult,
12};
13use ab_riscv_macros::instruction_execution;
14use ab_riscv_primitives::prelude::*;
15
16#[instruction_execution]
17const impl<Reg> ExecutableInstructionOperands for Rv32MInstruction<Reg> where
18    Reg: Register<Type = u32>
19{
20}
21
22#[instruction_execution]
23const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv32MInstruction<Reg> where
24    Reg: Register<Type = u32>
25{
26}
27
28#[instruction_execution]
29const impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
30    for Rv32MInstruction<Reg>
31where
32    Reg: [const] Register<Type = u32>,
33    Regs: [const] RegisterFile<Reg>,
34{
35    #[inline(always)]
36    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
37    fn execute(
38        self,
39        Rs1Rs2OperandValues {
40            rs1_value,
41            rs2_value,
42        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
43        _regs: &mut Regs,
44        _env: &mut Env,
45        _memory: &mut Memory,
46        _program_counter: &mut PC,
47    ) -> ExecutionResult<Self::Reg> {
48        match self {
49            Self::Mul { rd, rs1: _, rs2: _ } => {
50                let value = rs1_value.wrapping_mul(rs2_value);
51                ExecutionResult::Continue { rd, value }
52            }
53            Self::Mulh { rd, rs1: _, rs2: _ } => {
54                // Signed × signed: multiply and take upper 32 bits
55                let (_lo, prod) = rs1_value
56                    .cast_signed()
57                    .carrying_mul(rs2_value.cast_signed(), 0);
58                ExecutionResult::Continue {
59                    rd,
60                    value: prod.cast_unsigned(),
61                }
62            }
63            Self::Mulhsu { rd, rs1: _, rs2: _ } => {
64                // Signed × unsigned: widen to i64, take upper 32 bits
65                let prod = i64::from(rs1_value.cast_signed()) * i64::from(rs2_value);
66                let value = prod >> 32;
67                ExecutionResult::Continue {
68                    rd,
69                    value: value.cast_unsigned() as u32,
70                }
71            }
72            Self::Mulhu { rd, rs1: _, rs2: _ } => {
73                // Unsigned × unsigned: widen to u64, take upper 32 bits
74                let prod = u64::from(rs1_value) * u64::from(rs2_value);
75                let value = prod >> 32;
76                ExecutionResult::Continue {
77                    rd,
78                    value: value as u32,
79                }
80            }
81            Self::Div { rd, rs1: _, rs2: _ } => {
82                let dividend = rs1_value.cast_signed();
83                let divisor = rs2_value.cast_signed();
84                let value = if divisor == 0 {
85                    -1i32
86                } else if dividend == i32::MIN && divisor == -1 {
87                    i32::MIN
88                } else {
89                    dividend / divisor
90                };
91                ExecutionResult::Continue {
92                    rd,
93                    value: value.cast_unsigned(),
94                }
95            }
96            Self::Divu { rd, rs1: _, rs2: _ } => {
97                let dividend = rs1_value;
98                let divisor = rs2_value;
99                let value = dividend.checked_div(divisor).unwrap_or(u32::MAX);
100                ExecutionResult::Continue { rd, value }
101            }
102            Self::Rem { rd, rs1: _, rs2: _ } => {
103                let dividend = rs1_value.cast_signed();
104                let divisor = rs2_value.cast_signed();
105                #[expect(
106                    clippy::modulo_arithmetic,
107                    reason = "This is what the code is supposed to do"
108                )]
109                let value = if divisor == 0 {
110                    dividend
111                } else if dividend == i32::MIN && divisor == -1 {
112                    0
113                } else {
114                    dividend % divisor
115                };
116                ExecutionResult::Continue {
117                    rd,
118                    value: value.cast_unsigned(),
119                }
120            }
121            Self::Remu { rd, rs1: _, rs2: _ } => {
122                let dividend = rs1_value;
123                let divisor = rs2_value;
124                let value = if divisor == 0 {
125                    dividend
126                } else {
127                    dividend % divisor
128                };
129                ExecutionResult::Continue { rd, value }
130            }
131        }
132    }
133}