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