diff --git a/libs/scir/src/drivers.rs b/libs/scir/src/drivers.rs index 1dd3bd59..fb4749f0 100644 --- a/libs/scir/src/drivers.rs +++ b/libs/scir/src/drivers.rs @@ -183,7 +183,7 @@ impl Display for Cause { } } -impl LibraryBuilder { +impl LibraryBuilder { /// Perform driver analysis on this library. pub fn validate_drivers(&self) -> IssueSet { let _guard = span!(Level::INFO, "performing driver analysis on SCIR Library").entered(); @@ -240,7 +240,7 @@ impl LibraryBuilder { } } -fn analyze_instance( +fn analyze_instance( lib: &LibraryBuilder, net_states: &mut HashMap>, inst: &Instance, diff --git a/libs/scir/src/lib.rs b/libs/scir/src/lib.rs index 8d679a01..572bee78 100644 --- a/libs/scir/src/lib.rs +++ b/libs/scir/src/lib.rs @@ -490,7 +490,7 @@ pub struct LibraryBuilder { top: Option, } -impl Default for LibraryBuilder { +impl Default for LibraryBuilder { fn default() -> Self { Self { cell_id: 0, @@ -503,7 +503,7 @@ impl Default for LibraryBuilder { } } -impl> Clone for LibraryBuilder { +impl + ?Sized> Clone for LibraryBuilder { fn clone(&self) -> Self { Self { cell_id: self.cell_id, @@ -516,7 +516,7 @@ impl> Clone for LibraryBuilder { } } -impl> std::fmt::Debug for LibraryBuilder { +impl + ?Sized> std::fmt::Debug for LibraryBuilder { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut builder = f.debug_struct("LibraryBuilder"); let _ = builder.field("cell_id", &self.cell_id); @@ -535,7 +535,7 @@ impl> std::fmt::Debug for LibraryBui /// The contents of the library cannot be mutated. pub struct Library(LibraryBuilder); -impl> std::fmt::Debug for Library { +impl + ?Sized> std::fmt::Debug for Library { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut builder = f.debug_struct("Library"); let _ = builder.field("0", &self.0); @@ -543,7 +543,7 @@ impl> std::fmt::Debug for Library } } -impl Clone for Library +impl Clone for Library where LibraryBuilder: Clone, { @@ -552,14 +552,14 @@ where } } -impl Deref for Library { +impl Deref for Library { type Target = LibraryBuilder; fn deref(&self) -> &Self::Target { &self.0 } } -impl Library { +impl Library { /// Converts a [`Library`] to a [`Library`], throwing an error if there /// are any primitives. pub fn drop_schema(self) -> Result, NoSchemaError> { @@ -570,7 +570,7 @@ impl Library { /// /// A [`LibraryBuilder`] is created to indicate that validation must be done again /// to ensure errors were not introduced during the conversion. - pub fn convert_schema(self) -> Result, C::Error> + pub fn convert_schema(self) -> Result, C::Error> where C: FromSchema, { @@ -583,7 +583,7 @@ impl Library { } } -impl> Library { +impl + ?Sized> Library { /// Creates a new SCIR library containing only the named cell and its children /// from an existing library. pub fn from_cell_named(lib: &Self, cell: &str) -> Self { @@ -833,7 +833,7 @@ impl NetlistCellConversion { } } -impl LibraryBuilder { +impl LibraryBuilder { /// Creates a new, empty library. pub fn new() -> Self { Self::default() @@ -1350,7 +1350,7 @@ impl LibraryBuilder { } } - fn convert_inner( + fn convert_inner( self, convert_primitive: fn(::Primitive) -> Result<::Primitive, E>, convert_instance: fn(&mut Instance, &::Primitive) -> Result<(), E>, @@ -1396,7 +1396,7 @@ impl LibraryBuilder { /// Converts a [`LibraryBuilder`] into a [`LibraryBuilder`]. /// /// Instances associated with non-existent primitives will remain unchanged. - pub fn convert_schema(self) -> Result, C::Error> + pub fn convert_schema(self) -> Result, C::Error> where C: FromSchema, { @@ -1404,7 +1404,7 @@ impl LibraryBuilder { } } -impl> LibraryBuilder { +impl + ?Sized> LibraryBuilder { /// Creates a new SCIR library builder containing only the named cell and its children /// from an existing library builder. pub fn from_cell_named(lib: &Self, cell: &str) -> Self { diff --git a/libs/scir/src/merge.rs b/libs/scir/src/merge.rs index 25b1c176..41ebd863 100644 --- a/libs/scir/src/merge.rs +++ b/libs/scir/src/merge.rs @@ -10,7 +10,7 @@ pub struct MergedMapping { primitives: HashMap, } -struct Merger<'a, S: Schema> { +struct Merger<'a, S: Schema + ?Sized> { /// Source cell ID -> destination cell ID cell_mapping: HashMap, /// Source primitive ID -> destination primitive ID @@ -21,7 +21,7 @@ struct Merger<'a, S: Schema> { src: LibraryBuilder, } -impl<'a, S: Schema> Merger<'a, S> { +impl<'a, S: Schema + ?Sized> Merger<'a, S> { #[inline] fn new(dst: &'a mut LibraryBuilder, src: LibraryBuilder) -> Self { Self { @@ -114,7 +114,7 @@ impl MergedMapping { } } -impl LibraryBuilder { +impl LibraryBuilder { /// Merges another SCIR library into the current library. pub fn merge(&mut self, other: Self) -> MergedMapping { Merger::new(self, other).merge() diff --git a/libs/scir/src/schema.rs b/libs/scir/src/schema.rs index 07f14b9d..5ecd63d7 100644 --- a/libs/scir/src/schema.rs +++ b/libs/scir/src/schema.rs @@ -1,16 +1,16 @@ //! Traits and definitions associated with schemas, or data formats //! used for storing SCIR libraries. +use std::convert::Infallible; use crate::Instance; use arcstr::ArcStr; use serde::{Deserialize, Serialize}; -use std::convert::Infallible; /// A data format for storing SCIR libraries. // TODO: Add method of validating primitive instances. pub trait Schema { /// A primitive used for storing arbitrary data that is opaque to SCIR. - type Primitive: Primitive; + type Primitive: Primitive + Sized; } /// A primitive of a SCIR schema. @@ -19,7 +19,7 @@ pub trait Primitive {} impl Primitive for T {} /// A schema that can be converted from another schema. -pub trait FromSchema: Schema { +pub trait FromSchema: Schema { /// The conversion error type. type Error; @@ -36,8 +36,8 @@ pub trait FromSchema: Schema { ) -> Result<(), Self::Error>; } -impl FromSchema for S { - type Error = Infallible; +impl FromSchema for S { + type Error = Infallible fn convert_primitive( primitive: ::Primitive, diff --git a/libs/scir/src/validation.rs b/libs/scir/src/validation.rs index e6d489b8..e32bc4cd 100644 --- a/libs/scir/src/validation.rs +++ b/libs/scir/src/validation.rs @@ -253,7 +253,7 @@ impl Display for Cause { } } -impl LibraryBuilder { +impl LibraryBuilder { /// Check whether or not this library is valid. pub fn validate(&self) -> IssueSet { let _guard = span!(Level::INFO, "validating SCIR Library").entered(); diff --git a/libs/spice/src/netlist.rs b/libs/spice/src/netlist.rs index 3fe7155d..d67e9f75 100644 --- a/libs/spice/src/netlist.rs +++ b/libs/spice/src/netlist.rs @@ -3,19 +3,17 @@ use arcstr::ArcStr; use itertools::Itertools; use std::collections::HashMap; -use std::fs::File; + use std::io::{Result, Write}; -use std::path::{Path, PathBuf}; -use std::sync::Arc; +use std::path::PathBuf; use crate::{BlackboxElement, Primitive, Spice}; use scir::schema::Schema; use scir::{ Cell, ChildId, Library, NetlistCellConversion, NetlistLibConversion, SignalInfo, Slice, }; -use substrate::context::Context; -use substrate::schematic::conv::RawLib; -use substrate::schematic::Schematic; + +use substrate::schematic::netlist::ConvertibleNetlister; /// A netlist include statement. #[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] @@ -433,58 +431,16 @@ impl HasSpiceLikeNetlist for Spice { } } -impl Spice { - /// Writes a nestlist of a SPICE library to the provided buffer. - pub fn write_scir_netlist( +impl ConvertibleNetlister for Spice { + type Error = std::io::Error; + type Options<'a> = NetlistOptions<'a>; + + fn write_scir_netlist( &self, lib: &Library, out: &mut W, - opts: NetlistOptions<'_>, - ) -> Result { + opts: Self::Options<'_>, + ) -> std::result::Result { NetlisterInstance::new(self, lib, out, opts).export() } - /// Writes a netlist of a SPICE library to a file at the given path. - pub fn write_scir_netlist_to_file( - &self, - lib: &Library, - path: impl AsRef, - opts: NetlistOptions<'_>, - ) -> Result { - let path = path.as_ref(); - if let Some(parent) = path.parent() { - std::fs::create_dir_all(parent)?; - } - let mut f = File::create(path)?; - self.write_scir_netlist(lib, &mut f, opts) - } - /// Writes a SPICE netlist of a Substrate block to the given buffer. - pub fn write_block_netlist, W: Write>( - &self, - ctx: &Context, - block: B, - out: &mut W, - opts: NetlistOptions<'_>, - ) -> substrate::error::Result<(RawLib, NetlistLibConversion)> { - let raw_lib = ctx.export_scir::(block)?; - - let conv = self - .write_scir_netlist(&raw_lib.scir, out, opts) - .map_err(Arc::new)?; - Ok((raw_lib, conv)) - } - /// Writes a SPICE netlist of a Substrate block to a file at the given path. - pub fn write_block_netlist_to_file>( - &self, - ctx: &Context, - block: B, - path: impl AsRef, - opts: NetlistOptions<'_>, - ) -> substrate::error::Result<(RawLib, NetlistLibConversion)> { - let path = path.as_ref(); - if let Some(parent) = path.parent() { - std::fs::create_dir_all(parent).map_err(Arc::new)?; - } - let mut f = File::create(path).map_err(Arc::new)?; - self.write_block_netlist(ctx, block, &mut f, opts) - } } diff --git a/substrate/src/context.rs b/substrate/src/context.rs index 8d7326b3..9004760a 100644 --- a/substrate/src/context.rs +++ b/substrate/src/context.rs @@ -281,7 +281,7 @@ impl Context { /// - If yes: /// - Retrieve created cell ID, io_data, and handle to cell /// - being generated and return immediately - pub(crate) fn generate_schematic_inner>( + pub(crate) fn generate_schematic_inner>( &self, block: Arc, ) -> SchemaCellHandle { @@ -337,7 +337,11 @@ impl Context { } } - fn generate_cross_schematic_inner, B: Schematic>( + fn generate_cross_schematic_inner< + S1: Schema + ?Sized, + S2: FromSchema + ?Sized, + B: Schematic, + >( &self, block: Arc, ) -> SchemaCellHandle { @@ -369,7 +373,11 @@ impl Context { /// Generates a schematic of a block in schema `S1` for use in schema `S2`. /// /// Can only generate a cross schematic with one layer of [`FromSchema`] indirection. - pub fn generate_cross_schematic, B: Schematic>( + pub fn generate_cross_schematic< + S1: Schema + ?Sized, + S2: FromSchema + ?Sized, + B: Schematic, + >( &self, block: B, ) -> SchemaCellHandle { @@ -379,7 +387,7 @@ impl Context { /// Generates a schematic for `block` in the background. /// /// Returns a handle to the cell being generated. - pub fn generate_schematic>( + pub fn generate_schematic>( &self, block: T, ) -> SchemaCellHandle { @@ -390,7 +398,7 @@ impl Context { /// Export the given block and all sub-blocks as a SCIR library. /// /// Returns a SCIR library and metadata for converting between SCIR and Substrate formats. - pub fn export_scir>( + pub fn export_scir>( &self, block: T, ) -> Result, ConvError> { @@ -558,7 +566,7 @@ impl PdkContext { } } -fn prepare_cell_builder( +fn prepare_cell_builder( id: CellId, context: Context, block: &T, diff --git a/substrate/src/error.rs b/substrate/src/error.rs index 5a4d76c4..2ec0ccf3 100644 --- a/substrate/src/error.rs +++ b/substrate/src/error.rs @@ -52,6 +52,12 @@ pub enum Error { UnsupportedPrimitive, } +impl From for Error { + fn from(value: std::io::Error) -> Self { + Self::Io(Arc::new(value)) + } +} + impl From for Error { fn from(value: LayoutError) -> Self { Error::Layout(value) diff --git a/substrate/src/schematic/conv.rs b/substrate/src/schematic/conv.rs index a5632368..ffc4d200 100644 --- a/substrate/src/schematic/conv.rs +++ b/substrate/src/schematic/conv.rs @@ -16,7 +16,7 @@ use crate::schematic::{ConvertPrimitive, InstancePath, RawCellContents, RawCellK use super::{CellId, InstanceId, RawCell}; /// An SCIR library with associated conversion metadata. -pub struct RawLib { +pub struct RawLib { /// The SCIR library. pub scir: scir::Library, /// Associated conversion metadata. @@ -374,13 +374,13 @@ pub(crate) struct ScirInstanceConversion { instance: ConvertedScirInstance, } -pub(crate) struct ScirLibExportContext { +pub(crate) struct ScirLibExportContext { lib: LibraryBuilder, conv: ScirLibConversionBuilder, cell_names: Names, } -impl Default for ScirLibExportContext { +impl Default for ScirLibExportContext { fn default() -> Self { Self { lib: LibraryBuilder::new(), @@ -390,7 +390,7 @@ impl Default for ScirLibExportContext { } } -impl> Clone for ScirLibExportContext { +impl + ?Sized> Clone for ScirLibExportContext { fn clone(&self) -> Self { Self { lib: self.lib.clone(), @@ -400,7 +400,9 @@ impl> Clone for ScirLibExportContext { } } -impl> std::fmt::Debug for ScirLibExportContext { +impl + ?Sized> std::fmt::Debug + for ScirLibExportContext +{ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut builder = f.debug_struct("ScirLibExportContext"); let _ = builder.field("lib", &self.lib); @@ -410,7 +412,7 @@ impl> std::fmt::Debug for ScirLibExp } } -impl ScirLibExportContext { +impl ScirLibExportContext { fn new() -> Self { Self::default() } @@ -447,7 +449,7 @@ impl ScirCellExportContext { } } -impl RawCell { +impl RawCell { /// The name associated with the given node. /// /// # Panics diff --git a/substrate/src/schematic/mod.rs b/substrate/src/schematic/mod.rs index 3ccd30b1..1fc42f88 100644 --- a/substrate/src/schematic/mod.rs +++ b/substrate/src/schematic/mod.rs @@ -1,6 +1,7 @@ //! Substrate's schematic generator framework. pub mod conv; +pub mod netlist; pub mod primitives; pub mod schema; @@ -44,7 +45,7 @@ pub trait ExportsNestedData: Block { } /// A block that has a schematic associated with the given PDK and schema. -pub trait Schematic: ExportsNestedData { +pub trait Schematic: ExportsNestedData { /// Generates the block's schematic. fn schematic( &self, @@ -54,7 +55,7 @@ pub trait Schematic: ExportsNestedData { } /// A builder for creating a schematic cell. -pub struct CellBuilder { +pub struct CellBuilder { /// The current global context. pub(crate) ctx: Context, pub(crate) id: CellId, @@ -73,7 +74,7 @@ pub struct CellBuilder { pub(crate) contents: RawCellContentsBuilder, } -impl CellBuilder { +impl CellBuilder { pub(crate) fn finish(self) -> RawCell { let mut roots = HashMap::with_capacity(self.node_names.len()); let mut uf = self.node_ctx.into_uf(); @@ -313,7 +314,7 @@ impl CellBuilder { } /// Creates a [`SubCellBuilder`] for instantiating blocks from schema `S2`. - pub fn sub_builder(&mut self) -> SubCellBuilder + pub fn sub_builder(&mut self) -> SubCellBuilder where S: FromSchema, { @@ -322,9 +323,12 @@ impl CellBuilder { } /// A cell builder for instantiating blocks from schema `S2` in schema `S`. -pub struct SubCellBuilder<'a, S: Schema, S2: Schema>(&'a mut CellBuilder, PhantomData); +pub struct SubCellBuilder<'a, S: Schema + ?Sized, S2: Schema + ?Sized>( + &'a mut CellBuilder, + PhantomData, +); -impl<'a, S: FromSchema, S2: Schema> SubCellBuilder<'a, S, S2> { +impl<'a, S: FromSchema + ?Sized, S2: Schema + ?Sized> SubCellBuilder<'a, S, S2> { /// Create a new signal with the given name and hardware type. #[track_caller] pub fn signal( @@ -566,13 +570,13 @@ impl CellHandle { } } -pub(crate) struct SchemaCellCacheValue { +pub(crate) struct SchemaCellCacheValue { pub(crate) raw: Arc>, pub(crate) cell: Arc>, } /// A cell handle associated with a schema `S`. -pub struct SchemaCellHandle { +pub struct SchemaCellHandle { pub(crate) handle: CacheHandle>>, pub(crate) cell: CellHandle, } @@ -598,7 +602,7 @@ impl SchemaCellHandle { } } -impl Deref for SchemaCellHandle { +impl Deref for SchemaCellHandle { type Target = CellHandle; fn deref(&self) -> &Self::Target { @@ -606,7 +610,7 @@ impl Deref for SchemaCellHandle { } } -impl Clone for SchemaCellHandle { +impl Clone for SchemaCellHandle { fn clone(&self) -> Self { Self { handle: self.handle.clone(), @@ -815,12 +819,12 @@ impl Clone for CellMetadata { } } -pub(crate) struct CellCacheKey { +pub(crate) struct CellCacheKey { pub(crate) block: Arc, pub(crate) phantom: PhantomData, } -impl Clone for CellCacheKey { +impl Clone for CellCacheKey { fn clone(&self) -> Self { Self { block: self.block.clone(), @@ -829,22 +833,22 @@ impl Clone for CellCacheKey { } } -impl PartialEq for CellCacheKey { +impl PartialEq for CellCacheKey { fn eq(&self, other: &Self) -> bool { self.block.eq(&other.block) } } -impl Eq for CellCacheKey {} +impl Eq for CellCacheKey {} -impl Hash for CellCacheKey { +impl Hash for CellCacheKey { fn hash(&self, state: &mut H) { self.block.hash(state) } } /// A key for a block that was generated in schema `S1` and converted to schema `S2`. -pub(crate) type ConvCacheKey = CellCacheKey; +pub(crate) type ConvCacheKey = CellCacheKey, S2)>; /// A path to an instance from a top level cell. /// @@ -977,14 +981,16 @@ impl HasNestedView for Option { /// A raw (weakly-typed) instance of a cell. #[allow(dead_code)] -pub(crate) struct RawInstanceBuilder { +pub(crate) struct RawInstanceBuilder { id: InstanceId, name: ArcStr, connections: Vec, child: CacheHandle>>, } -impl> std::fmt::Debug for RawInstanceBuilder { +impl + ?Sized> std::fmt::Debug + for RawInstanceBuilder +{ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut builder = f.debug_struct("RawInstanceBuilder"); let _ = builder.field("id", &self.id); @@ -995,7 +1001,7 @@ impl> std::fmt::Debug for RawInstanc } } -impl RawInstanceBuilder { +impl RawInstanceBuilder { fn build(self) -> RawInstance { RawInstance { id: self.id, @@ -1008,14 +1014,14 @@ impl RawInstanceBuilder { /// A raw (weakly-typed) instance of a cell. #[allow(dead_code)] -pub(crate) struct RawInstance { +pub(crate) struct RawInstance { id: InstanceId, name: ArcStr, connections: Vec, child: Arc>, } -impl> std::fmt::Debug for RawInstance { +impl + ?Sized> std::fmt::Debug for RawInstance { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut builder = f.debug_struct("RawInstance"); let _ = builder.field("id", &self.id); @@ -1026,7 +1032,7 @@ impl> std::fmt::Debug for RawInstanc } } -impl Clone for RawInstance { +impl Clone for RawInstance { fn clone(&self) -> Self { Self { id: self.id, @@ -1037,8 +1043,8 @@ impl Clone for RawInstance { } } -impl RawInstance { - fn convert_schema>(self) -> Result> { +impl RawInstance { + fn convert_schema + ?Sized>(self) -> Result> { Ok(RawInstance { id: self.id, name: self.name, @@ -1054,7 +1060,7 @@ impl RawInstance { /// should not have any public methods. #[allow(dead_code)] #[doc(hidden)] -pub struct RawCell { +pub struct RawCell { id: CellId, pub(crate) name: ArcStr, ports: Vec, @@ -1066,7 +1072,7 @@ pub struct RawCell { contents: RawCellContents, } -impl> std::fmt::Debug for RawCell { +impl + ?Sized> std::fmt::Debug for RawCell { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut builder = f.debug_struct("RawCell"); let _ = builder.field("id", &self.id); @@ -1081,7 +1087,7 @@ impl> std::fmt::Debug for RawCell } } -impl Clone for RawCell { +impl Clone for RawCell { fn clone(&self) -> Self { Self { id: self.id, @@ -1096,8 +1102,8 @@ impl Clone for RawCell { } } -impl RawCell { - pub(crate) fn convert_schema>(self) -> Result> { +impl RawCell { + pub(crate) fn convert_schema + ?Sized>(self) -> Result> { Ok(RawCell { id: self.id, name: self.name, @@ -1115,7 +1121,7 @@ impl RawCell { pub(crate) type RawCellContentsBuilder = RawCellKind, ScirBinding, PrimitiveBinding, ConvertedPrimitive>; -impl RawCellContentsBuilder { +impl RawCellContentsBuilder { fn build(self) -> RawCellContents { match self { RawCellContentsBuilder::Cell(b) => RawCellContents::Cell(b.build()), @@ -1130,8 +1136,8 @@ impl RawCellContentsBuilder { pub(crate) type RawCellContents = RawCellKind, ScirBinding, PrimitiveBinding, ConvertedPrimitive>; -impl RawCellContents { - fn convert_schema>(self) -> Result> { +impl RawCellContents { + fn convert_schema + ?Sized>(self) -> Result> { Ok(match self { RawCellContents::Cell(c) => RawCellContents::Cell(c.convert_schema()?), RawCellContents::Scir(s) => RawCellContents::Scir(ScirBinding { @@ -1166,13 +1172,15 @@ impl RawCellContents { } } -pub(crate) trait ConvertPrimitive: Any + Send + Sync { +pub(crate) trait ConvertPrimitive: Any + Send + Sync { fn convert_primitive(&self) -> Result<::Primitive>; fn convert_instance(&self, inst: &mut scir::Instance) -> Result<()>; fn port_map(&self) -> &HashMap>; } -impl, S2: Schema> ConvertPrimitive for PrimitiveBinding { +impl + ?Sized, S2: Schema + ?Sized> ConvertPrimitive + for PrimitiveBinding +{ // TODO: Improve error handling fn convert_primitive(&self) -> Result<::Primitive> { >::convert_primitive(self.primitive.clone()) @@ -1187,7 +1195,9 @@ impl, S2: Schema> ConvertPrimitive for PrimitiveBinding, S2: Schema> ConvertPrimitive for ConvertedPrimitive { +impl + ?Sized, S2: Schema + ?Sized> ConvertPrimitive + for ConvertedPrimitive +{ // TODO: Improve error handling fn convert_primitive(&self) -> Result<::Primitive> { >::convert_primitive(self.original.convert_primitive()?) @@ -1205,12 +1215,12 @@ impl, S2: Schema> ConvertPrimitive for ConvertedPrimitive /// A binding to a schema primitive that can be used to define /// a Substrate schematic. -pub struct PrimitiveBinding { +pub struct PrimitiveBinding { pub(crate) primitive: ::Primitive, pub(crate) port_map: HashMap>, } -impl> std::fmt::Debug for PrimitiveBinding { +impl + ?Sized> std::fmt::Debug for PrimitiveBinding { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut builder = f.debug_struct("Primitive"); let _ = builder.field("primitive", &self.primitive); @@ -1219,7 +1229,7 @@ impl> std::fmt::Debug for PrimitiveB } } -impl Clone for PrimitiveBinding { +impl Clone for PrimitiveBinding { fn clone(&self) -> Self { Self { primitive: self.primitive.clone(), @@ -1243,12 +1253,14 @@ impl PrimitiveBinding { } } -pub(crate) struct ConvertedPrimitive { +pub(crate) struct ConvertedPrimitive { converted: ::Primitive, original: Arc>, } -impl> std::fmt::Debug for ConvertedPrimitive { +impl + ?Sized> std::fmt::Debug + for ConvertedPrimitive +{ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut builder = f.debug_struct("ConvertedPrimitive"); let _ = builder.field("converted", &self.converted); @@ -1256,7 +1268,7 @@ impl> std::fmt::Debug for ConvertedP } } -impl Clone for ConvertedPrimitive { +impl Clone for ConvertedPrimitive { fn clone(&self) -> Self { Self { converted: self.converted.clone(), @@ -1265,7 +1277,7 @@ impl Clone for ConvertedPrimitive { } } -impl ConvertedPrimitive { +impl ConvertedPrimitive { pub(crate) fn port_map(&self) -> &HashMap> { self.original.port_map() } @@ -1283,12 +1295,14 @@ pub(crate) enum RawCellKind { ConvertedPrimitive(CP), } -pub(crate) struct RawCellInnerBuilder { +pub(crate) struct RawCellInnerBuilder { pub(crate) next_instance_id: InstanceId, pub(crate) instances: Vec>, } -impl> std::fmt::Debug for RawCellInnerBuilder { +impl + ?Sized> std::fmt::Debug + for RawCellInnerBuilder +{ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut builder = f.debug_struct("RawCellInnerBuilder"); let _ = builder.field("next_instance_id", &self.next_instance_id); @@ -1297,7 +1311,7 @@ impl> std::fmt::Debug for RawCellInn } } -impl Default for RawCellInnerBuilder { +impl Default for RawCellInnerBuilder { fn default() -> Self { Self { next_instance_id: Default::default(), @@ -1306,7 +1320,7 @@ impl Default for RawCellInnerBuilder { } } -impl RawCellInnerBuilder { +impl RawCellInnerBuilder { fn build(self) -> RawCellInner { RawCellInner { instances: self @@ -1318,11 +1332,11 @@ impl RawCellInnerBuilder { } } -pub(crate) struct RawCellInner { +pub(crate) struct RawCellInner { pub(crate) instances: Vec>, } -impl> std::fmt::Debug for RawCellInner { +impl + ?Sized> std::fmt::Debug for RawCellInner { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut builder = f.debug_struct("RawCellInner"); let _ = builder.field("instances", &self.instances); @@ -1330,7 +1344,7 @@ impl> std::fmt::Debug for RawCellInn } } -impl Clone for RawCellInner { +impl Clone for RawCellInner { fn clone(&self) -> Self { Self { instances: self.instances.clone(), @@ -1338,8 +1352,8 @@ impl Clone for RawCellInner { } } -impl RawCellInner { - fn convert_schema>(self) -> Result> { +impl RawCellInner { + fn convert_schema + ?Sized>(self) -> Result> { Ok(RawCellInner { instances: self .instances @@ -1351,13 +1365,13 @@ impl RawCellInner { } /// A binding to a cell within a SCIR library that can be used to define a Substrate schematic. -pub struct ScirBinding { +pub struct ScirBinding { pub(crate) lib: scir::Library, pub(crate) cell: scir::CellId, pub(crate) port_map: HashMap>, } -impl> Clone for ScirBinding { +impl + ?Sized> Clone for ScirBinding { fn clone(&self) -> Self { Self { lib: self.lib.clone(), @@ -1367,7 +1381,7 @@ impl> Clone for ScirBinding { } } -impl> std::fmt::Debug for ScirBinding { +impl + ?Sized> std::fmt::Debug for ScirBinding { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut builder = f.debug_struct("ScirCellInner"); let _ = builder.field("lib", &self.lib); @@ -1376,7 +1390,7 @@ impl> std::fmt::Debug for ScirBindin } } -impl ScirBinding { +impl ScirBinding { /// Creates a new [`ScirBinding`] corresponding to the given cell in /// SCIR library `lib`. /// @@ -1413,7 +1427,9 @@ impl ScirBinding { } /// Converts the underlying SCIR library to schema `S2`. - pub fn convert_schema>(self) -> substrate::error::Result> { + pub fn convert_schema + ?Sized>( + self, + ) -> substrate::error::Result> { Ok(ScirBinding { // TODO: More descriptive error. lib: self diff --git a/substrate/src/schematic/netlist.rs b/substrate/src/schematic/netlist.rs new file mode 100644 index 00000000..3d314e46 --- /dev/null +++ b/substrate/src/schematic/netlist.rs @@ -0,0 +1,85 @@ +//! Netlist export. + +use crate::context::Context; +use crate::schematic::conv::RawLib; +use crate::schematic::Schematic; +use scir::{Library, NetlistLibConversion}; +use std::io::Write; +use std::path::Path; +use std::sync::Arc; +use substrate::schematic::schema::Schema; + +/// A netlister that tracks how cells and instances are translated between SCIR and the output netlist format. +pub trait ConvertibleNetlister { + /// The error type returned when writing out a SCIR netlist. + type Error: Into; + + /// The netlist options type. + /// + /// Many netlisters accept options, allowing the user to configure things like + /// netlist indentation, naming conventions, etc. This is the type of the object + /// that stores those options. + type Options<'a>; + + /// Writes a netlist of a SCIR library to the provided output stream. + fn write_scir_netlist( + &self, + lib: &Library, + out: &mut W, + opts: Self::Options<'_>, + ) -> Result; + + /// Writes a netlist of a SCIR library to a file at the given path. + /// + /// The file and any parent directories will be created if necessary. + fn write_scir_netlist_to_file( + &self, + lib: &Library, + path: impl AsRef, + opts: Self::Options<'_>, + ) -> substrate::error::Result { + let path = path.as_ref(); + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent).map_err(Arc::new)?; + } + let mut f = std::fs::File::create(path).map_err(Arc::new)?; + let conv = self + .write_scir_netlist(lib, &mut f, opts) + .map_err(|e| e.into())?; + Ok(conv) + } + + /// Writes a netlist of a Substrate block to the given output stream. + fn write_netlist, W: Write>( + &self, + ctx: &Context, + block: B, + out: &mut W, + opts: Self::Options<'_>, + ) -> substrate::error::Result<(RawLib, NetlistLibConversion)> { + let raw_lib = ctx.export_scir::(block)?; + + let conv = self + .write_scir_netlist(&raw_lib.scir, out, opts) + .map_err(|e| e.into())?; + Ok((raw_lib, conv)) + } + + /// Writes a netlist of a Substrate block to a file at the given path. + /// + /// The file and any parent directories will be created if necessary. + fn write_netlist_to_file>( + &self, + ctx: &Context, + block: B, + path: impl AsRef, + opts: Self::Options<'_>, + ) -> substrate::error::Result<(RawLib, NetlistLibConversion)> { + let path = path.as_ref(); + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent).map_err(Arc::new)?; + } + let mut f = std::fs::File::create(path).map_err(Arc::new)?; + self.write_netlist(ctx, block, &mut f, opts) + } +} diff --git a/substrate/src/schematic/schema.rs b/substrate/src/schematic/schema.rs index 6ba81938..26f2d80b 100644 --- a/substrate/src/schematic/schema.rs +++ b/substrate/src/schematic/schema.rs @@ -27,6 +27,9 @@ impl Primitive for T {} /// /// This trait should never be directly implemented. Implementing [`scir::schema::FromSchema`] /// should suffice provided that the necessary trait bounds are satisfied. -pub trait FromSchema: Schema + scir::schema::FromSchema {} +pub trait FromSchema: Schema + scir::schema::FromSchema {} -impl> FromSchema for S2 {} +impl> FromSchema + for S2 +{ +} diff --git a/tests/src/hard_macro.rs b/tests/src/hard_macro.rs index e99c4bf7..092b9b25 100644 --- a/tests/src/hard_macro.rs +++ b/tests/src/hard_macro.rs @@ -11,6 +11,7 @@ use spice::Spice; use substrate::block::Block; use substrate::io::schematic::HardwareType; use substrate::layout::Layout; +use substrate::schematic::netlist::ConvertibleNetlister; use substrate::schematic::{CellBuilder, ExportsNestedData, Schematic}; use test_log::test; diff --git a/tests/src/netlist.rs b/tests/src/netlist.rs index fad3370d..6b340664 100644 --- a/tests/src/netlist.rs +++ b/tests/src/netlist.rs @@ -5,6 +5,7 @@ use spectre::Spectre; use spice::netlist::{NetlistKind, NetlistOptions, NetlisterInstance}; use spice::{BlackboxContents, BlackboxElement, Spice}; use std::collections::HashMap; +use substrate::schematic::netlist::ConvertibleNetlister; use substrate::schematic::schema::Schema; pub(crate) trait HasRes2: Schema { diff --git a/tools/spectre/src/lib.rs b/tools/spectre/src/lib.rs index a49464b3..16cfeff4 100644 --- a/tools/spectre/src/lib.rs +++ b/tools/spectre/src/lib.rs @@ -35,6 +35,7 @@ use substrate::execute::Executor; use substrate::io::schematic::HardwareType; use substrate::io::schematic::NodePath; use substrate::schematic::conv::ConvertedNodePath; +use substrate::schematic::netlist::ConvertibleNetlister; use substrate::schematic::primitives::{Capacitor, RawInstance, Resistor}; use substrate::schematic::schema::Schema; use substrate::schematic::{CellBuilder, PrimitiveBinding, Schematic}; @@ -412,6 +413,20 @@ impl CacheableWithState for CachedSim { } } +impl ConvertibleNetlister for Spectre { + type Error = std::io::Error; + type Options<'a> = NetlistOptions<'a>; + + fn write_scir_netlist( + &self, + lib: &Library, + out: &mut W, + opts: Self::Options<'_>, + ) -> std::result::Result { + NetlisterInstance::new(self, lib, out, opts).export() + } +} + impl Spectre { fn simulate( &self, @@ -438,16 +453,14 @@ impl Spectre { saves.sort(); ics.sort(); - let netlister = NetlisterInstance::new( - self, + let conv = self.write_scir_netlist( &ctx.lib.scir, &mut w, NetlistOptions::new( NetlistKind::Testbench(RenameGround::Yes("0".into())), &includes, ), - ); - let conv = netlister.export()?; + )?; writeln!(w)?; for save in saves {