use crate::common::{LineAddr, PhysAddr};
use crate::config::Config;
use crate::sim::components::{ComponentId, DeviceId, PipelineId, ReqId};
use crate::sim::events::EventQueue;
use crate::sim::handle::{Handle, HandleCtx};
use crate::sim::memory::GlobalMemory;
use crate::sim::packet::WriteOrigin;
use crate::sim::packet::{AccessSize, HitLevel, MemOp, MemRespData, MesiState, Packet, WriteData};
use crate::sim::stats::Stats;
fn access_size_for(width: u8) -> AccessSize {
match width {
1 => AccessSize::B1,
2 => AccessSize::B2,
4 => AccessSize::B4,
_ => AccessSize::B8,
}
}
pub fn read<H: Handle>(device: &mut H, paddr: PhysAddr, width: u8) -> u64 {
let req_id = ReqId::new(u64::MAX);
let mut queue = EventQueue::new();
let mut stats = Stats::new();
let mut memory = GlobalMemory::new(None, 1, 64);
let config = Config::default();
let mut ctx = HandleCtx {
scheduler: &mut queue,
stats: &mut stats,
memory: &mut memory,
config: &config,
cycle: 0,
self_id: ComponentId::Device(DeviceId::new(0)),
};
device.handle(
Packet::MemReq {
req_id,
paddr,
vaddr: None,
pc: None,
size: access_size_for(width),
op: MemOp::Read,
},
ComponentId::Pipeline(PipelineId::new(0)),
&mut ctx,
);
while let Some(event) = queue.pop_ready(u64::MAX) {
if let Packet::MemResp { req_id: rid, data, .. } = event.packet
&& rid == req_id
{
return match data {
MemRespData::Small(value) | MemRespData::Performed { value, .. } => value,
MemRespData::Line(_) | MemRespData::PerformedBytes { .. } => 0,
};
}
}
0
}
pub fn write<H: Handle>(device: &mut H, paddr: PhysAddr, value: u64, width: u8) {
let req_id = ReqId::new(u64::MAX);
let mut queue = EventQueue::new();
let mut stats = Stats::new();
let mut memory = GlobalMemory::new(None, 1, 64);
let config = Config::default();
let mut ctx = HandleCtx {
scheduler: &mut queue,
stats: &mut stats,
memory: &mut memory,
config: &config,
cycle: 0,
self_id: ComponentId::Device(DeviceId::new(0)),
};
device.handle(
Packet::MemReq {
req_id,
paddr,
vaddr: None,
pc: None,
size: access_size_for(width),
op: MemOp::Write { data: WriteData::Small(value), origin: WriteOrigin::Host },
},
ComponentId::Pipeline(PipelineId::new(0)),
&mut ctx,
);
let _ = queue.pop_ready(u64::MAX);
}
pub fn write_and_run_dma<H: Handle>(
device: &mut H,
memory: &mut GlobalMemory,
paddr: PhysAddr,
value: u64,
width: u8,
) {
let mut queue = EventQueue::new();
let mut stats = Stats::new();
let config = Config::default();
let mut cycle = 0;
let mut pending = vec![Packet::MemReq {
req_id: ReqId::new(u64::MAX),
paddr,
vaddr: None,
pc: None,
size: access_size_for(width),
op: MemOp::Write { data: WriteData::Small(value), origin: WriteOrigin::Host },
}];
while !pending.is_empty() {
for packet in std::mem::take(&mut pending) {
let mut ctx = HandleCtx {
scheduler: &mut queue,
stats: &mut stats,
memory: &mut *memory,
config: &config,
cycle,
self_id: ComponentId::Device(DeviceId::new(0)),
};
device.handle(packet, ComponentId::Bus, &mut ctx);
}
cycle += 1;
while let Some(event) = queue.pop_ready(u64::MAX) {
if let (ComponentId::Bus, Packet::MemReq { req_id, paddr, .. }) =
(event.target, event.packet)
{
pending.push(Packet::MemResp {
req_id,
line_addr: LineAddr::from_phys(paddr, 64),
data: MemRespData::Small(0),
hit_level: HitLevel::Dram,
state: MesiState::Exclusive,
});
}
}
}
}