use super::{Backend, RegisterAddress, private};
use crate::spec::NUM_REGISTERS;
use core::num::NonZeroU8;
use core::ptr::NonNull;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Hash)]
pub struct MmioAddress(pub(crate) NonNull<u8>);
unsafe impl Send for MmioAddress {}
impl RegisterAddress for MmioAddress {
#[inline(always)]
fn add_offset(self, offset: u8) -> Self {
let address = unsafe { self.0.add(offset as usize) };
Self(address)
}
}
impl private::Sealed for MmioAddress {}
mod arch {
use super::MmioAddress;
#[cfg(any(doc, not(target_arch = "aarch64")))]
use core::ptr;
#[cfg(target_arch = "aarch64")]
#[inline(always)]
pub unsafe fn mmio_read_register(address: MmioAddress) -> u8 {
let ptr = address.0.as_ptr();
let ret: u8;
unsafe {
core::arch::asm!(
"ldrb {ret:w}, [{ptr}]",
ptr = in(reg) ptr,
ret = out(reg) ret,
options(nostack, preserves_flags)
);
}
ret
}
#[cfg(not(target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn mmio_read_register(address: MmioAddress) -> u8 {
unsafe { ptr::read_volatile(address.0.as_ptr()) }
}
#[cfg(target_arch = "aarch64")]
#[inline(always)]
pub unsafe fn mmio_write_register(address: MmioAddress, value: u8) {
let ptr = address.0.as_ptr();
unsafe {
core::arch::asm!(
"strb {val:w}, [{ptr}]",
val = in(reg) value,
ptr = in(reg) ptr,
options(nostack, preserves_flags)
);
}
}
#[cfg(not(target_arch = "aarch64"))]
#[inline(always)]
pub unsafe fn mmio_write_register(address: MmioAddress, value: u8) {
unsafe { ptr::write_volatile(address.0.as_ptr(), value) }
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Hash)]
pub struct MmioBackend {
pub(crate) base_address: MmioAddress,
pub(crate) stride: NonZeroU8,
}
impl private::Sealed for MmioBackend {}
impl Backend for MmioBackend {
type Address = MmioAddress;
#[inline(always)]
fn base(&self) -> Self::Address {
self.base_address
}
#[inline(always)]
fn stride(&self) -> NonZeroU8 {
self.stride
}
#[inline(always)]
unsafe fn _read_register(&mut self, address: MmioAddress) -> u8 {
debug_assert!(address >= self.base());
let upper_bound_incl = (NUM_REGISTERS - 1) * usize::from(u8::from(self.stride));
debug_assert!(address.0.as_ptr() <= self.base().0.as_ptr().wrapping_add(upper_bound_incl));
unsafe { arch::mmio_read_register(address) }
}
#[inline(always)]
unsafe fn _write_register(&mut self, address: MmioAddress, value: u8) {
debug_assert!(address >= self.base());
let upper_bound_incl = (NUM_REGISTERS - 1) * usize::from(u8::from(self.stride));
debug_assert!(address.0.as_ptr() <= self.base().0.as_ptr().wrapping_add(upper_bound_incl));
unsafe { arch::mmio_write_register(address, value) }
}
}