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}