use std::any::Any;
use std::path::PathBuf;
use std::sync::Arc;
use data::{Save, Saved};
use impl_trait_for_tuples::impl_for_tuples;
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use crate::block::Block;
use crate::context::{Context, Installation};
use crate::schematic::conv::RawLib;
use crate::schematic::schema::Schema;
use crate::schematic::{Cell, HasNestedView, NestedView, Schematic};
use crate::types::TestbenchIo;
pub mod data;
pub mod options;
pub mod waveform;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct Pvt<C> {
pub corner: C,
pub voltage: Decimal,
pub temp: Decimal,
}
impl<C> Pvt<C> {
#[inline]
pub fn new(corner: C, voltage: Decimal, temp: Decimal) -> Self {
Self {
corner,
voltage,
temp,
}
}
}
pub trait Analysis {
type Output;
}
pub trait Simulator: Installation + Any + Send + Sync {
type Schema: Schema;
type Input;
type Options;
type Output;
type Error;
fn simulate_inputs(
&self,
ctx: &SimulationContext<Self>,
options: Self::Options,
input: Vec<Self::Input>,
) -> Result<Vec<Self::Output>, Self::Error>;
fn simulate<A>(
&self,
ctx: &SimulationContext<Self>,
options: Self::Options,
input: A,
) -> Result<A::Output, Self::Error>
where
A: SupportedBy<Self>,
Self: Sized,
{
let mut inputs = Vec::new();
input.into_input(&mut inputs);
let output = self.simulate_inputs(ctx, options, inputs)?;
let mut output = output.into_iter();
Ok(A::from_output(&mut output))
}
}
pub struct SimulationContext<S: Simulator + ?Sized> {
pub work_dir: PathBuf,
pub lib: Arc<RawLib<S::Schema>>,
pub ctx: Context,
}
pub trait SupportedBy<S: Simulator>: Analysis {
fn into_input(self, inputs: &mut Vec<<S as Simulator>::Input>);
fn from_output(outputs: &mut impl Iterator<Item = <S as Simulator>::Output>) -> Self::Output;
}
pub struct SimController<S: Simulator, T: Schematic> {
pub(crate) simulator: Arc<S>,
pub tb: Arc<Cell<T>>,
pub(crate) ctx: SimulationContext<S>,
}
pub type SavedData<T, S, A> = Saved<NestedView<<T as Schematic>::NestedData>, S, A>;
impl<S: Simulator, T: Testbench<S>> SimController<S, T> {
pub fn simulate_default<A: SupportedBy<S>>(
&self,
options: S::Options,
input: A,
) -> Result<A::Output, S::Error> {
self.simulator.simulate(&self.ctx, options, input)
}
pub fn simulate<A: SupportedBy<S>>(
&self,
mut options: S::Options,
input: A,
) -> Result<SavedData<T, S, A>, S::Error>
where
T: Schematic<NestedData: HasNestedView<NestedView: Save<S, A>>>,
{
let key = <NestedView<<T as Schematic>::NestedData> as Save<S, A>>::save(
&self.tb.data(),
&self.ctx,
&mut options,
);
let output = self.simulate_default(options, input)?;
Ok(
<<<T as Schematic>::NestedData as HasNestedView>::NestedView>::from_saved(
&output, &key,
),
)
}
pub fn set_option<O>(&self, opt: O, options: &mut S::Options)
where
O: options::SimOption<S>,
{
opt.set_option(options, &self.ctx);
}
}
pub trait Testbench<S: Simulator>: Schematic<Schema = S::Schema> + Block<Io = TestbenchIo> {}
impl<S: Simulator, T: Schematic<Schema = S::Schema> + Block<Io = TestbenchIo>> Testbench<S> for T {}
#[impl_for_tuples(64)]
impl Analysis for Tuple {
for_tuples!( type Output = ( #( Tuple::Output ),* ); );
}
#[impl_for_tuples(64)]
impl<S: Simulator> SupportedBy<S> for Tuple {
fn into_input(self, inputs: &mut Vec<<S as Simulator>::Input>) {
for_tuples!( #( <Tuple as SupportedBy<S>>::into_input(self.Tuple, inputs); )* )
}
#[allow(clippy::unused_unit)]
fn from_output(
outputs: &mut impl Iterator<Item = <S as Simulator>::Output>,
) -> <Self as Analysis>::Output {
(for_tuples!( #( <Tuple as SupportedBy<S>>::from_output(outputs) ),* ))
}
}