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, Hart> ExecutableInstructionOperands for Rv64MInstruction<Hart>
18where
19    Reg: Register<Type = u64>,
20    Hart: HartConfig<Reg = Reg>,
21{
22}
23
24#[instruction_execution]
25const impl<Reg, Hart, Env> ExecutableInstructionCsr<Env> for Rv64MInstruction<Hart>
26where
27    Reg: Register<Type = u64>,
28    Hart: HartConfig<Reg = Reg>,
29{
30}
31
32#[instruction_execution]
33const impl<Reg, Hart, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
34    for Rv64MInstruction<Hart>
35where
36    Reg: [const] Register<Type = u64>,
37    Hart: HartConfig<Reg = Reg>,
38    Regs: [const] RegisterFile<Reg>,
39{
40    #[inline(always)]
41    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
42    fn execute(
43        self,
44        Rs1Rs2OperandValues {
45            rs1_value,
46            rs2_value,
47        }: Rs1Rs2OperandValues<Reg::Type>,
48        _regs: &mut Regs,
49        _env: &mut Env,
50        _memory: &mut Memory,
51        _program_counter: &PC,
52    ) -> ExecutionResult<Reg> {
53        match self {
54            Self::Div { rd, rs1: _, rs2: _ } => {
55                let dividend = rs1_value.cast_signed();
56                let divisor = rs2_value.cast_signed();
57                let value = if divisor == 0 {
58                    -1i64
59                } else if dividend == i64::MIN && divisor == -1 {
60                    i64::MIN
61                } else {
62                    dividend / divisor
63                };
64                ExecutionResult::Continue {
65                    rd,
66                    value: value.cast_unsigned(),
67                }
68            }
69            Self::Divu { rd, rs1: _, rs2: _ } => {
70                let dividend = rs1_value;
71                let divisor = rs2_value;
72                let value = dividend.checked_div(divisor).unwrap_or(u64::MAX);
73                ExecutionResult::Continue { rd, value }
74            }
75            Self::Rem { rd, rs1: _, rs2: _ } => {
76                let dividend = rs1_value.cast_signed();
77                let divisor = rs2_value.cast_signed();
78                #[expect(
79                    clippy::modulo_arithmetic,
80                    reason = "This is what the code is supposed to do"
81                )]
82                let value = if divisor == 0 {
83                    dividend
84                } else if dividend == i64::MIN && divisor == -1 {
85                    0
86                } else {
87                    dividend % divisor
88                };
89                ExecutionResult::Continue {
90                    rd,
91                    value: value.cast_unsigned(),
92                }
93            }
94            Self::Remu { rd, rs1: _, rs2: _ } => {
95                let dividend = rs1_value;
96                let divisor = rs2_value;
97                let value = if divisor == 0 {
98                    dividend
99                } else {
100                    dividend % divisor
101                };
102                ExecutionResult::Continue { rd, value }
103            }
104
105            // RV64 R-type W
106            Self::Divw { rd, rs1: _, rs2: _ } => {
107                let dividend = rs1_value as i32;
108                let divisor = rs2_value as i32;
109                let value = if divisor == 0 {
110                    -1i64
111                } else if dividend == i32::MIN && divisor == -1 {
112                    i64::from(i32::MIN)
113                } else {
114                    i64::from(dividend / divisor)
115                };
116                ExecutionResult::Continue {
117                    rd,
118                    value: value.cast_unsigned(),
119                }
120            }
121            Self::Divuw { rd, rs1: _, rs2: _ } => {
122                let dividend = rs1_value as u32;
123                let divisor = rs2_value as u32;
124                let value = match dividend.checked_div(divisor) {
125                    Some(value) => i64::from(value.cast_signed()).cast_unsigned(),
126                    None => u64::MAX,
127                };
128                ExecutionResult::Continue { rd, value }
129            }
130            Self::Remw { rd, rs1: _, rs2: _ } => {
131                let dividend = rs1_value as i32;
132                let divisor = rs2_value as i32;
133                #[expect(
134                    clippy::modulo_arithmetic,
135                    reason = "This is what the code is supposed to do"
136                )]
137                let value = if divisor == 0 {
138                    i64::from(dividend).cast_unsigned()
139                } else if dividend == i32::MIN && divisor == -1 {
140                    0
141                } else {
142                    i64::from(dividend % divisor).cast_unsigned()
143                };
144                ExecutionResult::Continue { rd, value }
145            }
146            Self::Remuw { rd, rs1: _, rs2: _ } => {
147                let dividend = rs1_value as u32;
148                let divisor = rs2_value as u32;
149                let value = if divisor == 0 {
150                    dividend.cast_signed()
151                } else {
152                    (dividend % divisor).cast_signed()
153                };
154                ExecutionResult::Continue {
155                    rd,
156                    value: i64::from(value).cast_unsigned(),
157                }
158            }
159        }
160    }
161}