Skip to main content

ab_riscv_interpreter/rv64/
m.rs

1//! RV64 M extension
2
3#[cfg(test)]
4mod tests;
5pub mod zmmul;
6
7use crate::{
8    ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands, ExecutionError,
9    RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
10};
11use ab_riscv_macros::instruction_execution;
12use ab_riscv_primitives::prelude::*;
13use core::ops::ControlFlow;
14
15#[instruction_execution]
16impl<Reg> ExecutableInstructionOperands for Rv64MInstruction<Reg> where Reg: Register<Type = u64> {}
17
18#[instruction_execution]
19impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
20    for Rv64MInstruction<Reg>
21where
22    Reg: Register<Type = u64>,
23{
24}
25
26#[instruction_execution]
27impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
28    ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
29    for Rv64MInstruction<Reg>
30where
31    Reg: Register<Type = u64>,
32    Regs: RegisterFile<Reg>,
33{
34    #[inline(always)]
35    fn execute(
36        self,
37        Rs1Rs2OperandValues {
38            rs1_value,
39            rs2_value,
40        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
41        _regs: &mut Regs,
42        _ext_state: &mut ExtState,
43        _memory: &mut Memory,
44        _program_counter: &mut PC,
45        _system_instruction_handler: &mut InstructionHandler,
46    ) -> Result<
47        ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
48        ExecutionError<Reg::Type, CustomError>,
49    > {
50        match self {
51            Self::Mul { rd, rs1: _, rs2: _ } => {
52                let value = rs1_value.wrapping_mul(rs2_value);
53                Ok(ControlFlow::Continue((rd, value)))
54            }
55            Self::Mulh { rd, rs1: _, rs2: _ } => {
56                // Signed × signed: multiply and take upper 64 bits
57                let (_lo, prod) = rs1_value
58                    .cast_signed()
59                    .carrying_mul(rs2_value.cast_signed(), 0);
60                Ok(ControlFlow::Continue((rd, prod.cast_unsigned())))
61            }
62            Self::Mulhsu { rd, rs1: _, rs2: _ } => {
63                // Signed × unsigned: widen to i128, take upper 64 bits
64                let prod = i128::from(rs1_value.cast_signed()) * i128::from(rs2_value);
65                let value = prod >> 64;
66                Ok(ControlFlow::Continue((rd, value.cast_unsigned() as u64)))
67            }
68            Self::Mulhu { rd, rs1: _, rs2: _ } => {
69                // Unsigned × unsigned: widen to u128, take upper 64 bits
70                let prod = u128::from(rs1_value) * u128::from(rs2_value);
71                let value = prod >> 64;
72                Ok(ControlFlow::Continue((rd, value as u64)))
73            }
74            Self::Div { rd, rs1: _, rs2: _ } => {
75                let dividend = rs1_value.cast_signed();
76                let divisor = rs2_value.cast_signed();
77                let value = if divisor == 0 {
78                    -1i64
79                } else if dividend == i64::MIN && divisor == -1 {
80                    i64::MIN
81                } else {
82                    dividend / divisor
83                };
84                Ok(ControlFlow::Continue((rd, value.cast_unsigned())))
85            }
86            Self::Divu { rd, rs1: _, rs2: _ } => {
87                let dividend = rs1_value;
88                let divisor = rs2_value;
89                let value = dividend.checked_div(divisor).unwrap_or(u64::MAX);
90                Ok(ControlFlow::Continue((rd, value)))
91            }
92            Self::Rem { rd, rs1: _, rs2: _ } => {
93                let dividend = rs1_value.cast_signed();
94                let divisor = rs2_value.cast_signed();
95                #[expect(
96                    clippy::modulo_arithmetic,
97                    reason = "This is what the code is supposed to do"
98                )]
99                let value = if divisor == 0 {
100                    dividend
101                } else if dividend == i64::MIN && divisor == -1 {
102                    0
103                } else {
104                    dividend % divisor
105                };
106                Ok(ControlFlow::Continue((rd, value.cast_unsigned())))
107            }
108            Self::Remu { rd, rs1: _, rs2: _ } => {
109                let dividend = rs1_value;
110                let divisor = rs2_value;
111                let value = if divisor == 0 {
112                    dividend
113                } else {
114                    dividend % divisor
115                };
116                Ok(ControlFlow::Continue((rd, value)))
117            }
118
119            // RV64 R-type W
120            Self::Mulw { rd, rs1: _, rs2: _ } => {
121                let prod = (rs1_value as i32).wrapping_mul(rs2_value as i32);
122                Ok(ControlFlow::Continue((rd, i64::from(prod).cast_unsigned())))
123            }
124            Self::Divw { rd, rs1: _, rs2: _ } => {
125                let dividend = rs1_value as i32;
126                let divisor = rs2_value as i32;
127                let value = if divisor == 0 {
128                    -1i64
129                } else if dividend == i32::MIN && divisor == -1 {
130                    i64::from(i32::MIN)
131                } else {
132                    i64::from(dividend / divisor)
133                };
134                Ok(ControlFlow::Continue((rd, value.cast_unsigned())))
135            }
136            Self::Divuw { rd, rs1: _, rs2: _ } => {
137                let dividend = rs1_value as u32;
138                let divisor = rs2_value as u32;
139                let value = dividend.checked_div(divisor).map_or(u64::MAX, |value| {
140                    i64::from(value.cast_signed()).cast_unsigned()
141                });
142                Ok(ControlFlow::Continue((rd, value)))
143            }
144            Self::Remw { rd, rs1: _, rs2: _ } => {
145                let dividend = rs1_value as i32;
146                let divisor = rs2_value as i32;
147                #[expect(
148                    clippy::modulo_arithmetic,
149                    reason = "This is what the code is supposed to do"
150                )]
151                let value = if divisor == 0 {
152                    i64::from(dividend).cast_unsigned()
153                } else if dividend == i32::MIN && divisor == -1 {
154                    0
155                } else {
156                    i64::from(dividend % divisor).cast_unsigned()
157                };
158                Ok(ControlFlow::Continue((rd, value)))
159            }
160            Self::Remuw { rd, rs1: _, rs2: _ } => {
161                let dividend = rs1_value as u32;
162                let divisor = rs2_value as u32;
163                let value = if divisor == 0 {
164                    dividend.cast_signed()
165                } else {
166                    (dividend % divisor).cast_signed()
167                };
168                Ok(ControlFlow::Continue((
169                    rd,
170                    i64::from(value).cast_unsigned(),
171                )))
172            }
173        }
174    }
175}