use std::fmt;
use wbase::addr;
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct HashBucketEntry(pub u64);
impl HashBucketEntry {
pub const ADDRESS_BITS: u32 = addr::ADDRESS_BITS;
pub const ADDRESS_MASK: u64 = addr::ADDRESS_MASK;
pub const TAG_BITS: u32 = 15;
pub const TAG_SHIFT: u32 = Self::ADDRESS_BITS;
pub const TAG_MASK: u64 = (1u64 << Self::TAG_BITS) - 1;
pub const TAG_POS_MASK: u64 = Self::TAG_MASK << Self::TAG_SHIFT;
pub const TENTATIVE_SHIFT: u32 = 63;
pub const TENTATIVE_MASK: u64 = 1u64 << Self::TENTATIVE_SHIFT;
pub const HASH_TAG_SHIFT: u32 = 64 - Self::TAG_BITS;
pub const INVALID_ADDRESS: u64 = addr::INVALID_ADDRESS;
#[inline]
pub const fn new(address: u64, tag: u16, tentative: bool) -> Self {
let word = (address & Self::ADDRESS_MASK)
| (((tag as u64) & Self::TAG_MASK) << Self::TAG_SHIFT)
| if tentative { Self::TENTATIVE_MASK } else { 0 };
Self(word)
}
#[inline]
pub const fn from_raw(raw: u64) -> Self {
Self(raw)
}
#[inline]
pub const fn as_raw(&self) -> u64 {
self.0
}
#[inline]
pub const fn address(&self) -> u64 {
self.0 & Self::ADDRESS_MASK
}
#[inline]
pub const fn tag(&self) -> u16 {
((self.0 & Self::TAG_POS_MASK) >> Self::TAG_SHIFT) as u16
}
#[inline]
pub const fn is_tentative(&self) -> bool {
(self.0 & Self::TENTATIVE_MASK) != 0
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.0 == 0
}
#[inline]
pub const fn is_valid(&self) -> bool {
self.0 != 0 && !self.is_tentative()
}
pub const READ_CACHE_BIT: u64 = addr::READ_CACHE_BIT;
pub const ABSOLUTE_ADDRESS_MASK: u64 = addr::ABSOLUTE_ADDRESS_MASK;
#[inline]
pub const fn is_read_cache(&self) -> bool {
(self.0 & Self::READ_CACHE_BIT) != 0
}
#[inline]
pub const fn absolute_address(&self) -> u64 {
self.0 & Self::ABSOLUTE_ADDRESS_MASK
}
#[inline]
pub const fn matches_tag(&self, tag: u16) -> bool {
(self.0 >> Self::TAG_SHIFT) == ((tag as u64) & Self::TAG_MASK)
&& (self.0 & Self::ADDRESS_MASK) != 0
}
#[inline]
#[must_use]
pub const fn with_tentative(self, tentative: bool) -> Self {
let word = if tentative {
self.0 | Self::TENTATIVE_MASK
} else {
self.0 & !Self::TENTATIVE_MASK
};
Self(word)
}
#[inline]
#[must_use]
pub const fn with_tag(self, tag: u16) -> Self {
let word =
(self.0 & !Self::TAG_POS_MASK) | (((tag as u64) & Self::TAG_MASK) << Self::TAG_SHIFT);
Self(word)
}
#[inline]
pub const fn tag_from_hash(hash: u64) -> u16 {
((hash >> Self::HASH_TAG_SHIFT) & Self::TAG_MASK) as u16
}
}
impl fmt::Debug for HashBucketEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("HashBucketEntry")
.field("address", &format_args!("{:#x}", self.address()))
.field("tag", &self.tag())
.field("tentative", &self.is_tentative())
.field("raw", &format_args!("{:#018x}", self.0))
.finish()
}
}
impl fmt::Display for HashBucketEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Entry(addr: {:#x}, tag: {}, tentative: {})",
self.address(),
self.tag(),
self.is_tentative()
)
}
}