Skip to main content

ab_riscv_interpreter/rv32/a/
amo_helpers.rs

1//! Opaque helpers shared by AMO-style extensions (`Zaamo`, `Zabha`, `Zacas`)
2
3use crate::{BasicInt, ExecutionError, PackedAddress, VirtualMemory};
4use core::hint::cold_path;
5
6/// Read memory for the read half of an AMO instruction's atomic read-modify-write cycle.
7///
8/// An AMO's memory access is a single atomic operation; per spec, a fault on it - whether it
9/// surfaces during the read half or the write half - must be reported as a Store/AMO fault, never
10/// a Load fault. [`VirtualMemory::read`] alone can't tell an AMO's read from an ordinary load's,
11/// so this maps any error onto [`ExecutionError::OutOfBoundsWrite`] before it can be misclassified
12/// as a load fault by the caller.
13#[inline(always)]
14#[doc(hidden)]
15pub const fn amo_read<T, M, Address>(memory: &M, address: u64) -> Result<T, ExecutionError<Address>>
16where
17    T: BasicInt,
18    M: [const] VirtualMemory,
19    Address: Copy,
20{
21    if let Ok(value) = memory.read::<T>(address) {
22        Ok(value)
23    } else {
24        cold_path();
25        Err(ExecutionError::OutOfBoundsWrite {
26            address: PackedAddress::new(address),
27        })
28    }
29}