Skip to main content

ab_riscv_interpreter/rv32/zce/
zcmp.rs

1//! RV32 Zcmp extension
2
3pub mod rv32_zcmp_helpers;
4#[cfg(test)]
5mod tests;
6
7use crate::{
8    ExecutableInstruction, ExecutableInstructionCsr, ExecutableInstructionOperands, ExecutionError,
9    ExecutionResult, FetchInstructionResult, InstructionFetcher, OpaqueThreadedExecutionResult,
10    PackedAddress, ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands,
11    SystemInstructionHandler, ThreadedExecutableInstruction, ThreadedExecutionResult,
12    VirtualMemory,
13};
14use ab_riscv_macros::instruction_execution;
15use ab_riscv_primitives::prelude::*;
16use core::ops::ControlFlow;
17
18#[instruction_execution]
19const impl<Reg> ExecutableInstructionOperands for Rv32ZcmpInstruction<Reg> where
20    Reg: ZcmpRegister<Type = u32>
21{
22}
23
24#[instruction_execution]
25const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv32ZcmpInstruction<Reg> where
26    Reg: ZcmpRegister<Type = u32>
27{
28}
29
30#[instruction_execution]
31const impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
32    for Rv32ZcmpInstruction<Reg>
33where
34    Reg: [const] ZcmpRegister<Type = u32>,
35{
36    #[inline(always)]
37    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
38    fn execute(
39        self,
40        Rs1Rs2OperandValues {
41            rs1_value,
42            rs2_value,
43        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
44        regs: &mut Regs,
45        _env: &mut Env,
46        memory: &mut Memory,
47        program_counter: &mut PC,
48    ) -> ExecutionResult<Self::Reg> {
49        ExecutionResult::ContinueNoWrite
50    }
51}
52
53#[instruction_execution]
54const impl<Reg> ExecutableInstructionOperands for Rv32ZcmpOnlyInstruction<Reg> where
55    Reg: ZcmpRegister<Type = u32>
56{
57}
58
59#[instruction_execution]
60const impl<Reg, Env> ExecutableInstructionCsr<Env> for Rv32ZcmpOnlyInstruction<Reg> where
61    Reg: ZcmpRegister<Type = u32>
62{
63}
64
65#[instruction_execution]
66const impl<Reg, Regs, Env, Memory, PC> ExecutableInstruction<Regs, Env, Memory, PC>
67    for Rv32ZcmpOnlyInstruction<Reg>
68where
69    Reg: [const] ZcmpRegister<Type = u32>,
70    Regs: [const] RegisterFile<Reg>,
71    Memory: [const] VirtualMemory,
72    PC: [const] ProgramCounter<Reg::Type, Memory>,
73    Env: [const] SystemInstructionHandler<Reg, Regs, Memory, PC>,
74{
75    #[inline(always)]
76    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
77    fn execute(
78        self,
79        Rs1Rs2OperandValues {
80            rs1_value,
81            rs2_value,
82        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
83        regs: &mut Regs,
84        _env: &mut Env,
85        memory: &mut Memory,
86        _program_counter: &mut PC,
87    ) -> ExecutionResult<Self::Reg> {
88        match self {
89            Self::CmPush { urlist, stack_adj } => {
90                rv32_zcmp_helpers::do_push(regs, memory, urlist, stack_adj)
91            }
92            Self::CmPop { urlist, stack_adj } => {
93                rv32_zcmp_helpers::do_pop(regs, memory, urlist, stack_adj)?;
94                ExecutionResult::ContinueNoWrite
95            }
96            Self::CmPopretz { urlist, stack_adj } => {
97                let ra_val = rv32_zcmp_helpers::do_pop(regs, memory, urlist, stack_adj)?;
98                // Zero a0 before returning
99                regs.write(Reg::A0, 0);
100                // Jump to ra with LSB cleared (RISC-V mode bit)
101                let target = ra_val & !1;
102                ExecutionResult::Jump { target }
103            }
104            Self::CmPopret { urlist, stack_adj } => {
105                let ra_val = rv32_zcmp_helpers::do_pop(regs, memory, urlist, stack_adj)?;
106                // Jump to ra with LSB cleared (RISC-V mode bit)
107                let target = ra_val & !1;
108                ExecutionResult::Jump { target }
109            }
110            Self::CmMva01s { rs1: _, rs2: _ } => {
111                // Read both sources before any write to avoid aliasing
112                let v1 = rs1_value;
113                let v2 = rs2_value;
114                regs.write(Reg::A0, v1);
115                ExecutionResult::Continue {
116                    rd: Reg::A1,
117                    value: v2,
118                }
119            }
120            Self::CmMvsa01 { rs1, rs2 } => {
121                // Read both sources before any write to avoid aliasing
122                let a0_val = regs.read(Reg::A0);
123                let a1_val = regs.read(Reg::A1);
124                regs.write(rs1, a0_val);
125                ExecutionResult::Continue {
126                    rd: rs2,
127                    value: a1_val,
128                }
129            }
130        }
131    }
132}