Skip to content

Commit 0da1908

Browse files
committed
chore: release main
1 parent 530f86c commit 0da1908

File tree

10 files changed

+2622
-0
lines changed

10 files changed

+2622
-0
lines changed

examples/release/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ resolver = "2"
44

55
members = [
66
"colbuf",
7+
"resistor_bank",
78
"sky130_inverter",
89
"spice_vdivider",
10+
"strongarm",
911
"substrate_api_examples",
1012
"vdivider",
1113
"via"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "resistor_bank"
3+
version = "0.1.1"
4+
edition = "2024"
5+
6+
[dependencies]
7+
atoll = { version = "0.1.4", registry = "substrate" }
8+
substrate = { version = "0.10.3", registry = "substrate" }
9+
sky130 = { version = "0.10.3", registry = "substrate" }
10+
layir = { version = "0.2.2", registry = "substrate" }
11+
gdsconv = { version = "0.2.2", registry = "substrate" }
12+
gds = { version = "0.4.2", registry = "substrate" }
13+
scir = { version = "0.9.2", registry = "substrate" }
14+
spice = { version = "0.9.3", registry = "substrate" }
15+
16+
arcstr = "1"
17+
rust_decimal = "1"
18+
rust_decimal_macros = "1"
19+
derive-where = "1"
20+
approx = "0.5"
21+
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
use atoll::fold::Foldable;
2+
use atoll::straps::{GreedyStrapper, LayerStrappingParams, StrappingParams};
3+
use atoll::{Tile, TileData, route::GreedyRouter};
4+
use sky130::{
5+
Sky130,
6+
atoll::{NmosTile, PtapTile, Sky130ViaMaker},
7+
res::PrecisionResistorCell,
8+
};
9+
use substrate::types::codegen::{PortGeometryBundle, View};
10+
use substrate::{
11+
block::Block,
12+
geometry::align::AlignMode,
13+
geometry::bbox::Bbox,
14+
types::{FlatLen, InOut, Input, Io, Signal, layout::PortGeometryBuilder},
15+
};
16+
17+
#[derive(Debug, Default, Clone, Io)]
18+
pub struct ResistorBankSliceIo {
19+
pub din: Input<Signal>,
20+
pub en: Input<Signal>,
21+
pub vss: InOut<Signal>,
22+
}
23+
24+
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Block)]
25+
#[substrate(io = "ResistorBankSliceIo")]
26+
pub struct ResistorBankSlice {
27+
pub n: NmosTile,
28+
pub res: PrecisionResistorCell,
29+
pub tap: PtapTile,
30+
}
31+
32+
impl Foldable for ResistorBankSlice {
33+
type ViaMaker = Sky130ViaMaker;
34+
fn via_maker() -> Self::ViaMaker {
35+
Sky130ViaMaker
36+
}
37+
}
38+
39+
impl Tile for ResistorBankSlice {
40+
type Schema = Sky130;
41+
type NestedData = ();
42+
type LayoutBundle = View<ResistorBankSliceIo, PortGeometryBundle<Self::Schema>>;
43+
type LayoutData = ();
44+
45+
fn tile<'a>(
46+
&self,
47+
io: &'a substrate::types::schematic::IoNodeBundle<Self>,
48+
cell: &mut atoll::TileBuilder<'a, Self::Schema>,
49+
) -> substrate::error::Result<atoll::TileData<Self>> {
50+
let mut din = PortGeometryBuilder::new();
51+
let mut en = PortGeometryBuilder::new();
52+
let mut vss = PortGeometryBuilder::new();
53+
let x = cell.signal("x", Signal);
54+
let n = cell.generate_primitive_named(self.n, "nmos");
55+
for i in 0..n.io().g.len() {
56+
cell.connect(n.io().g[i], io.en);
57+
}
58+
for i in 0..n.io().sd.len() {
59+
if i % 2 == 0 {
60+
cell.connect(n.io().sd[i], io.din);
61+
} else {
62+
cell.connect(n.io().sd[i], x);
63+
}
64+
}
65+
cell.connect(n.io().b, io.vss);
66+
let mut tap = cell.generate_primitive_named(self.tap, "tap");
67+
cell.connect(tap.io().vnb, io.vss);
68+
let mut res = cell.generate_primitive_named(self.res, "res");
69+
cell.connect(res.io().p, x);
70+
cell.connect(res.io().n, io.vss);
71+
let nbbox = n.lcm_bounds();
72+
res.align_rect_mut(nbbox, AlignMode::CenterHorizontal, 0);
73+
res.align_rect_mut(nbbox, AlignMode::Beneath, 0);
74+
let resbbox = res.lcm_bounds();
75+
tap.align_rect_mut(nbbox, AlignMode::Left, 0);
76+
tap.align_rect_mut(resbbox, AlignMode::Beneath, 0);
77+
78+
let n = cell.draw(n)?;
79+
let res = cell.draw(res)?;
80+
let tap = cell.draw(tap)?;
81+
82+
en.merge(n.layout.io().g[0].clone());
83+
din.merge(n.layout.io().sd[1].clone());
84+
vss.merge(n.layout.io().b);
85+
vss.merge(res.layout.io().n);
86+
vss.merge(tap.layout.io().vnb);
87+
88+
cell.set_top_layer(2);
89+
cell.set_router(GreedyRouter::new());
90+
cell.set_via_maker(Sky130ViaMaker);
91+
cell.set_strapper(GreedyStrapper);
92+
cell.set_strapping(
93+
io.vss,
94+
StrappingParams::new(1, vec![LayerStrappingParams::ViaDown { min_period: 30 }]),
95+
);
96+
97+
Ok(TileData {
98+
nested_data: (),
99+
layout_bundle: ResistorBankSliceIoView {
100+
din: din.build()?,
101+
en: en.build()?,
102+
vss: vss.build()?,
103+
},
104+
layout_data: (),
105+
outline: cell.layout.bbox_rect(),
106+
})
107+
}
108+
}
109+
110+
#[cfg(test)]
111+
mod tests {
112+
use super::*;
113+
114+
use atoll::TileWrapper;
115+
use atoll::fold::{FoldedArray, PinConfig};
116+
use scir::netlist::ConvertibleNetlister;
117+
use sky130::Sky130SrcNdaSchema;
118+
use sky130::atoll::MosLength;
119+
use sky130::res::{PrecisionResistor, PrecisionResistorWidth};
120+
use sky130::{Sky130, layout::to_gds};
121+
use spice::{Spice, netlist::NetlistOptions};
122+
use std::path::PathBuf;
123+
use substrate::context::Context;
124+
use substrate::geometry::dir::Dir;
125+
use substrate::geometry::side::Side;
126+
127+
pub fn sky130_src_nda_ctx() -> Context {
128+
// Open PDK needed for standard cells.
129+
let open_pdk_root = std::env::var("SKY130_OPEN_PDK_ROOT")
130+
.expect("the SKY130_OPEN_PDK_ROOT environment variable must be set");
131+
let src_nda_pdk_root = std::env::var("SKY130_SRC_NDA_PDK_ROOT")
132+
.expect("the SKY130_SRC_NDA_PDK_ROOT environment variable must be set");
133+
Context::builder()
134+
.install(Sky130::src_nda(open_pdk_root, src_nda_pdk_root))
135+
.build()
136+
}
137+
138+
#[test]
139+
fn resistor_bank_slice_lvs() {
140+
let work_dir = PathBuf::from(concat!(
141+
env!("CARGO_MANIFEST_DIR"),
142+
"/build/resistor_bank_slice_lvs"
143+
));
144+
let gds_path = work_dir.join("layout.gds");
145+
let netlist_path = work_dir.join("netlist.sp");
146+
let ctx = sky130_src_nda_ctx();
147+
148+
let block = TileWrapper::new(ResistorBankSlice {
149+
tap: PtapTile::new(7, 4),
150+
res: PrecisionResistorCell {
151+
resistor: PrecisionResistor {
152+
width: PrecisionResistorWidth::W285,
153+
length: 4_000,
154+
},
155+
dir: Dir::Vert,
156+
},
157+
n: NmosTile::new(2_000, MosLength::L150, 6),
158+
});
159+
160+
let scir = ctx
161+
.export_scir(block)
162+
.unwrap()
163+
.scir
164+
.convert_schema::<Sky130SrcNdaSchema>()
165+
.unwrap()
166+
.convert_schema::<Spice>()
167+
.unwrap()
168+
.build()
169+
.unwrap();
170+
Spice
171+
.write_scir_netlist_to_file(&scir, &netlist_path, NetlistOptions::default())
172+
.expect("failed to write netlist");
173+
174+
ctx.write_layout(block, to_gds, &gds_path)
175+
.expect("failed to write layout");
176+
}
177+
178+
#[test]
179+
fn resistor_bank() {
180+
let work_dir = PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"), "/build/resistor_bank"));
181+
let gds_path = work_dir.join("layout.gds");
182+
let netlist_path = work_dir.join("netlist.sp");
183+
let ctx = sky130_src_nda_ctx();
184+
185+
let block = TileWrapper::new(FoldedArray {
186+
rows: 2,
187+
cols: 20,
188+
pins: vec![
189+
PinConfig::Parallel { layer: 1 },
190+
PinConfig::Escape {
191+
layer: 0,
192+
side: Side::Top,
193+
},
194+
PinConfig::Parallel { layer: 1 },
195+
],
196+
tile: ResistorBankSlice {
197+
tap: PtapTile::new(7, 4),
198+
res: PrecisionResistorCell {
199+
resistor: PrecisionResistor {
200+
width: PrecisionResistorWidth::W141,
201+
length: 2_000,
202+
},
203+
dir: Dir::Vert,
204+
},
205+
n: NmosTile::new(2_000, MosLength::L150, 6),
206+
},
207+
top_layer: 3,
208+
dir: Dir::Horiz,
209+
});
210+
211+
let scir = ctx
212+
.export_scir(block.clone())
213+
.unwrap()
214+
.scir
215+
.convert_schema::<Sky130SrcNdaSchema>()
216+
.unwrap()
217+
.convert_schema::<Spice>()
218+
.unwrap()
219+
.build()
220+
.unwrap();
221+
Spice
222+
.write_scir_netlist_to_file(&scir, &netlist_path, NetlistOptions::default())
223+
.expect("failed to write netlist");
224+
ctx.write_layout(block, to_gds, &gds_path)
225+
.expect("failed to write layout");
226+
}
227+
}

0 commit comments

Comments
 (0)