pub mod coherence;
use crate::common::{HartId, LineAddr, PhysAddr, VirtAddr};
use crate::isa::op::AtomicOp;
use crate::sim::components::ReqId;
use crate::sim::memory::write_log::WriteSeq;
use crate::sim::packet::coherence::CoherenceMsg;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AccessSize {
B1,
B2,
B4,
B8,
Part(u8),
Line,
Span(u8),
}
impl AccessSize {
#[must_use]
pub const fn bytes(self) -> usize {
match self {
Self::B1 => 1,
Self::B2 => 2,
Self::B4 => 4,
Self::B8 => 8,
Self::Part(bytes) | Self::Span(bytes) => bytes as usize,
Self::Line => 64,
}
}
#[must_use]
pub const fn of_bytes(bytes: usize) -> Self {
match bytes {
1 => Self::B1,
2 => Self::B2,
4 => Self::B4,
8 => Self::B8,
other => Self::Part(other as u8),
}
}
}
#[derive(Clone, Debug)]
pub enum WriteData {
Small(u64),
Line {
bytes: Box<[u8]>,
mask: u64,
},
}
#[derive(Clone, Debug)]
pub enum MemRespData {
Small(u64),
Performed {
value: u64,
observed: Option<WriteSeq>,
},
Line(Box<[u8]>),
PerformedBytes {
bytes: Box<[u8]>,
observed: Option<WriteSeq>,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum WriteOrigin {
Hart(HartId),
Placed,
Host,
}
#[derive(Clone, Debug)]
pub enum MemOp {
Read,
ReadOwn,
Write {
data: WriteData,
origin: WriteOrigin,
},
Atomic {
op: AtomicOp,
data: u64,
hart: HartId,
},
Fetch,
Writeback {
dirty: bool,
},
Maintain {
op: Maintenance,
dirty: bool,
},
Prefetch {
into: CacheLevel,
exclusive: bool,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Maintenance {
Clean,
Flush,
Invalidate,
}
impl MemOp {
#[must_use]
pub const fn takes_effect_when_served(&self, size: AccessSize) -> bool {
match self {
Self::Read => !matches!(size, AccessSize::Line),
Self::Atomic { .. } | Self::Write { origin: WriteOrigin::Hart(_), .. } => true,
Self::ReadOwn
| Self::Write { .. }
| Self::Fetch
| Self::Writeback { .. }
| Self::Maintain { .. }
| Self::Prefetch { .. } => false,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum HitLevel {
L1,
L2,
L3,
Dram,
Mmio,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CacheLevel {
L1I,
L1D,
L2,
L3,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ProbeKind {
Invalidate,
Downgrade,
Clean,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum MesiState {
Modified,
Exclusive,
Shared,
#[default]
Invalid,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DramCmdKind {
Activate,
Precharge,
PrechargeAll,
Read,
Write,
Refresh,
PowerDownEntry,
PowerDownExit,
}
#[derive(Clone, Debug)]
pub enum Packet {
MemReq {
req_id: ReqId,
paddr: PhysAddr,
vaddr: Option<VirtAddr>,
pc: Option<VirtAddr>,
size: AccessSize,
op: MemOp,
},
MemResp {
req_id: ReqId,
line_addr: LineAddr,
data: MemRespData,
hit_level: HitLevel,
state: MesiState,
},
Probe {
line_addr: LineAddr,
kind: ProbeKind,
txn: ReqId,
},
ProbeResp {
txn: ReqId,
had_copy: bool,
dirty: bool,
},
CacheInval {
line_addr: LineAddr,
},
Coh(CoherenceMsg),
DramCmd {
channel: u8,
rank: u8,
bank: u8,
kind: DramCmdKind,
row: u32,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn writedata_small_round_trip() {
let w = WriteData::Small(0x12_34_56_78);
match w {
WriteData::Small(v) => assert_eq!(v, 0x12_34_56_78),
WriteData::Line { .. } => panic!("wrong variant"),
}
}
#[test]
fn memresp_line_payload() {
let bytes: Box<[u8]> = vec![0xAA; 64].into_boxed_slice();
let r = MemRespData::Line(bytes);
if let MemRespData::Line(b) = r {
assert_eq!(b.len(), 64);
assert_eq!(b[0], 0xAA);
} else {
panic!("wrong variant");
}
}
#[test]
fn mesistate_default_is_invalid() {
assert_eq!(MesiState::default(), MesiState::Invalid);
}
}