use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use crate::common::LineAddr;
use crate::sim::components::ComponentId;
use crate::sim::handle::{Handle, HandleCtx};
use crate::sim::packet::{AccessSize, HitLevel, MemOp, MemRespData, MesiState, Packet, WriteData};
use crate::soc::devices::Device;
const COMMAND: u64 = 0x00;
const ARG: u64 = 0x08;
const RESET_STATS: u64 = 1;
const DUMP_STATS: u64 = 2;
const EXIT: u64 = 3;
const BREAK: u64 = 4;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SimOp {
ResetStats,
DumpStats {
label: u64,
},
Break {
label: u64,
},
}
#[derive(Debug)]
pub struct SimControl {
base_addr: u64,
arg: u64,
pending: Vec<SimOp>,
exit_signal: Arc<AtomicU64>,
}
impl SimControl {
pub const fn new(base_addr: u64, exit_signal: Arc<AtomicU64>) -> Self {
Self { base_addr, arg: 0, pending: Vec::new(), exit_signal }
}
fn command(&mut self, command: u64) {
match command {
RESET_STATS => self.pending.push(SimOp::ResetStats),
DUMP_STATS => self.pending.push(SimOp::DumpStats { label: self.arg }),
EXIT => self.exit_signal.store(self.arg, Ordering::Relaxed),
BREAK => self.pending.push(SimOp::Break { label: self.arg }),
_ => {}
}
}
}
impl Handle for SimControl {
fn handle(&mut self, packet: Packet, source: ComponentId, ctx: &mut HandleCtx<'_>) {
let Packet::MemReq { req_id, paddr, size, op, .. } = packet else { return };
let offset = paddr.val().saturating_sub(self.base_addr);
let whole_register = matches!(size, AccessSize::B4 | AccessSize::B8);
let mut value = 0;
match op {
MemOp::Write { data: WriteData::Small(written), .. } if whole_register => {
match offset {
COMMAND => self.command(written),
ARG => self.arg = written,
_ => {}
}
}
MemOp::Read if offset == ARG => value = self.arg,
_ => {}
}
ctx.scheduler.schedule(
ctx.cycle + ctx.config.system.device_access_cycles(self.name()),
source,
ctx.self_id,
Packet::MemResp {
req_id,
line_addr: LineAddr::from_phys(paddr, 64),
data: MemRespData::Small(value),
hit_level: HitLevel::Mmio,
state: MesiState::Exclusive,
},
);
}
}
impl Device for SimControl {
fn name(&self) -> &'static str {
"SimControl"
}
fn address_range(&self) -> (u64, u64) {
(self.base_addr, 0x1000)
}
fn quiet_ticks(&self) -> Option<u64> {
None
}
fn take_sim_ops(&mut self) -> Vec<SimOp> {
std::mem::take(&mut self.pending)
}
}