forked from libre-chip/fayalite
WIP: added running generators to settle loop
This commit is contained in:
parent
b4650f1bff
commit
f378b9a1d2
1 changed files with 362 additions and 122 deletions
|
@ -55,13 +55,17 @@ use petgraph::{
|
|||
use std::{
|
||||
any::Any,
|
||||
borrow::Cow,
|
||||
cell::RefCell,
|
||||
collections::BTreeSet,
|
||||
fmt,
|
||||
future::{Future, IntoFuture},
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
ops::IndexMut,
|
||||
pin::Pin,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
task::Poll,
|
||||
};
|
||||
|
||||
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 {
|
||||
module_state: SimulationModuleState,
|
||||
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 {
|
||||
|
@ -6767,6 +6796,7 @@ impl fmt::Debug for SimulationExternModuleState {
|
|||
module_state,
|
||||
sim,
|
||||
running_generator,
|
||||
wait_target,
|
||||
} = self;
|
||||
f.debug_struct("SimulationExternModuleState")
|
||||
.field("module_state", module_state)
|
||||
|
@ -6775,6 +6805,7 @@ impl fmt::Debug for SimulationExternModuleState {
|
|||
"running_generator",
|
||||
&running_generator.as_ref().map(|_| DebugAsDisplay("...")),
|
||||
)
|
||||
.field("wait_target", wait_target)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -6782,7 +6813,7 @@ impl fmt::Debug for SimulationExternModuleState {
|
|||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
enum WhichModule {
|
||||
Main,
|
||||
Extern { index: usize },
|
||||
Extern { module_index: usize },
|
||||
}
|
||||
|
||||
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 {
|
||||
state: interpreter::State,
|
||||
io: Expr<Bundle>,
|
||||
main_module: SimulationModuleState,
|
||||
extern_modules: Vec<SimulationExternModuleState>,
|
||||
extern_modules: Box<[SimulationExternModuleState]>,
|
||||
needs_settle: bool,
|
||||
trace_decls: TraceModule,
|
||||
traces: SimTraces<Box<[SimTrace<SimTraceKind, BitVec>]>>,
|
||||
|
@ -6868,6 +6907,7 @@ struct SimulationImpl {
|
|||
instant: SimInstant,
|
||||
clocks_triggered: Interned<[StatePartIndex<StatePartKindSmallSlots>]>,
|
||||
breakpoints: Option<BreakpointsSet>,
|
||||
generator_waker: std::task::Waker,
|
||||
}
|
||||
|
||||
impl fmt::Debug for SimulationImpl {
|
||||
|
@ -6891,6 +6931,7 @@ impl SimulationImpl {
|
|||
instant,
|
||||
clocks_triggered,
|
||||
breakpoints: _,
|
||||
generator_waker: _,
|
||||
} = self;
|
||||
f.debug_struct("Simulation")
|
||||
.field("state", state)
|
||||
|
@ -6908,6 +6949,8 @@ impl SimulationImpl {
|
|||
}
|
||||
fn new(compiled: Compiled<Bundle>) -> Self {
|
||||
let io_target = Target::from(compiled.io);
|
||||
// TODO: add extern_modules
|
||||
let extern_modules: Box<[SimulationExternModuleState]> = Box::new([]);
|
||||
Self {
|
||||
state: State::new(compiled.insns),
|
||||
io: compiled.io.to_expr(),
|
||||
|
@ -6928,8 +6971,7 @@ impl SimulationImpl {
|
|||
)
|
||||
}),
|
||||
),
|
||||
// TODO: add extern_modules
|
||||
extern_modules: vec![],
|
||||
extern_modules,
|
||||
needs_settle: true,
|
||||
trace_decls: compiled.base_module.trace_decls,
|
||||
traces: SimTraces(Box::from_iter(compiled.traces.0.iter().map(
|
||||
|
@ -6948,6 +6990,7 @@ impl SimulationImpl {
|
|||
instant: SimInstant::START,
|
||||
clocks_triggered: compiled.clocks_triggered,
|
||||
breakpoints: None,
|
||||
generator_waker: Arc::new(GeneratorWaker).into(),
|
||||
}
|
||||
}
|
||||
fn write_traces<const ONLY_IF_CHANGED: bool>(
|
||||
|
@ -7086,10 +7129,11 @@ impl SimulationImpl {
|
|||
}
|
||||
}
|
||||
#[track_caller]
|
||||
fn advance_time(&mut self, duration: SimDuration) {
|
||||
self.settle();
|
||||
self.instant += duration;
|
||||
self.for_each_trace_writer_storing_error(|this, mut trace_writer_state| {
|
||||
fn advance_time(this: &Rc<RefCell<Self>>, duration: SimDuration) {
|
||||
Self::settle(this);
|
||||
let mut this = this.borrow_mut();
|
||||
this.instant += duration;
|
||||
this.for_each_trace_writer_storing_error(|this, mut trace_writer_state| {
|
||||
match &mut trace_writer_state {
|
||||
TraceWriterState::Decls(_) | TraceWriterState::Init(_) => unreachable!(),
|
||||
TraceWriterState::Running(trace_writer) => {
|
||||
|
@ -7100,31 +7144,130 @@ impl SimulationImpl {
|
|||
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]
|
||||
fn settle(&mut self) {
|
||||
fn settle(this_ref: &Rc<RefCell<Self>>) {
|
||||
let mut this = this_ref.borrow_mut();
|
||||
assert!(
|
||||
self.main_module.uninitialized_ios.is_empty(),
|
||||
this.main_module.uninitialized_ios.is_empty(),
|
||||
"didn't initialize all inputs",
|
||||
);
|
||||
let mut run_list = Vec::new();
|
||||
let generator_waker = this.generator_waker.clone();
|
||||
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;
|
||||
}
|
||||
for module_index in run_list.drain(..) {
|
||||
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;
|
||||
}
|
||||
self.state.setup_call(0);
|
||||
if self.breakpoints.is_some() {
|
||||
this.state.setup_call(0);
|
||||
if this.breakpoints.is_some() {
|
||||
loop {
|
||||
match self
|
||||
let this = &mut *this;
|
||||
match this
|
||||
.state
|
||||
.run(self.breakpoints.as_mut().expect("just checked"))
|
||||
.run(this.breakpoints.as_mut().expect("just checked"))
|
||||
{
|
||||
RunResult::Break(break_action) => {
|
||||
println!(
|
||||
"hit breakpoint at:\n{:?}",
|
||||
self.state.debug_insn_at(self.state.pc),
|
||||
this.state.debug_insn_at(this.state.pc),
|
||||
);
|
||||
match break_action {
|
||||
BreakAction::DumpStateAndContinue => {
|
||||
println!("{self:#?}");
|
||||
println!("{this:#?}");
|
||||
}
|
||||
BreakAction::Continue => {}
|
||||
}
|
||||
|
@ -7133,21 +7276,21 @@ impl SimulationImpl {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let RunResult::Return(()) = self.state.run(());
|
||||
let RunResult::Return(()) = this.state.run(());
|
||||
}
|
||||
if self.main_module.did_initial_settle {
|
||||
self.read_traces::<false>();
|
||||
if this.main_module.did_initial_settle {
|
||||
this.read_traces::<false>();
|
||||
} else {
|
||||
self.read_traces::<true>();
|
||||
this.read_traces::<true>();
|
||||
}
|
||||
self.state.memory_write_log.sort_unstable();
|
||||
self.state.memory_write_log.dedup();
|
||||
self.main_module.did_initial_settle = true;
|
||||
self.needs_settle = self
|
||||
this.state.memory_write_log.sort_unstable();
|
||||
this.state.memory_write_log.dedup();
|
||||
this.main_module.did_initial_settle = true;
|
||||
this.needs_settle = this
|
||||
.clocks_triggered
|
||||
.iter()
|
||||
.any(|i| self.state.small_slots[*i] != 0);
|
||||
self.for_each_trace_writer_storing_error(|this, trace_writer_state| {
|
||||
.any(|i| this.state.small_slots[*i] != 0);
|
||||
this.for_each_trace_writer_storing_error(|this, trace_writer_state| {
|
||||
Ok(match trace_writer_state {
|
||||
TraceWriterState::Decls(trace_writer_decls) => TraceWriterState::Running(
|
||||
this.init_trace_writer(trace_writer_decls.write_decls(
|
||||
|
@ -7165,20 +7308,22 @@ impl SimulationImpl {
|
|||
TraceWriterState::Errored(e) => TraceWriterState::Errored(e),
|
||||
})
|
||||
});
|
||||
self.state.memory_write_log.clear();
|
||||
this.state.memory_write_log.clear();
|
||||
}
|
||||
panic!("settle(): took too many steps");
|
||||
}
|
||||
fn get_module(&self, which_module: WhichModule) -> &SimulationModuleState {
|
||||
match which_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 {
|
||||
match which_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]
|
||||
|
@ -7374,14 +7519,31 @@ impl SimulationImpl {
|
|||
);
|
||||
}
|
||||
#[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
|
||||
for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>,
|
||||
{
|
||||
match v {
|
||||
MaybeNeedsSettle::NeedsSettle(v) => {
|
||||
self.settle();
|
||||
v.call(&mut self.state)
|
||||
Self::settle(this_ref);
|
||||
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,
|
||||
}
|
||||
|
@ -7455,17 +7617,17 @@ impl SimulationImpl {
|
|||
self.trace_writers = trace_writers;
|
||||
retval
|
||||
}
|
||||
fn close(mut self) -> std::io::Result<()> {
|
||||
if self.main_module.did_initial_settle {
|
||||
self.settle();
|
||||
fn close(this: Rc<RefCell<Self>>) -> std::io::Result<()> {
|
||||
if this.borrow().main_module.did_initial_settle {
|
||||
Self::settle(&this);
|
||||
}
|
||||
self.close_all_trace_writers()
|
||||
this.borrow_mut().close_all_trace_writers()
|
||||
}
|
||||
fn flush_traces(&mut self) -> std::io::Result<()> {
|
||||
if self.main_module.did_initial_settle {
|
||||
self.settle();
|
||||
fn flush_traces(this_ref: &Rc<RefCell<Self>>) -> std::io::Result<()> {
|
||||
if this_ref.borrow().main_module.did_initial_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 {
|
||||
TraceWriterState::Decls(v) => {
|
||||
let mut v = v.write_decls(
|
||||
|
@ -7499,7 +7661,7 @@ impl Drop for SimulationImpl {
|
|||
}
|
||||
|
||||
pub struct Simulation<T: BundleType> {
|
||||
sim_impl: SimulationImpl,
|
||||
sim_impl: Rc<RefCell<SimulationImpl>>,
|
||||
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> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
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> {
|
||||
pub fn new(module: Interned<Module<T>>) -> Self {
|
||||
Self::from_compiled(Compiled::new(module))
|
||||
}
|
||||
pub fn add_trace_writer<W: TraceWriterDecls>(&mut self, writer: W) {
|
||||
self.sim_impl
|
||||
.borrow_mut()
|
||||
.trace_writers
|
||||
.push(TraceWriterState::Decls(DynTraceWriterDecls::new(writer)));
|
||||
}
|
||||
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<()> {
|
||||
self.sim_impl.close()
|
||||
SimulationImpl::close(self.sim_impl)
|
||||
}
|
||||
pub fn canonical(self) -> Simulation<Bundle> {
|
||||
let Self { sim_impl, io } = self;
|
||||
|
@ -7586,92 +7837,29 @@ impl<T: BundleType> Simulation<T> {
|
|||
let sim_impl = SimulationImpl::new(compiled.canonical());
|
||||
Self {
|
||||
io: Expr::from_bundle(sim_impl.io),
|
||||
sim_impl,
|
||||
sim_impl: Rc::new(RefCell::new(sim_impl)),
|
||||
}
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn settle(&mut self) {
|
||||
self.sim_impl.settle();
|
||||
SimulationImpl::settle(&self.sim_impl);
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn advance_time(&mut self, duration: SimDuration) {
|
||||
self.sim_impl.advance_time(duration);
|
||||
SimulationImpl::advance_time(&self.sim_impl, duration);
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn read_bool_or_int<I: BoolOrIntType>(&mut self, io: Expr<I>) -> I::Value {
|
||||
let retval = self.sim_impl.read_bool_or_int(io, WhichModule::Main);
|
||||
self.sim_impl.settle_if_needed(retval)
|
||||
}
|
||||
#[track_caller]
|
||||
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,
|
||||
);
|
||||
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::settle_if_needed(&self.sim_impl, v)
|
||||
}
|
||||
impl_simulation_methods!(async_await = ());
|
||||
#[doc(hidden)]
|
||||
/// This is explicitly unstable and may be changed/removed at any time
|
||||
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,
|
||||
set: pcs,
|
||||
trace,
|
||||
|
@ -7679,22 +7867,74 @@ impl<T: BundleType> Simulation<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExternModuleSimulationState<T: BundleType> {
|
||||
sim_impl: Rc<RefCell<SimulationImpl>>,
|
||||
module_index: usize,
|
||||
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> {
|
||||
pub fn canonical(self) -> ExternModuleSimulationState<Bundle> {
|
||||
let Self {
|
||||
sim_impl,
|
||||
module_index,
|
||||
io_ty,
|
||||
} = self;
|
||||
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 {
|
||||
let ExternModuleSimulationState {
|
||||
sim_impl,
|
||||
module_index,
|
||||
io_ty,
|
||||
} = sim;
|
||||
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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue