Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into sky130-mos-both-side-…
Browse files Browse the repository at this point in the history
…gate-contact
  • Loading branch information
rahulk29 committed Oct 18, 2024
2 parents 5ca3ee9 + c9420cc commit 2475332
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 61 deletions.
151 changes: 90 additions & 61 deletions pdks/sky130_common_pdk/src/mos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,72 +157,101 @@ impl Sky130Pdk {
ypoly += params.length() + FINGER_SPACE;
}

// Place gate contacts and create gate ports
let line = gate_bbox.height();
let space = POLY_SPACE;
let total_contact_len = nf as i64 * line + (nf as i64 - 1) * space;
let gate_span = Span::new(poly_rects[0].p0.y, poly_rects.last().unwrap().p1.y);
// TODO: Should be gridded.
let contact_span = Span::from_center_span(gate_span.center(), total_contact_len);

let mut npc_boxes = Vec::new();
let mut npc_boxes_x = Vec::new();

for i in 0..nf as i64 {
let empty_rect = Rect::new(Point::zero(), Point::zero());
let gate_ctp = ViaParams::builder()
.layers(poly, gate_metal)
.geometry(empty_rect, empty_rect)
.expand(ViaExpansion::Minimum)
.build();
let mut gate_ct = ctx.instantiate::<Via>(&gate_ctp)?;

let bot = contact_span.start() + i * (line + space);
let rect = poly_rects[i as usize];
let ofsx = rect.p0.x - gate_bbox.p1.x;
let ofsy = bot - gate_bbox.p0.y;

let ct_ofs = Point::new(ofsx, ofsy);
gate_ct.translate(ct_ofs);
let ct_box = gate_ct.layer_bbox(gate_metal).into_rect();
let mut port = CellPort::new(format!("gate_{i}"));
port.add(gate_metal, Shape::Rect(ct_box));
ctx.add_port(port).unwrap();
// Place gate contacts and create gate ports
match params.contact_strategy {
GateContactStrategy::SingleSide | GateContactStrategy::BothSides => {
assert!(
nf <= 3,
"can only contact nf>=3 transistors on a single side"
);
let line = gate_bbox.height();
let space = POLY_SPACE;
let total_contact_len = nf as i64 * line + (nf as i64 - 1) * space;
let contact_span = Span::from_center_span_gridded(
gate_span.center(),
total_contact_len,
ctx.pdk().layout_grid(),
);

let mut npc_boxes = Vec::new();
let mut npc_boxes_x = Vec::new();

for i in 0..nf as i64 {
let empty_rect = Rect::new(Point::zero(), Point::zero());
let gate_ctp = ViaParams::builder()
.layers(poly, gate_metal)
.geometry(empty_rect, empty_rect)
.expand(ViaExpansion::Minimum)
.build();
let mut gate_ct = ctx.instantiate::<Via>(&gate_ctp)?;

let bot = contact_span.start() + i * (line + space);
let rect = poly_rects[i as usize];
let ofsx = rect.p0.x - gate_bbox.p1.x;
let ofsy = bot - gate_bbox.p0.y;

let ct_ofs = Point::new(ofsx, ofsy);
gate_ct.translate(ct_ofs);
let ct_box = gate_ct.layer_bbox(gate_metal).into_rect();
let mut port = CellPort::new(format!("gate_{i}"));
port.add(gate_metal, Shape::Rect(ct_box));
ctx.add_port(port).unwrap();

if params.contact_strategy == GateContactStrategy::BothSides {
let mut gate_ct = ctx.instantiate::<Via>(&gate_ctp)?;
let ofsx = rect.p1.x - gate_bbox.p0.x;
let ct_ofs = Point::new(ofsx, ofsy);
gate_ct.translate(ct_ofs);
let ct_box = gate_ct.layer_bbox(gate_metal).into_rect();
let mut port = CellPort::new(format!("gate_{i}_x"));
port.add(gate_metal, Shape::Rect(ct_box));
ctx.add_port(port).unwrap();
let npc_bbox = gate_ct.layer_bbox(npc).into_rect();
npc_boxes_x.push(npc_bbox);
ctx.draw(gate_ct)?;
}

if params.contact_strategy == GateContactStrategy::BothSides {
let mut gate_ct = ctx.instantiate::<Via>(&gate_ctp)?;
let ofsx = rect.p1.x - gate_bbox.p0.x;
let ct_ofs = Point::new(ofsx, ofsy);
gate_ct.translate(ct_ofs);
let npc_bbox = gate_ct.layer_bbox(npc).into_rect();
npc_boxes.push(npc_bbox);
ctx.draw(gate_ct)?;
}

for boxes in [npc_boxes, npc_boxes_x] {
if boxes.is_empty() {
continue;
}
let top_npc = boxes.last().unwrap();
let npc_merge_rect = Rect::new(
Point::new(boxes[0].p0.x, boxes[0].p0.y),
Point::new(top_npc.p1.x, top_npc.p1.y),
);
ctx.draw(Element {
net: None,
layer: LayerSpec::new(npc, LayerPurpose::Drawing),
inner: Shape::Rect(npc_merge_rect),
})?;
}
}
GateContactStrategy::Merge => {
let ct_rect = Rect::from_spans(
Span::with_stop_and_length(poly_rects[0].p0.x, 330),
gate_span,
);
let gate_ctp = ViaParams::builder()
.layers(poly, gate_metal)
.geometry(ct_rect, ct_rect)
.expand(ViaExpansion::LongerDirection)
.build();
ctx.draw_rect(poly, ct_rect);
let gate_ct = ctx.instantiate::<Via>(&gate_ctp)?;
ctx.draw_ref(&gate_ct)?;
let ct_box = gate_ct.layer_bbox(gate_metal).into_rect();
let mut port = CellPort::new(format!("gate_{i}_x"));
let mut port = CellPort::new("gate");
port.add(gate_metal, Shape::Rect(ct_box));
ctx.add_port(port).unwrap();
let npc_bbox = gate_ct.layer_bbox(npc).into_rect();
npc_boxes_x.push(npc_bbox);
ctx.draw(gate_ct)?;
ctx.add_port(port).unwrap()
}

let npc_bbox = gate_ct.layer_bbox(npc).into_rect();
npc_boxes.push(npc_bbox);

ctx.draw(gate_ct)?;
}

for boxes in [npc_boxes, npc_boxes_x] {
if boxes.is_empty() {
continue;
}
let top_npc = boxes.last().unwrap();
let npc_merge_rect = Rect::new(
Point::new(boxes[0].p0.x, boxes[0].p0.y),
Point::new(top_npc.p1.x, top_npc.p1.y),
);
ctx.draw(Element {
net: None,
layer: LayerSpec::new(npc, LayerPurpose::Drawing),
inner: Shape::Rect(npc_merge_rect),
})?;
_ => unimplemented!(),
}

// Add source/drain contacts
Expand Down
2 changes: 2 additions & 0 deletions substrate/src/pdk/mos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub enum GateContactStrategy {
Alternate,
/// ABBA placement
Abba,
/// Merge all contacts on one side (usually the left)
Merge,
/// Other; effect depends on layout generator
Other(String),
}
Expand Down

0 comments on commit 2475332

Please sign in to comment.