Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding MIM-B table for GF180MCU DRC #73

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
150 changes: 150 additions & 0 deletions klayout/drc/rule_decks/mim_b.drc
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# frozen_string_literal: true

################################################################################################
# Copyright 2022 GlobalFoundries PDK Authors
proppy marked this conversation as resolved.
Show resolved Hide resolved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################################

if MIM_OPTION == 'B'
#================================================
#-------------MIM CAPACITOR OPTION B-------------
#================================================

logger.info('Starting MIM Capacitor Option B derivations')

topmin1_metal_fusetop = topmin1_metal.interacting(fusetop)
# mimtm_virtual: Used for MIMTM.1,2,3
mimtm_virtual = fusetop.sized(1.06.um).and(topmin1_metal_fusetop)

# Rule MIMTM.1: Minimum MiM bottom plate spacing to the bottom plate metal
## (whether adjacent MiM or routing metal) is 1.2µm.
logger.info('Executing rule MIMTM.1')
mimtm1_l1 = topmin1_metal.separation(mimtm_virtual, transparent, 1.2.um)
proppy marked this conversation as resolved.
Show resolved Hide resolved
mimtm1_l1.output('MIMTM.1', "MIMTM.1 : Minimum MiM bottom plate spacing to the bottom plate metal
(whether adjacent MiM or routing metal): 1.2µm")
mimtm1_l1.forget

# Rule MIMTM.2: Minimum MiM bottom plate overlap of Vian-1 layer.
## [This is applicable for Vian-1 within 1.06um oversize of FuseTop layer
proppy marked this conversation as resolved.
Show resolved Hide resolved
## (referenced to virtual bottom plate)] is 0.4µm.
logger.info('Executing rule MIMTM.2')
mimtm_via = top_via.overlapping(mimtm_virtual)
mimtm2_l1 = mimtm_via.enclosed(topmin1_metal, 0.4.um, euclidian).polygons(0.001.um)
proppy marked this conversation as resolved.
Show resolved Hide resolved
mimtm2_l2 = mimtm_via.not_outside(topmin1_metal).not(topmin1_metal)
mimtm2_l = mimtm2_l1.join(mimtm2_l2)
mimtm2_l.output('MIMTM.2', "MIMTM.2 : Minimum MiM bottom plate overlap of Vian-1 layer.
[This is applicable for Vian-1 within 1.06um oversize of FuseTop layer
(referenced to virtual bottom plate)]: 0.4µm")
mimtm2_l1.forget
mimtm2_l2.forget
mimtm2_l.forget
mimtm_via.forget

# Rule MIMTM.3: Minimum MiM bottom plate overlap of Top plate is 0.6um.
logger.info('Executing rule MIMTM.3')
mimtm3_l1 = fusetop.enclosed(mimtm_virtual, 0.6.um).polygons(0.001.um)
mimtm3_l2 = fusetop.not_inside(mimtm_virtual)
mimtm3_l = mimtm3_l1.join(mimtm3_l2)
mimtm3_l.output('MIMTM.3', 'MIMTM.3 : Minimum MiM bottom plate overlap of Top plate: 0.6um')
mimtm3_l.forget
mimtm3_l1.forget
mimtm3_l2.forget
mimtm_virtual.forget

# Rule MIMTM.4: Minimum MiM top plate (FuseTop) overlap of Vian-1 is 0.4µm.
logger.info('Executing rule MIMTM.4')
mimtm4_l1 = fusetop.enclosing(top_via, 0.4.um, euclidian).polygons(0.001.um)
mimtm4_l2 = top_via.not_outside(fusetop).not(fusetop)
mimtm4_l = mimtm4_l1.join(mimtm4_l2)
mimtm4_l.output('MIMTM.4', 'MIMTM.4 : Minimum MiM top plate (FuseTop) overlap of Vian-1: 0.4µm')
mimtm4_l1.forget
mimtm4_l2.forget
mimtm4_l.forget

# Rule MIMTM.5: Minimum spacing between top plate and the Vian-1 connecting to the bottom plate is 0.4µm.
logger.info('Executing rule MIMTM.5')
mimtm5_l1 = fusetop.separation(top_via.interacting(topmin1_metal), 0.4.um, euclidian)
mimtm5_l1.output('MIMTM.5',
'MIMTM.5 : Minimum spacing between top plate and the Vian-1 connecting to the bottom plate: 0.4µm')
mimtm5_l1.forget

# Rule MIMTM.6: Minimum spacing between unrelated top plates is 0.6µm.
logger.info('Executing rule MIMTM.6')
mimtm6_l1 = fusetop.space(0.6.um, euclidian)
proppy marked this conversation as resolved.
Show resolved Hide resolved
mimtm6_l1.output('MIMTM.6', 'MIMTM.6 : Minimum spacing between unrelated top plates: 0.6µm')
mimtm6_l1.forget

# Rule MIMTM.7: Min FuseTop enclosure by CAP_MK is 0um.
proppy marked this conversation as resolved.
Show resolved Hide resolved
logger.info('Executing rule MIMTM.7')
mimtm7_l1 = fusetop.not(cap_mk)
mimtm7_l1.output('MIMTM.7', 'MIMTM.7 : Min FuseTop enclosure by CAP_MK: 0um')
mimtm7_l1.forget

# Rule MIMTM.8a: Minimum MIM cap area (defined by FuseTop area) is 25µm².
logger.info('Executing rule MIMTM.8a')
mimtm8a_l1 = fusetop.with_area(nil, 25.um)
mimtm8a_l1.output('MIMTM.8a', 'MIMTM.8a : Minimum MIM cap area (defined by FuseTop area): 25µm²')
mimtm8a_l1.forget

# Rule MIMTM.8b: Maximum single MIM Cap area (Use multiple MIM caps in
## parallel connection if bigger capacitors are required) (um2) is 10000µm.
logger.info('Executing rule MIMTM.8b')
mimtm8b_l1 = fusetop.with_area(10_000.um, nil).not_in(fusetop.with_area(10_000.um))
proppy marked this conversation as resolved.
Show resolved Hide resolved
mimtm8b_l1.output('MIMTM.8b', "MIMTM.8b : Maximum single MIM Cap area (Use multiple MIM caps in
parallel connection if bigger capacitors are required) (um2): 10000µm")
mimtm8b_l1.forget

# Rule MIMTM.9: Min. Via (Vian-1) spacing for sea of Via on MIM top plate is 0.5µm.
logger.info('Executing rule MIMTM.9')
mimtm9_l1 = top_via.inside(fusetop).space(0.5.um, euclidian)
mimtm9_l1.output('MIMTM.9', 'MIMTM.9 : Min. Via (Vian-1) spacing for sea of Via on MIM top plate: 0.5µm')
mimtm9_l1.forget

# Rule MIMTM.10: (a) There cannot be any Vian-2 touching MIM bottom plate Metaln-1.
## (b) MIM bottom plate Metaln-1 can only be connected through the higher Via (Vian-1).
logger.info('Executing rule MIMTM.10')
mimtm10_l1 = topmin1_via.interacting(topmin1_metal_fusetop)
mimtm10_l1.output('MIMTM.10', "MIMTM.10 : (a) There cannot be any Vian-2 touching MIM bottom plate Metaln-1.
(b) MIM bottom plate Metaln-1 can only be connected through the higher Via (Vian-1).")
mimtm10_l1.forget

# Rule MIMTM.11: Bottom plate of multiple MIM caps can be shared (for common nodes)
## as long as total MIM area with that single common plate does not exceed MIMTM.8b rule.
logger.info('Executing rule MIMTM.11')
mimtm11_large_topmin1_metal = topmin1_metal_fusetop.with_area(10_000, nil)
proppy marked this conversation as resolved.
Show resolved Hide resolved
mimtm11_large_topmin1_metal_violation = polygon_layer
proppy marked this conversation as resolved.
Show resolved Hide resolved
mimtm11_large_topmin1_metal.data.each do |p|
mimtm11_topmin1_metal_polygon_layer = polygon_layer
mimtm11_topmin1_metal_polygon_layer.data.insert(p)
fuse_in_polygon = fusetop.and(mimtm11_topmin1_metal_polygon_layer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't it be more effective to test fusetop.and(mimtm11_large_topmin1_metal) outside of a loop, and then look if any resulting shape has an area > 10_000?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@proppy We have to use all checks inside the loop as we need to iterate over each single plate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, but is there a difference between:

fuse_in_polygon = fusetop.and(mimtm11_large_topmin1_metal)
fuse_in_polygon_bad = fuse_in_polygon.filter {|p| p > 10_000 }

and what we currently have?

next unless fuse_in_polygon.area > 10_000
proppy marked this conversation as resolved.
Show resolved Hide resolved

mimtm11_bad_topmin1_metal_polygon = mimtm11_topmin1_metal_polygon_layer.interacting(fuse_in_polygon)
mimtm11_bad_topmin1_metal_polygon.data.each do |b|
b.num_points.positive? && mimtm11_large_topmin1_metal_violation.data.insert(b)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does num_points.positive? check here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@proppy It's a sanity check (num_points > 0) to ignore empty polygons.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@proppy Yes, using !b.is_empty? will get same results.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we switch to it? assuming you agree it makes things more readable?

end
end
mimtm11_l1 = mimtm11_large_topmin1_metal_violation
mimtm11_l1.output('MIMTM.11',
'MIMTM.11 : Bottom plate of multiple MIM caps can be shared (for common nodes)
as long as total MIM area with that single common plate does not exceed MIMTM.8b rule.')
mimtm11_l1.forget
mimtm11_large_topmin1_metal.forget
mimtm11_large_topmin1_metal_violation.forget
topmin1_metal_fusetop.forget

# Rule MIMTM.12 is not a DRC check
# Please refer to https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_10_4_2.html
proppy marked this conversation as resolved.
Show resolved Hide resolved

end
Binary file added klayout/drc/testing/testcases/unit/mim_b.gds
Binary file not shown.
Loading