diff --git a/Cargo.lock b/Cargo.lock index 7dc3208e..3fce8f9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -2540,6 +2540,7 @@ dependencies = [ name = "spectre" version = "0.9.1" dependencies = [ + "approx", "arcstr", "cache", "itertools 0.11.0", @@ -2617,7 +2618,6 @@ dependencies = [ "ena", "enumify", "examples", - "float_eq", "gds", "geometry", "impl-trait-for-tuples", diff --git a/codegen/src/block/schematic.rs b/codegen/src/block/schematic.rs index 6cacf612..f028d490 100644 --- a/codegen/src/block/schematic.rs +++ b/codegen/src/block/schematic.rs @@ -1,8 +1,9 @@ use darling::ast::{Fields, Style}; use darling::{ast, FromDeriveInput, FromField, FromVariant}; -use proc_macro2::TokenStream; +use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote, ToTokens}; -use syn::parse_quote; +use syn::token::Where; +use syn::{parse_quote, Token, WhereClause}; use crate::substrate_ident; use type_dispatch::derive::{add_trait_bounds, struct_body}; @@ -35,16 +36,13 @@ pub struct DataField { attrs: Vec, } -fn transform_variant_decl(variant: &DataVariant) -> TokenStream { +fn variant_decl(variant: &DataVariant) -> TokenStream { let DataVariant { ref ident, ref fields, .. } = variant; - let decls = fields - .iter() - .enumerate() - .map(|(i, f)| transform_field_decl(i, f)); + let decls = fields.iter().enumerate().map(|(i, f)| field_decl(i, f)); match fields.style { Style::Unit => quote!(#ident,), Style::Tuple => quote!(#ident( #(#decls)* ),), @@ -56,9 +54,10 @@ fn tuple_ident(idx: usize) -> syn::Ident { format_ident!("__substrate_derive_field{idx}") } -fn transform_variant_match_arm( - transformed_ident: syn::Ident, +fn variant_match_arm( + enum_ident: syn::Ident, variant: &DataVariant, + val: impl Fn(&syn::Type, &TokenStream) -> TokenStream, ) -> TokenStream { let DataVariant { ref ident, @@ -73,60 +72,62 @@ fn transform_variant_match_arm( let assign = fields .iter() .enumerate() - .map(|(i, f)| transform_field_assign(false, i, f)); + .map(|(i, f)| field_assign(None, i, f, &val)); match fields.style { - Style::Unit => quote!(Self::#ident => #transformed_ident::#ident,), + Style::Unit => quote!(Self::#ident => #enum_ident::#ident,), Style::Tuple => { - quote!(Self::#ident( #(#destructure),* ) => #transformed_ident::#ident( #(#assign)* ),) + quote!(Self::#ident( #(#destructure),* ) => #enum_ident::#ident( #(#assign)* ),) } Style::Struct => { - quote!(Self::#ident { #(#destructure),* } => #transformed_ident::#ident { #(#assign)* },) + quote!(Self::#ident { #(#destructure),* } => #enum_ident::#ident { #(#assign)* },) } } } -fn transform_field_decl(_idx: usize, field: &DataField) -> TokenStream { +fn field_decl(_idx: usize, field: &DataField) -> TokenStream { let DataField { ref ident, ref vis, ref ty, ref attrs, } = field; - let substrate = substrate_ident(); - let field_ty = quote!(#substrate::schematic::NestedView<#ty>); match ident { Some(ident) => { quote! { #(#attrs)* - #vis #ident: #field_ty, + #vis #ident: #ty, } } None => { quote! { #(#attrs)* - #vis #field_ty, + #vis #ty, } } } } -fn transform_field_assign(use_self: bool, idx: usize, field: &DataField) -> TokenStream { +fn field_assign( + prefix: Option<&TokenStream>, + idx: usize, + field: &DataField, + val: impl FnOnce(&syn::Type, &TokenStream) -> TokenStream, +) -> TokenStream { let DataField { ref ident, ref ty, .. } = field; - let substrate = substrate_ident(); let tuple_ident = tuple_ident(idx); let idx = syn::Index::from(idx); - let val = match (use_self, ident) { - (true, Some(ident)) => quote!(&self.#ident), - (true, None) => quote!(&self.#idx), - (false, Some(ident)) => quote!(&#ident), - (false, None) => quote!(&#tuple_ident), + let refer = match (prefix, ident) { + (Some(prefix), Some(ident)) => quote!(&#prefix.#ident), + (Some(prefix), None) => quote!(&#prefix.#idx), + (None, Some(ident)) => quote!(&#ident), + (None, None) => quote!(&#tuple_ident), }; - let value = quote!(<#ty as #substrate::schematic::HasNestedView>::nested_view(#val, __substrate_derive_parent)); + let value = val(ty, &refer); match ident { Some(ident) => quote! { #ident: #value, }, @@ -145,51 +146,142 @@ impl ToTokens for DataInputReceiver { ref attrs, } = *self; - let mut generics = generics.clone(); - add_trait_bounds(&mut generics, quote!(#substrate::schematic::HasNestedView)); + let mut hnv_generics = generics.clone(); + add_trait_bounds( + &mut hnv_generics, + quote!(#substrate::schematic::HasNestedView), + ); + let (hnv_imp, hnv_ty, hnv_wher) = hnv_generics.split_for_impl(); + + let mut save_generics = generics.clone(); + save_generics + .params + .push(parse_quote!(__substrate_S: #substrate::simulation::Simulator)); + save_generics + .params + .push(parse_quote!(__substrate_A: #substrate::simulation::Analysis)); - let (imp, ty, wher) = generics.split_for_impl(); - let transformed_ident = format_ident!("{}NestedView", ident); + let has_nested_view_ident = format_ident!("{}NestedView", ident); + let save_key_ident = format_ident!("{}SaveKey", ident); + let save_ident = format_ident!("{}Save", ident); let expanded = match data { ast::Data::Struct(ref fields) => { + let mut save_generics = save_generics.clone(); + let mut save_where_clause = + save_generics.where_clause.clone().unwrap_or(WhereClause { + where_token: Where { + span: Span::call_site(), + }, + predicates: Default::default(), + }); + for f in fields.iter() { + let ty = &f.ty; + save_where_clause.predicates.push(parse_quote!(<#ty as #substrate::schematic::HasNestedView>::NestedView: #substrate::simulation::data::Save<__substrate_S, __substrate_A>)); + } + save_generics.where_clause = Some(save_where_clause.clone()); + let (save_imp, save_ty, save_wher) = save_generics.split_for_impl(); + let nested_fields = fields.clone().map(|mut f| { let ty = f.ty.clone(); f.ty = parse_quote!(<#ty as #substrate::schematic::HasNestedView>::NestedView); f }); - let decls = fields + let save_key_fields = nested_fields.clone().map(|mut f| { + let ty = f.ty.clone(); + f.ty = parse_quote!(<#ty as #substrate::simulation::data::Save<__substrate_S, __substrate_A>>::SaveKey); + f + }); + + let save_fields = nested_fields.clone().map(|mut f| { + let ty = f.ty.clone(); + f.ty = parse_quote!(<#ty as #substrate::simulation::data::Save<__substrate_S, __substrate_A>>::Save); + f + }); + + let nested_view_decls = nested_fields .iter() .enumerate() - .map(|(i, f)| transform_field_decl(i, f)); - let assignments = fields + .map(|(i, f)| field_decl(i, f)); + let save_key_decls = save_key_fields .iter() .enumerate() - .map(|(i, f)| transform_field_assign(true, i, f)); + .map(|(i, f)| field_decl(i, f)); + let save_decls = save_fields + .iter() + .enumerate() + .map(|(i, f)| field_decl(i, f)); + let assignments = fields.iter().enumerate().map(|(i, f)| { + field_assign( + Some("e!{ self }), + i, + f, + |ty, val| quote! { <#ty as #substrate::schematic::HasNestedView>::nested_view(#val, __substrate_derive_parent) }, + ) + }); let retval = match fields.style { - Style::Unit => quote!(#transformed_ident), - Style::Tuple => quote!(#transformed_ident( #(#assignments)* )), - Style::Struct => quote!(#transformed_ident { #(#assignments)* }), + Style::Unit => quote!(#has_nested_view_ident), + Style::Tuple => quote!(#has_nested_view_ident( #(#assignments)* )), + Style::Struct => quote!(#has_nested_view_ident { #(#assignments)* }), }; - let body = struct_body(fields.style, true, quote! {#( #decls )*}); + let nested_view_body = + struct_body(fields.style, true, quote! {#( #nested_view_decls )*}); - let nested_assignments = nested_fields - .iter() - .enumerate() - .map(|(i, f)| transform_field_assign(true, i, f)); + let save_key_body = struct_body(fields.style, true, quote! {#( #save_key_decls )*}); + let save_body = struct_body(fields.style, true, quote! {#( #save_decls )*}); + + let nested_assignments = nested_fields.iter().enumerate().map(|(i, f)| { + field_assign( + Some("e!{ self }), + i, + f, + |ty, val| quote! { <#ty as #substrate::schematic::HasNestedView>::nested_view(#val, __substrate_derive_parent) }, + ) + }); let nested_retval = match nested_fields.style { - Style::Unit => quote!(#transformed_ident), - Style::Tuple => quote!(#transformed_ident( #(#nested_assignments)* )), - Style::Struct => quote!(#transformed_ident { #(#nested_assignments)* }), + Style::Unit => quote!(#has_nested_view_ident), + Style::Tuple => quote!(#has_nested_view_ident( #(#nested_assignments)* )), + Style::Struct => quote!(#has_nested_view_ident { #(#nested_assignments)* }), + }; + + let save_key_assignments = nested_fields.iter().enumerate().map(|(i, f)| { + field_assign( + Some("e!{ self }), + i, + f, + |ty, val| quote! { <#ty as #substrate::simulation::data::Save<__substrate_S, __substrate_A>>::save(#val, ctx, opts) }, + ) + }); + let save_key_retval = match nested_fields.style { + Style::Unit => quote!(#save_key_ident), + Style::Tuple => quote!(#save_key_ident( #(#save_key_assignments)* )), + Style::Struct => quote!(#save_key_ident { #(#save_key_assignments)* }), + }; + let save_assignments = nested_fields.iter().enumerate().map(|(i, f)| { + field_assign( + Some("e!{ key }), + i, + f, + |ty, val| quote! { <#ty as #substrate::simulation::data::Save<__substrate_S, __substrate_A>>::from_saved(output, #val) }, + ) + }); + let save_retval = match nested_fields.style { + Style::Unit => quote!(#save_ident), + Style::Tuple => quote!(#save_ident( #(#save_assignments)* )), + Style::Struct => quote!(#save_ident { #(#save_assignments)* }), }; quote! { #(#attrs)* - #vis struct #transformed_ident #generics #body + #vis struct #has_nested_view_ident #generics #nested_view_body + #(#attrs)* + #vis struct #save_key_ident #save_generics #save_where_clause #save_key_body + #(#attrs)* + #vis struct #save_ident #save_generics #save_where_clause #save_body - impl #imp #substrate::schematic::HasNestedView for #ident #ty #wher { - type NestedView = #transformed_ident #ty; + impl #hnv_imp #substrate::schematic::HasNestedView for #ident #hnv_ty #hnv_wher { + type NestedView = #has_nested_view_ident #hnv_ty; fn nested_view( &self, @@ -198,8 +290,8 @@ impl ToTokens for DataInputReceiver { #retval } } - impl #imp #substrate::schematic::HasNestedView for #transformed_ident #ty #wher { - type NestedView = #transformed_ident #ty; + impl #hnv_imp #substrate::schematic::HasNestedView for #has_nested_view_ident #hnv_ty #hnv_wher { + type NestedView = #has_nested_view_ident #hnv_ty; fn nested_view( &self, @@ -208,9 +300,43 @@ impl ToTokens for DataInputReceiver { #nested_retval } } + impl #save_imp #substrate::simulation::data::Save<__substrate_S, __substrate_A> for #has_nested_view_ident #hnv_ty #save_wher { + type SaveKey = #save_key_ident #save_ty; + type Save = #save_ident #save_ty; + + fn save( + &self, + ctx: &#substrate::simulation::SimulationContext<__substrate_S>, + opts: &mut <__substrate_S as #substrate::simulation::Simulator>::Options, + ) -> >::SaveKey { + #save_key_retval + } + + fn from_saved( + output: &<__substrate_A as #substrate::simulation::Analysis>::Output, + key: &>::SaveKey, + ) -> >::Save { + #save_retval + } + } } } ast::Data::Enum(ref variants) => { + let mut save_generics = save_generics.clone(); + let mut save_where_clause = + save_generics.where_clause.clone().unwrap_or(WhereClause { + where_token: Where { + span: Span::call_site(), + }, + predicates: Default::default(), + }); + for v in variants.iter() { + for f in v.fields.iter() { + let ty = &f.ty; + save_where_clause.predicates.push(parse_quote!(<#ty as #substrate::schematic::HasNestedView>::NestedView: #substrate::simulation::data::Save<__substrate_S, __substrate_A>)); + } + } + let mut nested_variants = (*variants).clone(); nested_variants.iter_mut().for_each(|v| { v.fields = v.fields.clone().map(|mut f| { @@ -220,20 +346,58 @@ impl ToTokens for DataInputReceiver { f }); }); - let decls = variants.iter().map(transform_variant_decl); - let arms = variants - .iter() - .map(|v| transform_variant_match_arm(transformed_ident.clone(), v)); - let nested_arms = nested_variants - .iter() - .map(|v| transform_variant_match_arm(transformed_ident.clone(), v)); + let mut save_key_variants = nested_variants.clone(); + save_key_variants.iter_mut().for_each(|v| { + v.fields = v.fields.clone().map(|mut f| { + let ty = f.ty.clone(); + f.ty = + parse_quote!(<#ty as #substrate::simulation::data::Save<__substrate_S, __substrate_A>>::SaveKey); + f + }); + }); + let mut save_variants = nested_variants.clone(); + save_variants.iter_mut().for_each(|v| { + v.fields = v.fields.clone().map(|mut f| { + let ty = f.ty.clone(); + f.ty = + parse_quote!(<#ty as #substrate::simulation::data::Save<__substrate_S, __substrate_A>>::Save); + f + }); + }); + + let nested_view_decls = variants.iter().map(variant_decl); + let save_key_decls = variants.iter().map(variant_decl); + let save_decls = variants.iter().map(variant_decl); + let arms = variants.iter().map(|v| { + variant_match_arm( + has_nested_view_ident.clone(), + v, + |ty, val| quote! { <#ty as #substrate::schematic::HasNestedView>::nested_view(#val, __substrate_derive_parent) }, + ) + }); + let nested_arms = nested_variants.iter().map(|v| { + variant_match_arm( + has_nested_view_ident.clone(), + v, + |ty, val| quote! { <#ty as #substrate::schematic::HasNestedView>::nested_view(#val, __substrate_derive_parent) }, + ) + }); quote! { #(#attrs)* - #vis enum #transformed_ident #generics { - #( #decls )* + #vis enum #has_nested_view_ident #generics { + #( #nested_view_decls )* + } + #(#attrs)* + #vis enum #save_key_ident #save_generics #save_where_clause { + #( #save_key_decls )* } - impl #imp #substrate::schematic::HasNestedView for #ident #ty #wher { - type NestedView = #transformed_ident #ty; + #(#attrs)* + #vis enum #save_key_ident #save_generics #save_where_clause { + #( #save_decls )* + } + + impl #hnv_imp #substrate::schematic::HasNestedView for #ident #hnv_ty #hnv_wher { + type NestedView = #has_nested_view_ident #hnv_ty; fn nested_view( &self, @@ -244,8 +408,8 @@ impl ToTokens for DataInputReceiver { } } } - impl #imp #substrate::schematic::HasNestedView for #transformed_ident #ty #wher { - type NestedView = #transformed_ident #ty; + impl #hnv_imp #substrate::schematic::HasNestedView for #has_nested_view_ident #hnv_ty #hnv_wher { + type NestedView = #has_nested_view_ident #hnv_ty; fn nested_view( &self, diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index 953c049e..f368e4f9 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -39,7 +39,5 @@ splines = { version = "4.3.1", features = ["serde"] } [dev-dependencies] toml = "0.8" -# TODO: use one or the other approx = "0.5" -float_eq = "1.0.1" spice = { version = "<=0.7.1", registry = "substrate", path = "../libs/spice" } diff --git a/substrate/src/block.rs b/substrate/src/block.rs index 8cd2efb0..049762cb 100644 --- a/substrate/src/block.rs +++ b/substrate/src/block.rs @@ -6,8 +6,6 @@ use std::sync::Arc; use arcstr::ArcStr; pub use codegen::Block; -use serde::de::DeserializeOwned; -use serde::Serialize; use crate::types::Io; @@ -16,7 +14,7 @@ use crate::types::Io; /// # Examples /// #[doc = examples::get_snippets!("core", "inverter")] -pub trait Block: Serialize + DeserializeOwned + Hash + Eq + Send + Sync + Any { +pub trait Block: Hash + Eq + Send + Sync + Any { /// The ports of this block. type Io: Io; diff --git a/substrate/src/schematic/mod.rs b/substrate/src/schematic/mod.rs index a9c374d1..2df9cafe 100644 --- a/substrate/src/schematic/mod.rs +++ b/substrate/src/schematic/mod.rs @@ -65,8 +65,7 @@ impl Schematic for Arc { /// Block that implements [`Schematic`] in schema `S` for block `B`. #[derive_where::derive_where(Debug, Hash, PartialEq, Eq; B)] -#[derive(Serialize, Deserialize)] -pub struct ConvertSchema(Arc, #[serde(bound(deserialize = ""))] PhantomData); +pub struct ConvertSchema(Arc, PhantomData); impl Clone for ConvertSchema { fn clone(&self) -> Self { @@ -1651,7 +1650,7 @@ mod tests { pub n: InOut, } - #[derive(Serialize, Deserialize, Block, Debug, Copy, Clone, Hash, PartialEq, Eq)] + #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)] #[substrate(io = "ResistorIo")] pub struct Resistor; @@ -1701,7 +1700,7 @@ mod tests { pub data: Output>, } - #[derive(Serialize, Deserialize, Debug, Copy, Clone, Hash, PartialEq, Eq)] + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct MultiDecoupledBlock; impl Block for MultiDecoupledBlock { @@ -1746,7 +1745,7 @@ mod tests { } } - #[derive(Serialize, Deserialize, Block, Debug, Copy, Clone, Hash, PartialEq, Eq)] + #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)] #[substrate(io = "()")] pub struct SuperBlock; @@ -1795,7 +1794,7 @@ mod tests { } } - #[derive(Serialize, Deserialize, Block, Debug, Copy, Clone, Hash, PartialEq, Eq)] + #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)] #[substrate(io = "()")] pub struct NestedBlock(T); @@ -1822,7 +1821,7 @@ mod tests { pub dout: Output, } - #[derive(Serialize, Deserialize, Block, Debug, Copy, Clone, Hash, PartialEq, Eq)] + #[derive(Block, Debug, Copy, Clone, Hash, PartialEq, Eq)] #[substrate(io = "VdividerIo")] pub struct Vdivider; diff --git a/substrate/src/simulation/data.rs b/substrate/src/simulation/data.rs index 5713f4cc..03558196 100644 --- a/substrate/src/simulation/data.rs +++ b/substrate/src/simulation/data.rs @@ -2,9 +2,30 @@ pub use codegen::FromSaved; -use crate::schematic::Schematic; +use crate::schematic::{HasNestedView, Schematic}; use crate::simulation::{Analysis, SimulationContext, Simulator}; +#[derive(Debug, Clone, Copy)] +pub struct SaveOutput; +#[derive(Debug, Clone, Copy)] +pub struct SaveTime; + +impl HasNestedView for SaveOutput { + type NestedView = SaveOutput; + + fn nested_view(&self, _parent: &substrate::schematic::InstancePath) -> Self::NestedView { + *self + } +} + +impl HasNestedView for SaveTime { + type NestedView = SaveTime; + + fn nested_view(&self, _parent: &substrate::schematic::InstancePath) -> Self::NestedView { + *self + } +} + /// Gets the [`Save::SaveKey`] corresponding to type `T`. pub type SaveKey = >::SaveKey; @@ -13,11 +34,11 @@ pub type SaveKey = >::SaveKey; /// `T` is any type that can be used as arguments for deciding what should be saved in /// this simulation output. pub trait Save { - type Save; /// The key type used to address the saved output within the analysis. /// /// This key is assigned in [`Save::save`]. type SaveKey; + type Save; /// Marks the given output for saving, returning a key that can be used to recover /// the output once the simulation is complete. @@ -33,84 +54,3 @@ pub trait Save { key: &>::SaveKey, ) -> >::Save; } - -/// Transient data definitions. -pub mod tran { - use serde::{Deserialize, Serialize}; - use std::ops::Deref; - use std::sync::Arc; - - /// A time-series of voltage measurements from a transient simulation. - #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] - pub struct Voltage(pub Arc>); - - impl Deref for Voltage { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - /// A time-series of current measurements from a transient simulation. - #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] - pub struct Current(pub Arc>); - - impl Deref for Current { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - /// The time points associated with a transient simulation. - #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] - pub struct Time(pub Arc>); - - impl Deref for Time { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } - } -} - -/// AC data definitions. -pub mod ac { - use num::complex::Complex64; - use serde::{Deserialize, Serialize}; - use std::ops::Deref; - use std::sync::Arc; - - /// A series of voltage vs frequency measurements from an AC simulation. - #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] - pub struct Voltage(pub Arc>); - - impl Deref for Voltage { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - /// A series of current vs frequency measurements from an AC simulation. - #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] - pub struct Current(pub Arc>); - - impl Deref for Current { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - /// The frequency points associated with an AC simulation. - #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] - pub struct Freq(pub Arc>); - - impl Deref for Freq { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } - } -} diff --git a/substrate/src/simulation/mod.rs b/substrate/src/simulation/mod.rs index c00eedd7..9e5f1472 100644 --- a/substrate/src/simulation/mod.rs +++ b/substrate/src/simulation/mod.rs @@ -6,8 +6,6 @@ use std::sync::Arc; use data::Save; use impl_trait_for_tuples::impl_for_tuples; -use serde::de::DeserializeOwned; -use serde::Serialize; use crate::block::Block; use crate::context::{Context, Installation}; diff --git a/tools/spectre/Cargo.toml b/tools/spectre/Cargo.toml index f73736a5..0b2e67c0 100644 --- a/tools/spectre/Cargo.toml +++ b/tools/spectre/Cargo.toml @@ -22,3 +22,5 @@ spice = { version = "0.7.1", registry = "substrate", path = "../../libs/spice" } regex = "1.10.2" num = { version = "0.4.1", features = ["serde"] } +[dev-dependencies] +approx = "0.5" diff --git a/tools/spectre/src/analysis/ac.rs b/tools/spectre/src/analysis/ac.rs index a33ce561..3652546b 100644 --- a/tools/spectre/src/analysis/ac.rs +++ b/tools/spectre/src/analysis/ac.rs @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::sync::Arc; use substrate::schematic::conv::ConvertedNodePath; -use substrate::simulation::data::{ac, FromSaved, Save}; +use substrate::simulation::data::Save; use substrate::simulation::{Analysis, SimulationContext, Simulator, SupportedBy}; use substrate::type_dispatch::impl_dispatch; use substrate::types::schematic::{NestedNode, NestedTerminal, NodePath, TerminalPath}; @@ -53,246 +53,246 @@ pub struct Output { pub(crate) saved_values: HashMap, } -impl FromSaved for Output { - type SavedKey = (); - - fn from_saved(output: &::Output, _key: &Self::SavedKey) -> Self { - (*output).clone() - } -} - -impl Save for Output { - fn save( - _ctx: &SimulationContext, - _to_save: (), - _opts: &mut ::Options, - ) -> Self::SavedKey { - } -} - -impl FromSaved for ac::Freq { - type SavedKey = (); - fn from_saved(output: &::Output, _key: &Self::SavedKey) -> Self { - ac::Freq(output.freq.clone()) - } -} - -impl Save for ac::Freq { - fn save( - _ctx: &SimulationContext, - _to_save: (), - _opts: &mut ::Options, - ) -> Self::SavedKey { - } -} +// impl FromSaved for Output { +// type SavedKey = (); +// +// fn from_saved(output: &::Output, _key: &Self::SavedKey) -> Self { +// (*output).clone() +// } +// } +// +// impl Save for Output { +// fn save( +// _ctx: &SimulationContext, +// _to_save: (), +// _opts: &mut ::Options, +// ) -> Self::SavedKey { +// } +// } +// +// impl FromSaved for ac::Freq { +// type SavedKey = (); +// fn from_saved(output: &::Output, _key: &Self::SavedKey) -> Self { +// ac::Freq(output.freq.clone()) +// } +// } +// +// impl Save for ac::Freq { +// fn save( +// _ctx: &SimulationContext, +// _to_save: (), +// _opts: &mut ::Options, +// ) -> Self::SavedKey { +// } +// } /// An identifier for a saved AC voltage. #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)] -pub struct VoltageSavedKey(pub(crate) u64); - -impl FromSaved for ac::Voltage { - type SavedKey = VoltageSavedKey; - fn from_saved(output: &::Output, key: &Self::SavedKey) -> Self { - ac::Voltage( - output - .raw_values - .get(output.saved_values.get(&key.0).unwrap()) - .unwrap() - .clone(), - ) - } -} - -#[impl_dispatch({&str; &String; ArcStr; String; SimSignal})] -impl Save for ac::Voltage { - fn save( - _ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> Self::SavedKey { - opts.save_ac_voltage(to_save) - } -} - -impl Save for ac::Voltage { - fn save( - _ctx: &SimulationContext, - to_save: &SliceOnePath, - opts: &mut ::Options, - ) -> Self::SavedKey { - opts.save_ac_voltage(SimSignal::ScirVoltage(to_save.clone())) - } -} - -impl Save for ac::Voltage { - fn save( - ctx: &SimulationContext, - to_save: &ConvertedNodePath, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save( - ctx, - match to_save { - ConvertedNodePath::Cell(path) => path.clone(), - ConvertedNodePath::Primitive { - instances, port, .. - } => SliceOnePath::new(instances.clone(), NamedSliceOne::new(port.clone())), - }, - opts, - ) - } -} - -impl Save for ac::Voltage { - fn save( - ctx: &SimulationContext, - to_save: &NodePath, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save(ctx, ctx.lib.convert_node_path(to_save).unwrap(), opts) - } -} - -#[impl_dispatch({SliceOnePath; ConvertedNodePath; NodePath})] -impl Save for ac::Voltage { - fn save( - ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save(ctx, &to_save, opts) - } -} +pub struct VoltageSaveKey(pub(crate) u64); -#[impl_dispatch({NestedNode; &NestedNode; NestedTerminal; &NestedTerminal})] -impl Save for ac::Voltage { - fn save( - ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save(ctx, to_save.path(), opts) - } -} - -#[impl_dispatch({TerminalPath; &TerminalPath})] -impl Save for ac::Voltage { - fn save( - ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save(ctx, to_save.as_ref(), opts) - } -} +// impl FromSaved for ac::Voltage { +// type SavedKey = VoltageSavedKey; +// fn from_saved(output: &::Output, key: &Self::SavedKey) -> Self { +// ac::Voltage( +// output +// .raw_values +// .get(output.saved_values.get(&key.0).unwrap()) +// .unwrap() +// .clone(), +// ) +// } +// } +// +// #[impl_dispatch({&str; &String; ArcStr; String; SimSignal})] +// impl Save for ac::Voltage { +// fn save( +// _ctx: &SimulationContext, +// to_save: T, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// opts.save_ac_voltage(to_save) +// } +// } +// +// impl Save for ac::Voltage { +// fn save( +// _ctx: &SimulationContext, +// to_save: &SliceOnePath, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// opts.save_ac_voltage(SimSignal::ScirVoltage(to_save.clone())) +// } +// } +// +// impl Save for ac::Voltage { +// fn save( +// ctx: &SimulationContext, +// to_save: &ConvertedNodePath, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// Self::save( +// ctx, +// match to_save { +// ConvertedNodePath::Cell(path) => path.clone(), +// ConvertedNodePath::Primitive { +// instances, port, .. +// } => SliceOnePath::new(instances.clone(), NamedSliceOne::new(port.clone())), +// }, +// opts, +// ) +// } +// } +// +// impl Save for ac::Voltage { +// fn save( +// ctx: &SimulationContext, +// to_save: &NodePath, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// Self::save(ctx, ctx.lib.convert_node_path(to_save).unwrap(), opts) +// } +// } +// +// #[impl_dispatch({SliceOnePath; ConvertedNodePath; NodePath})] +// impl Save for ac::Voltage { +// fn save( +// ctx: &SimulationContext, +// to_save: T, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// Self::save(ctx, &to_save, opts) +// } +// } +// +// #[impl_dispatch({NestedNode; &NestedNode; NestedTerminal; &NestedTerminal})] +// impl Save for ac::Voltage { +// fn save( +// ctx: &SimulationContext, +// to_save: T, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// Self::save(ctx, to_save.path(), opts) +// } +// } +// +// #[impl_dispatch({TerminalPath; &TerminalPath})] +// impl Save for ac::Voltage { +// fn save( +// ctx: &SimulationContext, +// to_save: T, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// Self::save(ctx, to_save.as_ref(), opts) +// } +// } /// An identifier for a saved AC current. #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] -pub struct CurrentSavedKey(pub(crate) Vec); - -impl FromSaved for ac::Current { - type SavedKey = CurrentSavedKey; - fn from_saved(output: &::Output, key: &Self::SavedKey) -> Self { - let currents: Vec>> = key - .0 - .iter() - .map(|key| { - output - .raw_values - .get(output.saved_values.get(key).unwrap()) - .unwrap() - .clone() - }) - .collect(); - - let mut total_current = vec![Complex64::zero(); output.freq.len()]; - for ac_current in currents { - for (i, current) in ac_current.iter().enumerate() { - total_current[i] += *current; - } - } - ac::Current(Arc::new(total_current)) - } -} - -#[impl_dispatch({&str; &String; ArcStr; String; SimSignal})] -impl Save for ac::Current { - fn save( - _ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> Self::SavedKey { - opts.save_ac_current(to_save) - } -} +pub struct CurrentSaveKey(pub(crate) Vec); -impl Save for ac::Current { - fn save( - _ctx: &SimulationContext, - to_save: &SliceOnePath, - opts: &mut ::Options, - ) -> Self::SavedKey { - opts.save_ac_current(SimSignal::ScirCurrent(to_save.clone())) - } -} - -impl Save for ac::Current { - fn save( - ctx: &SimulationContext, - to_save: &ConvertedNodePath, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save( - ctx, - match to_save { - ConvertedNodePath::Cell(path) => path.clone(), - ConvertedNodePath::Primitive { - instances, port, .. - } => SliceOnePath::new(instances.clone(), NamedSliceOne::new(port.clone())), - }, - opts, - ) - } -} - -impl Save for ac::Current { - fn save( - ctx: &SimulationContext, - to_save: &TerminalPath, - opts: &mut ::Options, - ) -> Self::SavedKey { - CurrentSavedKey( - ctx.lib - .convert_terminal_path(to_save) - .unwrap() - .into_iter() - .flat_map(|path| Self::save(ctx, path, opts).0) - .collect(), - ) - } -} - -#[impl_dispatch({SliceOnePath; ConvertedNodePath; TerminalPath})] -impl Save for ac::Current { - fn save( - ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save(ctx, &to_save, opts) - } -} - -#[impl_dispatch({NestedTerminal; &NestedTerminal})] -impl Save for ac::Current { - fn save( - ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save(ctx, to_save.path(), opts) - } -} +// impl FromSaved for ac::Current { +// type SavedKey = CurrentSavedKey; +// fn from_saved(output: &::Output, key: &Self::SavedKey) -> Self { +// let currents: Vec>> = key +// .0 +// .iter() +// .map(|key| { +// output +// .raw_values +// .get(output.saved_values.get(key).unwrap()) +// .unwrap() +// .clone() +// }) +// .collect(); +// +// let mut total_current = vec![Complex64::zero(); output.freq.len()]; +// for ac_current in currents { +// for (i, current) in ac_current.iter().enumerate() { +// total_current[i] += *current; +// } +// } +// ac::Current(Arc::new(total_current)) +// } +// } +// +// #[impl_dispatch({&str; &String; ArcStr; String; SimSignal})] +// impl Save for ac::Current { +// fn save( +// _ctx: &SimulationContext, +// to_save: T, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// opts.save_ac_current(to_save) +// } +// } +// +// impl Save for ac::Current { +// fn save( +// _ctx: &SimulationContext, +// to_save: &SliceOnePath, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// opts.save_ac_current(SimSignal::ScirCurrent(to_save.clone())) +// } +// } +// +// impl Save for ac::Current { +// fn save( +// ctx: &SimulationContext, +// to_save: &ConvertedNodePath, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// Self::save( +// ctx, +// match to_save { +// ConvertedNodePath::Cell(path) => path.clone(), +// ConvertedNodePath::Primitive { +// instances, port, .. +// } => SliceOnePath::new(instances.clone(), NamedSliceOne::new(port.clone())), +// }, +// opts, +// ) +// } +// } +// +// impl Save for ac::Current { +// fn save( +// ctx: &SimulationContext, +// to_save: &TerminalPath, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// CurrentSavedKey( +// ctx.lib +// .convert_terminal_path(to_save) +// .unwrap() +// .into_iter() +// .flat_map(|path| Self::save(ctx, path, opts).0) +// .collect(), +// ) +// } +// } +// +// #[impl_dispatch({SliceOnePath; ConvertedNodePath; TerminalPath})] +// impl Save for ac::Current { +// fn save( +// ctx: &SimulationContext, +// to_save: T, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// Self::save(ctx, &to_save, opts) +// } +// } +// +// #[impl_dispatch({NestedTerminal; &NestedTerminal})] +// impl Save for ac::Current { +// fn save( +// ctx: &SimulationContext, +// to_save: T, +// opts: &mut ::Options, +// ) -> Self::SavedKey { +// Self::save(ctx, to_save.path(), opts) +// } +// } impl Analysis for Ac { type Output = Output; diff --git a/tools/spectre/src/analysis/montecarlo.rs b/tools/spectre/src/analysis/montecarlo.rs index 43e988df..eb96e33a 100644 --- a/tools/spectre/src/analysis/montecarlo.rs +++ b/tools/spectre/src/analysis/montecarlo.rs @@ -82,32 +82,32 @@ impl> From> for MonteCarlo> { } } -impl> FromSaved> for Output { - type SavedKey = T::SavedKey; - - fn from_saved(output: & as Analysis>::Output, key: &Self::SavedKey) -> Self { - Output( - output - .0 - .iter() - .map(|output| T::from_saved(output, key)) - .collect(), - ) - } -} - -impl, T, S> Save, T> for Output -where - S: Save, -{ - fn save( - ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> >>::SavedKey { - S::save(ctx, to_save, opts) - } -} +// impl> FromSaved> for Output { +// type SavedKey = T::SavedKey; +// +// fn from_saved(output: & as Analysis>::Output, key: &Self::SavedKey) -> Self { +// Output( +// output +// .0 +// .iter() +// .map(|output| T::from_saved(output, key)) +// .collect(), +// ) +// } +// } +// +// impl, T, S> Save, T> for Output +// where +// S: Save, +// { +// fn save( +// ctx: &SimulationContext, +// to_save: T, +// opts: &mut ::Options, +// ) -> >>::SavedKey { +// S::save(ctx, to_save, opts) +// } +// } impl Analysis for MonteCarlo { type Output = Output; diff --git a/tools/spectre/src/analysis/tran.rs b/tools/spectre/src/analysis/tran.rs index 5c768fbe..009db06d 100644 --- a/tools/spectre/src/analysis/tran.rs +++ b/tools/spectre/src/analysis/tran.rs @@ -9,10 +9,11 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::sync::Arc; use substrate::schematic::conv::ConvertedNodePath; -use substrate::simulation::data::{tran, FromSaved, Save}; +use substrate::schematic::HasNestedView; +use substrate::simulation::data::{Save, SaveOutput, SaveTime}; use substrate::simulation::{Analysis, SimulationContext, Simulator, SupportedBy}; use substrate::type_dispatch::impl_dispatch; -use substrate::types::schematic::{NestedNode, NestedTerminal, NodePath, TerminalPath}; +use substrate::types::schematic::{NestedNode, NestedTerminal, Node, NodePath, TerminalPath}; /// A transient analysis. #[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize)] @@ -49,165 +50,161 @@ pub struct Output { pub(crate) saved_values: HashMap, } -impl FromSaved for Output { - type SavedKey = (); +impl Save for SaveOutput { + type SaveKey = (); + type Save = Output; - fn from_saved(output: &::Output, _key: &Self::SavedKey) -> Self { - (*output).clone() - } -} - -impl Save for Output { fn save( + &self, _ctx: &SimulationContext, - _to_save: (), _opts: &mut ::Options, - ) -> Self::SavedKey { + ) -> >::SaveKey { } -} - -impl FromSaved for tran::Time { - type SavedKey = (); - fn from_saved(output: &::Output, _key: &Self::SavedKey) -> Self { - tran::Time(output.time.clone()) - } -} - -impl Save for tran::Time { - fn save( - _ctx: &SimulationContext, - _to_save: (), - _opts: &mut ::Options, - ) -> Self::SavedKey { - } -} -/// An identifier for a saved transient voltage. -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)] -pub struct VoltageSavedKey(pub(crate) u64); - -impl FromSaved for tran::Voltage { - type SavedKey = VoltageSavedKey; - fn from_saved(output: &::Output, key: &Self::SavedKey) -> Self { - tran::Voltage( - output - .raw_values - .get(output.saved_values.get(&key.0).unwrap()) - .unwrap() - .clone(), - ) + fn from_saved( + output: &::Output, + _key: &>::SaveKey, + ) -> >::Save { + output.clone() } } -#[impl_dispatch({&str; &String; ArcStr; String; SimSignal})] -impl Save for tran::Voltage { - fn save( - _ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> Self::SavedKey { - opts.save_tran_voltage(to_save) - } -} +impl Save for SaveTime { + type SaveKey = (); + type Save = Arc>; -impl Save for tran::Voltage { fn save( + &self, ctx: &SimulationContext, - to_save: DspfNode, opts: &mut ::Options, - ) -> >::SavedKey { - let itail = InstanceTail { - instance: ctx - .lib - .convert_instance_path(&to_save.dspf_instance) - .unwrap(), - tail: to_save.path.into(), - }; - opts.save_tran_voltage(itail) + ) -> >::SaveKey { } -} -impl Save for tran::Voltage { - fn save( - _ctx: &SimulationContext, - to_save: &SliceOnePath, - opts: &mut ::Options, - ) -> Self::SavedKey { - opts.save_tran_voltage(SimSignal::ScirVoltage(to_save.clone())) + fn from_saved( + output: &::Output, + key: &>::SaveKey, + ) -> >::Save { + output.time.clone() } } -impl Save for tran::Voltage { +/// An identifier for a saved transient voltage. +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub struct VoltageSaveKey(pub(crate) u64); + +impl Save for NestedNode { + type SaveKey = VoltageSaveKey; + type Save = Arc>; + fn save( + &self, ctx: &SimulationContext, - to_save: &ConvertedNodePath, opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save( - ctx, - match to_save { + ) -> >::SaveKey { + opts.save_tran_voltage(SimSignal::ScirVoltage( + match ctx.lib.convert_node_path(&self.path()).unwrap() { ConvertedNodePath::Cell(path) => path.clone(), ConvertedNodePath::Primitive { instances, port, .. } => SliceOnePath::new(instances.clone(), NamedSliceOne::new(port.clone())), }, - opts, - ) + )) } -} -impl Save for tran::Voltage { - fn save( - ctx: &SimulationContext, - to_save: &NodePath, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save(ctx, ctx.lib.convert_node_path(to_save).unwrap(), opts) + fn from_saved( + output: &::Output, + key: &>::SaveKey, + ) -> >::Save { + output + .raw_values + .get(output.saved_values.get(&key.0).unwrap()) + .unwrap() + .clone() } } -#[impl_dispatch({SliceOnePath; ConvertedNodePath; NodePath})] -impl Save for tran::Voltage { +impl Save for DspfNode { + type SaveKey = VoltageSaveKey; + type Save = Arc>; + fn save( + &self, ctx: &SimulationContext, - to_save: T, opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save(ctx, &to_save, opts) + ) -> >::SaveKey { + let itail = InstanceTail { + instance: ctx.lib.convert_instance_path(&self.dspf_instance).unwrap(), + tail: self.path.clone().into(), + }; + opts.save_tran_voltage(itail) } -} -#[impl_dispatch({NestedNode; &NestedNode; NestedTerminal; &NestedTerminal})] -impl Save for tran::Voltage { - fn save( - ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save(ctx, to_save.path(), opts) + fn from_saved( + output: &::Output, + key: &>::SaveKey, + ) -> >::Save { + output + .raw_values + .get(output.saved_values.get(&key.0).unwrap()) + .unwrap() + .clone() } } -#[impl_dispatch({TerminalPath; &TerminalPath})] -impl Save for tran::Voltage { +/// An identifier for a saved transient current. +#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub struct CurrentSaveKey(pub(crate) Vec); + +pub struct NestedTerminalOutput { + v: Arc>, + i: Arc>, +} + +impl Save for NestedTerminal { + type SaveKey = (VoltageSaveKey, CurrentSaveKey); + type Save = NestedTerminalOutput; + fn save( + &self, ctx: &SimulationContext, - to_save: T, opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save(ctx, to_save.as_ref(), opts) + ) -> >::SaveKey { + ( + >::save(&*self, ctx, opts), + CurrentSaveKey( + ctx.lib + .convert_terminal_path(&self.path()) + .unwrap() + .into_iter() + .flat_map(|path| { + opts.save_tran_current(SimSignal::ScirCurrent(match path { + ConvertedNodePath::Cell(path) => path.clone(), + ConvertedNodePath::Primitive { + instances, port, .. + } => SliceOnePath::new( + instances.clone(), + NamedSliceOne::new(port.clone()), + ), + })) + .0 + }) + .collect(), + ), + ) } -} - -/// An identifier for a saved transient current. -#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] -pub struct CurrentSavedKey(pub(crate) Vec); -impl FromSaved for tran::Current { - type SavedKey = CurrentSavedKey; - fn from_saved(output: &::Output, key: &Self::SavedKey) -> Self { + fn from_saved( + output: &::Output, + key: &>::SaveKey, + ) -> >::Save { + let v = output + .raw_values + .get(output.saved_values.get(&key.0 .0).unwrap()) + .unwrap() + .clone(); let currents: Vec>> = key - .0 + .1 + .0 .iter() .map(|key| { output @@ -224,86 +221,10 @@ impl FromSaved for tran::Current { total_current[i] += *current; } } - tran::Current(Arc::new(total_current)) - } -} - -#[impl_dispatch({&str; &String; ArcStr; String; SimSignal})] -impl Save for tran::Current { - fn save( - _ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> Self::SavedKey { - opts.save_tran_current(to_save) - } -} - -impl Save for tran::Current { - fn save( - _ctx: &SimulationContext, - to_save: &SliceOnePath, - opts: &mut ::Options, - ) -> Self::SavedKey { - opts.save_tran_current(SimSignal::ScirCurrent(to_save.clone())) - } -} - -impl Save for tran::Current { - fn save( - ctx: &SimulationContext, - to_save: &ConvertedNodePath, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save( - ctx, - match to_save { - ConvertedNodePath::Cell(path) => path.clone(), - ConvertedNodePath::Primitive { - instances, port, .. - } => SliceOnePath::new(instances.clone(), NamedSliceOne::new(port.clone())), - }, - opts, - ) - } -} - -impl Save for tran::Current { - fn save( - ctx: &SimulationContext, - to_save: &TerminalPath, - opts: &mut ::Options, - ) -> Self::SavedKey { - CurrentSavedKey( - ctx.lib - .convert_terminal_path(to_save) - .unwrap() - .into_iter() - .flat_map(|path| Self::save(ctx, path, opts).0) - .collect(), - ) - } -} - -#[impl_dispatch({SliceOnePath; ConvertedNodePath; TerminalPath})] -impl Save for tran::Current { - fn save( - ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save(ctx, &to_save, opts) - } -} - -#[impl_dispatch({NestedTerminal; &NestedTerminal})] -impl Save for tran::Current { - fn save( - ctx: &SimulationContext, - to_save: T, - opts: &mut ::Options, - ) -> Self::SavedKey { - Self::save(ctx, to_save.path(), opts) + NestedTerminalOutput { + v, + i: Arc::new(total_current), + } } } diff --git a/tools/spectre/src/lib.rs b/tools/spectre/src/lib.rs index c61ef43c..6e2e36a4 100644 --- a/tools/spectre/src/lib.rs +++ b/tools/spectre/src/lib.rs @@ -262,23 +262,23 @@ impl Options { } /// Marks a transient voltage to be saved in all transient analyses. - pub fn save_tran_voltage(&mut self, save: impl Into) -> tran::VoltageSavedKey { - tran::VoltageSavedKey(self.save_inner(save)) + pub fn save_tran_voltage(&mut self, save: impl Into) -> tran::VoltageSaveKey { + tran::VoltageSaveKey(self.save_inner(save)) } /// Marks a transient current to be saved in all transient analyses. - pub fn save_tran_current(&mut self, save: impl Into) -> tran::CurrentSavedKey { - tran::CurrentSavedKey(vec![self.save_inner(save)]) + pub fn save_tran_current(&mut self, save: impl Into) -> tran::CurrentSaveKey { + tran::CurrentSaveKey(vec![self.save_inner(save)]) } /// Marks an AC voltage to be saved in all AC analyses. - pub fn save_ac_voltage(&mut self, save: impl Into) -> ac::VoltageSavedKey { - ac::VoltageSavedKey(self.save_inner(save)) + pub fn save_ac_voltage(&mut self, save: impl Into) -> ac::VoltageSaveKey { + ac::VoltageSaveKey(self.save_inner(save)) } /// Marks an AC current to be saved in all AC analyses. - pub fn save_ac_current(&mut self, save: impl Into) -> ac::CurrentSavedKey { - ac::CurrentSavedKey(vec![self.save_inner(save)]) + pub fn save_ac_current(&mut self, save: impl Into) -> ac::CurrentSaveKey { + ac::CurrentSaveKey(vec![self.save_inner(save)]) } /// Set the simulation temperature. @@ -1135,3 +1135,138 @@ impl HasSpiceLikeNetlist for Spectre { Ok(()) } } + +#[cfg(test)] +mod tests { + use std::{path::PathBuf, sync::Arc}; + + use approx::assert_relative_eq; + use rust_decimal_macros::dec; + use spice::{BlackboxContents, BlackboxElement}; + use substrate::{ + block::Block, + context::Context, + schematic::{CellBuilder, NestedData, PrimitiveBinding, Schematic}, + simulation::{data::Save, Analysis, SimController, Simulator}, + types::{ + schematic::{IoBundle, NestedNode, Node}, + InOut, Io, Signal, TestbenchIo, + }, + }; + + use crate::{ + analysis::tran::Tran, + blocks::{Resistor, Vsource}, + ErrPreset, Options, Primitive, Spectre, + }; + + pub const BUILD_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/build"); + pub const TEST_DATA_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../tests/data"); + + #[test] + fn spectre_can_include_sections() { + #[derive(Default, Clone, Io)] + struct LibIncludeResistorIo { + p: InOut, + n: InOut, + } + + #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Block)] + #[substrate(io = "LibIncludeResistorIo")] + struct LibIncludeResistor; + + impl Schematic for LibIncludeResistor { + type Schema = Spectre; + type NestedData = (); + fn schematic( + &self, + io: &IoBundle, + cell: &mut CellBuilder, + ) -> substrate::error::Result { + let mut prim = PrimitiveBinding::new(Primitive::BlackboxInstance { + contents: BlackboxContents { + elems: vec![ + BlackboxElement::InstanceName, + " ( ".into(), + BlackboxElement::Port("p".into()), + " ".into(), + BlackboxElement::Port("n".into()), + " ) example_resistor".into(), + ], + }, + }); + prim.connect("p", io.p); + prim.connect("n", io.n); + cell.set_primitive(prim); + Ok(()) + } + } + + #[derive(Debug, Clone, Hash, Eq, PartialEq, Block)] + #[substrate(io = "TestbenchIo")] + struct LibIncludeTb(String); + + #[derive(Debug, Clone, Copy, NestedData)] + struct LibIncludeTbData { + n: Node, + } + + impl Schematic for LibIncludeTb { + type Schema = Spectre; + type NestedData = LibIncludeTbData; + fn schematic( + &self, + io: &IoBundle, + cell: &mut CellBuilder, + ) -> substrate::error::Result { + let vdd = cell.signal("vdd", Signal); + let dut = cell.instantiate(LibIncludeResistor); + let res = cell.instantiate(Resistor::new(1000)); + + cell.connect(dut.io().p, vdd); + cell.connect(dut.io().n, res.io().p); + cell.connect(io.vss, res.io().n); + + let vsource = cell.instantiate(Vsource::dc(dec!(1.8))); + cell.connect(vsource.io().p, vdd); + cell.connect(vsource.io().n, io.vss); + + Ok(LibIncludeTbData { n: *dut.io().n }) + } + } + + fn run(sim: SimController) -> f64 { + let mut opts = Options::default(); + opts.include_section( + PathBuf::from(TEST_DATA_DIR).join("spectre/example_lib.scs"), + &sim.tb.block().0, + ); + let vout = sim + .simulate( + opts, + Tran { + stop: dec!(2e-9), + errpreset: Some(ErrPreset::Conservative), + ..Default::default() + }, + ) + .expect("failed to run simulation"); + + *vout.n.first().unwrap() + } + + let test_name = "spectre_can_include_sections"; + let sim_dir = PathBuf::from(BUILD_DIR).join(test_name).join("sim/"); + let ctx = Context::builder().install(Spectre::default()).build(); + + let output_tt = run(ctx + .get_sim_controller(LibIncludeTb("section_a".to_string()), &sim_dir) + .unwrap()); + let output_ss = run(ctx + .get_sim_controller(LibIncludeTb("section_b".to_string()), sim_dir) + .unwrap()); + + assert_relative_eq!(output_tt, 0.9); + assert_relative_eq!(output_ss, 1.2); + } +}