use core::{fmt, ops::Deref};
pub const ADDRESS_BITS: u32 = 48;
pub const ADDRESS_MASK: u64 = (1u64 << ADDRESS_BITS) - 1;
pub const READ_CACHE_BIT: u64 = 1u64 << (ADDRESS_BITS - 1);
pub const ABSOLUTE_ADDRESS_MASK: u64 = ADDRESS_MASK & !READ_CACHE_BIT;
pub const INVALID_ADDRESS: u64 = 0;
pub const TEMP_INVALID_ADDRESS: u64 = 1;
pub const FIRST_VALID_ADDRESS: u64 = 64;
pub const MAX_VALID_ADDRESS: u64 = ABSOLUTE_ADDRESS_MASK;
#[inline(always)]
pub const fn clean_address(addr: u64) -> u64 {
addr & ADDRESS_MASK
}
#[inline(always)]
pub const fn is_valid(addr: u64) -> bool {
clean_address(addr) != INVALID_ADDRESS
}
#[inline(always)]
pub const fn is_read_cache(addr: u64) -> bool {
(addr & READ_CACHE_BIT) == READ_CACHE_BIT
}
#[inline(always)]
pub const fn to_absolute(addr: u64) -> u64 {
addr & ABSOLUTE_ADDRESS_MASK
}
#[inline(always)]
pub const fn with_read_cache(addr: u64) -> u64 {
(addr & ADDRESS_MASK) | READ_CACHE_BIT
}
#[inline(always)]
pub const fn page_of_address(addr: u64, page_bits: u32) -> u64 {
to_absolute(addr) >> page_bits
}
#[inline(always)]
pub const fn address_of_page_start(page: u64, page_bits: u32) -> u64 {
page << page_bits
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(transparent)]
pub struct LogAddress(pub u64);
impl LogAddress {
pub const INVALID: Self = Self(INVALID_ADDRESS);
#[inline(always)]
pub const fn new(addr: u64) -> Self {
Self(clean_address(addr))
}
#[inline(always)]
pub const fn from_raw(raw: u64) -> Self {
Self(raw)
}
#[inline(always)]
pub const fn as_raw(&self) -> u64 {
self.0
}
#[inline(always)]
pub const fn is_valid(&self) -> bool {
is_valid(self.0)
}
#[inline(always)]
pub const fn is_read_cache(&self) -> bool {
is_read_cache(self.0)
}
#[inline(always)]
pub const fn absolute(&self) -> Self {
Self(to_absolute(self.0))
}
#[inline(always)]
pub const fn with_read_cache(&self) -> Self {
Self(with_read_cache(self.0))
}
#[inline(always)]
pub const fn page(&self, page_bits: u32) -> u64 {
page_of_address(self.0, page_bits)
}
#[inline(always)]
pub const fn page_start(page: u64, page_bits: u32) -> Self {
Self(address_of_page_start(page, page_bits))
}
}
impl Deref for LogAddress {
type Target = u64;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<u64> for LogAddress {
#[inline(always)]
fn from(addr: u64) -> Self {
Self::new(addr)
}
}
impl From<LogAddress> for u64 {
#[inline(always)]
fn from(addr: LogAddress) -> Self {
addr.0
}
}
impl fmt::Debug for LogAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LogAddress")
.field("addr", &format_args!("{:#x}", self.0))
.field("read_cache", &self.is_read_cache())
.field("valid", &self.is_valid())
.finish()
}
}
impl fmt::Display for LogAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_read_cache() {
write!(f, "rc:{}", self.absolute().0)
} else if self.0 == INVALID_ADDRESS {
f.write_str("kInvalid")
} else if self.0 == TEMP_INVALID_ADDRESS {
f.write_str("kTempInvalid")
} else {
write!(f, "log:{}", self.0)
}
}
}