Skip to content

Commit 008cff4

Browse files
authored
Merge branch 'main' into logic-min-var-value
2 parents 62e1d45 + b7e4e6b commit 008cff4

File tree

3 files changed

+83
-66
lines changed

3 files changed

+83
-66
lines changed

pdks/sky130_commercial_pdk/src/mos.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use sky130_common_pdk::Sky130Pdk;
12
use substrate::error::Result;
23
use substrate::pdk::mos::spec::{MosFlavor, MosId, MosKind, MosSpec};
34
use substrate::pdk::mos::MosParams;
@@ -44,27 +45,19 @@ impl Sky130CommercialPdk {
4445
// larger transistors into several 100um segments plus one smaller segment containing
4546
// the leftover width.
4647
let mut spice = String::new();
47-
const MAX_WIDTH: i64 = 90_000;
48-
let n_extra = params.w / MAX_WIDTH;
4948
let l = params.l as f64 / 1_000.0;
5049
let nf = params.nf;
5150
let m = params.m;
5251

53-
for i in 1..=n_extra {
52+
for (i, w) in Sky130Pdk::fold_mos(params.w).into_iter().enumerate() {
53+
let w = w as f64 / 1_000.0;
5454
writeln!(
5555
&mut spice,
56-
"M{i} d g s b {name} w=90.0 l={l:.3} nf={nf} mult={m}"
56+
"M{i} d g s b {name} w={w:.3} l={l:.3} nf={nf} mult={m}"
5757
)
5858
.expect("failed to write to string");
5959
}
6060

61-
let w = (params.w % MAX_WIDTH) as f64 / 1_000.0;
62-
writeln!(
63-
&mut spice,
64-
"M0 d g s b {name} w={w:.3} l={l:.3} nf={nf} mult={m}"
65-
)
66-
.expect("failed to write to string");
67-
6861
ctx.set_spice(spice);
6962
Ok(())
7063
}

pdks/sky130_common_pdk/src/mos.rs

+77-53
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ use crate::constants::{
1919
use crate::Sky130Pdk;
2020

2121
impl Sky130Pdk {
22+
/// Fold MOS devices to avoid MOS devices wider than 100 microns.
23+
pub fn fold_mos(w: i64) -> Vec<i64> {
24+
let grid_w = w / 5;
25+
const MAX_WIDTH: i64 = 100_000;
26+
let n = grid_w / MAX_WIDTH + 1;
27+
let div = grid_w / n;
28+
let rem = grid_w % n;
29+
let mut out = vec![5 * (div + 1); rem as usize];
30+
out.extend(vec![5 * div; (n - rem) as usize]);
31+
out
32+
}
33+
2234
pub fn mos_layout(ctx: &mut LayoutCtx, params: &LayoutMosParams) -> Result<()> {
2335
params.validate()?;
2436

@@ -48,60 +60,64 @@ impl Sky130Pdk {
4860
let mut prev_nsdm: Option<Rect> = None;
4961

5062
for d in params.devices.iter() {
51-
if let Some(mt) = prev {
52-
if mt != d.kind(&ctx.mos_db()) {
53-
cx += DIFF_TO_OPPOSITE_DIFF;
54-
} else {
55-
cx += DIFF_SPACE;
63+
let mut d_diff_xs = Vec::new();
64+
for w in Self::fold_mos(d.w) {
65+
if let Some(mt) = prev {
66+
if mt != d.kind(&ctx.mos_db()) {
67+
cx += DIFF_TO_OPPOSITE_DIFF;
68+
} else {
69+
cx += DIFF_SPACE;
70+
}
5671
}
57-
}
5872

59-
diff_xs.push(cx);
73+
d_diff_xs.push(cx);
6074

61-
let rect = Rect::new(Point::new(cx, y0), Point::new(cx + d.w, y0 + diff_perp));
75+
let rect = Rect::new(Point::new(cx, y0), Point::new(cx + w, y0 + diff_perp));
6276

63-
if d.kind(&ctx.mos_db()) == MosKind::Pmos {
64-
let mut psdm_box = rect;
65-
psdm_box = psdm_box.expand(DIFF_PSDM_ENCLOSURE);
77+
if d.kind(&ctx.mos_db()) == MosKind::Pmos {
78+
let mut psdm_box = rect;
79+
psdm_box = psdm_box.expand(DIFF_PSDM_ENCLOSURE);
6680

67-
let psdm = layers.get(Selector::Name("psdm"))?;
81+
let psdm = layers.get(Selector::Name("psdm"))?;
6882

69-
if let Some(prev_psdm) = prev_psdm {
70-
psdm_box = psdm_box.union(prev_psdm.into()).into_rect();
71-
}
83+
if let Some(prev_psdm) = prev_psdm {
84+
psdm_box = psdm_box.union(prev_psdm.into()).into_rect();
85+
}
7286

73-
ctx.draw_rect(psdm, psdm_box);
87+
ctx.draw_rect(psdm, psdm_box);
7488

75-
prev_psdm = Some(psdm_box);
76-
prev_nsdm = None;
89+
prev_psdm = Some(psdm_box);
90+
prev_nsdm = None;
7791

78-
let mut well_box = rect;
79-
well_box = well_box.expand(DIFF_NWELL_ENCLOSURE);
92+
let mut well_box = rect;
93+
well_box = well_box.expand(DIFF_NWELL_ENCLOSURE);
8094

81-
let nwell = layers.get(Selector::Name("nwell"))?;
95+
let nwell = layers.get(Selector::Name("nwell"))?;
8296

83-
ctx.draw_rect(nwell, well_box);
84-
} else {
85-
let mut nsdm_box = rect;
86-
nsdm_box = nsdm_box.expand(DIFF_NSDM_ENCLOSURE);
97+
ctx.draw_rect(nwell, well_box);
98+
} else {
99+
let mut nsdm_box = rect;
100+
nsdm_box = nsdm_box.expand(DIFF_NSDM_ENCLOSURE);
87101

88-
let nsdm = layers.get(Selector::Name("nsdm"))?;
102+
let nsdm = layers.get(Selector::Name("nsdm"))?;
89103

90-
if let Some(prev_nsdm) = prev_nsdm {
91-
nsdm_box = nsdm_box.union(prev_nsdm.into()).into_rect();
92-
}
104+
if let Some(prev_nsdm) = prev_nsdm {
105+
nsdm_box = nsdm_box.union(prev_nsdm.into()).into_rect();
106+
}
93107

94-
prev_nsdm = Some(nsdm_box);
95-
prev_psdm = None;
108+
prev_nsdm = Some(nsdm_box);
109+
prev_psdm = None;
96110

97-
ctx.draw_rect(nsdm, nsdm_box);
98-
}
111+
ctx.draw_rect(nsdm, nsdm_box);
112+
}
99113

100-
ctx.draw_rect(diff, rect);
114+
ctx.draw_rect(diff, rect);
101115

102-
cx += d.w;
116+
cx += w;
103117

104-
prev = Some(d.kind(&ctx.mos_db()));
118+
prev = Some(d.kind(&ctx.mos_db()));
119+
}
120+
diff_xs.push(d_diff_xs);
105121
}
106122

107123
let empty_rect = Rect::new(Point::zero(), Point::zero());
@@ -197,32 +213,40 @@ impl Sky130Pdk {
197213
.collect::<Vec<_>>();
198214

199215
for i in 0..=nf {
200-
for ((device, skip_sd_metal), (j, x)) in params
216+
for ((device, skip_sd_metal), (j, xs)) in params
201217
.devices
202218
.iter()
203219
.zip(params.skip_sd_metal.iter())
204220
.zip(diff_xs.iter().enumerate())
205221
{
206-
if skip_sd_metal.contains(&(i as usize)) {
222+
if Self::fold_mos(device.w).len() == 1 && skip_sd_metal.contains(&(i as usize)) {
207223
continue;
208224
}
209225

210-
let via_rect = Rect::new(Point::zero(), Point::new(device.w, 0));
211-
let via_params = ViaParams::builder()
212-
.layers(diff, sd_metal)
213-
.geometry(via_rect, via_rect)
214-
.expand(ViaExpansion::LongerDirection)
215-
.bot_extension(Dir::Horiz)
216-
.top_extension(Dir::Horiz)
217-
.build();
218-
let mut inst = ctx.instantiate::<Via>(&via_params)?;
219-
let bbox = inst.layer_bbox(diff);
220-
let ofsx = (device.w - bbox.width()) / 2;
221-
let loc = Point::new(x - bbox.p0.x + ofsx, cy - bbox.p0.y);
222-
inst.translate(loc);
223-
let sd_rect = inst.layer_bbox(sd_metal).into_rect();
224-
ctx.draw(inst)?;
226+
let mut sd_rects = Vec::new();
227+
for (w, x) in Sky130Pdk::fold_mos(device.w).into_iter().zip(xs) {
228+
let via_rect = Rect::new(Point::zero(), Point::new(w, 0));
229+
let via_params = ViaParams::builder()
230+
.layers(diff, sd_metal)
231+
.geometry(via_rect, via_rect)
232+
.expand(ViaExpansion::LongerDirection)
233+
.bot_extension(Dir::Horiz)
234+
.top_extension(Dir::Horiz)
235+
.build();
236+
let mut inst = ctx.instantiate::<Via>(&via_params)?;
237+
let bbox = inst.layer_bbox(diff);
238+
let ofsx = (w - bbox.width()) / 2;
239+
let loc = Point::new(x - bbox.p0.x + ofsx, cy - bbox.p0.y);
240+
inst.translate(loc);
241+
sd_rects.push(inst.layer_bbox(sd_metal));
242+
ctx.draw(inst)?;
243+
}
225244

245+
let sd_rect = sd_rects
246+
.into_iter()
247+
.reduce(|a, b| a.union(b))
248+
.unwrap()
249+
.into_rect();
226250
let mut port = CellPort::new(format!("sd_{j}_{i}"));
227251
port.add(sd_metal, Shape::Rect(sd_rect));
228252
ctx.add_port(port).unwrap();

substrate/tests/mos.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ fn test_sky130_mos_nand2() {
1515
contact_strategy: substrate::pdk::mos::GateContactStrategy::SingleSide,
1616
devices: vec![
1717
MosParams {
18-
w: 1_000,
18+
w: 200_000,
1919
l: 150,
2020
m: 1,
2121
nf: 2,
2222
id: MosId::new(0),
2323
},
2424
MosParams {
25-
w: 1_400,
25+
w: 100_000,
2626
l: 150,
2727
m: 1,
2828
nf: 2,

0 commit comments

Comments
 (0)