ab_riscv_interpreter/
m_64_ext.rs

1//! RV64 M extension
2
3#[cfg(test)]
4mod tests;
5
6use ab_riscv_primitives::instruction::m_64_ext::M64ExtInstruction;
7use ab_riscv_primitives::registers::{Register, Registers};
8
9/// Execute instructions from M extension
10#[inline(always)]
11pub fn execute_m_64_ext<Reg>(regs: &mut Registers<Reg>, instruction: M64ExtInstruction<Reg>)
12where
13    Reg: Register<Type = u64>,
14    [(); Reg::N]:,
15{
16    match instruction {
17        M64ExtInstruction::Mul { rd, rs1, rs2 } => {
18            let value = regs.read(rs1).wrapping_mul(regs.read(rs2));
19            regs.write(rd, value);
20        }
21        M64ExtInstruction::Mulh { rd, rs1, rs2 } => {
22            let (_lo, prod) = regs
23                .read(rs1)
24                .cast_signed()
25                .widening_mul(regs.read(rs2).cast_signed());
26            regs.write(rd, prod.cast_unsigned());
27        }
28        M64ExtInstruction::Mulhsu { rd, rs1, rs2 } => {
29            let prod = (regs.read(rs1).cast_signed() as i128) * (regs.read(rs2) as i128);
30            let value = prod >> 64;
31            regs.write(rd, value.cast_unsigned() as u64);
32        }
33        M64ExtInstruction::Mulhu { rd, rs1, rs2 } => {
34            let prod = (regs.read(rs1) as u128) * (regs.read(rs2) as u128);
35            let value = prod >> 64;
36            regs.write(rd, value as u64);
37        }
38        M64ExtInstruction::Div { rd, rs1, rs2 } => {
39            let dividend = regs.read(rs1).cast_signed();
40            let divisor = regs.read(rs2).cast_signed();
41            let value = if divisor == 0 {
42                -1i64
43            } else if dividend == i64::MIN && divisor == -1 {
44                i64::MIN
45            } else {
46                dividend / divisor
47            };
48            regs.write(rd, value.cast_unsigned());
49        }
50        M64ExtInstruction::Divu { rd, rs1, rs2 } => {
51            let dividend = regs.read(rs1);
52            let divisor = regs.read(rs2);
53            let value = if divisor == 0 {
54                u64::MAX
55            } else {
56                dividend / divisor
57            };
58            regs.write(rd, value);
59        }
60        M64ExtInstruction::Rem { rd, rs1, rs2 } => {
61            let dividend = regs.read(rs1).cast_signed();
62            let divisor = regs.read(rs2).cast_signed();
63            let value = if divisor == 0 {
64                dividend
65            } else if dividend == i64::MIN && divisor == -1 {
66                0
67            } else {
68                dividend % divisor
69            };
70            regs.write(rd, value.cast_unsigned());
71        }
72        M64ExtInstruction::Remu { rd, rs1, rs2 } => {
73            let dividend = regs.read(rs1);
74            let divisor = regs.read(rs2);
75            let value = if divisor == 0 {
76                dividend
77            } else {
78                dividend % divisor
79            };
80            regs.write(rd, value);
81        }
82
83        // RV64 R-type W
84        M64ExtInstruction::Mulw { rd, rs1, rs2 } => {
85            let prod = (regs.read(rs1) as i32).wrapping_mul(regs.read(rs2) as i32);
86            regs.write(rd, (prod as i64).cast_unsigned());
87        }
88        M64ExtInstruction::Divw { rd, rs1, rs2 } => {
89            let dividend = regs.read(rs1) as i32;
90            let divisor = regs.read(rs2) as i32;
91            let value = if divisor == 0 {
92                -1i64
93            } else if dividend == i32::MIN && divisor == -1 {
94                i32::MIN as i64
95            } else {
96                (dividend / divisor) as i64
97            };
98            regs.write(rd, value.cast_unsigned());
99        }
100        M64ExtInstruction::Divuw { rd, rs1, rs2 } => {
101            let dividend = regs.read(rs1) as u32;
102            let divisor = regs.read(rs2) as u32;
103            let value = if divisor == 0 {
104                u64::MAX
105            } else {
106                ((dividend / divisor).cast_signed() as i64).cast_unsigned()
107            };
108            regs.write(rd, value);
109        }
110        M64ExtInstruction::Remw { rd, rs1, rs2 } => {
111            let dividend = regs.read(rs1) as i32;
112            let divisor = regs.read(rs2) as i32;
113            let value = if divisor == 0 {
114                (dividend as i64).cast_unsigned()
115            } else if dividend == i32::MIN && divisor == -1 {
116                0
117            } else {
118                ((dividend % divisor) as i64).cast_unsigned()
119            };
120            regs.write(rd, value);
121        }
122        M64ExtInstruction::Remuw { rd, rs1, rs2 } => {
123            let dividend = regs.read(rs1) as u32;
124            let divisor = regs.read(rs2) as u32;
125            let value = if divisor == 0 {
126                dividend.cast_signed() as i64
127            } else {
128                (dividend % divisor).cast_signed() as i64
129            };
130            regs.write(rd, value.cast_unsigned());
131        }
132    }
133}