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::{
|
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:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue