From 9e7e16d5f7de8bc7a9dc91388cf1905ffcecea21 Mon Sep 17 00:00:00 2001 From: rohanku Date: Thu, 26 Oct 2023 12:17:01 -0700 Subject: [PATCH] fix converted node paths --- substrate/src/schematic/conv.rs | 51 +++++++++++++++++++++-------- tests/src/hard_macro.rs | 16 ++++----- tools/ngspice/src/tran.rs | 57 ++++++++++++++++++++++++++++++--- tools/spectre/src/lib.rs | 24 ++++++++++++-- tools/spectre/src/tran.rs | 57 ++++++++++++++++++++++++++++++--- 5 files changed, 171 insertions(+), 34 deletions(-) diff --git a/substrate/src/schematic/conv.rs b/substrate/src/schematic/conv.rs index a308489f..fad54d74 100644 --- a/substrate/src/schematic/conv.rs +++ b/substrate/src/schematic/conv.rs @@ -62,6 +62,16 @@ pub(crate) struct ScirLibConversionBuilder { pub(crate) cells: HashMap, } +pub enum ConvertedNodePath { + Cell(scir::SliceOnePath), + Primitive { + id: scir::PrimitiveId, + instances: scir::InstancePath, + port: ArcStr, + index: usize, + }, +} + impl ScirLibConversionBuilder { fn new() -> Self { Default::default() @@ -109,17 +119,22 @@ impl RawLib { } /// Converts a Substrate [`NodePath`] to a SCIR [`scir::SliceOnePath`]. - pub fn convert_node_path(&self, path: &NodePath) -> Option { + pub fn convert_node_path(&self, path: &NodePath) -> Option { let (instances, cell) = self.convert_instance_path_inner(path.top, &path.instances)?; Some(match cell { - SubstrateCellConversionRef::Cell(cell) => { - scir::SliceOnePath::new(instances, *cell.signals.get(&path.node)?).into() - } + SubstrateCellConversionRef::Cell(cell) => ConvertedNodePath::Cell( + scir::SliceOnePath::new(instances, *cell.signals.get(&path.node)?), + ), SubstrateCellConversionRef::Primitive(p) => { let prim = self.scir.primitive(p.primitive_id); let (port, index) = p.ports.get(&path.node)?.first()?; - scir::SliceOnePath::new(instances, NamedSliceOne::with_index(port.clone(), *index)) + ConvertedNodePath::Primitive { + id: p.primitive_id, + instances, + port: port.clone(), + index: *index, + } } }) } @@ -135,7 +150,7 @@ impl RawLib { /// /// Returns [`None`] if the path is invalid. Only flattened instances will /// return more than one [`scir::SignalPath`]. - pub fn convert_terminal_path(&self, path: &TerminalPath) -> Option> { + pub fn convert_terminal_path(&self, path: &TerminalPath) -> Option> { let mut cell = self.conv.cells.get(&path.top)?.as_ref(); let scir_id = self.scir.top_cell()?; @@ -177,16 +192,20 @@ impl RawLib { ); signals } else { - vec![scir::SliceOnePath::new(instances, slice)] + vec![ConvertedNodePath::Cell(scir::SliceOnePath::new( + instances, slice, + ))] }) } SubstrateCellConversionRef::Primitive(p) => { let mut out = Vec::new(); for (port, index) in p.ports.get(&path.node)? { - out.push(scir::SliceOnePath::new( - instances.clone(), - NamedSliceOne::with_index(port.clone(), *index), - )); + out.push(ConvertedNodePath::Primitive { + id: p.primitive_id, + instances: instances.clone(), + port: port.clone(), + index: *index, + }); } Some(out) } @@ -201,7 +220,7 @@ impl RawLib { id: scir::InstanceId, slice: scir::SliceOne, instances: &mut scir::InstancePath, - signals: &mut Vec, + signals: &mut Vec, ) -> Option<()> { instances.push(id); let inst = parent_cell.instance(id); @@ -222,13 +241,17 @@ impl RawLib { }; if let Some(concat_index) = concat_index { + // TODO: Handle primitive case. let child_cell = self.scir.cell(inst.child().into_cell()?); let port = child_cell.port(name); let port_slice = child_cell.signal(port.signal()).slice(); let tail = port_slice .slice_one() .unwrap_or_else(|| port_slice.index(concat_index)); - signals.push(scir::SliceOnePath::new(instances.clone(), tail)); + signals.push(ConvertedNodePath::Cell(scir::SliceOnePath::new( + instances.clone(), + tail, + ))); } } port_index += part.width(); @@ -246,7 +269,7 @@ impl RawLib { parent_cell: &scir::Cell, slice: scir::SliceOne, instances: &mut scir::InstancePath, - signals: &mut Vec, + signals: &mut Vec, ) -> Option<()> { for (_, conv) in conv.instances.iter() { match conv.instance.as_ref() { diff --git a/tests/src/hard_macro.rs b/tests/src/hard_macro.rs index 1080e92a..fd68de3d 100644 --- a/tests/src/hard_macro.rs +++ b/tests/src/hard_macro.rs @@ -4,7 +4,6 @@ use serde::{Deserialize, Serialize}; use sky130pdk::Sky130Pdk; use scir::netlist::{NetlistKind, NetlisterInstance}; -#[cfg(feature = "spectre")] use spectre::Spectre; use spice::Spice; use substrate::block::Block; @@ -57,15 +56,12 @@ pub struct BufferInlineHardMacro; fmt = "spice", pdk = "Spice" ))] -#[cfg_attr( - feature = "spectre", - substrate(schematic( - source = "crate::paths::test_data(\"spice/vdivider_duplicate_subckt.spice\")", - name = "vdivider", - fmt = "spice", - pdk = "Spectre" - )) -)] +#[substrate(schematic( + source = "crate::paths::test_data(\"spice/vdivider_duplicate_subckt.spice\")", + name = "vdivider", + fmt = "spice", + pdk = "Spectre" +))] pub struct VdividerDuplicateSubckt; #[test] diff --git a/tools/ngspice/src/tran.rs b/tools/ngspice/src/tran.rs index 8fc815e7..f3745ad3 100644 --- a/tools/ngspice/src/tran.rs +++ b/tools/ngspice/src/tran.rs @@ -4,13 +4,13 @@ use crate::{node_voltage_path, Ngspice, ProbeStmt, SaveStmt}; use arcstr::ArcStr; use rust_decimal::Decimal; use scir::netlist::NetlistLibConversion; -use scir::SliceOnePath; +use scir::{NamedSliceOne, SliceOnePath}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::ops::Deref; use std::sync::Arc; use substrate::io::{NodePath, TerminalPath}; -use substrate::schematic::conv::RawLib; +use substrate::schematic::conv::{ConvertedNodePath, RawLib}; use substrate::schematic::primitives::Resistor; use substrate::schematic::{Cell, ExportsNestedData, NestedInstance}; use substrate::simulation::data::{FromSaved, HasSimData, Save}; @@ -153,6 +153,25 @@ impl Save for TranVoltage { } } +impl Save for TranVoltage { + fn save( + ctx: &SimulationContext, + to_save: &ConvertedNodePath, + opts: &mut ::Options, + ) -> Self::Key { + 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 TranVoltage { fn save( ctx: &SimulationContext, @@ -163,7 +182,7 @@ impl Save for TranVoltage { } } -#[impl_dispatch({SliceOnePath; NodePath})] +#[impl_dispatch({SliceOnePath; ConvertedNodePath; NodePath})] impl Save for TranVoltage { fn save( ctx: &SimulationContext, @@ -251,6 +270,25 @@ impl Save for TranCurrent { } } +impl Save for TranCurrent { + fn save( + ctx: &SimulationContext, + to_save: &ConvertedNodePath, + opts: &mut ::Options, + ) -> Self::Key { + 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 TranCurrent { fn save( ctx: &SimulationContext, @@ -268,7 +306,7 @@ impl Save for TranCurrent { } } -#[impl_dispatch({SliceOnePath; TerminalPath})] +#[impl_dispatch({SliceOnePath; ConvertedNodePath; TerminalPath})] impl Save for TranCurrent { fn save( ctx: &SimulationContext, @@ -295,6 +333,17 @@ impl HasSimData> for TranOutput { } } +impl HasSimData> for TranOutput { + fn get_data(&self, k: &ConvertedNodePath) -> Option<&Vec> { + self.get_data(&match k { + ConvertedNodePath::Cell(path) => path.clone(), + ConvertedNodePath::Primitive { + instances, port, .. + } => SliceOnePath::new(instances.clone(), NamedSliceOne::new(port.clone())), + }) + } +} + impl HasSimData> for TranOutput { fn get_data(&self, k: &NodePath) -> Option<&Vec> { self.get_data(&self.lib.convert_node_path(k)?) diff --git a/tools/spectre/src/lib.rs b/tools/spectre/src/lib.rs index 44e8cc7c..434d2207 100644 --- a/tools/spectre/src/lib.rs +++ b/tools/spectre/src/lib.rs @@ -17,11 +17,12 @@ use error::*; use rust_decimal::Decimal; use scir::netlist::{Include, NetlistKind, NetlistLibConversion, NetlisterInstance, RenameGround}; use scir::schema::{FromSchema, NoSchema, NoSchemaError}; -use scir::{Library, ParamValue, SliceOnePath}; +use scir::{Library, NamedSliceOne, ParamValue, SliceOnePath}; use serde::{Deserialize, Serialize}; use substrate::block::Block; use substrate::execute::Executor; use substrate::io::{NestedNode, NodePath, SchematicType}; +use substrate::schematic::conv::ConvertedNodePath; use substrate::schematic::primitives::{Capacitor, RawInstance, Resistor}; use substrate::schematic::schema::Schema; use substrate::schematic::{Primitive, PrimitiveSchematic}; @@ -187,6 +188,25 @@ impl SetInitialCondition<&SliceOnePath, Decimal, Spectre> for Options { } } +impl SetInitialCondition<&ConvertedNodePath, Decimal, Spectre> for Options { + fn set_initial_condition( + &mut self, + key: &ConvertedNodePath, + value: Decimal, + _ctx: &SimulationContext, + ) { + self.set_ic_inner( + SimSignal::ScirVoltage(match key { + ConvertedNodePath::Cell(path) => path.clone(), + ConvertedNodePath::Primitive { + instances, port, .. + } => SliceOnePath::new(instances.clone(), NamedSliceOne::new(port.clone())), + }), + value, + ); + } +} + impl SetInitialCondition<&NodePath, Decimal, Spectre> for Options { fn set_initial_condition( &mut self, @@ -220,7 +240,7 @@ impl SetInitialCondition for Options { } } -#[impl_dispatch({SliceOnePath; NodePath})] +#[impl_dispatch({SliceOnePath; ConvertedNodePath; NodePath})] impl SetInitialCondition for Options { fn set_initial_condition(&mut self, key: T, value: Decimal, ctx: &SimulationContext) { self.set_initial_condition(&key, value, ctx); diff --git a/tools/spectre/src/tran.rs b/tools/spectre/src/tran.rs index 4354e116..edd0393f 100644 --- a/tools/spectre/src/tran.rs +++ b/tools/spectre/src/tran.rs @@ -4,13 +4,13 @@ use crate::{node_voltage_path, ErrPreset, SimSignal, Spectre}; use arcstr::ArcStr; use rust_decimal::Decimal; use scir::netlist::NetlistLibConversion; -use scir::SliceOnePath; +use scir::{NamedSliceOne, SliceOnePath}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::ops::Deref; use std::sync::Arc; use substrate::io::{NodePath, TerminalPath}; -use substrate::schematic::conv::RawLib; +use substrate::schematic::conv::{ConvertedNodePath, RawLib}; use substrate::schematic::{Cell, ExportsNestedData}; use substrate::simulation::data::{FromSaved, HasSimData, Save}; use substrate::simulation::{Analysis, SimulationContext, Simulator, Supports}; @@ -153,6 +153,25 @@ impl Save for TranVoltage { } } +impl Save for TranVoltage { + fn save( + ctx: &SimulationContext, + to_save: &ConvertedNodePath, + opts: &mut ::Options, + ) -> Self::Key { + 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 TranVoltage { fn save( ctx: &SimulationContext, @@ -163,7 +182,7 @@ impl Save for TranVoltage { } } -#[impl_dispatch({SliceOnePath; NodePath})] +#[impl_dispatch({SliceOnePath; ConvertedNodePath; NodePath})] impl Save for TranVoltage { fn save( ctx: &SimulationContext, @@ -235,6 +254,25 @@ impl Save for TranCurrent { } } +impl Save for TranCurrent { + fn save( + ctx: &SimulationContext, + to_save: &ConvertedNodePath, + opts: &mut ::Options, + ) -> Self::Key { + 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 TranCurrent { fn save( ctx: &SimulationContext, @@ -252,7 +290,7 @@ impl Save for TranCurrent { } } -#[impl_dispatch({SliceOnePath; TerminalPath})] +#[impl_dispatch({SliceOnePath; ConvertedNodePath; TerminalPath})] impl Save for TranCurrent { fn save( ctx: &SimulationContext, @@ -280,6 +318,17 @@ impl HasSimData> for TranOutput { } } +impl HasSimData> for TranOutput { + fn get_data(&self, k: &ConvertedNodePath) -> Option<&Vec> { + self.get_data(&match k { + ConvertedNodePath::Cell(path) => path.clone(), + ConvertedNodePath::Primitive { + instances, port, .. + } => SliceOnePath::new(instances.clone(), NamedSliceOne::new(port.clone())), + }) + } +} + impl HasSimData> for TranOutput { fn get_data(&self, k: &NodePath) -> Option<&Vec> { self.get_data(&self.lib.convert_node_path(k)?)