Skip to content

Commit

Permalink
Merge pull request google#48 from klayoutmatthias/wip
Browse files Browse the repository at this point in the history
Some optimizations for DRC
  • Loading branch information
atorkmabrains authored Dec 19, 2022
2 parents d870721 + b9eb862 commit 8e9c151
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 20 deletions.
5 changes: 2 additions & 3 deletions rules/klayout/drc/rule_decks/comp.drc
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ if FEOL

# Rule DF.2b: Max. COMP width for all cases except those used for capacitors, marked by ‘MOS_CAP_MK’ layer. is 100um
logger.info("Executing rule DF.2b")
df_2b = comp.not(mos_cap_mk).width(100.um + 1.dbu).polygons(0.001)
df2b_l1 = comp.not(mos_cap_mk).not_interacting(df_2b)
df2b_l1 = comp.not(mos_cap_mk).sized(-50.um).sized(50.um)
df2b_l1.output("DF.2b", "DF.2b : Max. COMP width for all cases except those used for capacitors, marked by 'MOS_CAP_MK' layer: 100um")
df2b_l1.forget

Expand Down Expand Up @@ -278,7 +277,7 @@ if FEOL

# Rule DF.12: COMP not covered by Nplus or Pplus is forbidden (except those COMP under marking).
logger.info("Executing rule DF.12")
df12_l1 = comp.not_interacting(schottky_diode).not(nplus.or(pplus))
df12_l1 = comp.not_interacting(schottky_diode).not(nplus).not(pplus)
df12_l1.output("DF.12", "DF.12 : COMP not covered by Nplus or Pplus is forbidden (except those COMP under marking).")
df12_l1.forget

Expand Down
13 changes: 10 additions & 3 deletions rules/klayout/drc/rule_decks/ldnmos.drc
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ if FEOL

end #CONNECTIVITY_RULES

# Rule MDN.3a: Min transistor channel length is 0.6µm.
# Rule MDN.3a: Min transistor channel length is 0.6µm
logger.info("Executing rule MDN.3a")
mdn3a_l1 = mvsd.enclosed(poly_mdn, 0.6.um, euclidian).polygons(0.001)
mdn3a_l1 = poly_mdn.enclosing(mvsd, 0.6.um, euclidian).polygons(0.001)
mdn3a_l1.output("MDN.3a", "MDN.3a : Min transistor channel length. : 0.6µm")
mdn3a_l1.forget

Expand All @@ -75,21 +75,23 @@ if FEOL
mdn3b_l1 = ldnmos_edges.inside_part(ncomp).not(mdn3b_pass)
mdn3b_l1.output("MDN.3b", "MDN.3b : Max transistor channel length: 20um")
mdn3b_l1.forget
mdn3b_pass.forget

# Rule MDN.4a: Min transistor channel width is 4µm.
logger.info("Executing rule MDN.4a")
mdn4a_fail = ldnmos.width(4.um, projection).edges
mdn4a_l1 = ldnmos_gate_ends.and(mdn4a_fail).extended(0, 0, 0.001, 0.001)
mdn4a_l1.output("MDN.4a", "MDN.4a : Min transistor channel width. : 4µm")
mdn4a_l1.forget
mdn4a_fail.forget

# Rule MDN.4b: Max transistor channel width is 50um.
logger.info("Executing rule MDN.4b")
mdn4b_pass = ldnmos.width(50.um + 1.dbu, projection).edges
mdn4b_l1 = ldnmos_gate_ends.not(mdn4b_pass).extended(0, 0, 0.001, 0.001)
mdn4b_l1.output("MDN.4b", "MDN.4b : Max transistor channel width : 50 um ")
mdn4b_l1.forget
ldnmos_gate_ends.forget
mdn4b_pass.forget

pcomp_mdn5a = pcomp.not_interacting(ncomp).inside(ldmos_xtor).inside(dualgate)
# Rule MDN.5ai: Min PCOMP (Pplus AND COMP) space to LDNMOS Drain MVSD (source and body tap non-butted). PCOMP (Pplus AND COMP) intercept with LDNMOS Drain MVSD is not allowed.
Expand Down Expand Up @@ -365,5 +367,10 @@ if FEOL

mdn_17_gr_in_ldmos_mk.forget

ldnmos_gate_ends.forget
ldnmos_edges.forget
ldnmos.forget
poly_mdn.forget

end #FEOL

27 changes: 18 additions & 9 deletions rules/klayout/drc/rule_decks/ldpmos.drc
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,29 @@ if FEOL
#-------------------10V LDPMOS-------------------
#================================================

mdp_source = (pcomp).interacting(poly2.and(dualgate).and(ldmos_xtor).and(mvpsd)).not(poly2)
ldpmos = poly2.and(pcomp).and(dualgate).not(mvpsd).inside(ldmos_xtor)
poly_mdp = poly2.and(pcomp).inside(ldmos_xtor).inside(dualgate)
mdp_source = pcomp.interacting(poly_mdp.and(mvpsd)).not(poly2)
ldpmos = poly_mdp.not(mvpsd)
ldpmos_edges = ldpmos.edges
ldpmos_gate_ends = ldpmos_edges.outside_part(pcomp) # defines the width
ldpmos_gate_sides = ldpmos_edges.inside_part(pcomp) # defines the length
ldpmos_edges.forget

