use crate::core::error::BusError;
use crate::core::value::{Endian, Width};
use core::fmt;
pub type MemResult<T = ()> = core::result::Result<T, BusError>;
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct RequesterId(pub u32);
impl RequesterId {
pub const ANONYMOUS: RequesterId = RequesterId(0);
}
impl fmt::Display for RequesterId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "requester#{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub struct MemAttrs {
pub requester: RequesterId,
pub secure: bool,
pub privileged: bool,
pub exclusive: bool,
pub debug: bool,
}
impl MemAttrs {
pub const DEFAULT: MemAttrs = MemAttrs {
requester: RequesterId::ANONYMOUS,
secure: false,
privileged: false,
exclusive: false,
debug: false,
};
pub const DEBUG: MemAttrs = MemAttrs {
requester: RequesterId::ANONYMOUS,
secure: true,
privileged: true,
exclusive: false,
debug: true,
};
#[must_use]
pub const fn with_requester(mut self, id: RequesterId) -> Self {
self.requester = id;
self
}
#[must_use]
pub const fn with_secure(mut self, secure: bool) -> Self {
self.secure = secure;
self
}
#[must_use]
pub const fn with_privileged(mut self, privileged: bool) -> Self {
self.privileged = privileged;
self
}
#[must_use]
pub const fn with_exclusive(mut self, exclusive: bool) -> Self {
self.exclusive = exclusive;
self
}
#[must_use]
pub const fn with_debug(mut self, debug: bool) -> Self {
self.debug = debug;
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct AccessConstraints {
pub min: Width,
pub max: Width,
pub natural_alignment: bool,
pub endian: Endian,
pub allow_bulk: bool,
pub secure_only: bool,
pub privileged_only: bool,
}
impl AccessConstraints {
pub const ANY: AccessConstraints = AccessConstraints {
min: Width::U8,
max: Width::U64,
natural_alignment: false,
endian: Endian::Little,
allow_bulk: true,
secure_only: false,
privileged_only: false,
};
pub const IO: AccessConstraints = AccessConstraints {
allow_bulk: false,
..AccessConstraints::ANY
};
#[must_use]
pub const fn word(width: Width, endian: Endian) -> Self {
AccessConstraints {
min: width,
max: width,
natural_alignment: true,
endian,
allow_bulk: false,
secure_only: false,
privileged_only: false,
}
}
#[must_use]
pub const fn with_endian(mut self, endian: Endian) -> Self {
self.endian = endian;
self
}
#[must_use]
pub const fn with_widths(mut self, min: Width, max: Width) -> Self {
self.min = min;
self.max = max;
self
}
#[must_use]
pub const fn with_natural_alignment(mut self, require: bool) -> Self {
self.natural_alignment = require;
self
}
#[must_use]
pub const fn with_bulk(mut self, allow: bool) -> Self {
self.allow_bulk = allow;
self
}
#[must_use]
pub const fn with_secure_only(mut self, secure_only: bool) -> Self {
self.secure_only = secure_only;
self
}
#[must_use]
pub const fn with_privileged_only(mut self, privileged_only: bool) -> Self {
self.privileged_only = privileged_only;
self
}
#[inline]
pub fn check(&self, offset: u64, width: Width, attrs: MemAttrs) -> MemResult {
self.check_attrs(attrs)?;
if width < self.min || width > self.max {
return Err(BusError::BadAccess);
}
if self.natural_alignment && !width.is_aligned(offset) {
return Err(BusError::BadAccess);
}
Ok(())
}
#[inline]
pub fn check_bulk(&self, offset: u64, len: u64, attrs: MemAttrs) -> MemResult {
if let Some(width) = Width::from_bytes(len)
&& self.check(offset, width, attrs).is_ok()
{
return Ok(());
}
self.check_attrs(attrs)?;
if self.allow_bulk {
Ok(())
} else {
Err(BusError::BadAccess)
}
}
#[inline]
fn check_attrs(&self, attrs: MemAttrs) -> MemResult {
if (self.secure_only && !attrs.secure) || (self.privileged_only && !attrs.privileged) {
return Err(BusError::BadAccess);
}
Ok(())
}
}
impl Default for AccessConstraints {
fn default() -> Self {
AccessConstraints::ANY
}
}
pub trait MemOps: fmt::Debug + Send + Sync {
fn read(&self, offset: u64, dst: &mut [u8], attrs: MemAttrs) -> MemResult;
fn write(&self, offset: u64, src: &[u8], attrs: MemAttrs) -> MemResult;
fn constraints(&self) -> AccessConstraints {
AccessConstraints::IO
}
}