Skip to main content

ab_riscv_interpreter/rv32/zce/zcmp/
rv32_zcmp_helpers.rs

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