Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(netlists): consistent Spectre/Spice netlist API #349

Merged
merged 3 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions libs/scir/src/drivers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ impl Display for Cause {
}
}

impl<S: Schema> LibraryBuilder<S> {
impl<S: Schema + ?Sized> LibraryBuilder<S> {
/// Perform driver analysis on this library.
pub fn validate_drivers(&self) -> IssueSet<DriverIssue> {
let _guard = span!(Level::INFO, "performing driver analysis on SCIR Library").entered();
Expand Down Expand Up @@ -240,7 +240,7 @@ impl<S: Schema> LibraryBuilder<S> {
}
}

fn analyze_instance<S: Schema>(
fn analyze_instance<S: Schema + ?Sized>(
lib: &LibraryBuilder<S>,
net_states: &mut HashMap<SignalId, Vec<NetState>>,
inst: &Instance,
Expand Down
26 changes: 13 additions & 13 deletions libs/scir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ pub struct LibraryBuilder<S: Schema + ?Sized = NoSchema> {
top: Option<CellId>,
}

impl<S: Schema> Default for LibraryBuilder<S> {
impl<S: Schema + ?Sized> Default for LibraryBuilder<S> {
fn default() -> Self {
Self {
cell_id: 0,
Expand All @@ -503,7 +503,7 @@ impl<S: Schema> Default for LibraryBuilder<S> {
}
}

impl<S: Schema<Primitive = impl Clone>> Clone for LibraryBuilder<S> {
impl<S: Schema<Primitive = impl Clone> + ?Sized> Clone for LibraryBuilder<S> {
fn clone(&self) -> Self {
Self {
cell_id: self.cell_id,
Expand All @@ -516,7 +516,7 @@ impl<S: Schema<Primitive = impl Clone>> Clone for LibraryBuilder<S> {
}
}

impl<S: Schema<Primitive = impl std::fmt::Debug>> std::fmt::Debug for LibraryBuilder<S> {
impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for LibraryBuilder<S> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut builder = f.debug_struct("LibraryBuilder");
let _ = builder.field("cell_id", &self.cell_id);
Expand All @@ -535,15 +535,15 @@ impl<S: Schema<Primitive = impl std::fmt::Debug>> std::fmt::Debug for LibraryBui
/// The contents of the library cannot be mutated.
pub struct Library<S: Schema + ?Sized = NoSchema>(LibraryBuilder<S>);

impl<S: Schema<Primitive = impl std::fmt::Debug>> std::fmt::Debug for Library<S> {
impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for Library<S> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut builder = f.debug_struct("Library");
let _ = builder.field("0", &self.0);
builder.finish()
}
}

impl<S: Schema> Clone for Library<S>
impl<S: Schema + ?Sized> Clone for Library<S>
where
LibraryBuilder<S>: Clone,
{
Expand All @@ -552,14 +552,14 @@ where
}
}

impl<S: Schema> Deref for Library<S> {
impl<S: Schema + ?Sized> Deref for Library<S> {
type Target = LibraryBuilder<S>;
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<S: Schema> Library<S> {
impl<S: Schema + ?Sized> Library<S> {
/// Converts a [`Library<S>`] to a [`Library<NoSchema>`], throwing an error if there
/// are any primitives.
pub fn drop_schema(self) -> Result<Library<NoSchema>, NoSchemaError> {
Expand All @@ -570,7 +570,7 @@ impl<S: Schema> Library<S> {
///
/// 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<C: Schema>(self) -> Result<LibraryBuilder<C>, C::Error>
pub fn convert_schema<C: Schema + ?Sized>(self) -> Result<LibraryBuilder<C>, C::Error>
where
C: FromSchema<S>,
{
Expand All @@ -583,7 +583,7 @@ impl<S: Schema> Library<S> {
}
}

impl<S: Schema<Primitive = impl Clone>> Library<S> {
impl<S: Schema<Primitive = impl Clone> + ?Sized> Library<S> {
/// 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 {
Expand Down Expand Up @@ -833,7 +833,7 @@ impl NetlistCellConversion {
}
}

impl<S: Schema> LibraryBuilder<S> {
impl<S: Schema + ?Sized> LibraryBuilder<S> {
/// Creates a new, empty library.
pub fn new() -> Self {
Self::default()
Expand Down Expand Up @@ -1350,7 +1350,7 @@ impl<S: Schema> LibraryBuilder<S> {
}
}

fn convert_inner<C: Schema, E>(
fn convert_inner<C: Schema + ?Sized, E>(
self,
convert_primitive: fn(<S as Schema>::Primitive) -> Result<<C as Schema>::Primitive, E>,
convert_instance: fn(&mut Instance, &<S as Schema>::Primitive) -> Result<(), E>,
Expand Down Expand Up @@ -1396,15 +1396,15 @@ impl<S: Schema> LibraryBuilder<S> {
/// Converts a [`LibraryBuilder<S>`] into a [`LibraryBuilder<C>`].
///
/// Instances associated with non-existent primitives will remain unchanged.
pub fn convert_schema<C: Schema>(self) -> Result<LibraryBuilder<C>, C::Error>
pub fn convert_schema<C: Schema + ?Sized>(self) -> Result<LibraryBuilder<C>, C::Error>
where
C: FromSchema<S>,
{
self.convert_inner(C::convert_primitive, C::convert_instance)
}
}

impl<S: Schema<Primitive = impl Clone>> LibraryBuilder<S> {
impl<S: Schema<Primitive = impl Clone> + ?Sized> LibraryBuilder<S> {
/// 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 {
Expand Down
6 changes: 3 additions & 3 deletions libs/scir/src/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct MergedMapping {
primitives: HashMap<PrimitiveId, PrimitiveId>,
}

struct Merger<'a, S: Schema> {
struct Merger<'a, S: Schema + ?Sized> {
/// Source cell ID -> destination cell ID
cell_mapping: HashMap<CellId, CellId>,
/// Source primitive ID -> destination primitive ID
Expand All @@ -21,7 +21,7 @@ struct Merger<'a, S: Schema> {
src: LibraryBuilder<S>,
}

impl<'a, S: Schema> Merger<'a, S> {
impl<'a, S: Schema + ?Sized> Merger<'a, S> {
#[inline]
fn new(dst: &'a mut LibraryBuilder<S>, src: LibraryBuilder<S>) -> Self {
Self {
Expand Down Expand Up @@ -114,7 +114,7 @@ impl MergedMapping {
}
}

impl<S: Schema> LibraryBuilder<S> {
impl<S: Schema + ?Sized> LibraryBuilder<S> {
/// Merges another SCIR library into the current library.
pub fn merge(&mut self, other: Self) -> MergedMapping {
Merger::new(self, other).merge()
Expand Down
6 changes: 3 additions & 3 deletions libs/scir/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
// 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.
Expand All @@ -18,7 +18,7 @@ pub trait Primitive {}
impl<T> Primitive for T {}

/// A schema that can be converted from another schema.
pub trait FromSchema<S: Schema>: Schema {
pub trait FromSchema<S: Schema + ?Sized>: Schema {
/// The conversion error type.
type Error;

Expand All @@ -35,7 +35,7 @@ pub trait FromSchema<S: Schema>: Schema {
) -> Result<(), Self::Error>;
}

impl<S: Schema> FromSchema<S> for S {
impl<S: Schema + ?Sized> FromSchema<S> for S {
type Error = ();

fn convert_primitive(
Expand Down
2 changes: 1 addition & 1 deletion libs/scir/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ impl Display for Cause {
}
}

impl<S: Schema> LibraryBuilder<S> {
impl<S: Schema + ?Sized> LibraryBuilder<S> {
/// Check whether or not this library is valid.
pub fn validate(&self) -> IssueSet<ValidatorIssue> {
let _guard = span!(Level::INFO, "validating SCIR Library").entered();
Expand Down
66 changes: 11 additions & 55 deletions libs/spice/src/netlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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<W: Write>(
impl ConvertibleNetlister<Spice> for Spice {
type Error = std::io::Error;
type Options<'a> = NetlistOptions<'a>;

fn write_scir_netlist<W: Write>(
&self,
lib: &Library<Spice>,
out: &mut W,
opts: NetlistOptions<'_>,
) -> Result<NetlistLibConversion> {
opts: Self::Options<'_>,
) -> std::result::Result<NetlistLibConversion, Self::Error> {
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<Spice>,
path: impl AsRef<Path>,
opts: NetlistOptions<'_>,
) -> Result<NetlistLibConversion> {
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<B: Schematic<Spice>, W: Write>(
&self,
ctx: &Context,
block: B,
out: &mut W,
opts: NetlistOptions<'_>,
) -> substrate::error::Result<(RawLib<Spice>, NetlistLibConversion)> {
let raw_lib = ctx.export_scir::<Spice, _>(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<B: Schematic<Spice>>(
&self,
ctx: &Context,
block: B,
path: impl AsRef<Path>,
opts: NetlistOptions<'_>,
) -> substrate::error::Result<(RawLib<Spice>, 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)
}
}
20 changes: 14 additions & 6 deletions substrate/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<S: Schema, B: Schematic<S>>(
pub(crate) fn generate_schematic_inner<S: Schema + ?Sized, B: Schematic<S>>(
&self,
block: Arc<B>,
) -> SchemaCellHandle<S, B> {
Expand Down Expand Up @@ -337,7 +337,11 @@ impl Context {
}
}

fn generate_cross_schematic_inner<S1: Schema, S2: FromSchema<S1>, B: Schematic<S1>>(
fn generate_cross_schematic_inner<
S1: Schema + ?Sized,
S2: FromSchema<S1> + ?Sized,
B: Schematic<S1>,
>(
&self,
block: Arc<B>,
) -> SchemaCellHandle<S2, B> {
Expand Down Expand Up @@ -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<S1: Schema, S2: FromSchema<S1>, B: Schematic<S1>>(
pub fn generate_cross_schematic<
S1: Schema + ?Sized,
S2: FromSchema<S1> + ?Sized,
B: Schematic<S1>,
>(
&self,
block: B,
) -> SchemaCellHandle<S2, B> {
Expand All @@ -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<S: Schema, T: Schematic<S>>(
pub fn generate_schematic<S: Schema + ?Sized, T: Schematic<S>>(
&self,
block: T,
) -> SchemaCellHandle<S, T> {
Expand All @@ -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<S: Schema, T: Schematic<S>>(
pub fn export_scir<S: Schema + ?Sized, T: Schematic<S>>(
&self,
block: T,
) -> Result<RawLib<S>, ConvError> {
Expand Down Expand Up @@ -558,7 +566,7 @@ impl<PDK: Pdk> PdkContext<PDK> {
}
}

fn prepare_cell_builder<S: Schema, T: Block>(
fn prepare_cell_builder<S: Schema + ?Sized, T: Block>(
id: CellId,
context: Context,
block: &T,
Expand Down
6 changes: 6 additions & 0 deletions substrate/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ pub enum Error {
UnsupportedPrimitive,
}

impl From<std::io::Error> for Error {
fn from(value: std::io::Error) -> Self {
Self::Io(Arc::new(value))
}
}

impl From<LayoutError> for Error {
fn from(value: LayoutError) -> Self {
Error::Layout(value)
Expand Down
Loading