simplify setting an extern module simulation
All checks were successful
/ deps (pull_request) Successful in 12m46s
/ test (pull_request) Successful in 4m8s

This commit is contained in:
Jacob Lifshay 2025-03-21 17:08:29 -07:00
parent d1bd176b28
commit ab9ff4f2db
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
5 changed files with 111 additions and 163 deletions

View file

@ -34,6 +34,7 @@ use std::{
collections::VecDeque,
convert::Infallible,
fmt,
future::IntoFuture,
hash::{Hash, Hasher},
iter::FusedIterator,
marker::PhantomData,
@ -1082,7 +1083,7 @@ pub struct ExternModuleBody<
> {
pub verilog_name: Interned<str>,
pub parameters: P,
pub simulation: Option<ExternModuleSimulation<Bundle>>,
pub simulation: Option<ExternModuleSimulation>,
}
impl From<ExternModuleBody<Vec<ExternModuleParameter>>> for ExternModuleBody {
@ -1767,12 +1768,8 @@ impl AssertValidityState {
ModuleBody::Extern(ExternModuleBody {
verilog_name: _,
parameters: _,
simulation,
}) => {
if let Some(simulation) = simulation {
simulation.check_io_ty(self.module.io_ty);
}
}
simulation: _,
}) => {}
ModuleBody::Normal(NormalModuleBody { body }) => {
let body = self.make_block_index(body);
assert_eq!(body, 0);
@ -2250,6 +2247,17 @@ impl ModuleBuilder {
}
*simulation = Some(ExternModuleSimulation::new(generator));
}
#[track_caller]
pub fn extern_module_simulation_fn<
Args: fmt::Debug + Clone + Hash + Eq + Send + Sync + 'static,
Fut: IntoFuture<Output = ()> + 'static,
>(
&self,
args: Args,
f: fn(Args, crate::sim::ExternModuleSimulationState) -> Fut,
) {
self.extern_module_simulation(crate::sim::SimGeneratorFn { args, f });
}
}
#[track_caller]

View file

