Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/glayout/pdk/gf180_mapped/gf180_grules.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,5 +364,9 @@
grulesobj["capmet"]["met4"] = {}
grulesobj["capmet"]["via4"] = {}
grulesobj["capmet"]["met5"] = {}
grulesobj["capmet"]["capmet"] = {'capmettop': (81, 0), 'capmetbottom': (46, 0), 'min_separation': 1.2}
# via_enclosure: the MIM plate has its own, stricter enclosure of the via that
# contacts it -- 0.4um (MIMTM.4 / MIM.4). The generic metal-over-via rule is
# 0.12, so a via array sized off that reaches 0.28um too close to the plate
# edge and the cap fails DRC at sizes where the count happens to land there.
grulesobj["capmet"]["capmet"] = {'capmettop': (81, 0), 'capmetbottom': (46, 0), 'min_separation': 1.2, 'via_enclosure': 0.4}

27 changes: 26 additions & 1 deletion src/glayout/primitives/mimcap.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,33 @@ def mimcap(

# 3. Create top metal plate with via connections
# Use minus1=False to get maximum via coverage like KLayout generator
# via_array decides how many via columns fit using the generic
# metal-over-via enclosure -- 0.12um for met5 over via4 on gf180 -- but the
# MIM plate has a stricter one: MIMTM.4 (option B) and MIM.4 (option A)
# both want 0.4um of plate over the via that contacts it.
#
# The resulting plate-to-via margin is a sawtooth in `size`: it grows until
# one more column fits, then drops. The floor of that sawtooth is 0.390um,
# comfortable for 0.12 and 10nm short of 0.4, so the violations repeat with
# the via pitch of 0.80um rather than scaling with the size.
#
# Shrinking the array region by the difference between the two rules lifts
# the whole sawtooth by that amount, floor included: 0.390 -> 0.670um. A
# column enters later than it would, so some sizes get one fewer via
# row/column -- slightly more series resistance into the plate, which a MIM
# can afford, in exchange for an enclosure that holds at every size.
via_margin = pdk.get_grule("capmet").get("via_enclosure")
if via_margin is not None:
# the via that contacts the plate from below: met5 -> via4, met3 -> via2
via_glayer = "via" + str(int(capmettop[3:]) - 1)
generic = pdk.get_grule(capmettop, via_glayer)["min_enclosure"]
extra = max(0.0, float(via_margin) - float(generic))
array_size = (size[0] - 2 * extra, size[1] - 2 * extra)
else:
array_size = size
top_met_ref = mim_cap << via_array(
pdk, capmetbottom, capmettop, size=size, minus1=False, lay_bottom=False
pdk, capmetbottom, capmettop, size=array_size, minus1=False,
lay_bottom=False
)

# 4. Add FuseTop layer - required for both options (defines the MIM area)
Expand Down
Loading