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    ProgramCounter, RegisterFile, Rs1Rs2OperandValues, Rs1Rs2Operands, SystemInstructionHandler,
10    VirtualMemory,
11};
12use ab_riscv_macros::instruction_execution;
13use ab_riscv_primitives::prelude::*;
14use core::ops::ControlFlow;
15
16#[instruction_execution]
17impl<Reg> ExecutableInstructionOperands for Rv32ZcmpInstruction<Reg> where
18    Reg: ZcmpRegister<Type = u32>
19{
20}
21
22#[instruction_execution]
23impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
24    for Rv32ZcmpInstruction<Reg>
25where
26    Reg: ZcmpRegister<Type = u32>,
27{
28}
29
30#[instruction_execution]
31impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
32    ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
33    for Rv32ZcmpInstruction<Reg>
34where
35    Reg: ZcmpRegister<Type = u32>,
36{
37    #[inline(always)]
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        _ext_state: &mut ExtState,
46        memory: &mut Memory,
47        program_counter: &mut PC,
48        system_instruction_handler: &mut InstructionHandler,
49    ) -> Result<
50        ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
51        ExecutionError<Reg::Type, CustomError>,
52    > {
53        Ok(ControlFlow::Continue(Default::default()))
54    }
55}
56
57#[instruction_execution]
58impl<Reg> ExecutableInstructionOperands for Rv32ZcmpOnlyInstruction<Reg> where
59    Reg: ZcmpRegister<Type = u32>
60{
61}
62
63#[instruction_execution]
64impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
65    for Rv32ZcmpOnlyInstruction<Reg>
66where
67    Reg: ZcmpRegister<Type = u32>,
68{
69}
70
71#[instruction_execution]
72impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
73    ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
74    for Rv32ZcmpOnlyInstruction<Reg>
75where
76    Reg: ZcmpRegister<Type = u32>,
77    Regs: RegisterFile<Reg>,
78    Memory: VirtualMemory,
79    PC: ProgramCounter<Reg::Type, Memory, CustomError>,
80    InstructionHandler: SystemInstructionHandler<Reg, Regs, Memory, PC, CustomError>,
81{
82    #[inline(always)]
83    fn execute(
84        self,
85        Rs1Rs2OperandValues {
86            rs1_value,
87            rs2_value,
88        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
89        regs: &mut Regs,
90        _ext_state: &mut ExtState,
91        memory: &mut Memory,
92        program_counter: &mut PC,
93        _system_instruction_handler: &mut InstructionHandler,
94    ) -> Result<
95        ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
96        ExecutionError<Reg::Type, CustomError>,
97    > {
98        match self {
99            Self::CmPush { urlist, stack_adj } => {
100                rv32_zcmp_helpers::do_push(regs, memory, urlist, stack_adj)
101            }
102            Self::CmPop { urlist, stack_adj } => {
103                rv32_zcmp_helpers::do_pop(regs, memory, urlist, stack_adj)?;
104                Ok(ControlFlow::Continue(Default::default()))
105            }
106            Self::CmPopretz { urlist, stack_adj } => {
107                let ra_val = rv32_zcmp_helpers::do_pop(regs, memory, urlist, stack_adj)?;
108                // Zero a0 before returning
109                regs.write(Reg::A0, 0);
110                // Jump to ra with LSB cleared (RISC-V mode bit)
111                let target = ra_val & !1;
112                program_counter
113                    .set_pc(memory, target)
114                    .map(|control_flow| control_flow.map_continue(|()| Default::default()))
115                    .map_err(ExecutionError::from)
116            }
117            Self::CmPopret { urlist, stack_adj } => {
118                let ra_val = rv32_zcmp_helpers::do_pop(regs, memory, urlist, stack_adj)?;
119                // Jump to ra with LSB cleared (RISC-V mode bit)
120                let target = ra_val & !1;
121                program_counter
122                    .set_pc(memory, target)
123                    .map(|control_flow| control_flow.map_continue(|()| Default::default()))
124                    .map_err(ExecutionError::from)
125            }
126            Self::CmMva01s { rs1: _, rs2: _ } => {
127                // Read both sources before any write to avoid aliasing
128                let v1 = rs1_value;
129                let v2 = rs2_value;
130                regs.write(Reg::A0, v1);
131                Ok(ControlFlow::Continue((Reg::A1, v2)))
132            }
133            Self::CmMvsa01 { rs1, rs2 } => {
134                // Read both sources before any write to avoid aliasing
135                let a0_val = regs.read(Reg::A0);
136                let a1_val = regs.read(Reg::A1);
137                regs.write(rs1, a0_val);
138                Ok(ControlFlow::Continue((rs2, a1_val)))
139            }
140        }
141    }
142}