From 531323a5ebf49f6f588e420b7da35ab2e237d830 Mon Sep 17 00:00:00 2001 From: FaragElsayed2 Date: Sun, 5 Feb 2023 10:05:34 +0200 Subject: [PATCH] Adding linting checks for ruby/drc files --- .github/workflows/linting.yml | 14 +- .rubocop.yml | 45 + Makefile | 12 +- klayout/drc/rule_decks/drc_bjt.drc | 41 - klayout/drc/rule_decks/dualgate.drc | 121 +- klayout/drc/rule_decks/dummy_exclude.drc | 43 - klayout/drc/rule_decks/efuse.drc | 201 - klayout/drc/rule_decks/hres.drc | 137 - klayout/drc/rule_decks/lres.drc | 100 - klayout/drc/rule_decks/lvs_bjt.drc | 34 - klayout/drc/rule_decks/main.drc | 1426 +++--- klayout/drc/rule_decks/mcell.drc | 47 - klayout/drc/rule_decks/otp_mk.drc | 143 - klayout/drc/rule_decks/pres.drc | 99 - klayout/drc/rule_decks/tail.drc | 6 +- klayout/drc/testing/run_regression.py | 2 +- .../drc/testing/testcases/unit/drc_bjt.gds | Bin 5114 -> 0 bytes .../drc/testing/testcases/unit/drc_bjt.svg | 90 - .../testing/testcases/unit/dummy_exclude.gds | Bin 3448 -> 0 bytes .../testing/testcases/unit/dummy_exclude.svg | 46 - klayout/drc/testing/testcases/unit/efuse.gds | Bin 256920 -> 0 bytes klayout/drc/testing/testcases/unit/efuse.svg | 3817 ----------------- klayout/drc/testing/testcases/unit/hres.gds | Bin 78832 -> 0 bytes klayout/drc/testing/testcases/unit/hres.svg | 935 ---- klayout/drc/testing/testcases/unit/lres.gds | Bin 73290 -> 0 bytes klayout/drc/testing/testcases/unit/lres.svg | 690 --- .../drc/testing/testcases/unit/lvs_bjt.gds | Bin 1950 -> 0 bytes .../drc/testing/testcases/unit/lvs_bjt.svg | 42 - klayout/drc/testing/testcases/unit/mcell.gds | Bin 17168 -> 0 bytes klayout/drc/testing/testcases/unit/mcell.svg | 184 - klayout/drc/testing/testcases/unit/otp_mk.gds | Bin 121226 -> 0 bytes klayout/drc/testing/testcases/unit/otp_mk.svg | 1540 ------- klayout/drc/testing/testcases/unit/pres.gds | Bin 70460 -> 0 bytes klayout/drc/testing/testcases/unit/pres.svg | 658 --- 34 files changed, 783 insertions(+), 9690 deletions(-) create mode 100644 .rubocop.yml delete mode 100644 klayout/drc/rule_decks/drc_bjt.drc delete mode 100644 klayout/drc/rule_decks/dummy_exclude.drc delete mode 100644 klayout/drc/rule_decks/efuse.drc delete mode 100644 klayout/drc/rule_decks/hres.drc delete mode 100644 klayout/drc/rule_decks/lres.drc delete mode 100644 klayout/drc/rule_decks/lvs_bjt.drc delete mode 100644 klayout/drc/rule_decks/mcell.drc delete mode 100644 klayout/drc/rule_decks/otp_mk.drc delete mode 100644 klayout/drc/rule_decks/pres.drc delete mode 100644 klayout/drc/testing/testcases/unit/drc_bjt.gds delete mode 100644 klayout/drc/testing/testcases/unit/drc_bjt.svg delete mode 100644 klayout/drc/testing/testcases/unit/dummy_exclude.gds delete mode 100644 klayout/drc/testing/testcases/unit/dummy_exclude.svg delete mode 100644 klayout/drc/testing/testcases/unit/efuse.gds delete mode 100644 klayout/drc/testing/testcases/unit/efuse.svg delete mode 100644 klayout/drc/testing/testcases/unit/hres.gds delete mode 100644 klayout/drc/testing/testcases/unit/hres.svg delete mode 100644 klayout/drc/testing/testcases/unit/lres.gds delete mode 100644 klayout/drc/testing/testcases/unit/lres.svg delete mode 100644 klayout/drc/testing/testcases/unit/lvs_bjt.gds delete mode 100644 klayout/drc/testing/testcases/unit/lvs_bjt.svg delete mode 100644 klayout/drc/testing/testcases/unit/mcell.gds delete mode 100644 klayout/drc/testing/testcases/unit/mcell.svg delete mode 100644 klayout/drc/testing/testcases/unit/otp_mk.gds delete mode 100644 klayout/drc/testing/testcases/unit/otp_mk.svg delete mode 100644 klayout/drc/testing/testcases/unit/pres.gds delete mode 100644 klayout/drc/testing/testcases/unit/pres.svg diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 275c512b..a7968593 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -29,4 +29,16 @@ jobs: submodules: 'recursive' - name: Lint with flake8 run: | - make lint + make lint_python + + lint_ruby: + runs-on: ubuntu-latest + strategy: + max-parallel: 12 + steps: + - uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: Lint with rubocop + run: | + make lint_ruby \ No newline at end of file diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..ca447691 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,45 @@ +# The behavior of RuboCop can be controlled via the .rubocop.yml +# configuration file. It makes it possible to enable/disable +# certain cops (checks) and to alter their behavior if they accept +# any parameters. The file can be placed either in your home +# directory or in some project directory. +# +# RuboCop will start looking for the configuration file in the directory +# where the inspected file is and continue its way up to the root directory. +# +# See https://docs.rubocop.org/rubocop/configuration + +Style/FrozenStringLiteralComment: + Enabled: false + +GlobalVars: + Description: Do not introduce global variables. + Enabled: false + +UselessAssignment: + Description: Useless assignment to variable. + Enabled: false + +Metrics/AbcSize: + Description: Assignment Branch Condition size for conn_space is too high. + Enabled: false + +Metrics/MethodLength: + Description: Method has too many lines. + Enabled: false + +RSpec/VariableName: + Description: Use snake_case for variable names. + EnforcedStyle: "snake_case" + Enabled: false + +Metrics/BlockNesting: + Description: Avoid more than 3 levels of block nesting. + Enabled: false + +AllCops: + Exclude: + - 'env/**/*' + Include: + - '**/*.rb' + - '**/*.drc' diff --git a/Makefile b/Makefile index 21f134b2..18ba8191 100644 --- a/Makefile +++ b/Makefile @@ -25,12 +25,22 @@ ENVIRONMENT_FILE := pdk_regression.yml # Path to regression KLAYOUT_TESTS := klayout/drc/testing/ + include third_party/make-env/conda.mk # Lint python code -lint: | $(CONDA_ENV_PYTHON) +lint_python: | $(CONDA_ENV_PYTHON) @$(IN_CONDA_ENV) flake8 . +# Lint ruby code +lint_ruby:| $(CONDA_ENV_PYTHON) + @$(IN_CONDA_ENV) gem install rubocop + @$(IN_CONDA_ENV) rubocop=`which rubocop` + @$(IN_CONDA_ENV) rubocop_dir=`dirname $$rubocop` + @$(IN_CONDA_ENV) echo $$rubocop_dir + @$(IN_CONDA_ENV) ln -s ../../../bin/ruby $$rubocop_dir/ruby + @$(IN_CONDA_ENV) rubocop . + ################################################################################ ## DRC Regression section ################################################################################ diff --git a/klayout/drc/rule_decks/drc_bjt.drc b/klayout/drc/rule_decks/drc_bjt.drc deleted file mode 100644 index e6db3a5e..00000000 --- a/klayout/drc/rule_decks/drc_bjt.drc +++ /dev/null @@ -1,41 +0,0 @@ -################################################################################################ -# Copyright 2022 GlobalFoundries PDK Authors -# -# 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 FEOL - #================================================ - #--------------------DRC_BJT--------------------- - #================================================ - - # Rule BJT.1: Min. DRC_BJT overlap of DNWELL for NPN BJT. - logger.info("Executing rule BJT.1") - bjt1_l1 = dnwell.interacting(drc_bjt).not(dnwell.inside(drc_bjt)) - bjt1_l1.output("BJT.1", "BJT.1 : Min. DRC_BJT overlap of DNWELL for NPN BJT.") - bjt1_l1.forget - - # Rule BJT.2: Min. DRC_BJT overlap of PCOM in Psub. - logger.info("Executing rule BJT.2") - bjt2_l1 = pcomp.outside(nwell).outside(dnwell).interacting(drc_bjt).not(pcomp.outside(nwell).outside(dnwell).inside(drc_bjt)) - bjt2_l1.output("BJT.2", "BJT.2 : Min. DRC_BJT overlap of PCOM in Psub.") - bjt2_l1.forget - - # Rule BJT.3: Minimum space of DRC_BJT layer to unrelated COMP. is 0.1µm - logger.info("Executing rule BJT.3") - bjt3_l1 = comp.outside(drc_bjt).separation(drc_bjt, 0.1.um, euclidian).polygons(0.001) - bjt3_l1.output("BJT.3", "BJT.3 : Minimum space of DRC_BJT layer to unrelated COMP. : 0.1µm") - bjt3_l1.forget -end #FEOL - diff --git a/klayout/drc/rule_decks/dualgate.drc b/klayout/drc/rule_decks/dualgate.drc index 871a7a6e..0490b8b9 100644 --- a/klayout/drc/rule_decks/dualgate.drc +++ b/klayout/drc/rule_decks/dualgate.drc @@ -15,74 +15,73 @@ ################################################################################################ if FEOL - #================================================ - #--------------------DUALGATE-------------------- - #================================================ + #================================================ + #--------------------DUALGATE-------------------- + #================================================ - # Rule DV.1: Min. Dualgate enclose DNWELL. is 0.5µm - logger.info("Executing rule DV.1") - dv1_l1 = dualgate.enclosing(dnwell, 0.5.um, euclidian).polygons(0.001) - dv1_l2 = dnwell.not_outside(dualgate).not(dualgate) - dv1_l = dv1_l1.or(dv1_l2) - dv1_l.output("DV.1", "DV.1 : Min. Dualgate enclose DNWELL. : 0.5µm") - dv1_l1.forget - dv1_l2.forget - dv1_l.forget + # Rule DV.1: Min. Dualgate enclose DNWELL. is 0.5µm + logger.info('Executing rule DV.1') + dv1_l1 = dualgate.enclosing(dnwell, 0.5.um, euclidian).polygons(0.001) + dv1_l2 = dnwell.not_outside(dualgate).not(dualgate) + dv1_l = dv1_l1.or(dv1_l2) + dv1_l.output('DV.1', 'DV.1 : Min. Dualgate enclose DNWELL. : 0.5µm') + dv1_l1.forget + dv1_l2.forget + dv1_l.forget - # Rule DV.2: Min. Dualgate Space. Merge if Space is less than this design rule. is 0.44µm - logger.info("Executing rule DV.2") - dv2_l1 = dualgate.space(0.44.um, euclidian).polygons(0.001) - dv2_l1.output("DV.2", "DV.2 : Min. Dualgate Space. Merge if Space is less than this design rule. : 0.44µm") - dv2_l1.forget + # Rule DV.2: Min. Dualgate Space. Merge if Space is less than this design rule. is 0.44µm + logger.info('Executing rule DV.2') + dv2_l1 = dualgate.space(0.44.um, euclidian).polygons(0.001) + dv2_l1.output('DV.2', 'DV.2 : Min. Dualgate Space. Merge if Space is less than this design rule. : 0.44µm') + dv2_l1.forget - # Rule DV.3: Min. Dualgate to COMP space [unrelated]. is 0.24µm - logger.info("Executing rule DV.3") - dv3_l1 = dualgate.separation(comp.outside(dualgate), 0.24.um, euclidian).polygons(0.001) - dv3_l1.output("DV.3", "DV.3 : Min. Dualgate to COMP space [unrelated]. : 0.24µm") - dv3_l1.forget + # Rule DV.3: Min. Dualgate to COMP space [unrelated]. is 0.24µm + logger.info('Executing rule DV.3') + dv3_l1 = dualgate.separation(comp.outside(dualgate), 0.24.um, euclidian).polygons(0.001) + dv3_l1.output('DV.3', 'DV.3 : Min. Dualgate to COMP space [unrelated]. : 0.24µm') + dv3_l1.forget - # rule DV.4 is not a DRC check - # Refer to: https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_07_07.html + # rule DV.4 is not a DRC check + # Refer to: https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_07_07.html - # Rule DV.5: Min. Dualgate width. is 0.7µm - logger.info("Executing rule DV.5") - dv5_l1 = dualgate.width(0.7.um, euclidian).polygons(0.001) - dv5_l1.output("DV.5", "DV.5 : Min. Dualgate width. : 0.7µm") - dv5_l1.forget + # Rule DV.5: Min. Dualgate width. is 0.7µm + logger.info('Executing rule DV.5') + dv5_l1 = dualgate.width(0.7.um, euclidian).polygons(0.001) + dv5_l1.output('DV.5', 'DV.5 : Min. Dualgate width. : 0.7µm') + dv5_l1.forget - comp_dv = comp.not(pcomp.outside(nwell)) - # Rule DV.6: Min. Dualgate enclose COMP (except substrate tap). is 0.24µm - logger.info("Executing rule DV.6") - dv6_l1 = dualgate.enclosing(comp_dv, 0.24.um, euclidian).polygons(0.001) - dv6_l2 = comp_dv.not_outside(dualgate).not(dualgate) - dv6_l = dv6_l1.or(dv6_l2) - dv6_l.output("DV.6", "DV.6 : Min. Dualgate enclose COMP (except substrate tap). : 0.24µm") - dv6_l1.forget - dv6_l2.forget - dv6_l.forget + comp_dv = comp.not(pcomp.outside(nwell)) + # Rule DV.6: Min. Dualgate enclose COMP (except substrate tap). is 0.24µm + logger.info('Executing rule DV.6') + dv6_l1 = dualgate.enclosing(comp_dv, 0.24.um, euclidian).polygons(0.001) + dv6_l2 = comp_dv.not_outside(dualgate).not(dualgate) + dv6_l = dv6_l1.or(dv6_l2) + dv6_l.output('DV.6', 'DV.6 : Min. Dualgate enclose COMP (except substrate tap). : 0.24µm') + dv6_l1.forget + dv6_l2.forget + dv6_l.forget - # Rule DV.7: COMP (except substrate tap) can not be partially overlapped by Dualgate. - logger.info("Executing rule DV.7") - dv7_l1 = dualgate.not_outside(comp_dv).not(dualgate.covering(comp_dv)) - dv7_l1.output("DV.7", "DV.7 : COMP (except substrate tap) can not be partially overlapped by Dualgate.") - dv7_l1.forget + # Rule DV.7: COMP (except substrate tap) can not be partially overlapped by Dualgate. + logger.info('Executing rule DV.7') + dv7_l1 = dualgate.not_outside(comp_dv).not(dualgate.covering(comp_dv)) + dv7_l1.output('DV.7', 'DV.7 : COMP (except substrate tap) can not be partially overlapped by Dualgate.') + dv7_l1.forget - comp_dv.forget + comp_dv.forget - # Rule DV.8: Min Dualgate enclose Poly2. is 0.4µm - logger.info("Executing rule DV.8") - dv8_l1 = dualgate.enclosing(poly2, 0.4.um, euclidian).polygons(0.001) - dv8_l2 = poly2.not_outside(dualgate).not(dualgate) - dv8_l = dv8_l1.or(dv8_l2) - dv8_l.output("DV.8", "DV.8 : Min Dualgate enclose Poly2. : 0.4µm") - dv8_l1.forget - dv8_l2.forget - dv8_l.forget - - # Rule DV.9: 3.3V and 5V/6V PMOS cannot be sitting inside same NWELL. - logger.info("Executing rule DV.9") - dv9_l1 = nwell.covering(pgate.and(dualgate)).covering(pgate.not_inside(v5_xtor).not_inside(dualgate)) - dv9_l1.output("DV.9", "DV.9 : 3.3V and 5V/6V PMOS cannot be sitting inside same NWELL.") - dv9_l1.forget -end #FEOL + # Rule DV.8: Min Dualgate enclose Poly2. is 0.4µm + logger.info('Executing rule DV.8') + dv8_l1 = dualgate.enclosing(poly2, 0.4.um, euclidian).polygons(0.001) + dv8_l2 = poly2.not_outside(dualgate).not(dualgate) + dv8_l = dv8_l1.or(dv8_l2) + dv8_l.output('DV.8', 'DV.8 : Min Dualgate enclose Poly2. : 0.4µm') + dv8_l1.forget + dv8_l2.forget + dv8_l.forget + # Rule DV.9: 3.3V and 5V/6V PMOS cannot be sitting inside same NWELL. + logger.info('Executing rule DV.9') + dv9_l1 = nwell.covering(pgate.and(dualgate)).covering(pgate.not_inside(v5_xtor).not_inside(dualgate)) + dv9_l1.output('DV.9', 'DV.9 : 3.3V and 5V/6V PMOS cannot be sitting inside same NWELL.') + dv9_l1.forget +end diff --git a/klayout/drc/rule_decks/dummy_exclude.drc b/klayout/drc/rule_decks/dummy_exclude.drc deleted file mode 100644 index ed3c4656..00000000 --- a/klayout/drc/rule_decks/dummy_exclude.drc +++ /dev/null @@ -1,43 +0,0 @@ -################################################################################################ -# Copyright 2022 GlobalFoundries PDK Authors -# -# 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. -################################################################################################ - -#================================================ -#--------------DUMMY EXCLUDE LAYERS-------------- -#================================================ - -# rule DE.1 is not a DRC check -## Please refer to https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_10_08.html#design-rules-for-dummy-exclude-layers-ndmy-and-pmndmy - -# Rule DE.2: Minimum NDMY or PMNDMY size (x or y dimension in um). is 0.8µm -logger.info("Executing rule DE.2") -de2_l1 = ndmy.or(pmndmy).width(0.8.um, euclidian) -de2_l1.output("DE.2", "DE.2 : Minimum NDMY or PMNDMY size (x or y dimension in um). : 0.8µm") -de2_l1.forget - -# Rule DE.3: If size greater than 15000 um2 then two sides should not be greater than (80 um). -logger.info("Executing rule DE.3") -de3_ndmy_area = ndmy.with_area(15000.um, nil) -de3_l1 = de3_ndmy_area.edges.with_length(80.001.um, nil) -de3_l1.output("DE.3", "DE.3 : If size greater than 15000 um2 then two sides should not be greater than (80 um).") -de3_l1.forget -de3_ndmy_area.forget - -# Rule DE.4: Minimum NDMY to NDMY space (Merge if space is less). is 20µm -logger.info("Executing rule DE.4") -de4_l1 = ndmy.space(20.um, euclidian) -de4_l1.output("DE.4", "DE.4 : Minimum NDMY to NDMY space (Merge if space is less). : 20µm") -de4_l1.forget - diff --git a/klayout/drc/rule_decks/efuse.drc b/klayout/drc/rule_decks/efuse.drc deleted file mode 100644 index ccaf55a0..00000000 --- a/klayout/drc/rule_decks/efuse.drc +++ /dev/null @@ -1,201 +0,0 @@ -################################################################################################ -# Copyright 2022 GlobalFoundries PDK Authors -# -# 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. -################################################################################################ - - -#================================================ -#---------------------EFUSE---------------------- -#================================================ - - -logger.info("Starting EFUSE derivations") -plfuse_efuse = plfuse.and(efuse_mk) - -# Rule EF.01: Min. (Poly2 butt PLFUSE) within EFUSE_MK and Pplus. -logger.info("Executing rule EF.01") -ef01_l1 = poly2.or(plfuse).interacting(efuse_mk).not_inside(efuse_mk.and(pplus)) -ef01_l1.output("EF.01", "EF.01 : Min. (Poly2 butt PLFUSE) within EFUSE_MK and Pplus.") -ef01_l1.forget - -# Rule EF.02: Min. Max. PLFUSE width. is 0.18µm -logger.info("Executing rule EF.02") -ef02_l1 = plfuse.drc(width != 0.18.um) -ef02_l1.output("EF.02", "EF.02 : Min. Max. PLFUSE width. : 0.18µm") -ef02_l1.forget - -# Rule EF.03: Min. Max. PLFUSE length. is 1.26µm -logger.info("Executing rule EF.03") -ef03_l1 = plfuse.edges.interacting(poly2.edges.and(plfuse.edges).centers(0, 0.95)).without_length(1.26.um) -ef03_l1.output("EF.03", "EF.03 : Min. Max. PLFUSE length. : 1.26µm") -ef03_l1.forget - -# Rule EF.04a: Min. Max. PLFUSE overlap Poly2 (coinciding permitted) and touch cathode and anode. -logger.info("Executing rule EF.04a") -ef04a_l1 = plfuse.not_in(plfuse.interacting(poly2.not(plfuse), 2, 2)).inside(efuse_mk).or(plfuse.not(poly2).inside(efuse_mk)) -ef04a_l1.output("EF.04a", "EF.04a : Min. Max. PLFUSE overlap Poly2 (coinciding permitted) and touch cathode and anode.") -ef04a_l1.forget - -# Rule EF.04b: PLFUSE must be rectangular. -logger.info("Executing rule EF.04b") -ef04b_l1 = plfuse.non_rectangles -ef04b_l1.output("EF.04b", "EF.04b : PLFUSE must be rectangular.") -ef04b_l1.forget - -# Rule EF.04c: Cathode Poly2 must be rectangular. -logger.info("Executing rule EF.04c") -cathode = poly2.and(efuse_mk).not(lvs_source.or(plfuse)) -ef04c_l1 = cathode.non_rectangles -ef04c_l1.output("EF.04c", "EF.04c : Cathode Poly2 must be rectangular.") -ef04c_l1.forget - -# Rule EF.04d: Anode Poly2 must be rectangular. -logger.info("Executing rule EF.04d") -anode = poly2.and(lvs_source).and(efuse_mk) -ef04d_l1 = anode.non_rectangles -ef04d_l1.output("EF.04d", "EF.04d : Anode Poly2 must be rectangular.") -ef04d_l1.forget - -# Rule EF.05: Min./Max. LVS_Source overlap Poly2 (at Anode). -logger.info("Executing rule EF.05") -ef05_l1 = poly2.not(plfuse).interacting(lvs_source).not(lvs_source).and(efuse_mk).or(lvs_source.not(poly2).and(efuse_mk)) -ef05_l1.output("EF.05", "EF.05 : Min./Max. LVS_Source overlap Poly2 (at Anode).") -ef05_l1.forget - -# Rule EF.06: Min./Max. Cathode Poly2 width. is 2.26µm -logger.info("Executing rule EF.06") -cathode_width = cathode.edges.not_interacting(cathode.edges.interacting(plfuse)).or(cathode.edges.interacting(plfuse)) -ef06_l1 = cathode_width.without_length(2.26.um) -ef06_l1.output("EF.06", "EF.06 : Min./Max. Cathode Poly2 width. : 2.26µm") -ef06_l1.forget - -# Rule EF.07: Min./Max. Cathode Poly2 length. is 1.84µm -logger.info("Executing rule EF.07") -ef07_l1 = cathode.edges.not(cathode_width).without_length(1.84.um) -ef07_l1.output("EF.07", "EF.07 : Min./Max. Cathode Poly2 length. : 1.84µm") -ef07_l1.forget - -# Rule EF.08: Min./Max. Anode Poly2 width. is 1.06µm -logger.info("Executing rule EF.08") -anode_width = anode.edges.not_interacting(anode.edges.interacting(plfuse)).or(anode.edges.interacting(plfuse)) -ef08_l1 = anode_width.without_length(1.06.um) -ef08_l1.output("EF.08", "EF.08 : Min./Max. Anode Poly2 width. : 1.06µm") -ef08_l1.forget - -# Rule EF.09: Min./Max. Anode Poly2 length. is 2.43µm -logger.info("Executing rule EF.09") -ef09_l1 = anode.edges.not(anode_width).without_length(2.43.um) -ef09_l1.output("EF.09", "EF.09 : Min./Max. Anode Poly2 length. : 2.43µm") -ef09_l1.forget -anode_width.forget - -# Rule EF.10: Min. Cathode Poly2 to Poly2 space. is 0.26µm -logger.info("Executing rule EF.10") -ef10_l1 = cathode.space(0.26.um, euclidian) -ef10_l1.output("EF.10", "EF.10 : Min. Cathode Poly2 to Poly2 space. : 0.26µm") -ef10_l1.forget - -# Rule EF.11: Min. Anode Poly2 to Poly2 space. is 0.26µm -logger.info("Executing rule EF.11") -ef11_l1 = anode.space(0.26.um, euclidian) -ef11_l1.output("EF.11", "EF.11 : Min. Anode Poly2 to Poly2 space. : 0.26µm") -ef11_l1.forget - -# Rule EF.12: Min. Space of Cathode Contact to PLFUSE end. -logger.info("Executing rule EF.12") -cont_ef = contact.and(plfuse_efuse) -ef12_l1 = plfuse_efuse.separation(contact.and(cathode), 0.155.um).polygons(0.001).or(cont_ef) -ef12_l1.output("EF.12", "EF.12 : Min. Space of Cathode Contact to PLFUSE end.") -ef12_l1.forget - -# Rule EF.13: Min. Space of Anode Contact to PLFUSE end. -logger.info("Executing rule EF.13") -ef13_l1 = plfuse_efuse.separation(contact.and(anode), 0.14.um).polygons(0.001).or(cont_ef) -ef13_l1.output("EF.13", "EF.13 : Min. Space of Anode Contact to PLFUSE end.") -ef13_l1.forget -cont_ef.forget - -# Rule EF.14: Min. EFUSE_MK enclose LVS_Source. -logger.info("Executing rule EF.14") -ef14_l1 = lvs_source.not_outside(efuse_mk).not(efuse_mk) -ef14_l1.output("EF.14", "EF.14 : Min. EFUSE_MK enclose LVS_Source.") -ef14_l1.forget - -# Rule EF.15: NO Contact is allowed to touch PLFUSE. -logger.info("Executing rule EF.15") -ef15_l1 = plfuse.interacting(contact) -ef15_l1.output("EF.15", "EF.15 : NO Contact is allowed to touch PLFUSE.") -ef15_l1.forget - -# Rule EF.16a: Cathode must contain exact number of Contacts at each ends. is 4µm -logger.info("Executing rule EF.16a") -ef16a_l1 = cathode.not_covering(contact, 4, 4) -ef16a_l1.output("EF.16a", "EF.16a : Cathode must contain exact number of Contacts at each ends. : 4µm") -ef16a_l1.forget - -# Rule EF.16b: Anode must contain exact number of Contacts at each ends. is 4µm -logger.info("Executing rule EF.16b") -ef16b_l1 = anode.not_covering(contact, 4, 4) -ef16b_l1.output("EF.16b", "EF.16b : Anode must contain exact number of Contacts at each ends. : 4µm") -ef16b_l1.forget - -# Rule EF.17: Min. Space of EFUSE_MK to EFUSE_MK. is 0.26µm -logger.info("Executing rule EF.17") -ef17_l1 = efuse_mk.space(0.26.um, euclidian) -ef17_l1.output("EF.17", "EF.17 : Min. Space of EFUSE_MK to EFUSE_MK. : 0.26µm") -ef17_l1.forget - -# Rule EF.18: PLFUSE must sit on field oxide (NOT COMP), no cross with any COMP, Nplus, Pplus, ESD, SAB, Resistor, Metal1, Metal2. -logger.info("Executing rule EF.18") -ef18_l1 = plfuse.not(plfuse.outside(comp).outside(nplus).outside(esd).outside(sab).outside(resistor).outside(metal1).outside(metal2)) -ef18_l1.output("EF.18", "EF.18 : PLFUSE must sit on field oxide (NOT COMP), no cross with any COMP, Nplus, Pplus, ESD, SAB, Resistor, Metal1, Metal2.") -ef18_l1.forget - -# Rule EF.19: Min. PLFUSE space to Metal1, Metal2. -logger.info("Executing rule EF.19") -ef19_l1 = plfuse.not(plfuse.outside(metal1).outside(metal2)) -ef19_l1.output("EF.19", "EF.19 : Min. PLFUSE space to Metal1, Metal2.") -ef19_l1.forget - -# Rule EF.20: Min. PLFUSE space to COMP, Nplus, Pplus, Resistor, ESD, SAB. is 2.73µm -logger.info("Executing rule EF.20") -ef20_l1 = plfuse.separation(comp + nplus + esd + sab + resistor, 2.73.um, euclidian) -ef20_l1.output("EF.20", "EF.20 : Min. PLFUSE space to COMP, Nplus, Pplus, Resistor, ESD, SAB. : 2.73µm") -ef20_l1.forget - -# Rule EF.21: Min./Max. eFUSE Poly2 length. is 5.53µm -logger.info("Executing rule EF.21") -ef_21_fuse = poly2.interacting(plfuse).inside(efuse_mk.and(pplus)).extents.edges -ef_21_anode = anode.edges.not_interacting(anode.edges.interacting(plfuse)) -ef_21_cathode = cathode.edges.not_interacting(cathode.edges.interacting(plfuse)) -ef21_l1 = ef_21_fuse.not_interacting(ef_21_anode.or(ef_21_cathode).centers(0, 0.95)).without_length(5.53.um) -ef21_l1.output("EF.21", "EF.21 : Min./Max. eFUSE Poly2 length. : 5.53µm") -ef21_l1.forget -ef_21_fuse.forget -ef_21_anode.forget -ef_21_cathode.forget - -# Rule EF.22a: Min./Max. Cathode Poly2 overlap with PLFUSE in width direction. is 1.04µm -logger.info("Executing rule EF.22a") -ef22a_l1 = cathode.edges.interacting(plfuse).not(plfuse.edges).without_length(1.04.um) -ef22a_l1.output("EF.22a", "EF.22a : Min./Max. Cathode Poly2 overlap with PLFUSE in width direction. : 1.04µm") -ef22a_l1.forget - -# Rule EF.22b: Min./Max. Anode Poly2 overlap with PLFUSE in width direction. is 0.44µm -logger.info("Executing rule EF.22b") -ef22b_l1 = anode.edges.interacting(plfuse).not(plfuse.edges).without_length(0.44.um) -ef22b_l1.output("EF.22b", "EF.22b : Min./Max. Anode Poly2 overlap with PLFUSE in width direction. : 0.44µm") -ef22b_l1.forget -plfuse_efuse.forget - diff --git a/klayout/drc/rule_decks/hres.drc b/klayout/drc/rule_decks/hres.drc deleted file mode 100644 index fb55001f..00000000 --- a/klayout/drc/rule_decks/hres.drc +++ /dev/null @@ -1,137 +0,0 @@ -################################################################################################ -# Copyright 2022 GlobalFoundries PDK Authors -# -# 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 FEOL - #================================================ - #----------------H POLY RESISTOR----------------- - #================================================ - - logger.info("Starting HRES derivations") - hres_poly = poly2.interacting(pplus).interacting(sab).interacting(res_mk).interacting(resistor) - hres1_poly = poly2.interacting(pplus).interacting(sab).interacting(res_mk) - - # Rule HRES.1: Minimum space. Note : Merge if the spacing is less than 0.4 um. is 0.4µm - logger.info("Executing rule HRES.1") - hres1_l1 = resistor.interacting(hres1_poly).space(0.4.um, euclidian) - hres1_l1.output("HRES.1", "HRES.1 : Minimum space. Note : Merge if the spacing is less than 0.4 um. : 0.4µm") - hres1_l1.forget - - # Rule HRES.2: Minimum width of Poly2 resistor. is 1µm - logger.info("Executing rule HRES.2") - hres2_l1 = hres_poly.width(1.um, euclidian) - hres2_l1.output("HRES.2", "HRES.2 : Minimum width of Poly2 resistor. : 1µm") - hres2_l1.forget - - # Rule HRES.3: Minimum space between Poly2 resistors. is 0.4µm - logger.info("Executing rule HRES.3") - hres3_l1 = hres_poly.space(0.4.um, euclidian) - hres3_l1.output("HRES.3", "HRES.3 : Minimum space between Poly2 resistors. : 0.4µm") - hres3_l1.forget - - # Rule HRES.4: Minimum RESISTOR overlap of Poly2 resistor. is 0.4µm - logger.info("Executing rule HRES.4") - hres4_l1 = hres_poly.enclosed(resistor, 0.4.um, euclidian).polygons(0.001) - hres4_l2 = hres_poly.not_outside(resistor).not(resistor) - hres4_l = hres4_l1.or(hres4_l2) - hres4_l.output("HRES.4", "HRES.4 : Minimum RESISTOR overlap of Poly2 resistor. : 0.4µm") - hres4_l1.forget - hres4_l2.forget - hres4_l.forget - - # Rule HRES.5: Minimum RESISTOR space to unrelated Poly2. is 0.3µm - logger.info("Executing rule HRES.5") - hres5_l1 = resistor.interacting(hres1_poly).separation(poly2.not_interacting(sab), 0.3.um, euclidian) - hres5_l1.output("HRES.5", "HRES.5 : Minimum RESISTOR space to unrelated Poly2. : 0.3µm") - hres5_l1.forget - - # Rule HRES.6: Minimum RESISTOR space to COMP. - logger.info("Executing rule HRES.6") - hres6_l1 = resistor.interacting(hres1_poly).separation(comp, 0.3.um, euclidian).polygons(0.001) - hres6_l2 = comp.not_outside(resistor.interacting(hres1_poly)) - hres6_l = hres6_l1.or(hres6_l2) - hres6_l.output("HRES.6", "HRES.6 : Minimum RESISTOR space to COMP.") - hres6_l.forget - hres6_l1.forget - hres6_l2.forget - hres1_poly.forget - - # Rule HRES.7: Minimum Pplus overlap of contact on Poly2 resistor. is 0.2µm - logger.info("Executing rule HRES.7") - hres7_l1 = contact.and(hres_poly).enclosed(pplus, 0.2.um, euclidian).polygons(0.001) - hres7_l2 = contact.and(hres_poly).not_outside(pplus).not(pplus) - hres7_l = hres7_l1.or(hres7_l2) - hres7_l.output("HRES.7", "HRES.7 : Minimum Pplus overlap of contact on Poly2 resistor. : 0.2µm") - hres7_l1.forget - hres7_l2.forget - hres7_l.forget - - # Rule HRES.8: Space from salicide block to contact on Poly2 resistor. - logger.info("Executing rule HRES.8") - hres8_l1 = contact.and(hres_poly).separation(sab,0.22.um).polygons(0.001).or(contact.and(hres_poly).interacting(sab)) - hres8_l1.output("HRES.8", "HRES.8 : Space from salicide block to contact on Poly2 resistor.") - hres8_l1.forget - - # Rule HRES.9: Minimum salicide block overlap of Poly2 resistor in width direction. - logger.info("Executing rule HRES.9") - hres9_sab = sab.interacting(pplus).interacting(res_mk).interacting(resistor) - hres9_clear_sab = hres9_sab.not(hres_poly) - hres9_bad_inside_edge = hres9_sab.edges.inside_part(hres_poly).extended(0,0,0.001,0.001).interacting(hres9_clear_sab, 1, 1) - hres9_sab_hole = hres9_sab.holes.and(hres_poly) - hres9_l1 = hres_poly.enclosed(hres9_sab, 0.28.um, euclidian).polygons(0.001) - hres9_l2 = hres9_bad_inside_edge.or(hres9_sab_hole) - hres9_l = hres9_l1.or(hres9_l2) - hres9_l.output("HRES.9", "HRES.9 : Minimum salicide block overlap of Poly2 resistor in width direction.") - hres9_l.forget - hres9_l1.forget - hres9_l2.forget - hres9_sab.forget - hres9_clear_sab.forget - hres9_bad_inside_edge.forget - hres9_sab_hole.forget - - # Rule HRES.10: Minimum & maximum Pplus overlap of SAB. - logger.info("Executing rule HRES.10") - pplus1_hres10 = pplus.and(sab).drc(width != 0.1.um) - pplus2_hres10 = pplus.not_overlapping(sab).edges - hres10_l1 = pplus1_hres10.or(pplus2_hres10).extended(0, 0, 0.001, 0.001).interacting(hres_poly) - hres10_l1.output("HRES.10", "HRES.10 : Minimum & maximum Pplus overlap of SAB.") - hres10_l1.forget - pplus1_hres10.forget - pplus2_hres10.forget - - # Rule HRES.11 is not a DRC check - ## Please refer to https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_10_03.html#hres-poly-resistor-phres-optional-with-one-additional-mask - - # Rule HRES.12a: P type Poly2 resistor (high sheet rho) shall be covered by RES_MK marking. RES_MK length shall be coincide with resistor length (Defined by Pplus space) and width covering the width of Poly2. - logger.info("Executing rule HRES.12a") - mk_hres12a = res_mk.edges.not(poly2.not(pplus).and(sab).edges).inside_part(poly2) - hres12a_l1 = res_mk.interacting(resistor).interacting(mk_hres12a) - hres12a_l1.output("HRES.12a", "HRES.12a : P type Poly2 resistor (high sheet rho) shall be covered by RES_MK marking. RES_MK length shall be coincide with resistor length (Defined by Pplus space) and width covering the width of Poly2. ") - hres12a_l1.forget - mk_hres12a.forget - - # Rule HRES.12b: If the size of single RES_MK mark layer is greater than 15000 um2 and both side (X and Y) are greater than 80 um. Then the minimum spacing to adjacent RES_MK layer. is 20µm - logger.info("Executing rule HRES.12b") - hres12b = res_mk.with_area(15000.001.um,nil).edges.with_length(80.001.um,nil) - hres12b_l1 = hres12b.separation(res_mk.edges, 20.um) - hres12b_l1.output("HRES.12b", "HRES.12b : If the size of single RES_MK mark layer is greater than 15000 um2 and both side (X and Y) are greater than 80 um. Then the minimum spacing to adjacent RES_MK layer. : 20µm") - hres12b_l1.forget - hres12b.forget - hres_poly.forget - -end #FEOL - diff --git a/klayout/drc/rule_decks/lres.drc b/klayout/drc/rule_decks/lres.drc deleted file mode 100644 index 9f5d7ecd..00000000 --- a/klayout/drc/rule_decks/lres.drc +++ /dev/null @@ -1,100 +0,0 @@ -################################################################################################ -# Copyright 2022 GlobalFoundries PDK Authors -# -# 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 FEOL - #================================================ - #----------------N+ POLY RESISTOR---------------- - #================================================ - - logger.info("Starting LRES derivations") - lres_poly = poly2.and(nplus).interacting(sab).interacting(res_mk) - - # Rule LRES.1: Minimum width of Poly2 resistor. is 0.8µm - logger.info("Executing rule LRES.1") - lres1_l1 = lres_poly.width(0.8.um, euclidian) - lres1_l1.output("LRES.1", "LRES.1 : Minimum width of Poly2 resistor. : 0.8µm") - lres1_l1.forget - - # Rule LRES.2: Minimum space between Poly2 resistors. is 0.4µm - logger.info("Executing rule LRES.2") - lres2_l1 = lres_poly.isolated(0.4.um, euclidian) - lres2_l1.output("LRES.2", "LRES.2 : Minimum space between Poly2 resistors. : 0.4µm") - lres2_l1.forget - - # Rule LRES.3: Minimum space from Poly2 resistor to COMP. - logger.info("Executing rule LRES.3") - lres3_l1 = lres_poly.separation(comp, 0.6.um, euclidian).polygons(0.001).or(comp.not_outside(lres_poly)) - lres3_l1.output("LRES.3", "LRES.3 : Minimum space from Poly2 resistor to COMP.") - lres3_l1.forget - - # Rule LRES.4: Minimum space from Poly2 resistor to unrelated Poly2. is 0.6µm - logger.info("Executing rule LRES.4") - lres4_l1 = lres_poly.separation(poly2.not_interacting(sab), 0.6.um, euclidian) - lres4_l1.output("LRES.4", "LRES.4 : Minimum space from Poly2 resistor to unrelated Poly2. : 0.6µm") - lres4_l1.forget - - # Rule LRES.5: Minimum Nplus implant overlap of Poly2 resistor. is 0.3µm - logger.info("Executing rule LRES.5") - lres5_l1 = lres_poly.enclosed(nplus, 0.3.um, euclidian).polygons(0.001) - lres5_l2 = lres_poly.not_outside(nplus).not(nplus) - lres5_l = lres5_l1.or(lres5_l2) - lres5_l.output("LRES.5", "LRES.5 : Minimum Nplus implant overlap of Poly2 resistor. : 0.3µm") - lres5_l1.forget - lres5_l2.forget - lres5_l.forget - - # Rule LRES.6: Minimum salicide block overlap of Poly2 resistor in width direction. is 0.28µm - logger.info("Executing rule LRES.6") - lres6_l1 = lres_poly.enclosed(sab,0.28.um) - lres6_l1.output("LRES.6", "LRES.6 : Minimum salicide block overlap of Poly2 resistor in width direction. : 0.28µm") - lres6_l1.forget - - # Rule LRES.7: Space from salicide block to contact on Poly2 resistor. - logger.info("Executing rule LRES.7") - cont_lres7 = contact.and(lres_poly) - lres7_l1 = cont_lres7.separation(sab,0.22.um).polygons(0.001) - lres7_l2 = cont_lres7.interacting(sab) - lres7_l = lres7_l1.or(lres7_l2) - lres7_l.output("LRES.7", "LRES.7 : Space from salicide block to contact on Poly2 resistor.") - lres7_l.forget - lres7_l1.forget - lres7_l2.forget - cont_lres7.forget - - # Rule LRES.8 is not a DRC check - ## Please refer to https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_10_02.html#n-poly-resistor-low-sheet-rho - - # Rule LRES.9a: Nplus Poly2 resistor shall be covered by RES_MK marking. RES_MK length shall be coincide with resistor length (Defined by SAB length) and width covering the width of Poly2. - logger.info("Executing rule LRES.9a") - mk_lres9 = res_mk.edges.not(poly2.and(nplus).and(sab).edges).inside_part(poly2) - lres9a_l1 = res_mk.interacting(lres_poly).interacting(mk_lres9) - lres9a_l1.output("LRES.9a", "LRES.9a : Nplus Poly2 resistor shall be covered by RES_MK marking. RES_MK length shall be coincide with resistor length (Defined by SAB length) and width covering the width of Poly2. ") - lres9a_l1.forget - mk_lres9.forget - - # Rule LRES.9b: If the size of single RES_MK mark layer is greater than 15000um2 and both side (X and Y) are greater than 80um. - ## then the minimum spacing to adjacent RES_MK layer. is 20µm - logger.info("Executing rule LRES.9b") - lres9b = res_mk.with_area(15000.001.um,nil).edges.with_length(80.001.um,nil) - lres9b_l1 = lres9b.separation(res_mk.edges, 20.um) - lres9b_l1.output("LRES.9b", "LRES.9b : If the size of single RES_MK mark layer is greater than 15000um2 and both side (X and Y) are greater than 80um. then the minimum spacing to adjacent RES_MK layer. : 20µm") - lres9b_l1.forget - lres9b.forget - lres_poly.forget - -end #FEOL - diff --git a/klayout/drc/rule_decks/lvs_bjt.drc b/klayout/drc/rule_decks/lvs_bjt.drc deleted file mode 100644 index 38ad912b..00000000 --- a/klayout/drc/rule_decks/lvs_bjt.drc +++ /dev/null @@ -1,34 +0,0 @@ -################################################################################################ -# Copyright 2022 GlobalFoundries PDK Authors -# -# 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 FEOL - #================================================ - #--------------------LVS_BJT--------------------- - #================================================ - - vnpn_e = ncomp.interacting(lvs_bjt).inside(dnwell) - vpnp_e = pcomp.inside(nwell).interacting(lvs_bjt) - # Rule LVS_BJT.1: Minimum LVS_BJT enclosure of NPN or PNP Emitter COMP layers - logger.info("Executing rule LVS_BJT.1") - lvs_l1 = vnpn_e.or(vpnp_e).not_inside(lvs_bjt) - lvs_l1.output("LVS_BJT.1", "LVS_BJT.1 : Minimum LVS_BJT enclosure of NPN or PNP Emitter COMP layers") - lvs_l1.forget - - vnpn_e.forget - - vpnp_e.forget -end #FEOL - diff --git a/klayout/drc/rule_decks/main.drc b/klayout/drc/rule_decks/main.drc index e575e6c1..0431b117 100644 --- a/klayout/drc/rule_decks/main.drc +++ b/klayout/drc/rule_decks/main.drc @@ -14,880 +14,766 @@ # limitations under the License. ################################################################################################ -#=========================================================================================================================== -#------------------------------------------- GF 0.18um MCU DRC RULE DECK -------------------------------------------------- -#=========================================================================================================================== +#======================================================================================================================= +#--------------------------------------------- GF 0.18um MCU DRC RULE DECK --------------------------------------------- +#======================================================================================================================= require 'time' -require "logger" +require 'logger' require 'etc' exec_start_time = Time.now -logger = Logger.new(STDOUT) +logger = Logger.new($stdout) -logger.formatter = proc do |severity, datetime, progname, msg| - "#{datetime}: Memory Usage (" + `pmap #{Process.pid} | tail -1`[10,40].strip + ") : #{msg} +logger.formatter = proc do |_severity, datetime, _progname, msg| + "#{datetime}: Memory Usage (" + `pmap #{Process.pid} | tail -1`[10, 40].strip + ") : #{msg} " end #================================================ #----------------- FILE SETUP ------------------- #================================================ -logger.info("Starting running GF180MCU Klayout DRC runset on %s" % [$input]) -logger.info("Ruby Version for klayout: %s" % [RUBY_VERSION]) +logger.info(format('Starting running GF180MCU Klayout DRC runset on %s', $input)) +logger.info(format('Ruby Version for klayout: %s', RUBY_VERSION)) if $input - if $topcell - source($input, $topcell) - else - source($input) - end -end - -if $table_name - table_name = $table_name -else - table_name = "main" + if $topcell + source($input, $topcell) + else + source($input) + end end +table_name = $table_name || 'main' -logger.info("Loading database to memory is complete.") +logger.info('Loading database to memory is complete.') if $report - logger.info("GF180MCU Klayout DRC runset output at: %s" % [$report]) - report("DRC Run Report at", $report) + logger.info(format('GF180MCU Klayout DRC runset output at: %s', $report)) + report('DRC Run Report at', $report) else - layout_dir = Pathname.new(RBA::CellView::active.filename).parent.realpath - report_path = layout_dir.join("gf180_drc.lyrdb").to_s - logger.info("GF180MCU Klayout DRC runset output at default location: %s" % report_path) - report("DRC Run Report at", report_path) + layout_dir = Pathname.new(RBA::CellView.active.filename).parent.realpath + report_path = layout_dir.join('gf180_drc.lyrdb').to_s + logger.info('GF180MCU Klayout DRC runset output at default location: %s', report_path) + report('DRC Run Report at', report_path) end #================================================ #------------------ SWITCHES -------------------- #================================================ -logger.info("Evaluate switches.") +logger.info('Evaluate switches.') # connectivity rules -if $conn_drc == "true" +if $conn_drc == 'true' CONNECTIVITY_RULES = $conn_drc - logger.info("connectivity rules are enabled.") + logger.info('connectivity rules are enabled.') else CONNECTIVITY_RULES = false - logger.info("connectivity rules are disabled.") -end # connectivity rules + logger.info('connectivity rules are disabled.') +end # WEDGE -if $wedge == "false" - WEDGE = $wedge -else - WEDGE = "true" -end # WEDGE +WEDGE = if $wedge == 'false' + $wedge + else + 'true' + end -logger.info("Wedge enabled %s" % [WEDGE]) +logger.info(format('Wedge enabled %s', WEDGE)) # BALL -if $ball == "false" - BALL = $ball -else - BALL = "true" -end # BALL +BALL = if $ball == 'false' + $ball + else + 'true' + end -logger.info("Ball enabled %s" % [BALL]) +logger.info(format('Ball enabled %s', BALL)) # GOLD -if $gold == "false" - GOLD = $gold -else - GOLD = "true" -end # GOLD +GOLD = if $gold == 'false' + $gold + else + 'true' + end -logger.info("Gold enabled %s" % [GOLD]) +logger.info(format('Gold enabled %s', GOLD)) -if $mim_option - MIM_OPTION = $mim_option -else - MIM_OPTION = "B" -end +MIM_OPTION = $mim_option || 'B' -logger.info("MIM Option selected %s" % [MIM_OPTION]) +logger.info(format('MIM Option selected %s', MIM_OPTION)) # OFFGRID -if $offgrid == "false" - OFFGRID = false -else - OFFGRID = true -end # OFFGRID +OFFGRID = $offgrid != 'false' -logger.info("Offgrid enabled %s" % [OFFGRID]) +logger.info(format('Offgrid enabled %s', OFFGRID)) if $thr - threads($thr) + threads($thr) else - thr ||= Etc.nprocessors - threads(thr) + thr ||= Etc.nprocessors + threads(thr) end -logger.info("Number of threads to use %s" % [$thr]) +logger.info(format('Number of threads to use %s', $thr)) #=== PRINT DETAILS === logger.info("Verbose mode: #{$verbose}") -if $verbose == "true" +if $verbose == 'true' verbose(true) else verbose(false) end # === TILING MODE === -if $run_mode == "tiling" +case $run_mode +when 'tiling' tiles(500.um) tile_borders(10.um) - logger.info("Tiling mode is enabled.") + logger.info('Tiling mode is enabled.') -elsif $run_mode == "deep" +when 'deep' #=== HIER MODE === deep - logger.info("deep mode is enabled.") + logger.info('deep mode is enabled.') else #=== FLAT MODE === flat - logger.info("flat mode is enabled.") -end # run_mode + logger.info('flat mode is enabled.') +end # METAL_TOP -if $metal_top - METAL_TOP = $metal_top -else - METAL_TOP = "9K" -end # METAL_TOP +METAL_TOP = $metal_top || '9K' -logger.info("METAL_TOP Selected is %s" % [METAL_TOP]) +logger.info(format('METAL_TOP Selected is %s', METAL_TOP)) # METAL_LEVEL -if $metal_level - METAL_LEVEL = $metal_level -else - METAL_LEVEL = "5LM" -end # METAL_LEVEL +METAL_LEVEL = $metal_level || '5LM' -logger.info("METAL_STACK Selected is %s" % [METAL_LEVEL]) +logger.info(format('METAL_STACK Selected is %s', METAL_LEVEL)) # FEOL -if $feol == "false" +if $feol == 'false' FEOL = $feol - logger.info("FEOL is disabled.") + logger.info('FEOL is disabled.') else - FEOL = "true" - logger.info("FEOL is enabled.") -end # FEOL + FEOL = 'true'.freeze + logger.info('FEOL is enabled.') +end # BEOL -if $beol == "false" +if $beol == 'false' BEOL = $beol - logger.info("BEOL is disabled.") + logger.info('BEOL is disabled.') else - BEOL = "true" - logger.info("BEOL is enabled.") -end # BEOL + BEOL = 'true'.freeze + logger.info('BEOL is enabled.') +end #================================================ #------------- LAYERS DEFINITIONS --------------- #================================================ polygons_count = 0 -logger.info("Read in polygons from layers.") +logger.info('Read in polygons from layers.') -def get_polygons(l, d) - ps = polygons(l, d) - return $run_mode == "deep" ? ps : ps.merged +def get_polygons(layer, data_type) + ps = polygons(layer, data_type) + $run_mode == 'deep' ? ps : ps.merged end -comp = get_polygons(22 , 0 ) -count = comp.count() -logger.info("comp has %d polygons" % [count]) -polygons_count += count - -dnwell = get_polygons(12 , 0 ) -count = dnwell.count() -logger.info("dnwell has %d polygons" % [count]) -polygons_count += count - -nwell = get_polygons(21 , 0 ) -count = nwell.count() -logger.info("nwell has %d polygons" % [count]) -polygons_count += count - -lvpwell = get_polygons(204, 0 ) -count = lvpwell.count() -logger.info("lvpwell has %d polygons" % [count]) -polygons_count += count - -dualgate = get_polygons(55 , 0 ) -count = dualgate.count() -logger.info("dualgate has %d polygons" % [count]) -polygons_count += count - -poly2 = get_polygons(30 , 0 ) -count = poly2.count() -logger.info("poly2 has %d polygons" % [count]) -polygons_count += count - -nplus = get_polygons(32 , 0 ) -count = nplus.count() -logger.info("nplus has %d polygons" % [count]) -polygons_count += count - -pplus = get_polygons(31 , 0 ) -count = pplus.count() -logger.info("pplus has %d polygons" % [count]) -polygons_count += count - -sab = get_polygons(49 , 0 ) -count = sab.count() -logger.info("sab has %d polygons" % [count]) -polygons_count += count - -esd = get_polygons(24 , 0 ) -count = esd.count() -logger.info("esd has %d polygons" % [count]) -polygons_count += count - -resistor = get_polygons(62 , 0 ) -count = resistor.count() -logger.info("resistor has %d polygons" % [count]) -polygons_count += count - -fhres = get_polygons(227, 0 ) -count = fhres.count() -logger.info("fhres has %d polygons" % [count]) -polygons_count += count - -fusetop = get_polygons(75 , 0 ) -count = fusetop.count() -logger.info("fusetop has %d polygons" % [count]) -polygons_count += count - -fusewindow_d = get_polygons(96 , 1 ) -count = fusewindow_d.count() -logger.info("fusewindow_d has %d polygons" % [count]) -polygons_count += count - -polyfuse = get_polygons(220, 0 ) -count = polyfuse.count() -logger.info("polyfuse has %d polygons" % [count]) -polygons_count += count - -mvsd = get_polygons(210, 0 ) -count = mvsd.count() -logger.info("mvsd has %d polygons" % [count]) -polygons_count += count - -mvpsd = get_polygons(11 , 39) -count = mvpsd.count() -logger.info("mvpsd has %d polygons" % [count]) -polygons_count += count - -nat = get_polygons(5 , 0 ) -count = nat.count() -logger.info("nat has %d polygons" % [count]) -polygons_count += count - -comp_dummy = get_polygons(22 , 4 ) -count = comp_dummy.count() -logger.info("comp_dummy has %d polygons" % [count]) -polygons_count += count - -poly2_dummy = get_polygons(30 , 4 ) -count = poly2_dummy.count() -logger.info("poly2_dummy has %d polygons" % [count]) -polygons_count += count - -schottky_diode = get_polygons(241, 0 ) -count = schottky_diode.count() -logger.info("schottky_diode has %d polygons" % [count]) -polygons_count += count - -zener = get_polygons(178, 0 ) -count = zener.count() -logger.info("zener has %d polygons" % [count]) -polygons_count += count - -res_mk = get_polygons(110, 5 ) -count = res_mk.count() -logger.info("res_mk has %d polygons" % [count]) -polygons_count += count - -opc_drc = get_polygons(124, 5 ) -count = opc_drc.count() -logger.info("opc_drc has %d polygons" % [count]) -polygons_count += count - -ndmy = get_polygons(111, 5 ) -count = ndmy.count() -logger.info("ndmy has %d polygons" % [count]) -polygons_count += count - -pmndmy = get_polygons(152, 5 ) -count = pmndmy.count() -logger.info("pmndmy has %d polygons" % [count]) -polygons_count += count - -v5_xtor = get_polygons(112, 1 ) -count = v5_xtor.count() -logger.info("v5_xtor has %d polygons" % [count]) -polygons_count += count - -cap_mk = get_polygons(117, 5 ) -count = cap_mk.count() -logger.info("cap_mk has %d polygons" % [count]) -polygons_count += count - -mos_cap_mk = get_polygons(166, 5 ) -count = mos_cap_mk.count() -logger.info("mos_cap_mk has %d polygons" % [count]) -polygons_count += count - -ind_mk = get_polygons(151, 5 ) -count = ind_mk.count() -logger.info("ind_mk has %d polygons" % [count]) -polygons_count += count - -diode_mk = get_polygons(115, 5 ) -count = diode_mk.count() -logger.info("diode_mk has %d polygons" % [count]) -polygons_count += count - -drc_bjt = get_polygons(127, 5 ) -count = drc_bjt.count() -logger.info("drc_bjt has %d polygons" % [count]) -polygons_count += count - -lvs_bjt = get_polygons(118, 5 ) -count = lvs_bjt.count() -logger.info("lvs_bjt has %d polygons" % [count]) -polygons_count += count - -mim_l_mk = get_polygons(117, 10) -count = mim_l_mk.count() -logger.info("mim_l_mk has %d polygons" % [count]) -polygons_count += count - -latchup_mk = get_polygons(137, 5 ) -count = latchup_mk.count() -logger.info("latchup_mk has %d polygons" % [count]) -polygons_count += count - -guard_ring_mk = get_polygons(167, 5 ) -count = guard_ring_mk.count() -logger.info("guard_ring_mk has %d polygons" % [count]) -polygons_count += count - -otp_mk = get_polygons(173, 5 ) -count = otp_mk.count() -logger.info("otp_mk has %d polygons" % [count]) -polygons_count += count - -mtpmark = get_polygons(122, 5 ) -count = mtpmark.count() -logger.info("mtpmark has %d polygons" % [count]) -polygons_count += count - -neo_ee_mk = get_polygons(88 , 17) -count = neo_ee_mk.count() -logger.info("neo_ee_mk has %d polygons" % [count]) -polygons_count += count - -sramcore = get_polygons(108, 5 ) -count = sramcore.count() -logger.info("sramcore has %d polygons" % [count]) -polygons_count += count - -lvs_rf = get_polygons(100, 5 ) -count = lvs_rf.count() -logger.info("lvs_rf has %d polygons" % [count]) -polygons_count += count - -lvs_drain = get_polygons(100, 7 ) -count = lvs_drain.count() -logger.info("lvs_drain has %d polygons" % [count]) -polygons_count += count - -ind_mk = get_polygons(151, 5 ) -count = ind_mk.count() -logger.info("ind_mk has %d polygons" % [count]) -polygons_count += count - -hvpolyrs = get_polygons(123, 5 ) -count = hvpolyrs.count() -logger.info("hvpolyrs has %d polygons" % [count]) -polygons_count += count - -lvs_io = get_polygons(119, 5 ) -count = lvs_io.count() -logger.info("lvs_io has %d polygons" % [count]) -polygons_count += count - -probe_mk = get_polygons(13 , 17) -count = probe_mk.count() -logger.info("probe_mk has %d polygons" % [count]) -polygons_count += count - -esd_mk = get_polygons(24 , 5 ) -count = esd_mk.count() -logger.info("esd_mk has %d polygons" % [count]) -polygons_count += count - -lvs_source = get_polygons(100, 8 ) -count = lvs_source.count() -logger.info("lvs_source has %d polygons" % [count]) -polygons_count += count - -well_diode_mk = get_polygons(153, 51) -count = well_diode_mk.count() -logger.info("well_diode_mk has %d polygons" % [count]) -polygons_count += count - -ldmos_xtor = get_polygons(226, 0 ) -count = ldmos_xtor.count() -logger.info("ldmos_xtor has %d polygons" % [count]) -polygons_count += count - -plfuse = get_polygons(125, 5 ) -count = plfuse.count() -logger.info("plfuse has %d polygons" % [count]) -polygons_count += count - -efuse_mk = get_polygons(80 , 5 ) -count = efuse_mk.count() -logger.info("efuse_mk has %d polygons" % [count]) -polygons_count += count - -mcell_feol_mk = get_polygons(11 , 17) -count = mcell_feol_mk.count() -logger.info("mcell_feol_mk has %d polygons" % [count]) -polygons_count += count - -ymtp_mk = get_polygons(86 , 17) -count = ymtp_mk.count() -logger.info("ymtp_mk has %d polygons" % [count]) -polygons_count += count - -dev_wf_mk = get_polygons(128, 17) -count = dev_wf_mk.count() -logger.info("dev_wf_mk has %d polygons" % [count]) -polygons_count += count - -comp_label = get_polygons(22 , 10) -count = comp_label.count() -logger.info("comp_label has %d polygons" % [count]) -polygons_count += count - -poly2_label = get_polygons(30 , 10) -count = poly2_label.count() -logger.info("poly2_label has %d polygons" % [count]) -polygons_count += count - -mdiode = get_polygons(116, 5 ) -count = mdiode.count() -logger.info("mdiode has %d polygons" % [count]) -polygons_count += count - -contact = get_polygons(33 , 0 ) -count = contact.count() -logger.info("contact has %d polygons" % [count]) -polygons_count += count - -metal1_drawn = get_polygons(34 , 0 ) -count = metal1_drawn.count() -logger.info("metal1_drawn has %d polygons" % [count]) -polygons_count += count - -metal1_dummy = get_polygons(34 , 4 ) -count = metal1_dummy.count() -logger.info("metal1_dummy has %d polygons" % [count]) -polygons_count += count +comp = get_polygons(22, 0) +count = comp.count +logger.info(format('comp has %d polygons', count)) +polygons_count += count + +dnwell = get_polygons(12, 0) +count = dnwell.count +logger.info(format('dnwell has %d polygons', count)) +polygons_count += count + +nwell = get_polygons(21, 0) +count = nwell.count +logger.info(format('nwell has %d polygons', count)) +polygons_count += count + +lvpwell = get_polygons(204, 0) +count = lvpwell.count +logger.info(format('lvpwell has %d polygons', count)) +polygons_count += count + +dualgate = get_polygons(55, 0) +count = dualgate.count +logger.info(format('dualgate has %d polygons', count)) +polygons_count += count + +poly2 = get_polygons(30, 0) +count = poly2.count +logger.info(format('poly2 has %d polygons', count)) +polygons_count += count + +nplus = get_polygons(32, 0) +count = nplus.count +logger.info(format('nplus has %d polygons', count)) +polygons_count += count + +pplus = get_polygons(31, 0) +count = pplus.count +logger.info(format('pplus has %d polygons', count)) +polygons_count += count + +sab = get_polygons(49, 0) +count = sab.count +logger.info(format('sab has %d polygons', count)) +polygons_count += count + +esd = get_polygons(24, 0) +count = esd.count +logger.info(format('esd has %d polygons', count)) +polygons_count += count + +resistor = get_polygons(62, 0) +count = resistor.count +logger.info(format('resistor has %d polygons', count)) +polygons_count += count + +fhres = get_polygons(227, 0) +count = fhres.count +logger.info(format('fhres has %d polygons', count)) +polygons_count += count + +fusetop = get_polygons(75, 0) +count = fusetop.count +logger.info(format('fusetop has %d polygons', count)) +polygons_count += count + +fusewindow_d = get_polygons(96, 1) +count = fusewindow_d.count +logger.info(format('fusewindow_d has %d polygons', count)) +polygons_count += count + +polyfuse = get_polygons(220, 0) +count = polyfuse.count +logger.info(format('polyfuse has %d polygons', count)) +polygons_count += count + +mvsd = get_polygons(210, 0) +count = mvsd.count +logger.info(format('mvsd has %d polygons', count)) +polygons_count += count + +mvpsd = get_polygons(11, 39) +count = mvpsd.count +logger.info(format('mvpsd has %d polygons', count)) +polygons_count += count + +nat = get_polygons(5, 0) +count = nat.count +logger.info(format('nat has %d polygons', count)) +polygons_count += count + +comp_dummy = get_polygons(22, 4) +count = comp_dummy.count +logger.info(format('comp_dummy has %d polygons', count)) +polygons_count += count + +poly2_dummy = get_polygons(30, 4) +count = poly2_dummy.count +logger.info(format('poly2_dummy has %d polygons', count)) +polygons_count += count + +schottky_diode = get_polygons(241, 0) +count = schottky_diode.count +logger.info(format('schottky_diode has %d polygons', count)) +polygons_count += count + +zener = get_polygons(178, 0) +count = zener.count +logger.info(format('zener has %d polygons', count)) +polygons_count += count + +res_mk = get_polygons(110, 5) +count = res_mk.count +logger.info(format('res_mk has %d polygons', count)) +polygons_count += count + +opc_drc = get_polygons(124, 5) +count = opc_drc.count +logger.info(format('opc_drc has %d polygons', count)) +polygons_count += count + +ndmy = get_polygons(111, 5) +count = ndmy.count +logger.info(format('ndmy has %d polygons', count)) +polygons_count += count + +pmndmy = get_polygons(152, 5) +count = pmndmy.count +logger.info(format('pmndmy has %d polygons', count)) +polygons_count += count + +v5_xtor = get_polygons(112, 1) +count = v5_xtor.count +logger.info(format('v5_xtor has %d polygons', count)) +polygons_count += count + +cap_mk = get_polygons(117, 5) +count = cap_mk.count +logger.info(format('cap_mk has %d polygons', count)) +polygons_count += count + +mos_cap_mk = get_polygons(166, 5) +count = mos_cap_mk.count +logger.info(format('mos_cap_mk has %d polygons', count)) +polygons_count += count + +ind_mk = get_polygons(151, 5) +count = ind_mk.count +logger.info(format('ind_mk has %d polygons', count)) +polygons_count += count + +diode_mk = get_polygons(115, 5) +count = diode_mk.count +logger.info(format('diode_mk has %d polygons', count)) +polygons_count += count + +drc_bjt = get_polygons(127, 5) +count = drc_bjt.count +logger.info(format('drc_bjt has %d polygons', count)) +polygons_count += count + +lvs_bjt = get_polygons(118, 5) +count = lvs_bjt.count +logger.info(format('lvs_bjt has %d polygons', count)) +polygons_count += count + +mim_l_mk = get_polygons(117, 10) +count = mim_l_mk.count +logger.info(format('mim_l_mk has %d polygons', count)) +polygons_count += count + +latchup_mk = get_polygons(137, 5) +count = latchup_mk.count +logger.info(format('latchup_mk has %d polygons', count)) +polygons_count += count + +guard_ring_mk = get_polygons(167, 5) +count = guard_ring_mk.count +logger.info(format('guard_ring_mk has %d polygons', count)) +polygons_count += count + +otp_mk = get_polygons(173, 5) +count = otp_mk.count +logger.info(format('otp_mk has %d polygons', count)) +polygons_count += count + +mtpmark = get_polygons(122, 5) +count = mtpmark.count +logger.info(format('mtpmark has %d polygons', count)) +polygons_count += count + +neo_ee_mk = get_polygons(88, 17) +count = neo_ee_mk.count +logger.info(format('neo_ee_mk has %d polygons', count)) +polygons_count += count + +sramcore = get_polygons(108, 5) +count = sramcore.count +logger.info(format('sramcore has %d polygons', count)) +polygons_count += count + +lvs_rf = get_polygons(100, 5) +count = lvs_rf.count +logger.info(format('lvs_rf has %d polygons', count)) +polygons_count += count + +lvs_drain = get_polygons(100, 7) +count = lvs_drain.count +logger.info(format('lvs_drain has %d polygons', count)) +polygons_count += count + +ind_mk = get_polygons(151, 5) +count = ind_mk.count +logger.info(format('ind_mk has %d polygons', count)) +polygons_count += count + +hvpolyrs = get_polygons(123, 5) +count = hvpolyrs.count +logger.info(format('hvpolyrs has %d polygons', count)) +polygons_count += count + +lvs_io = get_polygons(119, 5) +count = lvs_io.count +logger.info(format('lvs_io has %d polygons', count)) +polygons_count += count + +probe_mk = get_polygons(13, 17) +count = probe_mk.count +logger.info(format('probe_mk has %d polygons', count)) +polygons_count += count + +esd_mk = get_polygons(24, 5) +count = esd_mk.count +logger.info(format('esd_mk has %d polygons', count)) +polygons_count += count + +lvs_source = get_polygons(100, 8) +count = lvs_source.count +logger.info(format('lvs_source has %d polygons', count)) +polygons_count += count + +well_diode_mk = get_polygons(153, 51) +count = well_diode_mk.count +logger.info(format('well_diode_mk has %d polygons', count)) +polygons_count += count + +ldmos_xtor = get_polygons(226, 0) +count = ldmos_xtor.count +logger.info(format('ldmos_xtor has %d polygons', count)) +polygons_count += count + +plfuse = get_polygons(125, 5) +count = plfuse.count +logger.info(format('plfuse has %d polygons', count)) +polygons_count += count + +efuse_mk = get_polygons(80, 5) +count = efuse_mk.count +logger.info(format('efuse_mk has %d polygons', count)) +polygons_count += count + +mcell_feol_mk = get_polygons(11, 17) +count = mcell_feol_mk.count +logger.info(format('mcell_feol_mk has %d polygons', count)) +polygons_count += count + +ymtp_mk = get_polygons(86, 17) +count = ymtp_mk.count +logger.info(format('ymtp_mk has %d polygons', count)) +polygons_count += count + +dev_wf_mk = get_polygons(128, 17) +count = dev_wf_mk.count +logger.info(format('dev_wf_mk has %d polygons', count)) +polygons_count += count + +comp_label = get_polygons(22, 10) +count = comp_label.count +logger.info(format('comp_label has %d polygons', count)) +polygons_count += count + +poly2_label = get_polygons(30, 10) +count = poly2_label.count +logger.info(format('poly2_label has %d polygons', count)) +polygons_count += count + +mdiode = get_polygons(116, 5) +count = mdiode.count +logger.info(format('mdiode has %d polygons', count)) +polygons_count += count + +contact = get_polygons(33, 0) +count = contact.count +logger.info(format('contact has %d polygons', count)) +polygons_count += count + +metal1_drawn = get_polygons(34, 0) +count = metal1_drawn.count +logger.info(format('metal1_drawn has %d polygons', count)) +polygons_count += count + +metal1_dummy = get_polygons(34, 4) +count = metal1_dummy.count +logger.info(format('metal1_dummy has %d polygons', count)) +polygons_count += count metal1 = metal1_drawn + metal1_dummy -metal1_label = get_polygons(34 , 10) -count = metal1_label.count() -logger.info("metal1_label has %d polygons" % [count]) -polygons_count += count - -metal1_slot = get_polygons(34 , 3 ) -count = metal1_slot.count() -logger.info("metal1_slot has %d polygons" % [count]) -polygons_count += count - -metal1_blk = get_polygons(34 , 5 ) -count = metal1_blk.count() -logger.info("metal1_blk has %d polygons" % [count]) -polygons_count += count - -via1 = get_polygons(35 , 0 ) -count = via1.count() -logger.info("via1 has %d polygons" % [count]) -polygons_count += count - - -if METAL_LEVEL == "2LM" - metal2_drawn = get_polygons(36 , 0 ) - count = metal2_drawn.count() - logger.info("metal2_drawn has %d polygons" % [count]) - polygons_count += count - - metal2_dummy = get_polygons(36 , 4 ) - count = metal2_dummy.count() - logger.info("metal2_dummy has %d polygons" % [count]) - polygons_count += count - - metal2 = metal2_drawn + metal2_dummy - - metal2_label = get_polygons(36 , 10) - count = metal2_label.count() - logger.info("metal2_label has %d polygons" % [count]) - polygons_count += count - - metal2_slot = get_polygons(36 , 3 ) - count = metal2_slot.count() - logger.info("metal2_slot has %d polygons" % [count]) - polygons_count += count - - metal2_blk = get_polygons(36 , 5 ) - count = metal2_blk.count() - logger.info("metal2_blk has %d polygons" % [count]) - polygons_count += count - +metal1_label = get_polygons(34, 10) +count = metal1_label.count +logger.info(format('metal1_label has %d polygons', count)) +polygons_count += count + +metal1_slot = get_polygons(34, 3) +count = metal1_slot.count +logger.info(format('metal1_slot has %d polygons', count)) +polygons_count += count + +metal1_blk = get_polygons(34, 5) +count = metal1_blk.count +logger.info(format('metal1_blk has %d polygons', count)) +polygons_count += count + +via1 = get_polygons(35, 0) +count = via1.count +logger.info(format('via1 has %d polygons', count)) +polygons_count += count + +metal2_drawn = get_polygons(36, 0) +count = metal2_drawn.count +logger.info(format('metal2_drawn has %d polygons', count)) +polygons_count += count +metal2_dummy = get_polygons(36, 4) +count = metal2_dummy.count +logger.info(format('metal2_dummy has %d polygons', count)) +polygons_count += count +metal2 = metal2_drawn + metal2_dummy +metal2_label = get_polygons(36, 10) +count = metal2_label.count +logger.info(format('metal2_label has %d polygons', count)) +polygons_count += count +metal2_slot = get_polygons(36, 3) +count = metal2_slot.count +logger.info(format('metal2_slot has %d polygons', count)) +polygons_count += count +metal2_blk = get_polygons(36, 5) +count = metal2_blk.count +logger.info(format('metal2_blk has %d polygons', count)) +polygons_count += count +if METAL_LEVEL == '2LM' + top_via = via1 topmin1_via = contact top_metal = metal2 topmin1_metal = metal1 - + else - metal2_drawn = get_polygons(36 , 0 ) - count = metal2_drawn.count() - logger.info("metal2_drawn has %d polygons" % [count]) - polygons_count += count - - metal2_dummy = get_polygons(36 , 4 ) - count = metal2_dummy.count() - logger.info("metal2_dummy has %d polygons" % [count]) - polygons_count += count - - metal2 = metal2_drawn + metal2_dummy - - metal2_label = get_polygons(36 , 10) - count = metal2_label.count() - logger.info("metal2_label has %d polygons" % [count]) - polygons_count += count - - metal2_slot = get_polygons(36 , 3 ) - count = metal2_slot.count() - logger.info("metal2_slot has %d polygons" % [count]) - polygons_count += count - - metal2_blk = get_polygons(36 , 5 ) - count = metal2_blk.count() - logger.info("metal2_blk has %d polygons" % [count]) - polygons_count += count - - via2 = get_polygons(38 , 0 ) - count = via2.count() - logger.info("via2 has %d polygons" % [count]) - polygons_count += count - - if METAL_LEVEL == "3LM" - metal3_drawn = get_polygons(42 , 0 ) - count = metal3_drawn.count() - logger.info("metal3_drawn has %d polygons" % [count]) - polygons_count += count - - metal3_dummy = get_polygons(42 , 4 ) - count = metal3_dummy.count() - logger.info("metal3_dummy has %d polygons" % [count]) - polygons_count += count - - metal3 = metal3_drawn + metal3_dummy - - metal3_label = get_polygons(42 , 10) - count = metal3_label.count() - logger.info("metal3_label has %d polygons" % [count]) - polygons_count += count - - metal3_slot = get_polygons(42 , 3 ) - count = metal3_slot.count() - logger.info("metal3_slot has %d polygons" % [count]) - polygons_count += count - - metal3_blk = get_polygons(42 , 5 ) - count = metal3_blk.count() - logger.info("metal3_blk has %d polygons" % [count]) - polygons_count += count - + + via2 = get_polygons(38, 0) + count = via2.count + logger.info(format('via2 has %d polygons', count)) + polygons_count += count + + metal3_drawn = get_polygons(42, 0) + count = metal3_drawn.count + logger.info(format('metal3_drawn has %d polygons', count)) + polygons_count += count + metal3_dummy = get_polygons(42, 4) + count = metal3_dummy.count + logger.info(format('metal3_dummy has %d polygons', count)) + polygons_count += count + metal3 = metal3_drawn + metal3_dummy + metal3_label = get_polygons(42, 10) + count = metal3_label.count + logger.info(format('metal3_label has %d polygons', count)) + polygons_count += count + metal3_slot = get_polygons(42, 3) + count = metal3_slot.count + logger.info(format('metal3_slot has %d polygons', count)) + polygons_count += count + metal3_blk = get_polygons(42, 5) + count = metal3_blk.count + logger.info(format('metal3_blk has %d polygons', count)) + polygons_count += count + if METAL_LEVEL == '3LM' + top_via = via2 topmin1_via = via1 top_metal = metal3 topmin1_metal = metal2 else - metal3_drawn = get_polygons(42 , 0 ) - count = metal3_drawn.count() - logger.info("metal3_drawn has %d polygons" % [count]) - polygons_count += count - - metal3_dummy = get_polygons(42 , 4 ) - count = metal3_dummy.count() - logger.info("metal3_dummy has %d polygons" % [count]) - polygons_count += count - - metal3 = metal3_drawn + metal3_dummy - - metal3_label = get_polygons(42 , 10) - count = metal3_label.count() - logger.info("metal3_label has %d polygons" % [count]) - polygons_count += count - - metal3_slot = get_polygons(42 , 3 ) - count = metal3_slot.count() - logger.info("metal3_slot has %d polygons" % [count]) - polygons_count += count - - metal3_blk = get_polygons(42 , 5 ) - count = metal3_blk.count() - logger.info("metal3_blk has %d polygons" % [count]) - polygons_count += count - - via3 = get_polygons(40 , 0 ) - - if METAL_LEVEL == "4LM" - metal4_drawn = get_polygons(46 , 0 ) - count = metal4_drawn.count() - logger.info("metal4_drawn has %d polygons" % [count]) - polygons_count += count - - metal4_dummy = get_polygons(46 , 4 ) - count = metal4_dummy.count() - logger.info("metal4_dummy has %d polygons" % [count]) - polygons_count += count - - metal4 = metal4_drawn + metal4_dummy - - metal4_label = get_polygons(46 , 10) - count = metal4_label.count() - logger.info("metal4_label has %d polygons" % [count]) - polygons_count += count - - metal4_slot = get_polygons(46 , 3 ) - count = metal4_slot.count() - logger.info("metal4_slot has %d polygons" % [count]) - polygons_count += count - - metal4_blk = get_polygons(46 , 5 ) - count = metal4_blk.count() - logger.info("metal4_blk has %d polygons" % [count]) - polygons_count += count - + + via3 = get_polygons(40, 0) + + metal4_drawn = get_polygons(46, 0) + count = metal4_drawn.count + logger.info(format('metal4_drawn has %d polygons', count)) + polygons_count += count + metal4_dummy = get_polygons(46, 4) + count = metal4_dummy.count + logger.info(format('metal4_dummy has %d polygons', count)) + polygons_count += count + metal4 = metal4_drawn + metal4_dummy + metal4_label = get_polygons(46, 10) + count = metal4_label.count + logger.info(format('metal4_label has %d polygons', count)) + polygons_count += count + metal4_slot = get_polygons(46, 3) + count = metal4_slot.count + logger.info(format('metal4_slot has %d polygons', count)) + polygons_count += count + metal4_blk = get_polygons(46, 5) + count = metal4_blk.count + logger.info(format('metal4_blk has %d polygons', count)) + polygons_count += count + if METAL_LEVEL == '4LM' + top_via = via3 topmin1_via = via2 top_metal = metal4 topmin1_metal = metal3 else - metal4_drawn = get_polygons(46 , 0 ) - count = metal4_drawn.count() - logger.info("metal4_drawn has %d polygons" % [count]) - polygons_count += count - - metal4_dummy = get_polygons(46 , 4 ) - count = metal4_dummy.count() - logger.info("metal4_dummy has %d polygons" % [count]) - polygons_count += count - - metal4 = metal4_drawn + metal4_dummy - - metal4_label = get_polygons(46 , 10) - count = metal4_label.count() - logger.info("metal4_label has %d polygons" % [count]) - polygons_count += count - - metal4_slot = get_polygons(46 , 3 ) - count = metal4_slot.count() - logger.info("metal4_slot has %d polygons" % [count]) - polygons_count += count - - metal4_blk = get_polygons(46 , 5 ) - count = metal4_blk.count() - logger.info("metal4_blk has %d polygons" % [count]) - polygons_count += count - - via4 = get_polygons(41 , 0 ) - count = via4.count() - logger.info("via4 has %d polygons" % [count]) - polygons_count += count - - if METAL_LEVEL == "5LM" - metal5_drawn = get_polygons(81 , 0 ) - count = metal5_drawn.count() - logger.info("metal5_drawn has %d polygons" % [count]) - polygons_count += count - - metal5_dummy = get_polygons(81 , 4 ) - count = metal5_dummy.count() - logger.info("metal5_dummy has %d polygons" % [count]) - polygons_count += count - - metal5 = metal5_drawn + metal5_dummy - - metal5_label = get_polygons(81 , 10) - count = metal5_label.count() - logger.info("metal5_label has %d polygons" % [count]) - polygons_count += count - - metal5_slot = get_polygons(81 , 3 ) - count = metal5_slot.count() - logger.info("metal5_slot has %d polygons" % [count]) - polygons_count += count - - metal5_blk = get_polygons(81 , 5 ) - count = metal5_blk.count() - logger.info("metal5_blk has %d polygons" % [count]) - polygons_count += count + + via4 = get_polygons(41, 0) + count = via4.count + logger.info(format('via4 has %d polygons', count)) + polygons_count += count + + case METAL_LEVEL + when '5LM' + metal5_drawn = get_polygons(81, 0) + count = metal5_drawn.count + logger.info(format('metal5_drawn has %d polygons', count)) + polygons_count += count + + metal5_dummy = get_polygons(81, 4) + count = metal5_dummy.count + logger.info(format('metal5_dummy has %d polygons', count)) + polygons_count += count + + metal5 = metal5_drawn + metal5_dummy + + metal5_label = get_polygons(81, 10) + count = metal5_label.count + logger.info(format('metal5_label has %d polygons', count)) + polygons_count += count + + metal5_slot = get_polygons(81, 3) + count = metal5_slot.count + logger.info(format('metal5_slot has %d polygons', count)) + polygons_count += count + + metal5_blk = get_polygons(81, 5) + count = metal5_blk.count + logger.info(format('metal5_blk has %d polygons', count)) + polygons_count += count top_via = via4 topmin1_via = via3 top_metal = metal5 topmin1_metal = metal4 - elsif METAL_LEVEL == "6LM" - metal5_drawn = get_polygons(81 , 0 ) - count = metal5_drawn.count() - logger.info("metal5_drawn has %d polygons" % [count]) - polygons_count += count + when '6LM' + metal5_drawn = get_polygons(81, 0) + count = metal5_drawn.count + logger.info(format('metal5_drawn has %d polygons', count)) + polygons_count += count - metal5_dummy = get_polygons(81 , 4 ) - count = metal5_dummy.count() - logger.info("metal5_dummy has %d polygons" % [count]) - polygons_count += count + metal5_dummy = get_polygons(81, 4) + count = metal5_dummy.count + logger.info(format('metal5_dummy has %d polygons', count)) + polygons_count += count metal5 = metal5_drawn + metal5_dummy - metal5_label = get_polygons(81 , 10) - count = metal5_label.count() - logger.info("metal5_label has %d polygons" % [count]) - polygons_count += count - - metal5_slot = get_polygons(81 , 3 ) - count = metal5_slot.count() - logger.info("metal5_slot has %d polygons" % [count]) - polygons_count += count + metal5_label = get_polygons(81, 10) + count = metal5_label.count + logger.info(format('metal5_label has %d polygons', count)) + polygons_count += count - metal5_blk = get_polygons(81 , 5 ) - count = metal5_blk.count() - logger.info("metal5_blk has %d polygons" % [count]) - polygons_count += count + metal5_slot = get_polygons(81, 3) + count = metal5_slot.count + logger.info(format('metal5_slot has %d polygons', count)) + polygons_count += count - via5 = get_polygons(82 , 0 ) - count = via5.count() - logger.info("via5 has %d polygons" % [count]) - polygons_count += count + metal5_blk = get_polygons(81, 5) + count = metal5_blk.count + logger.info(format('metal5_blk has %d polygons', count)) + polygons_count += count + via5 = get_polygons(82, 0) + count = via5.count + logger.info(format('via5 has %d polygons', count)) + polygons_count += count - metaltop_drawn = get_polygons(53 , 0 ) - count = metaltop_drawn.count() - logger.info("metaltop_drawn has %d polygons" % [count]) - polygons_count += count + metaltop_drawn = get_polygons(53, 0) + count = metaltop_drawn.count + logger.info(format('metaltop_drawn has %d polygons', count)) + polygons_count += count - metaltop_dummy = get_polygons(53 , 4 ) - count = metaltop_dummy.count() - logger.info("metaltop_dummy has %d polygons" % [count]) - polygons_count += count + metaltop_dummy = get_polygons(53, 4) + count = metaltop_dummy.count + logger.info(format('metaltop_dummy has %d polygons', count)) + polygons_count += count metaltop = metaltop_drawn + metaltop_dummy - metaltop_label = get_polygons(53 , 10) - count = metaltop_label.count() - logger.info("metaltop_label has %d polygons" % [count]) - polygons_count += count + metaltop_label = get_polygons(53, 10) + count = metaltop_label.count + logger.info(format('metaltop_label has %d polygons', count)) + polygons_count += count - metaltop_slot = get_polygons(53 , 3 ) - count = metaltop_slot.count() - logger.info("metaltop_slot has %d polygons" % [count]) - polygons_count += count + metaltop_slot = get_polygons(53, 3) + count = metaltop_slot.count + logger.info(format('metaltop_slot has %d polygons', count)) + polygons_count += count - metalt_blk = get_polygons(53 , 5 ) - count = metalt_blk.count() - logger.info("metalt_blk has %d polygons" % [count]) - polygons_count += count + metalt_blk = get_polygons(53, 5) + count = metalt_blk.count + logger.info(format('metalt_blk has %d polygons', count)) + polygons_count += count top_via = via5 topmin1_via = via4 top_metal = metaltop topmin1_metal = metal5 else - logger.error("Unknown metal stack %s" % [METAL_LEVEL]) + logger.error(format('Unknown metal stack %s', METAL_LEVEL)) raise end end end end -pad = get_polygons(37 , 0 ) -count = pad.count() -logger.info("pad has %d polygons" % [count]) -polygons_count += count - -ubmpperi = get_polygons(183, 0 ) -count = ubmpperi.count() -logger.info("ubmpperi has %d polygons" % [count]) -polygons_count += count - -ubmparray = get_polygons(184, 0 ) -count = ubmparray.count() -logger.info("ubmparray has %d polygons" % [count]) -polygons_count += count - -ubmeplate = get_polygons(185, 0 ) -count = ubmeplate.count() -logger.info("ubmeplate has %d polygons" % [count]) -polygons_count += count - -metal1_res = get_polygons(110, 11) -count = metal1_res.count() -logger.info("metal1_res has %d polygons" % [count]) -polygons_count += count - -metal2_res = get_polygons(110, 12) -count = metal2_res.count() -logger.info("metal2_res has %d polygons" % [count]) -polygons_count += count - -metal3_res = get_polygons(110, 13) -count = metal3_res.count() -logger.info("metal3_res has %d polygons" % [count]) -polygons_count += count - -metal4_res = get_polygons(110, 14) -count = metal4_res.count() -logger.info("metal4_res has %d polygons" % [count]) -polygons_count += count - -metal5_res = get_polygons(110, 15) -count = metal5_res.count() -logger.info("metal5_res has %d polygons" % [count]) -polygons_count += count - -metal6_res = get_polygons(110, 16) -count = metal6_res.count() -logger.info("metal6_res has %d polygons" % [count]) -polygons_count += count - -pr_bndry = get_polygons(0 , 0 ) -count = pr_bndry.count() -logger.info("pr_bndry has %d polygons" % [count]) -polygons_count += count - -border = get_polygons(63 , 0 ) -count = border.count() -logger.info("border has %d polygons" % [count]) -polygons_count += count +pad = get_polygons(37, 0) +count = pad.count +logger.info(format('pad has %d polygons', count)) +polygons_count += count + +ubmpperi = get_polygons(183, 0) +count = ubmpperi.count +logger.info(format('ubmpperi has %d polygons', count)) +polygons_count += count + +ubmparray = get_polygons(184, 0) +count = ubmparray.count +logger.info(format('ubmparray has %d polygons', count)) +polygons_count += count + +ubmeplate = get_polygons(185, 0) +count = ubmeplate.count +logger.info(format('ubmeplate has %d polygons', count)) +polygons_count += count + +metal1_res = get_polygons(110, 11) +count = metal1_res.count +logger.info(format('metal1_res has %d polygons', count)) +polygons_count += count + +metal2_res = get_polygons(110, 12) +count = metal2_res.count +logger.info(format('metal2_res has %d polygons', count)) +polygons_count += count + +metal3_res = get_polygons(110, 13) +count = metal3_res.count +logger.info(format('metal3_res has %d polygons', count)) +polygons_count += count + +metal4_res = get_polygons(110, 14) +count = metal4_res.count +logger.info(format('metal4_res has %d polygons', count)) +polygons_count += count + +metal5_res = get_polygons(110, 15) +count = metal5_res.count +logger.info(format('metal5_res has %d polygons', count)) +polygons_count += count + +metal6_res = get_polygons(110, 16) +count = metal6_res.count +logger.info(format('metal6_res has %d polygons', count)) +polygons_count += count + +pr_bndry = get_polygons(0, 0) +count = pr_bndry.count +logger.info(format('pr_bndry has %d polygons', count)) +polygons_count += count + +border = get_polygons(63, 0) +count = border.count +logger.info(format('border has %d polygons', count)) +polygons_count += count logger.info("Total no. of polygons in the design is #{polygons_count}") -logger.info("Starting deriving base layers.") +logger.info('Starting deriving base layers.') #===================================================== #------------- BASE LAYERS DERIVATIONS --------------- @@ -957,35 +843,35 @@ nwell_n_dn = nwell.not_interacting(dnwell) if CONNECTIVITY_RULES - logger.info("Construct connectivity for the design.") + logger.info('Construct connectivity for the design.') - connect(dnwell, ncomp) + connect(dnwell, ncomp) connect(ncomp, contact) connect(pcomp, contact) - connect(lvpwell_out, pcomp) + connect(lvpwell_out, pcomp) connect(lvpwell_dn, pcomp) - connect(nwell, ncomp) - connect(natcomp, contact) - connect(mvsd, ncomp) - connect(mvpsd, pcomp) - connect(contact, metal1) + connect(nwell, ncomp) + connect(natcomp, contact) + connect(mvsd, ncomp) + connect(mvpsd, pcomp) + connect(contact, metal1) connect(metal1, via1) connect(via1, metal2) - if METAL_LEVEL != "2LM" + if METAL_LEVEL != '2LM' connect(metal2, via2) connect(via2, metal3) - if METAL_LEVEL != "3LM" + if METAL_LEVEL != '3LM' connect(metal3, via3) connect(via3, metal4) - - if METAL_LEVEL != "4LM" + + if METAL_LEVEL != '4LM' connect(metal4, via4) connect(via4, metal5) - if METAL_LEVEL != "5LM" + if METAL_LEVEL != '5LM' connect(metal5, via5) connect(via5, metaltop) end @@ -993,21 +879,20 @@ if CONNECTIVITY_RULES end end -end #CONNECTIVITY_RULES +end #================================================ #------------ PRE-DEFINED FUNCTIONS ------------- #================================================ -def conn_space(layer,conn_val,not_conn_val, mode) - if conn_val > not_conn_val - raise "ERROR : Wrong connectivity implementation" - end +def conn_space(layer, conn_val, not_conn_val, mode) + raise 'ERROR : Wrong connectivity implementation' if conn_val > not_conn_val + connected_output = layer.space(conn_val.um, mode).polygons(0.001) unconnected_errors_unfiltered = layer.space(not_conn_val.um, mode) singularity_errors = layer.space(0.001.um) # Filter out the errors arising from the same net - unconnected_errors = DRC::DRCLayer::new(self, RBA::EdgePairs::new) + unconnected_errors = DRC::DRCLayer.new(self, RBA::EdgePairs.new) unconnected_errors_unfiltered.data.each do |ep| net1 = l2n_data.probe_net(layer.data, ep.first.p1) net2 = l2n_data.probe_net(layer.data, ep.second.p1) @@ -1019,17 +904,16 @@ def conn_space(layer,conn_val,not_conn_val, mode) end end unconnected_output = unconnected_errors.polygons.or(singularity_errors.polygons(0.001)) - return connected_output, unconnected_output + [connected_output, unconnected_output] end -def conn_separation(layer1, layer2, conn_val,not_conn_val, mode) - if conn_val > not_conn_val - raise "ERROR : Wrong connectivity implementation" - end +def conn_separation(layer1, layer2, conn_val, not_conn_val, mode) + raise 'ERROR : Wrong connectivity implementation' if conn_val > not_conn_val + connected_output = layer1.separation(layer2, conn_val.um, mode).polygons(0.001) unconnected_errors_unfiltered = layer1.separation(layer2, not_conn_val.um, mode) # Filter out the errors arising from the same net - unconnected_errors = DRC::DRCLayer::new(self, RBA::EdgePairs::new) + unconnected_errors = DRC::DRCLayer.new(self, RBA::EdgePairs.new) unconnected_errors_unfiltered.data.each do |ep| net1 = l2n_data.probe_net(layer1.data, ep.first.p1) net2 = l2n_data.probe_net(layer2.data, ep.second.p1) @@ -1041,30 +925,24 @@ def conn_separation(layer1, layer2, conn_val,not_conn_val, mode) end end unconnected_output = unconnected_errors.polygons(0.001) - return connected_output, unconnected_output + [connected_output, unconnected_output] end # === IMPLICIT EXTRACTION === if CONNECTIVITY_RULES - logger.info("Connectivity rules enabled, Netlist object will be generated.") + logger.info('Connectivity rules enabled, Netlist object will be generated.') netlist -end #CONNECTIVITY_RULES +end # === LAYOUT EXTENT === CHIP = extent.sized(0.0) -logger.info("Total area of the design is #{CHIP.area()} um^2.") +logger.info("Total area of the design is #{CHIP.area} um^2.") #================================================ #----------------- MAIN RUNSET ------------------ #================================================ -logger.info("Starting GF180MCU DRC rules.") -if FEOL - logger.info("Running all FEOL rules") -end #FEOL - -if BEOL - logger.info("Running all BEOL rules") -end #BEOL - +logger.info('Starting GF180MCU DRC rules.') +logger.info('Running all FEOL rules') if FEOL +logger.info('Running all BEOL rules') if BEOL diff --git a/klayout/drc/rule_decks/mcell.drc b/klayout/drc/rule_decks/mcell.drc deleted file mode 100644 index 70a0c585..00000000 --- a/klayout/drc/rule_decks/mcell.drc +++ /dev/null @@ -1,47 +0,0 @@ -################################################################################################ -# Copyright 2022 GlobalFoundries PDK Authors -# -# 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 FEOL - #================================================ - #---------------------MCELL---------------------- - #================================================ - - # Rule MC.1: min. mcell width is 0.4µm - logger.info("Executing rule MC.1") - mc1_l1 = mcell_feol_mk.width(0.4.um, euclidian).polygons(0.001) - mc1_l1.output("MC.1", "MC.1 : min. mcell width : 0.4µm") - mc1_l1.forget - - # Rule MC.2: min. mcell spacing is 0.4µm - logger.info("Executing rule MC.2") - mc2_l1 = mcell_feol_mk.space(0.4.um, euclidian).polygons(0.001) - mc2_l1.output("MC.2", "MC.2 : min. mcell spacing : 0.4µm") - mc2_l1.forget - - # Rule MC.3: Minimum Mcell area is 0.35µm² - logger.info("Executing rule MC.3") - mc3_l1 = mcell_feol_mk.with_area(nil, 0.35.um) - mc3_l1.output("MC.3", "MC.3 : Minimum Mcell area : 0.35µm²") - mc3_l1.forget - - # Rule MC.4: Minimum area enclosed by Mcell is 0.35µm² - logger.info("Executing rule MC.4") - mc4_l1 = mcell_feol_mk.holes.with_area(nil, 0.35.um) - mc4_l1.output("MC.4", "MC.4 : Minimum area enclosed by Mcell : 0.35µm²") - mc4_l1.forget -end #FEOL - - diff --git a/klayout/drc/rule_decks/otp_mk.drc b/klayout/drc/rule_decks/otp_mk.drc deleted file mode 100644 index ce62944c..00000000 --- a/klayout/drc/rule_decks/otp_mk.drc +++ /dev/null @@ -1,143 +0,0 @@ -################################################################################################ -# Copyright 2022 GlobalFoundries PDK Authors -# -# 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 FEOL - #================================================ - #---------------------OTP_MK--------------------- - #================================================ - - logger.info("Starting OTP_MK derivations") - - comp_otp = comp.and(otp_mk) - poly_otp = poly2.and(otp_mk) - sab_otp = sab.and(otp_mk) - - # Rule O.DF.3a: Min. COMP Space. P-substrate tap (PCOMP outside NWELL) can be butted for different voltage devices as the potential is same. is 0.24µm - logger.info("Executing rule O.DF.3a") - odf3a_l1 = comp_otp.space(0.24.um, euclidian) - odf3a_l1.output("O.DF.3a", "O.DF.3a : Min. COMP Space. P-substrate tap (PCOMP outside NWELL) can be butted for different voltage devices as the potential is same. : 0.24µm") - odf3a_l1.forget - - # Rule O.DF.6: Min. COMP extend beyond poly2 (it also means source/drain overhang). is 0.22µm - logger.info("Executing rule O.DF.6") - odf6_l1 = poly2.and(otp_mk).enclosed(comp_otp, 0.22.um, projection) - odf6_l1.output("O.DF.6", "O.DF.6 : Min. COMP extend beyond poly2 (it also means source/drain overhang). : 0.22µm") - odf6_l1.forget - - # Rule O.DF.9: Min. COMP area (um2). is 0.1444µm² - logger.info("Executing rule O.DF.9") - odf9_l1 = comp_otp.with_area(nil, 0.1444.um) - odf9_l1.output("O.DF.9", "O.DF.9 : Min. COMP area (um2). : 0.1444µm²") - odf9_l1.forget - - # Rule O.PL.2: Min. poly2 width. is 0.22µm - logger.info("Executing rule O.PL.2") - opl2_l1 = poly_otp.edges.and(tgate.edges).width(0.22.um, euclidian) - opl2_l1.output("O.PL.2", "O.PL.2 : Min. poly2 width. : 0.22µm") - opl2_l1.forget - - # Rule O.PL.3a: Min. poly2 Space on COMP. is 0.18µm - logger.info("Executing rule O.PL.3a") - opl3a_l1 = (tgate).or(poly2.not(comp)).and(otp_mk).space(0.18.um, euclidian) - opl3a_l1.output("O.PL.3a", "O.PL.3a : Min. poly2 Space on COMP. : 0.18µm") - opl3a_l1.forget - - # Rule O.PL.4: Min. extension beyond COMP to form Poly2 end cap. is 0.14µm - logger.info("Executing rule O.PL.4") - opl4_l1 = comp_otp.enclosed(poly_otp, 0.14.um, euclidian) - opl4_l1.output("O.PL.4", "O.PL.4 : Min. extension beyond COMP to form Poly2 end cap. : 0.14µm") - opl4_l1.forget - - # rule O.PL.5a is not a DRC check - ## Please refer to https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_10_10.html - - # rule O.PL.5b is not a DRC check - ## Please refer to https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_10_10.html - - # Rule O.SB.2: Min. salicide Block Space. is 0.28µm - logger.info("Executing rule O.SB.2") - osb2_l1 = sab_otp.space(0.28.um, euclidian) - osb2_l1.output("O.SB.2", "O.SB.2 : Min. salicide Block Space. : 0.28µm") - osb2_l1.forget - - # Rule O.SB.3: Min. space from salicide block to unrelated COMP. is 0.09µm - logger.info("Executing rule O.SB.3") - osb3_l1 = sab.outside(comp).and(otp_mk).separation(comp.outside(sab), 0.09.um, euclidian).polygons(0.001) - osb3_l1.output("O.SB.3", "O.SB.3 : Min. space from salicide block to unrelated COMP. : 0.09µm") - osb3_l1.forget - - # Rule O.SB.4: Min. space from salicide block to contact. - logger.info("Executing rule O.SB.4") - osb4_l1 = sab_otp.separation(contact, 0.03.um, euclidian).polygons(0.001).or(sab_otp.and(contact)) - osb4_l1.output("O.SB.4", "O.SB.4 : Min. space from salicide block to contact.") - osb4_l1.forget - - # rule O.SB.5a is not a DRC check - ## Please refer to https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_10_10.html - - # Rule O.SB.5b_LV: Min. space from salicide block to unrelated Poly2 on COMP. is 0.1µm - logger.info("Executing rule O.SB.5b_LV") - osb5b_l1 = sab_otp.outside(tgate).separation(tgate.outside(sab), 0.1.um, euclidian).polygons(0.001).not_interacting(v5_xtor).not_interacting(dualgate) - osb5b_l1.output("O.SB.5b_LV", "O.SB.5b_LV : Min. space from salicide block to unrelated Poly2 on COMP. : 0.1µm") - osb5b_l1.forget - - # rule O.SB.5b_MV is not a DRC check - ## Please refer to https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_10_10.html - - # Rule O.SB.9: Min. salicide block extension beyond unsalicided Poly2. is 0.1µm - logger.info("Executing rule O.SB.9") - osb9_l1 = poly_otp.enclosed(sab_otp, 0.1.um, euclidian) - osb9_l1.output("O.SB.9", "O.SB.9 : Min. salicide block extension beyond unsalicided Poly2. : 0.1µm") - osb9_l1.forget - - # Rule O.SB.11: Min. salicide block overlap with COMP. is 0.04µm - logger.info("Executing rule O.SB.11") - osb11_l1 = sab_otp.overlap(comp, 0.04.um, euclidian) - osb11_l1.output("O.SB.11", "O.SB.11 : Min. salicide block overlap with COMP. : 0.04µm") - osb11_l1.forget - - # rule O.SB.12 is not a DRC check - ## Please refer to https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_10_10.html - - # Rule O.SB.13_LV: Min. area of silicide block (um2). is 1.488µm² - logger.info("Executing rule O.SB.13_LV") - osb13_l1 = sab_otp.with_area(nil, 1.488.um).not_interacting(v5_xtor).not_interacting(dualgate) - osb13_l1.output("O.SB.13_LV", "O.SB.13_LV : Min. area of silicide block (um2). : 1.488µm²") - osb13_l1.forget - - # Rule O.SB.13_MV: Min. area of silicide block (um2). is 2µm² - logger.info("Executing rule O.SB.13_MV") - osb13_l1 = sab_otp.and(v5_xtor).with_area(nil, 2.um) - osb13_l1.output("O.SB.13_MV", "O.SB.13_MV : Min. area of silicide block (um2). : 2µm²") - osb13_l1.forget - - # rule O.SB.15b is not a DRC check - ## Please refer to https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_10_10.html - - # Rule O.CO.7: Min. space from COMP contact to Poly2 on COMP. is 0.13µm - logger.info("Executing rule O.CO.7") - oco7_l1 = contact.not_outside(comp_otp).separation(tgate.and(otp_mk), 0.13.um, euclidian) - oco7_l1.output("O.CO.7", "O.CO.7 : Min. space from COMP contact to Poly2 on COMP. : 0.13µm") - oco7_l1.forget - - # Rule O.PL.ORT: Orientation-restricted gates must have the gate width aligned along the X-axis (poly line running horizontally) in reference to wafer notch down. is 0µm - logger.info("Executing rule O.PL.ORT") - oplort_l1 = comp_otp.not(poly_otp).edges.and(tgate.edges).without_angle(0.um) - oplort_l1.output("O.PL.ORT", "O.PL.ORT : Orientation-restricted gates must have the gate width aligned along the X-axis (poly line running horizontally) in reference to wafer notch down. : 0µm") - oplort_l1.forget - -end #FEOL - diff --git a/klayout/drc/rule_decks/pres.drc b/klayout/drc/rule_decks/pres.drc deleted file mode 100644 index c6e64c72..00000000 --- a/klayout/drc/rule_decks/pres.drc +++ /dev/null @@ -1,99 +0,0 @@ -################################################################################################ -# Copyright 2022 GlobalFoundries PDK Authors -# -# 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 FEOL - #================================================ - #----------------P+ POLY RESISTOR---------------- - #================================================ - - logger.info("Starting PRES derivations") - pres_poly = poly2.and(pplus).interacting(sab).interacting(res_mk).not_interacting(resistor) - - # Rule PRES.1: Minimum width of Poly2 resistor. is 0.8µm - logger.info("Executing rule PRES.1") - pres1_l1 = pres_poly.width(0.8.um, euclidian) - pres1_l1.output("PRES.1", "PRES.1 : Minimum width of Poly2 resistor. : 0.8µm") - pres1_l1.forget - - # Rule PRES.2: Minimum space between Poly2 resistors. is 0.4µm - logger.info("Executing rule PRES.2") - pres2_l1 = pres_poly.isolated(0.4.um, euclidian) - pres2_l1.output("PRES.2", "PRES.2 : Minimum space between Poly2 resistors. : 0.4µm") - pres2_l1.forget - - # Rule PRES.3: Minimum space from Poly2 resistor to COMP. - logger.info("Executing rule PRES.3") - pres3_l1 = pres_poly.separation(comp, 0.6.um, euclidian).polygons(0.001) - pres3_l2 = comp.not_outside(pres_poly) - pres3_l = pres3_l1.or(pres3_l2) - pres3_l.output("PRES.3", "PRES.3 : Minimum space from Poly2 resistor to COMP.") - pres3_l.forget - pres3_l1.forget - pres3_l2.forget - - # Rule PRES.4: Minimum space from Poly2 resistor to unrelated Poly2. is 0.6µm - logger.info("Executing rule PRES.4") - pres4_l1 = pres_poly.separation(poly2.not_interacting(sab), 0.6.um, euclidian) - pres4_l1.output("PRES.4", "PRES.4 : Minimum space from Poly2 resistor to unrelated Poly2. : 0.6µm") - pres4_l1.forget - - # Rule PRES.5: Minimum Plus implant overlap of Poly2 resistor. is 0.3µm - logger.info("Executing rule PRES.5") - pres5_l1 = pres_poly.enclosed(pplus, 0.3.um, euclidian).polygons(0.001) - pres5_l2 = pres_poly.not_outside(pplus).not(pplus) - pres5_l = pres5_l1.or(pres5_l2) - pres5_l.output("PRES.5", "PRES.5 : Minimum Plus implant overlap of Poly2 resistor. : 0.3µm") - pres5_l1.forget - pres5_l2.forget - pres5_l.forget - - # Rule PRES.6: Minimum salicide block overlap of Poly2 resistor in width direction. is 0.28µm - logger.info("Executing rule PRES.6") - pres6_l1 = pres_poly.enclosed(sab,0.28.um) - pres6_l1.output("PRES.6", "PRES.6 : Minimum salicide block overlap of Poly2 resistor in width direction. : 0.28µm") - pres6_l1.forget - - # Rule PRES.7: Space from salicide block to contact on Poly2 resistor. - logger.info("Executing rule PRES.7") - pres7_l1 = contact.and(pres_poly).separation(sab,0.22.um).polygons(0.001) - pres7_l2 = contact.and(pres_poly).interacting(sab) - pres7_l = pres7_l1.or(pres7_l2) - pres7_l.output("PRES.7", "PRES.7 : Space from salicide block to contact on Poly2 resistor.") - pres7_l1.forget - pres7_l2.forget - - # Rule PRES.8 is not a DRC check - ## Please refer to https://gf180mcu-pdk.readthedocs.io/en/latest/physical_verification/design_manual/drm_10_01.html#p-poly-resistor-pres - - # Rule PRES.9a: Pplus Poly2 resistor shall be covered by RES_MK marking. RES_MK length shall be coincide with resistor length (Defined by SAB length) and width covering the width of Poly2. - logger.info("Executing rule PRES.9a") - mk_pres9a = res_mk.edges.not(poly2.and(pplus).and(sab).edges).inside_part(poly2) - pres9a_l1 = res_mk.interacting(pres_poly).interacting(mk_pres9a) - pres9a_l1.output("PRES.9a", "PRES.9a : Pplus Poly2 resistor shall be covered by RES_MK marking. RES_MK length shall be coincide with resistor length (Defined by SAB length) and width covering the width of Poly2.") - pres9a_l1.forget - mk_pres9a.forget - - # Rule PRES.9b: If the size of single RES_MK mark layer is greater than 15000um2 and both side (X and Y) are greater than 80um. - ## then the minimum spacing to adjacent RES_MK layer. is 20µm - logger.info("Executing rule PRES.9b") - pres9b = res_mk.with_area(15000.001.um,nil).edges.with_length(80.001.um,nil) - pres9b_l1 = pres9b.separation(res_mk.edges, 20.um) - pres9b_l1.output("PRES.9b", "PRES.9b : If the size of single RES_MK mark layer is greater than 15000um2 and both side (X and Y) are greater than 80um. then the minimum spacing to adjacent RES_MK layer. : 20µm") - pres9b_l1.forget - pres9b.forget - pres_poly.forget - -end #PRES diff --git a/klayout/drc/rule_decks/tail.drc b/klayout/drc/rule_decks/tail.drc index b4ef0bca..e38e24cb 100644 --- a/klayout/drc/rule_decks/tail.drc +++ b/klayout/drc/rule_decks/tail.drc @@ -14,10 +14,6 @@ # limitations under the License. ################################################################################################ - - exec_end_time = Time.now run_time = exec_end_time - exec_start_time -logger.info("%s DRC Total Run time %f seconds" % [table_name, run_time]) - - +logger.info(format('%s DRC Total Run time %