Skip to main content

ab_riscv_interpreter/rv32/zce/
zcmp.rs

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