WIP: added running generators to settle loop

This commit is contained in:
Jacob Lifshay 2025-03-20 03:50:23 -07:00
parent b4650f1bff
commit f378b9a1d2
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ

View file

@ -55,13 +55,17 @@ use petgraph::{
use std::{ use std::{
any::Any, any::Any,
borrow::Cow, borrow::Cow,
cell::RefCell,
collections::BTreeSet, collections::BTreeSet,
fmt, fmt,
future::{Future, IntoFuture}, future::{Future, IntoFuture},
marker::PhantomData, marker::PhantomData,
mem, mem,
ops::IndexMut, ops::IndexMut,
pin::Pin,
rc::Rc,
sync::Arc, sync::Arc,
task::Poll,
}; };
mod interpreter; mod interpreter;
@ -6755,10 +6759,35 @@ impl SimulationModuleState {
} }
} }
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum WaitTarget {
/// Settle is less than Instant
Settle,
Instant(SimInstant),
}
impl PartialOrd for WaitTarget {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for WaitTarget {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (self, other) {
(WaitTarget::Settle, WaitTarget::Settle) => std::cmp::Ordering::Equal,
(WaitTarget::Settle, WaitTarget::Instant(_)) => std::cmp::Ordering::Less,
(WaitTarget::Instant(_), WaitTarget::Settle) => std::cmp::Ordering::Greater,
(WaitTarget::Instant(l), WaitTarget::Instant(r)) => l.cmp(r),
}
}
}
struct SimulationExternModuleState { struct SimulationExternModuleState {
module_state: SimulationModuleState, module_state: SimulationModuleState,
sim: ExternModuleSimulation<Bundle>, sim: ExternModuleSimulation<Bundle>,
running_generator: Option<Box<dyn Future<Output = ()> + 'static>>, running_generator: Option<Pin<Box<dyn Future<Output = ()> + 'static>>>,
wait_target: Option<WaitTarget>,
} }
impl fmt::Debug for SimulationExternModuleState { impl fmt::Debug for SimulationExternModuleState {
@ -6767,6 +6796,7 @@ impl fmt::Debug for SimulationExternModuleState {
module_state, module_state,
sim, sim,
running_generator, running_generator,
wait_target,
} = self; } = self;
f.debug_struct("SimulationExternModuleState") f.debug_struct("SimulationExternModuleState")
.field("module_state", module_state) .field("module_state", module_state)
@ -6775,6 +6805,7 @@ impl fmt::Debug for SimulationExternModuleState {
"running_generator", "running_generator",
&running_generator.as_ref().map(|_| DebugAsDisplay("...")), &running_generator.as_ref().map(|_| DebugAsDisplay("...")),
) )
.field("wait_target", wait_target)
.finish() .finish()
} }
} }
@ -6782,7 +6813,7 @@ impl fmt::Debug for SimulationExternModuleState {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
enum WhichModule { enum WhichModule {
Main, Main,
Extern { index: usize }, Extern { module_index: usize },
} }
struct ReadBitFn { struct ReadBitFn {
@ -6855,11 +6886,19 @@ impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadFn {
} }
} }
struct GeneratorWaker;
impl std::task::Wake for GeneratorWaker {
fn wake(self: Arc<Self>) {
panic!("can't await other kinds of futures in function passed to ExternalModuleSimulation");
}
}
struct SimulationImpl { struct SimulationImpl {
state: interpreter::State, state: interpreter::State,
io: Expr<Bundle>, io: Expr<Bundle>,
main_module: SimulationModuleState, main_module: SimulationModuleState,
extern_modules: Vec<SimulationExternModuleState>, extern_modules: Box<[SimulationExternModuleState]>,
needs_settle: bool, needs_settle: bool,
trace_decls: TraceModule, trace_decls: TraceModule,
traces: SimTraces<Box<[SimTrace<SimTraceKind, BitVec>]>>, traces: SimTraces<Box<[SimTrace<SimTraceKind, BitVec>]>>,
@ -6868,6 +6907,7 @@ struct SimulationImpl {
instant: SimInstant, instant: SimInstant,
clocks_triggered: Interned<[StatePartIndex<StatePartKindSmallSlots>]>, clocks_triggered: Interned<[StatePartIndex<StatePartKindSmallSlots>]>,
breakpoints: Option<BreakpointsSet>, breakpoints: Option<BreakpointsSet>,
generator_waker: std::task::Waker,
} }
impl fmt::Debug for SimulationImpl { impl fmt::Debug for SimulationImpl {
@ -6891,6 +6931,7 @@ impl SimulationImpl {
instant, instant,
clocks_triggered, clocks_triggered,
breakpoints: _, breakpoints: _,
generator_waker: _,
} = self; } = self;
f.debug_struct("Simulation") f.debug_struct("Simulation")
.field("state", state) .field("state", state)
@ -6908,6 +6949,8 @@ impl SimulationImpl {
} }
fn new(compiled: Compiled<Bundle>) -> Self { fn new(compiled: Compiled<Bundle>) -> Self {
let io_target = Target::from(compiled.io); let io_target = Target::from(compiled.io);
// TODO: add extern_modules
let extern_modules: Box<[SimulationExternModuleState]> = Box::new([]);
Self { Self {
state: State::new(compiled.insns), state: State::new(compiled.insns),
io: compiled.io.to_expr(), io: compiled.io.to_expr(),
@ -6928,8 +6971,7 @@ impl SimulationImpl {
) )
}), }),
), ),
// TODO: add extern_modules extern_modules,
extern_modules: vec![],
needs_settle: true, needs_settle: true,
trace_decls: compiled.base_module.trace_decls, trace_decls: compiled.base_module.trace_decls,
traces: SimTraces(Box::from_iter(compiled.traces.0.iter().map( traces: SimTraces(Box::from_iter(compiled.traces.0.iter().map(
@ -6948,6 +6990,7 @@ impl SimulationImpl {
instant: SimInstant::START, instant: SimInstant::START,
clocks_triggered: compiled.clocks_triggered, clocks_triggered: compiled.clocks_triggered,
breakpoints: None, breakpoints: None,
generator_waker: Arc::new(GeneratorWaker).into(),
} }
} }
fn write_traces<const ONLY_IF_CHANGED: bool>( fn write_traces<const ONLY_IF_CHANGED: bool>(
@ -7086,10 +7129,11 @@ impl SimulationImpl {
} }
} }
#[track_caller] #[track_caller]
fn advance_time(&mut self, duration: SimDuration) { fn advance_time(this: &Rc<RefCell<Self>>, duration: SimDuration) {
self.settle(); Self::settle(this);
self.instant += duration; let mut this = this.borrow_mut();
self.for_each_trace_writer_storing_error(|this, mut trace_writer_state| { this.instant += duration;
this.for_each_trace_writer_storing_error(|this, mut trace_writer_state| {
match &mut trace_writer_state { match &mut trace_writer_state {
TraceWriterState::Decls(_) | TraceWriterState::Init(_) => unreachable!(), TraceWriterState::Decls(_) | TraceWriterState::Init(_) => unreachable!(),
TraceWriterState::Running(trace_writer) => { TraceWriterState::Running(trace_writer) => {
@ -7100,31 +7144,130 @@ impl SimulationImpl {
Ok(trace_writer_state) Ok(trace_writer_state)
}); });
} }
#[must_use]
fn yield_advance_time_or_settle(
this: Rc<RefCell<Self>>,
module_index: usize,
duration: Option<SimDuration>,
) -> impl Future<Output = ()> + 'static {
struct MyGenerator {
sim: Rc<RefCell<SimulationImpl>>,
yielded_at_all: bool,
module_index: usize,
target: WaitTarget,
}
impl Future for MyGenerator {
type Output = ();
fn poll(
mut self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> Poll<Self::Output> {
let this = &mut *self;
let yielded_at_all = mem::replace(&mut this.yielded_at_all, true);
let mut sim = this.sim.borrow_mut();
let sim = &mut *sim;
assert!(cx.waker().will_wake(&sim.generator_waker), "can't use ExternModuleSimulationState's methods outside of ExternModuleSimulation");
if let WaitTarget::Instant(target) = this.target {
if target < sim.instant {
this.target = WaitTarget::Settle;
} else if yielded_at_all && target == sim.instant {
this.target = WaitTarget::Settle;
}
}
if let WaitTarget::Settle = this.target {
if yielded_at_all {
return Poll::Ready(());
}
}
let wait_target = sim.extern_modules[this.module_index]
.wait_target
.get_or_insert(this.target);
*wait_target = (*wait_target).min(this.target);
Poll::Pending
}
}
let target = duration.map_or(WaitTarget::Settle, |duration| {
WaitTarget::Instant(this.borrow().instant + duration)
});
MyGenerator {
sim: this,
yielded_at_all: false,
module_index,
target,
}
}
fn get_ready_external_modules(&mut self, run_list: &mut Vec<usize>) -> Option<WaitTarget> {
run_list.clear();
let mut iter = self.extern_modules.iter_mut().enumerate().filter_map(
|(module_index, extern_module)| Some((module_index, extern_module.wait_target?)),
);
let (first_module_index, mut wait_target) = iter.next()?;
run_list.push(first_module_index);
for (next_module_index, next_wait_target) in iter {
match next_wait_target.cmp(&wait_target) {
std::cmp::Ordering::Less => run_list.clear(),
std::cmp::Ordering::Equal => {}
std::cmp::Ordering::Greater => continue,
}
run_list.push(next_module_index);
wait_target = next_wait_target;
}
Some(wait_target)
}
#[track_caller] #[track_caller]
fn settle(&mut self) { fn settle(this_ref: &Rc<RefCell<Self>>) {
let mut this = this_ref.borrow_mut();
assert!( assert!(
self.main_module.uninitialized_ios.is_empty(), this.main_module.uninitialized_ios.is_empty(),
"didn't initialize all inputs", "didn't initialize all inputs",
); );
let mut run_list = Vec::new();
let generator_waker = this.generator_waker.clone();
for _ in 0..100000 { for _ in 0..100000 {
if !self.needs_settle { if !this.needs_settle {
if let Some(wait_target) = this.get_ready_external_modules(&mut run_list) {
if wait_target > WaitTarget::Instant(this.instant) {
return; return;
} }
self.state.setup_call(0); for module_index in run_list.drain(..) {
if self.breakpoints.is_some() { this.extern_modules[module_index].wait_target = None;
let Some(mut generator) =
this.extern_modules[module_index].running_generator.take()
else {
continue;
};
drop(this);
let generator = match generator
.as_mut()
.poll(&mut std::task::Context::from_waker(&generator_waker))
{
Poll::Ready(()) => None,
Poll::Pending => Some(generator),
};
this = this_ref.borrow_mut();
this.extern_modules[module_index].running_generator = generator;
}
continue;
}
return;
}
this.state.setup_call(0);
if this.breakpoints.is_some() {
loop { loop {
match self let this = &mut *this;
match this
.state .state
.run(self.breakpoints.as_mut().expect("just checked")) .run(this.breakpoints.as_mut().expect("just checked"))
{ {
RunResult::Break(break_action) => { RunResult::Break(break_action) => {
println!( println!(
"hit breakpoint at:\n{:?}", "hit breakpoint at:\n{:?}",
self.state.debug_insn_at(self.state.pc), this.state.debug_insn_at(this.state.pc),
); );
match break_action { match break_action {
BreakAction::DumpStateAndContinue => { BreakAction::DumpStateAndContinue => {
println!("{self:#?}"); println!("{this:#?}");
} }
BreakAction::Continue => {} BreakAction::Continue => {}
} }
@ -7133,21 +7276,21 @@ impl SimulationImpl {
} }
} }
} else { } else {
let RunResult::Return(()) = self.state.run(()); let RunResult::Return(()) = this.state.run(());
} }
if self.main_module.did_initial_settle { if this.main_module.did_initial_settle {
self.read_traces::<false>(); this.read_traces::<false>();
} else { } else {
self.read_traces::<true>(); this.read_traces::<true>();
} }
self.state.memory_write_log.sort_unstable(); this.state.memory_write_log.sort_unstable();
self.state.memory_write_log.dedup(); this.state.memory_write_log.dedup();
self.main_module.did_initial_settle = true; this.main_module.did_initial_settle = true;
self.needs_settle = self this.needs_settle = this
.clocks_triggered .clocks_triggered
.iter() .iter()
.any(|i| self.state.small_slots[*i] != 0); .any(|i| this.state.small_slots[*i] != 0);
self.for_each_trace_writer_storing_error(|this, trace_writer_state| { this.for_each_trace_writer_storing_error(|this, trace_writer_state| {
Ok(match trace_writer_state { Ok(match trace_writer_state {
TraceWriterState::Decls(trace_writer_decls) => TraceWriterState::Running( TraceWriterState::Decls(trace_writer_decls) => TraceWriterState::Running(
this.init_trace_writer(trace_writer_decls.write_decls( this.init_trace_writer(trace_writer_decls.write_decls(
@ -7165,20 +7308,22 @@ impl SimulationImpl {
TraceWriterState::Errored(e) => TraceWriterState::Errored(e), TraceWriterState::Errored(e) => TraceWriterState::Errored(e),
}) })
}); });
self.state.memory_write_log.clear(); this.state.memory_write_log.clear();
} }
panic!("settle(): took too many steps"); panic!("settle(): took too many steps");
} }
fn get_module(&self, which_module: WhichModule) -> &SimulationModuleState { fn get_module(&self, which_module: WhichModule) -> &SimulationModuleState {
match which_module { match which_module {
WhichModule::Main => &self.main_module, WhichModule::Main => &self.main_module,
WhichModule::Extern { index } => &self.extern_modules[index].module_state, WhichModule::Extern { module_index } => &self.extern_modules[module_index].module_state,
} }
} }
fn get_module_mut(&mut self, which_module: WhichModule) -> &mut SimulationModuleState { fn get_module_mut(&mut self, which_module: WhichModule) -> &mut SimulationModuleState {
match which_module { match which_module {
WhichModule::Main => &mut self.main_module, WhichModule::Main => &mut self.main_module,
WhichModule::Extern { index } => &mut self.extern_modules[index].module_state, WhichModule::Extern { module_index } => {
&mut self.extern_modules[module_index].module_state
}
} }
} }
#[track_caller] #[track_caller]
@ -7374,14 +7519,31 @@ impl SimulationImpl {
); );
} }
#[track_caller] #[track_caller]
fn settle_if_needed<F, O>(&mut self, v: MaybeNeedsSettle<F, O>) -> O fn settle_if_needed<F, O>(this_ref: &Rc<RefCell<Self>>, v: MaybeNeedsSettle<F, O>) -> O
where where
for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>,
{ {
match v { match v {
MaybeNeedsSettle::NeedsSettle(v) => { MaybeNeedsSettle::NeedsSettle(v) => {
self.settle(); Self::settle(this_ref);
v.call(&mut self.state) v.call(&mut this_ref.borrow_mut().state)
}
MaybeNeedsSettle::NoSettleNeeded(v) => v,
}
}
#[track_caller]
async fn yield_settle_if_needed<F, O>(
this_ref: &Rc<RefCell<Self>>,
module_index: usize,
v: MaybeNeedsSettle<F, O>,
) -> O
where
for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>,
{
match v {
MaybeNeedsSettle::NeedsSettle(v) => {
Self::yield_advance_time_or_settle(this_ref.clone(), module_index, None).await;
v.call(&mut this_ref.borrow_mut().state)
} }
MaybeNeedsSettle::NoSettleNeeded(v) => v, MaybeNeedsSettle::NoSettleNeeded(v) => v,
} }
@ -7455,17 +7617,17 @@ impl SimulationImpl {
self.trace_writers = trace_writers; self.trace_writers = trace_writers;
retval retval
} }
fn close(mut self) -> std::io::Result<()> { fn close(this: Rc<RefCell<Self>>) -> std::io::Result<()> {
if self.main_module.did_initial_settle { if this.borrow().main_module.did_initial_settle {
self.settle(); Self::settle(&this);
} }
self.close_all_trace_writers() this.borrow_mut().close_all_trace_writers()
} }
fn flush_traces(&mut self) -> std::io::Result<()> { fn flush_traces(this_ref: &Rc<RefCell<Self>>) -> std::io::Result<()> {
if self.main_module.did_initial_settle { if this_ref.borrow().main_module.did_initial_settle {
self.settle(); Self::settle(this_ref);
} }
self.for_each_trace_writer_getting_error( this_ref.borrow_mut().for_each_trace_writer_getting_error(
|this, trace_writer: TraceWriterState<DynTraceWriterDecls>| match trace_writer { |this, trace_writer: TraceWriterState<DynTraceWriterDecls>| match trace_writer {
TraceWriterState::Decls(v) => { TraceWriterState::Decls(v) => {
let mut v = v.write_decls( let mut v = v.write_decls(
@ -7499,7 +7661,7 @@ impl Drop for SimulationImpl {
} }
pub struct Simulation<T: BundleType> { pub struct Simulation<T: BundleType> {
sim_impl: SimulationImpl, sim_impl: Rc<RefCell<SimulationImpl>>,
io: Expr<T>, io: Expr<T>,
} }
@ -7546,24 +7708,113 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for SortedMapDebug<'_, K, V> {
impl<T: BundleType> fmt::Debug for Simulation<T> { impl<T: BundleType> fmt::Debug for Simulation<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { sim_impl, io } = self; let Self { sim_impl, io } = self;
sim_impl.debug_fmt(Some(io), f) sim_impl.borrow().debug_fmt(Some(io), f)
} }
} }
macro_rules! impl_simulation_methods {
(async_await = ($($async:tt, $await:tt)?)) => {
#[track_caller]
pub $($async)? fn read_bool_or_int<I: BoolOrIntType>(&mut self, io: Expr<I>) -> I::Value {
let retval = self
.sim_impl
.borrow_mut()
.read_bool_or_int(io, WhichModule::Main);
self.settle_if_needed(retval)$(.$await)?
}
#[track_caller]
pub $($async)? fn write_bool_or_int<I: BoolOrIntType>(
&mut self,
io: Expr<I>,
value: impl ToExpr<Type = I>,
) {
let value = value.to_expr();
assert_eq!(Expr::ty(io), Expr::ty(value), "type mismatch");
let value = value
.to_literal_bits()
.expect("the value that is being written to an input must be a literal");
self.sim_impl.borrow_mut().write_bool_or_int(
io,
I::bits_to_value(Cow::Borrowed(&value)),
WhichModule::Main,
);
}
#[track_caller]
pub $($async)? fn write_clock(&mut self, io: Expr<Clock>, value: bool) {
self.sim_impl
.borrow_mut()
.write_bit(Expr::canonical(io), value, WhichModule::Main);
}
#[track_caller]
pub $($async)? fn read_clock(&mut self, io: Expr<Clock>) -> bool {
let retval = self
.sim_impl
.borrow_mut()
.read_bit(Expr::canonical(io), WhichModule::Main);
self.settle_if_needed(retval)$(.$await)?
}
#[track_caller]
pub $($async)? fn write_bool(&mut self, io: Expr<Bool>, value: bool) {
self.sim_impl
.borrow_mut()
.write_bit(Expr::canonical(io), value, WhichModule::Main);
}
#[track_caller]
pub $($async)? fn read_bool(&mut self, io: Expr<Bool>) -> bool {
let retval = self
.sim_impl
.borrow_mut()
.read_bit(Expr::canonical(io), WhichModule::Main);
self.settle_if_needed(retval)$(.$await)?
}
#[track_caller]
pub $($async)? fn write_reset<R: ResetType>(&mut self, io: Expr<R>, value: bool) {
self.sim_impl
.borrow_mut()
.write_bit(Expr::canonical(io), value, WhichModule::Main);
}
#[track_caller]
pub $($async)? fn read_reset<R: ResetType>(&mut self, io: Expr<R>) -> bool {
let retval = self
.sim_impl
.borrow_mut()
.read_bit(Expr::canonical(io), WhichModule::Main);
self.settle_if_needed(retval)$(.$await)?
}
#[track_caller]
pub $($async)? fn read<IO: Type>(&mut self, io: Expr<IO>) -> SimValue<IO> {
let retval = self
.sim_impl
.borrow_mut()
.read(Expr::canonical(io), WhichModule::Main);
SimValue::from_canonical(self.settle_if_needed(retval)$(.$await)?)
}
#[track_caller]
pub $($async)? fn write<IO: Type, V: ToSimValue<IO>>(&mut self, io: Expr<IO>, value: V) {
self.sim_impl.borrow_mut().write(
Expr::canonical(io),
value.into_sim_value(Expr::ty(io)).into_canonical(),
WhichModule::Main,
);
}
};
}
impl<T: BundleType> Simulation<T> { impl<T: BundleType> Simulation<T> {
pub fn new(module: Interned<Module<T>>) -> Self { pub fn new(module: Interned<Module<T>>) -> Self {
Self::from_compiled(Compiled::new(module)) Self::from_compiled(Compiled::new(module))
} }
pub fn add_trace_writer<W: TraceWriterDecls>(&mut self, writer: W) { pub fn add_trace_writer<W: TraceWriterDecls>(&mut self, writer: W) {
self.sim_impl self.sim_impl
.borrow_mut()
.trace_writers .trace_writers
.push(TraceWriterState::Decls(DynTraceWriterDecls::new(writer))); .push(TraceWriterState::Decls(DynTraceWriterDecls::new(writer)));
} }
pub fn flush_traces(&mut self) -> std::io::Result<()> { pub fn flush_traces(&mut self) -> std::io::Result<()> {
self.sim_impl.flush_traces() SimulationImpl::flush_traces(&self.sim_impl)
} }
pub fn close(self) -> std::io::Result<()> { pub fn close(self) -> std::io::Result<()> {
self.sim_impl.close() SimulationImpl::close(self.sim_impl)
} }
pub fn canonical(self) -> Simulation<Bundle> { pub fn canonical(self) -> Simulation<Bundle> {
let Self { sim_impl, io } = self; let Self { sim_impl, io } = self;
@ -7586,92 +7837,29 @@ impl<T: BundleType> Simulation<T> {
let sim_impl = SimulationImpl::new(compiled.canonical()); let sim_impl = SimulationImpl::new(compiled.canonical());
Self { Self {
io: Expr::from_bundle(sim_impl.io), io: Expr::from_bundle(sim_impl.io),
sim_impl, sim_impl: Rc::new(RefCell::new(sim_impl)),
} }
} }
#[track_caller] #[track_caller]
pub fn settle(&mut self) { pub fn settle(&mut self) {
self.sim_impl.settle(); SimulationImpl::settle(&self.sim_impl);
} }
#[track_caller] #[track_caller]
pub fn advance_time(&mut self, duration: SimDuration) { pub fn advance_time(&mut self, duration: SimDuration) {
self.sim_impl.advance_time(duration); SimulationImpl::advance_time(&self.sim_impl, duration);
} }
#[track_caller] #[track_caller]
pub fn read_bool_or_int<I: BoolOrIntType>(&mut self, io: Expr<I>) -> I::Value { fn settle_if_needed<F, O>(&mut self, v: MaybeNeedsSettle<F, O>) -> O
let retval = self.sim_impl.read_bool_or_int(io, WhichModule::Main); where
self.sim_impl.settle_if_needed(retval) for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>,
} {
#[track_caller] SimulationImpl::settle_if_needed(&self.sim_impl, v)
pub fn write_bool_or_int<I: BoolOrIntType>(
&mut self,
io: Expr<I>,
value: impl ToExpr<Type = I>,
) {
let value = value.to_expr();
assert_eq!(Expr::ty(io), Expr::ty(value), "type mismatch");
let value = value
.to_literal_bits()
.expect("the value that is being written to an input must be a literal");
self.sim_impl.write_bool_or_int(
io,
I::bits_to_value(Cow::Borrowed(&value)),
WhichModule::Main,
);
}
#[track_caller]
pub fn write_clock(&mut self, io: Expr<Clock>, value: bool) {
self.sim_impl
.write_bit(Expr::canonical(io), value, WhichModule::Main);
}
#[track_caller]
pub fn read_clock(&mut self, io: Expr<Clock>) -> bool {
let retval = self
.sim_impl
.read_bit(Expr::canonical(io), WhichModule::Main);
self.sim_impl.settle_if_needed(retval)
}
#[track_caller]
pub fn write_bool(&mut self, io: Expr<Bool>, value: bool) {
self.sim_impl
.write_bit(Expr::canonical(io), value, WhichModule::Main);
}
#[track_caller]
pub fn read_bool(&mut self, io: Expr<Bool>) -> bool {
let retval = self
.sim_impl
.read_bit(Expr::canonical(io), WhichModule::Main);
self.sim_impl.settle_if_needed(retval)
}
#[track_caller]
pub fn write_reset<R: ResetType>(&mut self, io: Expr<R>, value: bool) {
self.sim_impl
.write_bit(Expr::canonical(io), value, WhichModule::Main);
}
#[track_caller]
pub fn read_reset<R: ResetType>(&mut self, io: Expr<R>) -> bool {
let retval = self
.sim_impl
.read_bit(Expr::canonical(io), WhichModule::Main);
self.sim_impl.settle_if_needed(retval)
}
#[track_caller]
pub fn read<IO: Type>(&mut self, io: Expr<IO>) -> SimValue<IO> {
let retval = self.sim_impl.read(Expr::canonical(io), WhichModule::Main);
SimValue::from_canonical(self.sim_impl.settle_if_needed(retval))
}
#[track_caller]
pub fn write<IO: Type, V: ToSimValue<IO>>(&mut self, io: Expr<IO>, value: V) {
self.sim_impl.write(
Expr::canonical(io),
value.into_sim_value(Expr::ty(io)).into_canonical(),
WhichModule::Main,
);
} }
impl_simulation_methods!(async_await = ());
#[doc(hidden)] #[doc(hidden)]
/// This is explicitly unstable and may be changed/removed at any time /// This is explicitly unstable and may be changed/removed at any time
pub fn set_breakpoints_unstable(&mut self, pcs: HashSet<usize>, trace: bool) { pub fn set_breakpoints_unstable(&mut self, pcs: HashSet<usize>, trace: bool) {
self.sim_impl.breakpoints = Some(BreakpointsSet { self.sim_impl.borrow_mut().breakpoints = Some(BreakpointsSet {
last_was_break: false, last_was_break: false,
set: pcs, set: pcs,
trace, trace,
@ -7679,22 +7867,74 @@ impl<T: BundleType> Simulation<T> {
} }
} }
#[derive(Debug)]
pub struct ExternModuleSimulationState<T: BundleType> { pub struct ExternModuleSimulationState<T: BundleType> {
sim_impl: Rc<RefCell<SimulationImpl>>,
module_index: usize,
io_ty: T, io_ty: T,
} }
impl<T: BundleType> fmt::Debug for ExternModuleSimulationState<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
sim_impl: _,
module_index,
io_ty,
} = self;
f.debug_struct("ExternModuleSimulationState")
.field("sim_impl", &DebugAsDisplay("..."))
.field("module_index", module_index)
.field("io_ty", io_ty)
.finish()
}
}
impl<T: BundleType> ExternModuleSimulationState<T> { impl<T: BundleType> ExternModuleSimulationState<T> {
pub fn canonical(self) -> ExternModuleSimulationState<Bundle> { pub fn canonical(self) -> ExternModuleSimulationState<Bundle> {
let Self {
sim_impl,
module_index,
io_ty,
} = self;
ExternModuleSimulationState { ExternModuleSimulationState {
io_ty: Bundle::from_canonical(self.io_ty.canonical()), sim_impl,
module_index,
io_ty: Bundle::from_canonical(io_ty.canonical()),
} }
} }
pub fn from_canonical(sim: ExternModuleSimulationState<Bundle>) -> Self { pub fn from_canonical(sim: ExternModuleSimulationState<Bundle>) -> Self {
let ExternModuleSimulationState {
sim_impl,
module_index,
io_ty,
} = sim;
Self { Self {
io_ty: T::from_canonical(sim.io_ty.canonical()), sim_impl,
module_index,
io_ty: T::from_canonical(io_ty.canonical()),
} }
} }
#[track_caller]
pub async fn settle(&mut self) {
SimulationImpl::yield_advance_time_or_settle(self.sim_impl.clone(), self.module_index, None)
.await
}
#[track_caller]
pub async fn advance_time(&mut self, duration: SimDuration) {
SimulationImpl::yield_advance_time_or_settle(
self.sim_impl.clone(),
self.module_index,
Some(duration),
)
.await
}
#[track_caller]
async fn settle_if_needed<F, O>(&mut self, v: MaybeNeedsSettle<F, O>) -> O
where
for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>,
{
SimulationImpl::yield_settle_if_needed(&self.sim_impl, self.module_index, v).await
}
impl_simulation_methods!(async_await = (async, await));
} }
pub trait ExternModuleSimGenerator: pub trait ExternModuleSimGenerator: