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    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 Rv64MInstruction<Reg> where
18    Reg: Register<Type = u64>
19{
20}
21
22#[instruction_execution]
23const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv64MInstruction<Reg> where
24    Reg: Register<Type = u64>
25{
26}
27
28#[instruction_execution]
29const impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
30    for Rv64MInstruction<Reg>
31where
32    Reg: [const] Register<Type = u64>,
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 64 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 i128, take upper 64 bits
65                let prod = i128::from(rs1_value.cast_signed()) * i128::from(rs2_value);
66                let value = prod >> 64;
67                ExecutionResult::Continue {
68                    rd,
69                    value: value.cast_unsigned() as u64,
70                }
71            }
72            Self::Mulhu { rd, rs1: _, rs2: _ } => {
73                // Unsigned × unsigned: widen to u128, take upper 64 bits
74                let prod = u128::from(rs1_value) * u128::from(rs2_value);
75                let value = prod >> 64;
76                ExecutionResult::Continue {
77                    rd,
78                    value: value as u64,
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                    -1i64
86                } else if dividend == i64::MIN && divisor == -1 {
87                    i64::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(u64::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 == i64::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            // RV64 R-type W
133            Self::Mulw { rd, rs1: _, rs2: _ } => {
134                let prod = (rs1_value as i32).wrapping_mul(rs2_value as i32);
135                ExecutionResult::Continue {
136                    rd,
137                    value: i64::from(prod).cast_unsigned(),
138                }
139            }
140            Self::Divw { rd, rs1: _, rs2: _ } => {
141                let dividend = rs1_value as i32;
142                let divisor = rs2_value as i32;
143                let value = if divisor == 0 {
144                    -1i64
145                } else if dividend == i32::MIN && divisor == -1 {
146                    i64::from(i32::MIN)
147                } else {
148                    i64::from(dividend / divisor)
149                };
150                ExecutionResult::Continue {
151                    rd,
152                    value: value.cast_unsigned(),
153                }
154            }
155            Self::Divuw { rd, rs1: _, rs2: _ } => {
156                let dividend = rs1_value as u32;
157                let divisor = rs2_value as u32;
158                let value = match dividend.checked_div(divisor) {
159                    Some(value) => i64::from(value.cast_signed()).cast_unsigned(),
160                    None => u64::MAX,
161                };
162                ExecutionResult::Continue { rd, value }
163            }
164            Self::Remw { rd, rs1: _, rs2: _ } => {
165                let dividend = rs1_value as i32;
166                let divisor = rs2_value as i32;
167                #[expect(
168                    clippy::modulo_arithmetic,
169                    reason = "This is what the code is supposed to do"
170                )]
171                let value = if divisor == 0 {
172                    i64::from(dividend).cast_unsigned()
173                } else if dividend == i32::MIN && divisor == -1 {
174                    0
175                } else {
176                    i64::from(dividend % divisor).cast_unsigned()
177                };
178                ExecutionResult::Continue { rd, value }
179            }
180            Self::Remuw { rd, rs1: _, rs2: _ } => {
181                let dividend = rs1_value as u32;
182                let divisor = rs2_value as u32;
183                let value = if divisor == 0 {
184                    dividend.cast_signed()
185                } else {
186                    (dividend % divisor).cast_signed()
187                };
188                ExecutionResult::Continue {
189                    rd,
190                    value: i64::from(value).cast_unsigned(),
191                }
192            }
193        }
194    }
195}