use crate::common::LineAddr;
use crate::sim::components::ComponentId;
use crate::sim::handle::{Handle, HandleCtx};
use crate::sim::packet::{HitLevel, MemOp, MemRespData, MesiState, Packet, WriteData};
use crate::soc::devices::Device;
use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Debug)]
pub struct SysCon {
base_addr: u64,
exit_signal: Arc<AtomicU64>,
}
impl SysCon {
pub const fn new(base_addr: u64, exit_signal: Arc<AtomicU64>) -> Self {
Self { base_addr, exit_signal }
}
fn act_on_command(&self, val: u32) {
match val {
0x5555 => {
tracing::info!(target: "rvsim::syscon", "poweroff");
self.exit_signal.store(0, Ordering::Relaxed);
}
0x7777 => {
tracing::info!(target: "rvsim::syscon", "reset, taken as exit");
self.exit_signal.store(0, Ordering::Relaxed);
}
0x3333 => {
tracing::info!(target: "rvsim::syscon", "failure");
self.exit_signal.store(1, Ordering::Relaxed);
}
_ => {}
}
}
}
impl Handle for SysCon {
fn handle(&mut self, packet: Packet, source: ComponentId, ctx: &mut HandleCtx<'_>) {
if let Packet::MemReq { req_id, paddr, size, op, .. } = packet {
let offset = paddr.val().saturating_sub(self.base_addr);
if offset == 0
&& matches!(
size,
crate::sim::packet::AccessSize::B4 | crate::sim::packet::AccessSize::B8
)
&& let MemOp::Write { data: WriteData::Small(val), .. } = op
{
self.act_on_command(val as u32);
}
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(0),
hit_level: HitLevel::Mmio,
state: MesiState::Exclusive,
},
);
}
}
}
impl Device for SysCon {
fn name(&self) -> &'static str {
"SysCon"
}
fn address_range(&self) -> (u64, u64) {
(self.base_addr, 0x1000)
}
fn quiet_ticks(&self) -> Option<u64> {
None
}
}