Skip to main content

ab_riscv_interpreter/rv64/zce/zcmp/
rv64_zcmp_helpers.rs

1//! Opaque helpers for Zcmp extension
2
3use crate::{ExecutionError, RegisterFile, VirtualMemory};
4use ab_riscv_primitives::prelude::*;
5use core::ops::ControlFlow;
6
7/// Execute CM.PUSH: store registers below sp, then decrement sp
8#[inline]
9#[doc(hidden)]
10#[expect(clippy::type_complexity, reason = "Internal helper")]
11pub fn do_push<Reg, Regs, Memory, CustomError>(
12    regs: &mut Regs,
13    memory: &mut Memory,
14    urlist: ZcmpUrlist<Reg>,
15    stack_adj: u8,
16) -> Result<ControlFlow<(), (Reg, u64)>, ExecutionError<Reg::Type, CustomError>>
17where
18    Reg: ZcmpRegister<Type = u64>,
19    Regs: RegisterFile<Reg>,
20    Memory: VirtualMemory,
21{
22    let sp = regs.read(Reg::SP);
23    // Store from sp-8 downward, highest-priority register first
24    let mut store_addr = sp.wrapping_sub(size_of::<Reg::Type>() as u64);
25    for reg in urlist.reg_list() {
26        memory.write(store_addr, regs.read(reg))?;
27        store_addr = store_addr.wrapping_sub(size_of::<Reg::Type>() as u64);
28    }
29    Ok(ControlFlow::Continue((
30        Reg::SP,
31        sp.wrapping_sub(u64::from(stack_adj)),
32    )))
33}
34
35/// Execute CM.POP and variants: restore registers and increment sp.
36/// Returns the value of ra (x1) for use with popret/popretz.
37#[inline]
38#[doc(hidden)]
39pub fn do_pop<Reg, Regs, Memory, CustomError>(
40    regs: &mut Regs,
41    memory: &mut Memory,
42    urlist: ZcmpUrlist<Reg>,
43    stack_adj: u8,
44) -> Result<u64, ExecutionError<Reg::Type, CustomError>>
45where
46    Reg: ZcmpRegister<Type = u64>,
47    Regs: RegisterFile<Reg>,
48    Memory: VirtualMemory,
49{
50    let sp = regs.read(Reg::SP);
51    let new_sp = sp.wrapping_add(u64::from(stack_adj));
52    // Restore from [new_sp-8, new_sp-16, ...], matching push order
53    let mut load_addr = new_sp.wrapping_sub(size_of::<Reg::Type>() as u64);
54    for reg in urlist.reg_list() {
55        let value = memory.read::<u64>(load_addr)?;
56        regs.write(reg, value);
57        load_addr = load_addr.wrapping_sub(size_of::<Reg::Type>() as u64);
58    }
59    regs.write(Reg::SP, new_sp);
60    Ok(regs.read(Reg::RA))
61}