# Rule MDP.1: Minimum transistor channel length. is 0.6µm
logger.info("Executing rule MDP.1")
mdp1_l1 = poly2.and(comp).inside(ldmos_xtor).inside(dualgate).enclosing(mvpsd, 0.6.um, euclidian).polygons(0.001)
mdp1_l1 = poly_mdp.enclosing(mvpsd, 0.6.um, euclidian).polygons(0.001)
mdp1_l1.output("MDP.1", "MDP.1 : Minimum transistor channel length. : 0.6µm")
mdp1_l1.forget

mvpsd_mdp = mvpsd.edges.and(pcomp).and(poly2)
# Rule MDP.1a: Max transistor channel length.
logger.info("Executing rule MDP.1a")
mdp1a_l1 = poly2.edges.and(pcomp).or(mvpsd_mdp).and(ldmos_xtor).and(dualgate).not(pgate.not(mvpsd).edges.interacting(poly2.edges.and(pcomp).or(mvpsd_mdp)).width(20.001.um).edges)
mdp1a_l1 = ldpmos_gate_sides.not(ldpmos.width(20.um + 1.dbu, projection).edges).extended(0, 0, 0.001, 0.001)
mdp1a_l1.output("MDP.1a", "MDP.1a : Max transistor channel length.")
mdp1a_l1.forget

mvpsd_mdp.forget

# Rule MDP.2: Minimum transistor channel width. is 4µm
logger.info("Executing rule MDP.2")
mdp2_l1 = poly2.and(comp).inside(ldmos_xtor).inside(dualgate).edges.not(mvpsd).interacting(mvpsd).width(4.um, euclidian).polygons(0.001)
mdp2_l1 = ldpmos_gate_ends.and(ldpmos.width(4.um, projection).edges).extended(0, 0, 0.001, 0.001)
mdp2_l1.output("MDP.2", "MDP.2 : Minimum transistor channel width. : 4µm")
mdp2_l1.forget

Expand Down Expand Up @@ -337,6 +340,12 @@ if FEOL
mdp17c_l1 = dnwell.with_holes.not_covering(ncomp)
mdp17c_l1.output("MDP.17c", "MDP.17c : DNWELL guard ring shall have NCOMP tab to be connected to highest potential")
mdp17c_l1.forget


mdp_source.forget
ldpmos.forget
poly_mdp.forget
ldpmos_gate_ends.forget
ldpmos_gate_sides.forget

end

4 changes: 2 additions & 2 deletions rules/klayout/drc/rule_decks/main.drc
Original file line number Diff line number Diff line change
Expand Up @@ -901,12 +901,12 @@ tgate = poly2.and(comp).not(res_mk)
ngate = nplus.and(tgate)
nactive = ncomp.not(nwell)
nsd = nactive.interacting(ngate).not(ngate).not(res_mk)
ptap = pcomp.not(nwell).or(pcomp.and(lvpwell)).not(res_mk)
ptap = pcomp.not(nwell).join(pcomp.and(lvpwell)).not(res_mk)

pgate = pplus.and(tgate)
pactive = pcomp.and(nwell)
psd = pactive.interacting(pgate).not(pgate).not(res_mk)
ntap = ncomp.and(nwell).or(ncomp.and(dnwell).not(lvpwell)).not(res_mk)
ntap = ncomp.and(nwell).join(ncomp.and(dnwell).not(lvpwell)).not(res_mk)

ngate_dn = ngate.and(lvpwell).and(dnwell)
ptap_dn = ptap.and(dnwell).outside(well_diode_mk)
Expand Down
12 changes: 9 additions & 3 deletions rules/klayout/drc/run_drc.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
Usage:
run_drc.py (--help| -h)
run_drc.py (--path=<file_path>) (--variant=<combined_options>) [--table=<table_name>]... [--mp=<num_cores>] [--run_dir=<run_dir_path>] [--topcell=<topcell_name>] [--thr=<thr>] [--run_mode=<run_mode>] [--no_feol] [--no_beol] [--connectivity] [--density] [--density_only] [--antenna] [--antenna_only] [--no_offgrid]
run_drc.py (--path=<file_path>) (--variant=<combined_options>) [--verbose] [--table=<table_name>]... [--mp=<num_cores>] [--run_dir=<run_dir_path>] [--topcell=<topcell_name>] [--thr=<thr>] [--run_mode=<run_mode>] [--no_feol] [--no_beol] [--connectivity] [--density] [--density_only] [--antenna] [--antenna_only] [--no_offgrid]
Options:
--help -h Print this help message.
Expand All @@ -40,13 +40,14 @@
--antenna Turn on Antenna checks.
--antenna_only Turn on Antenna checks only.
--no_offgrid Turn off OFFGRID checking rules.
--verbose Detailed rule execution log for debugging.
"""

from docopt import docopt
import os
import xml.etree.ElementTree as ET
import logging
import pya
import klayout.db
import glob
from datetime import datetime
from subprocess import check_call
Expand Down Expand Up @@ -209,7 +210,7 @@ def get_top_cell_names(gds_path):
List of string
Names of the top cell in the layout.
"""
layout = pya.Layout()
layout = klayout.db.Layout()
layout.read(gds_path)
top_cells = [t.name for t in layout.top_cells()]

Expand Down Expand Up @@ -316,6 +317,11 @@ def generate_klayout_switches(arguments, layout_path):
logging.error("variant switch allowed values are (A , B, C) only")
exit()

if arguments["--verbose"]:
switches["verbose"] = "true"
else:
switches["verbose"] = "false"

if arguments["--no_feol"]:
switches["feol"] = "false"
else:
Expand Down

0 comments on commit 8e9c151

Please sign in to comment.