substrate/simulation/
mod.rs1use std::any::Any;
4use std::path::PathBuf;
5use std::sync::Arc;
6
7use data::{Save, Saved};
8use impl_trait_for_tuples::impl_for_tuples;
9use rust_decimal::Decimal;
10use serde::{Deserialize, Serialize};
11
12use crate::block::Block;
13use crate::context::{Context, Installation};
14use crate::schematic::conv::RawLib;
15use crate::schematic::schema::Schema;
16use crate::schematic::{Cell, HasNestedView, NestedView, Schematic};
17use crate::types::TestbenchIo;
18
19pub mod data;
20pub mod options;
21pub mod waveform;
22
23#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
27pub struct Pvt<C> {
28 pub corner: C,
30 pub voltage: Decimal,
32 pub temp: Decimal,
34}
35
36impl<C> Pvt<C> {
37 #[inline]
39 pub fn new(corner: C, voltage: Decimal, temp: Decimal) -> Self {
40 Self {
41 corner,
42 voltage,
43 temp,
44 }
45 }
46}
47
48pub trait Analysis {
50 type Output;
52}
53
54pub trait Simulator: Installation + Any + Send + Sync {
56 type Schema: Schema;
58 type Input;
60 type Options;
62 type Output;
64 type Error;
66
67 fn simulate_inputs(
69 &self,
70 ctx: &SimulationContext<Self>,
71 options: Self::Options,
72 input: Vec<Self::Input>,
73 ) -> Result<Vec<Self::Output>, Self::Error>;
74
75 fn simulate<A>(
77 &self,
78 ctx: &SimulationContext<Self>,
79 options: Self::Options,
80 input: A,
81 ) -> Result<A::Output, Self::Error>
82 where
83 A: SupportedBy<Self>,
84 Self: Sized,
85 {
86 let mut inputs = Vec::new();
87 input.into_input(&mut inputs);
88 let output = self.simulate_inputs(ctx, options, inputs)?;
89 let mut output = output.into_iter();
90 Ok(A::from_output(&mut output))
91 }
92}
93
94pub struct SimulationContext<S: Simulator + ?Sized> {
96 pub work_dir: PathBuf,
98 pub lib: Arc<RawLib<S::Schema>>,
100 pub ctx: Context,
102}
103
104pub trait SupportedBy<S: Simulator>: Analysis {
106 fn into_input(self, inputs: &mut Vec<<S as Simulator>::Input>);
108 fn from_output(outputs: &mut impl Iterator<Item = <S as Simulator>::Output>) -> Self::Output;
110}
111
112pub struct SimController<S: Simulator, T: Schematic> {
114 pub(crate) simulator: Arc<S>,
115 pub tb: Arc<Cell<T>>,
117 pub(crate) ctx: SimulationContext<S>,
118}
119
120pub type SavedData<T, S, A> = Saved<NestedView<<T as Schematic>::NestedData>, S, A>;
122
123impl<S: Simulator, T: Testbench<S>> SimController<S, T> {
124 pub fn simulate_default<A: SupportedBy<S>>(
126 &self,
127 options: S::Options,
128 input: A,
129 ) -> Result<A::Output, S::Error> {
130 self.simulator.simulate(&self.ctx, options, input)
131 }
132
133 pub fn simulate<A: SupportedBy<S>>(
135 &self,
136 mut options: S::Options,
137 input: A,
138 ) -> Result<SavedData<T, S, A>, S::Error>
139 where
140 T: Schematic<NestedData: HasNestedView<NestedView: Save<S, A>>>,
141 {
142 let key = <NestedView<<T as Schematic>::NestedData> as Save<S, A>>::save(
143 &self.tb.data(),
144 &self.ctx,
145 &mut options,
146 );
147 let output = self.simulate_default(options, input)?;
148 Ok(
149 <<<T as Schematic>::NestedData as HasNestedView>::NestedView>::from_saved(
150 &output, &key,
151 ),
152 )
153 }
154
155 pub fn set_option<O>(&self, opt: O, options: &mut S::Options)
157 where
158 O: options::SimOption<S>,
159 {
160 opt.set_option(options, &self.ctx);
161 }
162}
163
164pub trait Testbench<S: Simulator>: Schematic<Schema = S::Schema> + Block<Io = TestbenchIo> {}
166impl<S: Simulator, T: Schematic<Schema = S::Schema> + Block<Io = TestbenchIo>> Testbench<S> for T {}
167
168#[impl_for_tuples(64)]
169impl Analysis for Tuple {
170 for_tuples!( type Output = ( #( Tuple::Output ),* ); );
171}
172
173#[impl_for_tuples(64)]
174impl<S: Simulator> SupportedBy<S> for Tuple {
175 fn into_input(self, inputs: &mut Vec<<S as Simulator>::Input>) {
176 for_tuples!( #( <Tuple as SupportedBy<S>>::into_input(self.Tuple, inputs); )* )
177 }
178
179 #[allow(clippy::unused_unit)]
180 fn from_output(
181 outputs: &mut impl Iterator<Item = <S as Simulator>::Output>,
182 ) -> <Self as Analysis>::Output {
183 (for_tuples!( #( <Tuple as SupportedBy<S>>::from_output(outputs) ),* ))
184 }
185}