@ -60,6 +60,7 @@ use std::{
collections::BTreeSet,
fmt,
future::{Future, IntoFuture},
hash::Hash,
marker::PhantomData,
mem,
ops::IndexMut,
@ -1634,10 +1635,9 @@ impl<T> fmt::Debug for DebugOpaque<T> {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
struct CompiledExternModule {
io_ty: Bundle,
module_io_targets: Interned<[Target]>,
module_io: Interned<[CompiledValue<CanonicalType>]>,
simulation: ExternModuleSimulation<Bundle>,
simulation: ExternModuleSimulation,
}
#[derive(Debug)]
@ -4713,7 +4713,6 @@ impl Compiler {
);
};
self.extern_modules.push(CompiledExternModule {
io_ty: module.leaf_module().io_ty(),
module_io_targets: module
.leaf_module()
.module_io()
@ -6822,8 +6821,7 @@ impl Ord for WaitTarget {
struct SimulationExternModuleState {
module_state: SimulationModuleState,
io_ty: Bundle,
sim: ExternModuleSimulation<Bundle>,
sim: ExternModuleSimulation,
running_generator: Option<Pin<Box<dyn Future<Output = ()> + 'static>>>,
wait_target: Option<WaitTarget>,
}
@ -6832,14 +6830,12 @@ impl fmt::Debug for SimulationExternModuleState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
module_state,
io_ty,
sim,
running_generator,
wait_target,
} = self;
f.debug_struct("SimulationExternModuleState")
.field("module_state", module_state)
.field("io_ty", io_ty)
.field("sim", sim)
.field(
"running_generator",
@ -7008,7 +7004,6 @@ impl SimulationImpl {
let io_target = Target::from(compiled.io);
let extern_modules = Box::from_iter(compiled.extern_modules.iter().map(
|&CompiledExternModule {
io_ty,
module_io_targets,
module_io,
simulation,
@ -7020,7 +7015,6 @@ impl SimulationImpl {
.copied()
.zip(module_io.iter().copied()),
),
io_ty,
sim: simulation,
running_generator: None,
wait_target: Some(WaitTarget::Settle),
@ -7337,12 +7331,10 @@ impl SimulationImpl {
extern_module.wait_target = None;
let mut generator = if !extern_module.module_state.did_initial_settle {
let sim = extern_module.sim;
let io_ty = extern_module.io_ty;
drop(this);
Box::into_pin(sim.run(ExternModuleSimulationState {
sim_impl: this_ref.clone(),
module_index,
io_ty,
}))
} else if let Some(generator) = extern_module.running_generator.take() {
drop(this);
@ -8013,52 +8005,25 @@ impl<T: BundleType> Simulation<T> {
}
}
pub struct ExternModuleSimulationState<T: BundleType> {
pub struct ExternModuleSimulationState {
sim_impl: Rc<RefCell<SimulationImpl>>,
module_index: usize,
io_ty: T,
}
impl<T: BundleType> fmt::Debug for ExternModuleSimulationState<T> {
impl fmt::Debug for ExternModuleSimulationState {
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 {
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 {
sim_impl,
module_index,
io_ty: T::from_canonical(io_ty.canonical()),
}
}
impl ExternModuleSimulationState {
pub async fn settle(&mut self) {
SimulationImpl::yield_advance_time_or_settle(self.sim_impl.clone(), self.module_index, None)
.await
@ -8084,39 +8049,74 @@ impl<T: BundleType> ExternModuleSimulationState<T> {
);
}
pub trait ExternModuleSimGenerator:
Clone + Eq + std::hash::Hash + Any + Send + Sync + fmt::Debug
{
type IOType: BundleType;
pub trait ExternModuleSimGenerator: Clone + Eq + Hash + Any + Send + Sync + fmt::Debug {
fn run<'a>(&'a self, sim: ExternModuleSimulationState) -> impl IntoFuture<Output = ()> + 'a;
}
fn run<'a>(
&'a self,
sim: ExternModuleSimulationState<Self::IOType>,
) -> impl IntoFuture<Output = ()> + 'a;
pub struct SimGeneratorFn<Args, Fut> {
pub args: Args,
pub f: fn(Args, ExternModuleSimulationState) -> Fut,
}
impl<Args: fmt::Debug, Fut> fmt::Debug for SimGeneratorFn<Args, Fut> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { args, f: _ } = self;
f.debug_struct("SimGeneratorFn")
.field("args", args)
.field("f", &DebugAsDisplay("..."))
.finish()
}
}
impl<Args: Hash, Fut> Hash for SimGeneratorFn<Args, Fut> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let Self { args, f } = self;
args.hash(state);
f.hash(state);
}
}
impl<Args: Eq, Fut> Eq for SimGeneratorFn<Args, Fut> {}
impl<Args: PartialEq, Fut> PartialEq for SimGeneratorFn<Args, Fut> {
fn eq(&self, other: &Self) -> bool {
let Self { args, f } = self;
*args == other.args && *f == other.f
}
}
impl<Args: Clone, Fut> Clone for SimGeneratorFn<Args, Fut> {
fn clone(&self) -> Self {
Self {
args: self.args.clone(),
f: self.f,
}
}
}
impl<Args: Copy, Fut> Copy for SimGeneratorFn<Args, Fut> {}
impl<
T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static,
Fut: IntoFuture<Output = ()> + 'static,
> ExternModuleSimGenerator for SimGeneratorFn<T, Fut>
{
fn run<'a>(&'a self, sim: ExternModuleSimulationState) -> impl IntoFuture<Output = ()> + 'a {
(self.f)(self.args.clone(), sim)
}
}
trait DynExternModuleSimGenerator: Any + Send + Sync + SupportsPtrEqWithTypeId + fmt::Debug {
fn dyn_run<'a>(
&'a self,
sim: ExternModuleSimulationState<Bundle>,
) -> Box<dyn Future<Output = ()> + 'a>;
#[track_caller]
fn check_io_ty(&self, io_ty: Bundle);
fn dyn_run<'a>(&'a self, sim: ExternModuleSimulationState)
-> Box<dyn Future<Output = ()> + 'a>;
}
impl<T: ExternModuleSimGenerator> DynExternModuleSimGenerator for T {
fn dyn_run<'a>(
&'a self,
sim: ExternModuleSimulationState<Bundle>,
sim: ExternModuleSimulationState,
) -> Box<dyn Future<Output = ()> + 'a> {
Box::new(
self.run(ExternModuleSimulationState::from_canonical(sim))
.into_future(),
)
}
#[track_caller]
fn check_io_ty(&self, io_ty: Bundle) {
T::IOType::from_canonical(io_ty.canonical());
Box::new(self.run(sim).into_future())
}
}
@ -8129,13 +8129,12 @@ impl InternedCompare for dyn DynExternModuleSimGenerator {
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct ExternModuleSimulation<T: BundleType> {
pub struct ExternModuleSimulation {
generator: Interned<dyn DynExternModuleSimGenerator>,
source_location: SourceLocation,
_phantom: PhantomData<T>,
}
impl<T: BundleType> ExternModuleSimulation<T> {
impl ExternModuleSimulation {
pub fn new_with_loc<G: ExternModuleSimGenerator>(
source_location: SourceLocation,
generator: G,
@ -8146,48 +8145,13 @@ impl<T: BundleType> ExternModuleSimulation<T> {
|v| -> &dyn DynExternModuleSimGenerator { v },
),
source_location,
_phantom: PhantomData,
}
}
#[track_caller]
pub fn new<G: ExternModuleSimGenerator>(generator: G) -> Self {
Self::new_with_loc(SourceLocation::caller(), generator)
}
pub fn canonical(self) -> ExternModuleSimulation<Bundle> {
let Self {
generator,
source_location,
_phantom: _,
} = self;
ExternModuleSimulation {
generator,
source_location,
_phantom: PhantomData,
}
}
pub fn from_canonical(v: ExternModuleSimulation<Bundle>) -> Self {
let ExternModuleSimulation {
generator,
source_location,
_phantom: _,
} = v;
Self {
generator,
source_location,
_phantom: PhantomData,
}
}
}
impl ExternModuleSimulation<Bundle> {
fn run(
&self,
sim: ExternModuleSimulationState<Bundle>,
) -> Box<dyn Future<Output = ()> + 'static> {
fn run(&self, sim: ExternModuleSimulationState) -> Box<dyn Future<Output = ()> + 'static> {
Interned::into_inner(self.generator).dyn_run(sim)
}
#[track_caller]
pub fn check_io_ty(self, io_ty: Bundle) {
self.generator.check_io_ty(io_ty);
}
}

View file

@ -5,14 +5,11 @@ use fayalite::{
int::UIntValue,
prelude::*,
reset::ResetType,
sim::{
time::SimDuration, vcd::VcdWriterDecls, ExternModuleSimGenerator,
ExternModuleSimulationState, Simulation, ToSimValue,
},
sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation, ToSimValue},
ty::StaticType,
util::RcWriter,
};
use std::{future::IntoFuture, num::NonZeroUsize};
use std::num::NonZeroUsize;
#[hdl_module(outline_generated)]
pub fn connect_const() {
@ -1453,20 +1450,7 @@ pub fn extern_module() {
let i: Bool = m.input();
#[hdl]
let o: Bool = m.output();
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct Sim {
i: Expr<Bool>,
o: Expr<Bool>,
}
impl ExternModuleSimGenerator for Sim {
type IOType = extern_module;
fn run<'a>(
&'a self,
mut sim: ExternModuleSimulationState<Self::IOType>,
) -> impl IntoFuture<Output = ()> + 'a {
let Self { i, o } = *self;
async move {
m.extern_module_simulation_fn((i, o), |(i, o), mut sim| async move {
sim.write(o, true).await;
sim.advance_time(SimDuration::from_nanos(500)).await;
let mut invert = false;
@ -1476,10 +1460,7 @@ pub fn extern_module() {
sim.write(o, v ^ invert).await;
invert = !invert;
}
}
}
}
m.extern_module_simulation(Sim { i, o });
});
}
#[test]

View file

@ -128,31 +128,27 @@ Simulation {
},
did_initial_settle: true,
},
io_ty: Bundle {
#[hdl(flip)] /* offset = 0 */
i: Bool,
/* offset = 1 */
o: Bool,
},
sim: ExternModuleSimulation {
generator: Sim {
i: ModuleIO {
generator: SimGeneratorFn {
args: (
ModuleIO {
name: extern_module::i,
is_input: true,
ty: Bool,
..
},
o: ModuleIO {
ModuleIO {
name: extern_module::o,
is_input: false,
ty: Bool,
..
},
),
f: ...,
},
source_location: SourceLocation(
module-XXXXXXXXXX.rs:4:1,
),
_phantom: PhantomData<fayalite::bundle::Bundle>,
},
running_generator: Some(
...,

View file

@ -1274,8 +1274,7 @@
"ExternModuleSimulation": {
"data": {
"$kind": "Opaque"
},
"generics": "<T: BundleType>"
}
}
}
}