Skip to content

Commit

Permalink
feat(spice): refactor netlisting and fix voltage source netlist (#316)
Browse files Browse the repository at this point in the history
* start fixing spice and adding helper functions for netlisting

* fix errors

* delete extra files
  • Loading branch information
rohanku authored Nov 4, 2023
1 parent 77669d1 commit 7a3df69
Show file tree
Hide file tree
Showing 16 changed files with 523 additions and 494 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 0 additions & 45 deletions examples/sky130_inverter/tests/design_inverter/pw1200/netlist.scs

This file was deleted.

14 changes: 0 additions & 14 deletions examples/sky130_inverter/tests/design_inverter/pw1200/simulate.sh

This file was deleted.

1 change: 0 additions & 1 deletion libs/scir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ tracing = "0.1"
serde = "1"
indexmap = { version = "2", features = ["serde"] }
thiserror = "1"
itertools = "0.11.0"

diagnostics = { version = "0.3.0", path = "../diagnostics", registry = "substrate" }
uniquify = { version = "0.2.0", path = "../uniquify", registry = "substrate" }
Expand Down
30 changes: 28 additions & 2 deletions libs/scir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,9 @@ use serde::{Deserialize, Serialize};
use tracing::{span, Level};

pub mod merge;
pub mod netlist;
pub mod schema;
mod slice;

use crate::netlist::NetlistLibConversion;
use crate::schema::{FromSchema, NoSchema, NoSchemaError, Schema};
use crate::validation::ValidatorIssue;
pub use slice::{Concat, IndexOwned, NamedSlice, NamedSliceOne, Slice, SliceOne, SliceRange};
Expand Down Expand Up @@ -799,6 +797,34 @@ pub struct Cell {
instance_name_map: HashMap<ArcStr, InstanceId>,
}

/// Metadata associated with the conversion from a SCIR library to a netlist.
#[derive(Debug, Clone, Default)]
pub struct NetlistLibConversion {
/// Conversion metadata for each cell in the SCIR library.
pub cells: HashMap<CellId, NetlistCellConversion>,
}

impl NetlistLibConversion {
/// Creates a new [`NetlistLibConversion`].
pub fn new() -> Self {
Self::default()
}
}

/// Metadata associated with the conversion from a SCIR cell to a netlisted subcircuit.
#[derive(Debug, Clone, Default)]
pub struct NetlistCellConversion {
/// The netlisted names of SCIR instances.
pub instances: HashMap<InstanceId, ArcStr>,
}

impl NetlistCellConversion {
/// Creates a new [`NetlistCellConversion`].
pub fn new() -> Self {
Self::default()
}
}

impl<S: Schema> LibraryBuilder<S> {
/// Creates a new, empty library.
pub fn new() -> Self {
Expand Down
209 changes: 0 additions & 209 deletions libs/scir/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use itertools::Itertools;
use std::io::Write;
use test_log::test;

use crate::netlist::{HasSpiceLikeNetlist, Include, NetlistKind, NetlisterInstance, RenameGround};
use crate::schema::{FromSchema, StringSchema};
use crate::*;

Expand Down Expand Up @@ -319,209 +316,3 @@ fn name_path_conversion() {
);
}
}

#[test]
fn spice_like_netlist() {
pub struct SpiceLikeSchema {
bus_delimiter: (char, char),
}

impl Schema for SpiceLikeSchema {
type Primitive = ArcStr;
}

impl HasSpiceLikeNetlist for SpiceLikeSchema {
fn write_include<W: Write>(&self, out: &mut W, include: &Include) -> std::io::Result<()> {
if let Some(section) = &include.section {
write!(out, ".LIB {:?} {}", include.path, section)?;
} else {
write!(out, ".INCLUDE {:?}", include.path)?;
}
Ok(())
}

fn write_start_subckt<W: Write>(
&self,
out: &mut W,
name: &ArcStr,
ports: &[&SignalInfo],
) -> std::io::Result<()> {
let (start, end) = self.bus_delimiter;
write!(out, ".SUBCKT {}", name)?;
for sig in ports {
if let Some(width) = sig.width {
for i in 0..width {
write!(out, " {}{}{}{}", sig.name, start, i, end)?;
}
} else {
write!(out, " {}", sig.name)?;
}
}
Ok(())
}

fn write_end_subckt<W: Write>(&self, out: &mut W, name: &ArcStr) -> std::io::Result<()> {
write!(out, ".ENDS {}", name)
}

fn write_slice<W: Write>(
&self,
out: &mut W,
slice: Slice,
info: &SignalInfo,
) -> std::io::Result<()> {
let (start, end) = self.bus_delimiter;
if let Some(range) = slice.range() {
for i in range.indices() {
if i > range.start() {
write!(out, " ")?;
}
write!(out, "{}{}{}{}", &info.name, start, i, end)?;
}
} else {
write!(out, "{}", &info.name)?;
}
Ok(())
}

fn write_instance<W: Write>(
&self,
out: &mut W,
name: &ArcStr,
connections: Vec<ArcStr>,
child: &ArcStr,
) -> std::io::Result<ArcStr> {
write!(out, "{}", name)?;

for connection in connections {
write!(out, " {}", connection)?;
}

write!(out, " {}", child)?;

Ok(name.clone())
}

fn write_primitive_inst<W: Write>(
&self,
out: &mut W,
name: &ArcStr,
connections: HashMap<ArcStr, Vec<ArcStr>>,
primitive: &<Self as Schema>::Primitive,
) -> std::io::Result<ArcStr> {
write!(out, "{}", name)?;

let connections = connections
.into_iter()
.sorted_by_key(|(name, _)| name.clone())
.collect::<Vec<_>>();

for (_, connection) in connections {
for signal in connection {
write!(out, " {}", signal)?;
}
}

write!(out, " {}", primitive)?;

Ok(name.clone())
}
}

const N: usize = 3;

let mut lib = LibraryBuilder::<SpiceLikeSchema>::new();

let resistor = lib.add_primitive("resistor".into());

let mut dut = Cell::new("dut");

let p = dut.add_bus("p", N);
let n = dut.add_bus("n", N);

for i in 0..N {
let mut resistor = Instance::new(format!("inst_{i}"), resistor);
resistor.connect("p", p.index(i));
resistor.connect("n", n.index(i));
dut.add_instance(resistor);
}

dut.expose_port(p, Direction::InOut);
dut.expose_port(n, Direction::InOut);

let dut = lib.add_cell(dut);

let mut tb = Cell::new("tb");

let vdd = tb.add_node("vdd");
let vss = tb.add_node("vss");

let mut dut = Instance::new("dut", dut);
dut.connect("p", Concat::new(vec![vdd.into(); 3]));
dut.connect("n", Concat::new(vec![vss.into(); 3]));
tb.add_instance(dut);

tb.expose_port(vss, Direction::InOut);
let tb = lib.add_cell(tb);

lib.set_top(tb);

let lib = lib.build().unwrap();

let schema = SpiceLikeSchema {
bus_delimiter: ('<', '|'),
};
let mut buf = Vec::new();
let netlister = NetlisterInstance::new(
NetlistKind::Testbench(RenameGround::Yes("0".into())),
&schema,
&lib,
&[],
&mut buf,
);

netlister.export().unwrap();

let netlist = std::str::from_utf8(&buf).unwrap();

println!("{:?}", netlist);
for fragment in [
r#".SUBCKT dut p<0| p<1| p<2| n<0| n<1| n<2|
inst_0 n<0| p<0| resistor
inst_1 n<1| p<1| resistor
inst_2 n<2| p<2| resistor
.ENDS dut"#,
"dut vdd vdd vdd 0 0 0 dut",
] {
println!("{:?}", fragment);
assert!(netlist.contains(fragment));
}

let mut buf = Vec::new();
let netlister = NetlisterInstance::new(NetlistKind::Cells, &schema, &lib, &[], &mut buf);

netlister.export().unwrap();

let netlist = std::str::from_utf8(&buf).unwrap();

println!("{:?}", netlist);
for fragment in [
r#".SUBCKT dut p<0| p<1| p<2| n<0| n<1| n<2|
inst_0 n<0| p<0| resistor
inst_1 n<1| p<1| resistor
inst_2 n<2| p<2| resistor
.ENDS dut"#,
r#".SUBCKT tb vss
dut vdd vdd vdd vss vss vss dut
.ENDS tb"#,
] {
println!("{:?}", fragment);
assert!(netlist.contains(fragment));
}
}
1 change: 1 addition & 0 deletions libs/spice/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ rust_decimal_macros = "1"

scir = { version = "0.6.0", registry = "substrate", path = "../scir" }
substrate = { version = "0.7.0", registry = "substrate", path = "../../substrate" }
enumify = { version = "0.1.0", path = "../enumify", registry = "substrate" }
Loading

0 comments on commit 7a3df69

Please sign in to comment.