use core::fmt::{Debug, LowerHex};
use ax_memory_addr::AddrRange;
use axvm_types::GuestPhysAddr;
pub use axvm_types::{AccessWidth, Port, SysRegAddr};
pub trait DeviceAddr: Copy + Eq + Ord + core::fmt::Debug {}
pub trait DeviceAddrRange: Copy + Eq + LowerHex {
type Addr: DeviceAddr;
const BUS_NAME: &'static str;
fn contains(&self, addr: Self::Addr) -> bool;
fn is_empty(&self) -> bool;
fn overlaps(&self, other: &Self) -> bool;
}
impl DeviceAddr for GuestPhysAddr {}
impl DeviceAddrRange for AddrRange<GuestPhysAddr> {
type Addr = GuestPhysAddr;
const BUS_NAME: &'static str = "mmio";
fn contains(&self, addr: Self::Addr) -> bool {
Self::contains(*self, addr)
}
fn is_empty(&self) -> bool {
Self::is_empty(*self)
}
fn overlaps(&self, other: &Self) -> bool {
Self::overlaps(*self, *other)
}
}
impl DeviceAddr for SysRegAddr {}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct SysRegAddrRange {
pub start: SysRegAddr,
pub end: SysRegAddr,
}
impl SysRegAddrRange {
pub fn new(start: SysRegAddr, end: SysRegAddr) -> Self {
Self { start, end }
}
}
impl DeviceAddrRange for SysRegAddrRange {
type Addr = SysRegAddr;
const BUS_NAME: &'static str = "sys_reg";
fn contains(&self, addr: Self::Addr) -> bool {
addr.0 >= self.start.0 && addr.0 <= self.end.0
}
fn is_empty(&self) -> bool {
self.start > self.end
}
fn overlaps(&self, other: &Self) -> bool {
!self.is_empty() && !other.is_empty() && self.start <= other.end && other.start <= self.end
}
}
impl LowerHex for SysRegAddrRange {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#x}..={:#x}", self.start.0, self.end.0)
}
}
impl DeviceAddr for Port {}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct PortRange {
pub start: Port,
pub end: Port,
}
impl PortRange {
pub fn new(start: Port, end: Port) -> Self {
Self { start, end }
}
}
impl DeviceAddrRange for PortRange {
type Addr = Port;
const BUS_NAME: &'static str = "port";
fn contains(&self, addr: Self::Addr) -> bool {
addr.0 >= self.start.0 && addr.0 <= self.end.0
}
fn is_empty(&self) -> bool {
self.start > self.end
}
fn overlaps(&self, other: &Self) -> bool {
!self.is_empty() && !other.is_empty() && self.start <= other.end && other.start <= self.end
}
}
impl LowerHex for PortRange {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#x}..={:#x}", self.start.0, self.end.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BusKind {
Mmio,
Port,
SysReg,
}
#[derive(Debug, Clone, Copy)]
pub struct BusAccess {
pub kind: BusKind,
pub is_read: bool,
pub addr: u64,
pub width: AccessWidth,
pub data: u64,
}
#[derive(Debug, Clone, Copy)]
pub enum BusResponse {
Read {
value: u64,
},
Write,
}
#[derive(Debug, Clone)]
pub enum DeviceError {
NotFound,
InvalidWidth {
expected: AccessWidth,
actual: AccessWidth,
},
ReadOnly,
WriteOnly,
OutOfRange {
addr: u64,
},
Unimplemented,
Internal,
}