Skip to main content

ab_riscv_interpreter/rv64/m/
zmmul.rs

1//! RV64 Zmmul extension (multiplication subset of M extension)
2
3use crate::{
4    ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands, ExecutionError,
5    ExecutionResult, FetchInstructionResult, InstructionFetcher, OpaqueThreadedExecutionResult,
6    RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands, ThreadedExecutableInstruction,
7    ThreadedExecutionResult,
8};
9use ab_riscv_macros::instruction_execution;
10use ab_riscv_primitives::prelude::*;
11
12#[instruction_execution]
13const impl<Reg, Hart> ExecutableInstructionOperands for Rv64ZmmulInstruction<Hart>
14where
15    Reg: Register<Type = u64>,
16    Hart: HartConfig<Reg = Reg>,
17{
18}
19
20#[instruction_execution]
21const impl<Reg, Hart, Env> ExecutableInstructionCsr<Env> for Rv64ZmmulInstruction<Hart>
22where
23    Reg: Register<Type = u64>,
24    Hart: HartConfig<Reg = Reg>,
25{
26}
27
28#[instruction_execution]
29const impl<Reg, Hart, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
30    for Rv64ZmmulInstruction<Hart>
31where
32    Reg: [const] Register<Type = u64>,
33    Hart: HartConfig<Reg = 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<Reg::Type>,
43        _regs: &mut Regs,
44        _env: &mut Env,
45        _memory: &mut Memory,
46        _program_counter: &PC,
47    ) -> ExecutionResult<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
82            // RV64 R-type W
83            Self::Mulw { rd, rs1: _, rs2: _ } => {
84                let prod = (rs1_value as i32).wrapping_mul(rs2_value as i32);
85                ExecutionResult::Continue {
86                    rd,
87                    value: i64::from(prod).cast_unsigned(),
88                }
89            }
90        }
91    }
92}