blob: e3126a866e295c5fbf55d89e9b9106e41af69d79 [file] [log] [blame]
#=============================================================================================================================================================
#------------------------------------------------------------ GF 0.18um MCU DRC RULE DECK (NPLUS) ------------------------------------------------------------
#=============================================================================================================================================================
require 'time'
require "logger"
exec_start_time = Time.now
logger = Logger.new(STDOUT)
logger.formatter = proc do |severity, datetime, progname, msg|
"#{datetime}: Memory Usage (" + `pmap #{Process.pid} | tail -1`[10,40].strip + ") : #{msg}
"
end
#================================================
#----------------- FILE SETUP -------------------
#================================================
# optional for a batch launch : klayout -b -r gf180mcu.drc -rd input=design.gds -rd report=gf180mcu_main.lyrdb
logger.info("Starting running GF180MCU Klayout DRC runset on %s" % [$input])
if $input
if $topcell
source($input, $topcell)
else
source($input)
end
end
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)
else
logger.info("GF180MCU Klayout DRC runset output at default location." % [File.join(File.dirname(RBA::CellView::active.filename), "gf180_drc.lyrdb").path])
report("DRC Run Report at", File.join(File.dirname(RBA::CellView::active.filename), "gf180_drc.lyrdb"))
end
if $thr
logger.info("Number of threads to use %s" % [$thr])
threads($thr)
else
logger.info("Number of threads to use 16")
threads(16)
end
# === TILING MODE ===
if $run_mode == "tiling"
# use a tile size of 1mm - not used in deep mode-
# tiles(500.um)
# use a tile border of 10 micron:
# tile_borders(10.um)
tiles(1000)
logger.info("Tiling mode is enabled.")
elsif $run_mode == "deep"
#=== HIER MODE ===
deep
logger.info("deep mode is enabled.")
elsif $run_mode == "flat"
#=== FLAT MODE ===
flat
logger.info("flat mode is enabled.")
else
#=== FLAT MODE ===
flat
logger.info("flat mode is enabled.")
end # run_mode
#================================================
#------------- LAYERS DEFINITIONS ---------------
#================================================
v5_xtor = polygons(112, 1 )
dualgate = polygons(55 , 0 )
poly2 = polygons(30 , 0 )
nplus = polygons(32 , 0 )
pplus = polygons(31 , 0 )
comp = polygons(22 , 0 )
dnwell = polygons(12 , 0 )
nwell = polygons(21 , 0 )
lvpwell = polygons(204, 0 )
sab = polygons(49 , 0 )
logger.info("Starting deriving base layers.")
#================================================
#------------- LAYERS DERIVATIONS ---------------
#================================================
ncomp = comp & nplus
pcomp = comp & pplus
tgate = poly2 & comp
ngate = nplus & tgate
pgate = pplus & tgate
#================================================
#------------------ SWITCHES --------------------
#================================================
logger.info("Evaluate switches.")
# FEOL
if $feol == "false"
FEOL = $feol
logger.info("FEOL is disabled.")
else
FEOL = "true"
logger.info("FEOL is enabled.")
end # FEOL
# BEOL
if $beol == "false"
BEOL = $beol
logger.info("BEOL is disabled.")
else
BEOL = "true"
logger.info("BEOL is enabled.")
end # BEOL
# connectivity rules
if $conn_drc == "true"
CONNECTIVITY_RULES = $conn_drc
logger.info("connectivity rules are enabled.")
else
CONNECTIVITY_RULES = false
logger.info("connectivity rules are disabled.")
end # connectivity rules
# METAL_TOP
if $metal_top
METAL_TOP = $metal_top
else
METAL_TOP = "9K"
end # METAL_TOP
logger.info("METAL_TOP Selected is %s" % [METAL_TOP])
# METAL_LEVEL
if $metal_level
METAL_LEVEL = $metal_level
else
METAL_LEVEL = "6LM"
end # METAL_LEVEL
logger.info("METAL_STACK Selected is %s" % [METAL_LEVEL])
# WEDGE
if $wedge == "false"
WEDGE = $wedge
else
WEDGE = "true"
end # WEDGE
logger.info("Wedge enabled %s" % [WEDGE])
# BALL
if $ball == "false"
BALL = $ball
else
BALL = "true"
end # BALL
logger.info("Ball enabled %s" % [BALL])
# GOLD
if $gold == "false"
GOLD = $gold
else
GOLD = "true"
end # GOLD
logger.info("Gold enabled %s" % [GOLD])
if $mim_option
MIM_OPTION = $mim_option
else
MIM_OPTION = "Nan"
end
logger.info("MIM Option selected %s" % [MIM_OPTION])
# OFFGRID
if $offgrid == "false"
OFFGRID = false
else
OFFGRID = true
end # OFFGRID
logger.info("Offgrid enabled %s" % [OFFGRID])
#================================================
#---------------------NPLUS----------------------
#================================================
if FEOL
logger.info("FEOL section")
# Rule NP.1: min. nplus width is 0.4µm
logger.info("Executing rule NP.1")
np1_l1 = nplus.width(0.4.um, euclidian).polygons(0.001)
np1_l1.output("NP.1", "NP.1 : min. nplus width : 0.4µm")
np1_l1.forget
# Rule NP.2: min. nplus spacing is 0.4µm
logger.info("Executing rule NP.2")
np2_l1 = nplus.space(0.4.um, euclidian).polygons(0.001)
np2_l1.output("NP.2", "NP.2 : min. nplus spacing : 0.4µm")
np2_l1.forget
# Rule NP.3a: Space to PCOMP for PCOMP: (1) Inside Nwell (2) Outside LVPWELL but inside DNWELL. is 0.16µm
logger.info("Executing rule NP.3a")
np3a_l1 = nplus.separation((pcomp.inside(nwell)).or(pcomp.outside(lvpwell).inside(dnwell)), 0.16.um, euclidian).polygons(0.001)
np3a_l1.output("NP.3a", "NP.3a : Space to PCOMP for PCOMP: (1) Inside Nwell (2) Outside LVPWELL but inside DNWELL. : 0.16µm")
np3a_l1.forget
np_3bi_extend = lvpwell.inside(dnwell).sized(-0.429.um)
np_3bi = pcomp.edges.and(lvpwell.inside(dnwell).not(np_3bi_extend))
# Rule NP.3bi: Space to PCOMP: For Inside DNWELL, inside LVPWELL:(i) For PCOMP overlap by LVPWELL < 0.43um. is 0.16µm
logger.info("Executing rule NP.3bi")
np3bi_l1 = nplus.not_outside(lvpwell).inside(dnwell).edges.separation(np_3bi, 0.16.um, euclidian).polygons(0.001)
np3bi_l1.output("NP.3bi", "NP.3bi : Space to PCOMP: For Inside DNWELL, inside LVPWELL:(i) For PCOMP overlap by LVPWELL < 0.43um. : 0.16µm")
np3bi_l1.forget
np_3bi_extend.forget
np_3bi.forget
np_3bii_extend = lvpwell.inside(dnwell).sized(-0.429.um)
np_3bii = pcomp.edges.and(np_3bii_extend)
# Rule NP.3bii: Space to PCOMP: For Inside DNWELL, inside LVPWELL:(ii) For PCOMP overlap by LVPWELL >= 0.43um. is 0.08µm
logger.info("Executing rule NP.3bii")
np3bii_l1 = nplus.not_outside(lvpwell).inside(dnwell).edges.separation(np_3bii, 0.08.um, euclidian).polygons(0.001)
np3bii_l1.output("NP.3bii", "NP.3bii : Space to PCOMP: For Inside DNWELL, inside LVPWELL:(ii) For PCOMP overlap by LVPWELL >= 0.43um. : 0.08µm")
np3bii_l1.forget
np_3bii_extend.forget
np_3bii.forget
np_3ci = pcomp.edges.and(nwell.outside(dnwell).sized(0.429.um))
# Rule NP.3ci: Space to PCOMP: For Outside DNWELL:(i) For PCOMP space to Nwell < 0.43um. is 0.16µm
logger.info("Executing rule NP.3ci")
np3ci_l1 = nplus.outside(dnwell).edges.separation(np_3ci, 0.16.um, euclidian).polygons
np3ci_l1.output("NP.3ci", "NP.3ci : Space to PCOMP: For Outside DNWELL:(i) For PCOMP space to Nwell < 0.43um. : 0.16µm")
np3ci_l1.forget
np_3ci.forget
np_3cii = pcomp.edges.not(nwell.outside(dnwell).sized(0.429.um))
# Rule NP.3cii: Space to PCOMP: For Outside DNWELL:(ii) For PCOMP space to Nwell >= 0.43um. is 0.08µm
logger.info("Executing rule NP.3cii")
np3cii_l1 = nplus.outside(dnwell).edges.separation(np_3cii, 0.08.um, euclidian).polygons
np3cii_l1.output("NP.3cii", "NP.3cii : Space to PCOMP: For Outside DNWELL:(ii) For PCOMP space to Nwell >= 0.43um. : 0.08µm")
np3cii_l1.forget
np_3cii.forget
# Rule NP.3d: Min/max space to a butted PCOMP.
logger.info("Executing rule NP.3d")
np3d_l1 = nplus.not_outside(pcomp)
np3d_l1.output("NP.3d", "NP.3d : Min/max space to a butted PCOMP.")
np3d_l1.forget
# Rule NP.3e: Space to related PCOMP edge adjacent to a butting edge.
logger.info("Executing rule NP.3e")
np3e_l1 = nplus.not_outside(pcomp)
np3e_l1.output("NP.3e", "NP.3e : Space to related PCOMP edge adjacent to a butting edge.")
np3e_l1.forget
# Rule NP.4a: Space to related P-channel gate at a butting edge parallel to gate. is 0.32µm
logger.info("Executing rule NP.4a")
np4a_l1 = nplus.edges.and(pcomp.edges).separation(pgate.edges, 0.32.um, projection).polygons(0.001)
np4a_l1.output("NP.4a", "NP.4a : Space to related P-channel gate at a butting edge parallel to gate. : 0.32µm")
np4a_l1.forget
np_4b_poly = poly2.edges.interacting(pgate.edges.not(pcomp.edges)).centers(0, 0.99).and(pgate.sized(0.32.um))
# Rule NP.4b: Within 0.32um of channel, space to P-channel gate extension perpendicular to the direction of Poly2.
logger.info("Executing rule NP.4b")
np4b_l1 = nplus.interacting(nplus.edges.separation(np_4b_poly, 0.22.um, projection).polygons(0.001))
np4b_l1.output("NP.4b", "NP.4b : Within 0.32um of channel, space to P-channel gate extension perpendicular to the direction of Poly2.")
np4b_l1.forget
np_4b_poly.forget
# Rule NP.5a: Overlap of N-channel gate. is 0.23µm
logger.info("Executing rule NP.5a")
np5a_l1 = nplus.enclosing(ngate, 0.23.um, euclidian).polygons(0.001)
np5a_l2 = ngate.not_outside(nplus).not(nplus)
np5a_l = np5a_l1.or(np5a_l2)
np5a_l.output("NP.5a", "NP.5a : Overlap of N-channel gate. : 0.23µm")
np5a_l1.forget
np5a_l2.forget
np5a_l.forget
# Rule NP.5b: Extension beyond COMP for the COMP (1) inside LVPWELL (2) outside Nwell and DNWELL. is 0.16µm
logger.info("Executing rule NP.5b")
np5b_l1 = nplus.not_outside(lvpwell).or(nplus.outside(nwell).outside(dnwell)).edges.not(pplus).enclosing(comp.edges, 0.16.um, euclidian).polygons(0.001)
np5b_l1.output("NP.5b", "NP.5b : Extension beyond COMP for the COMP (1) inside LVPWELL (2) outside Nwell and DNWELL. : 0.16µm")
np5b_l1.forget
np_5ci_background = nplus.not_inside(lvpwell).inside(dnwell).edges
np_5ci_foreground = ncomp.not_inside(lvpwell).inside(dnwell).edges.not(pplus.edges).and(lvpwell.inside(dnwell).sized(0.429.um))
# Rule NP.5ci: Extension beyond COMP: For Inside DNWELL: (i)For Nplus < 0.43um from LVPWELL edge for Nwell or DNWELL tap inside DNWELL. is 0.16µm
logger.info("Executing rule NP.5ci")
np5ci_l1 = np_5ci_background.enclosing(np_5ci_foreground, 0.16.um, projection).polygons(0.001)
np5ci_l1.output("NP.5ci", "NP.5ci : Extension beyond COMP: For Inside DNWELL: (i)For Nplus < 0.43um from LVPWELL edge for Nwell or DNWELL tap inside DNWELL. : 0.16µm")
np5ci_l1.forget
np_5ci_background.forget
np_5ci_foreground.forget
np_5cii_background = nplus.not_inside(lvpwell).inside(dnwell).edges
np_5cii_foreground = ncomp.not_inside(lvpwell).inside(dnwell).edges.not(pplus.edges).not(lvpwell.inside(dnwell).sized(0.429.um))
# Rule NP.5cii: Extension beyond COMP: For Inside DNWELL: (ii) For Nplus >= 0.43um from LVPWELL edge for Nwell or DNWELL tap inside DNWELL. is 0.02µm
logger.info("Executing rule NP.5cii")
np5cii_l1 = np_5cii_background.enclosing(np_5cii_foreground, 0.02.um, projection).polygons(0.001)
np5cii_l1.output("NP.5cii", "NP.5cii : Extension beyond COMP: For Inside DNWELL: (ii) For Nplus >= 0.43um from LVPWELL edge for Nwell or DNWELL tap inside DNWELL. : 0.02µm")
np5cii_l1.forget
np_5cii_background.forget
np_5cii_foreground.forget
np_5di_background = nplus.not_outside(nwell).outside(dnwell).edges
np_5di_extend = nwell.outside(dnwell).not(nwell.outside(dnwell).sized(-0.429.um))
np_5di_foreground = ncomp.not_outside(nwell).outside(dnwell).edges.not(pplus.edges).and(np_5di_extend)
# Rule NP.5di: Extension beyond COMP: For Outside DNWELL, inside Nwell: (i) For Nwell overlap of Nplus < 0.43um. is 0.16µm
logger.info("Executing rule NP.5di")
np5di_l1 = np_5di_background.enclosing(np_5di_foreground, 0.16.um, projection).polygons(0.001)
np5di_l1.output("NP.5di", "NP.5di : Extension beyond COMP: For Outside DNWELL, inside Nwell: (i) For Nwell overlap of Nplus < 0.43um. : 0.16µm")
np5di_l1.forget
np_5di_background.forget
np_5di_extend.forget
np_5di_foreground.forget
np_5dii_background = nplus.not_outside(nwell).outside(dnwell).edges.not(pplus.edges)
np_5dii_extend = nwell.outside(dnwell).sized(-0.429.um)
np_5dii_foreground = ncomp.not_outside(nwell).outside(dnwell).edges.not(pplus.edges).and(np_5dii_extend)
# Rule NP.5dii: Extension beyond COMP: For Outside DNWELL, inside Nwell: (ii) For Nwell overlap of Nplus >= 0.43um. is 0.02µm
logger.info("Executing rule NP.5dii")
np5dii_l1 = np_5dii_background.enclosing(np_5dii_foreground, 0.02.um, euclidian).polygons(0.001)
np5dii_l1.output("NP.5dii", "NP.5dii : Extension beyond COMP: For Outside DNWELL, inside Nwell: (ii) For Nwell overlap of Nplus >= 0.43um. : 0.02µm")
np5dii_l1.forget
np_5dii_background.forget
np_5dii_extend.forget
np_5dii_foreground.forget
# Rule NP.6: Overlap with NCOMP butted to PCOMP. is 0.22µm
logger.info("Executing rule NP.6")
np6_l1 = comp.interacting(nplus).enclosing(pcomp.interacting(nplus), 0.22.um, projection).polygons
np6_l1.output("NP.6", "NP.6 : Overlap with NCOMP butted to PCOMP. : 0.22µm")
np6_l1.forget
# Rule NP.7: Space to unrelated unsalicided Poly2. is 0.18µm
logger.info("Executing rule NP.7")
np7_l1 = nplus.separation(poly2.and(sab), 0.18.um, euclidian).polygons(0.001)
np7_l1.output("NP.7", "NP.7 : Space to unrelated unsalicided Poly2. : 0.18µm")
np7_l1.forget
# Rule NP.8a: Minimum Nplus area (um2). is 0.35µm²
logger.info("Executing rule NP.8a")
np8a_l1 = nplus.with_area(nil, 0.35.um)
np8a_l1.output("NP.8a", "NP.8a : Minimum Nplus area (um2). : 0.35µm²")
np8a_l1.forget
# Rule NP.8b: Minimum area enclosed by Nplus (um2). is 0.35µm²
logger.info("Executing rule NP.8b")
np8b_l1 = nplus.holes.with_area(nil, 0.35.um)
np8b_l1.output("NP.8b", "NP.8b : Minimum area enclosed by Nplus (um2). : 0.35µm²")
np8b_l1.forget
# Rule NP.9: Overlap of unsalicided Poly2. is 0.18µm
logger.info("Executing rule NP.9")
np9_l1 = nplus.enclosing(poly2.and(sab), 0.18.um, euclidian).polygons(0.001)
np9_l2 = poly2.and(sab).not_outside(nplus).not(nplus)
np9_l = np9_l1.or(np9_l2)
np9_l.output("NP.9", "NP.9 : Overlap of unsalicided Poly2. : 0.18µm")
np9_l1.forget
np9_l2.forget
np9_l.forget
# Rule NP.10: Overlap of unsalicided COMP. is 0.18µm
logger.info("Executing rule NP.10")
np10_l1 = nplus.enclosing(comp.and(sab), 0.18.um, euclidian).polygons(0.001)
np10_l1.output("NP.10", "NP.10 : Overlap of unsalicided COMP. : 0.18µm")
np10_l1.forget
np_11_in_dnwell = nplus.interacting(nplus.edges.and(pcomp.edges).and(lvpwell.inside(dnwell).not(lvpwell.inside(dnwell).sized(-0.429.um))))
np_11_out_dnwell = nplus.interacting(nplus.edges.and(pcomp.edges).and(nwell.outside(dnwell).sized(0.429.um)))
# Rule NP.11: Butting Nplus and PCOMP is forbidden within 0.43um of Nwell edge (for outside DNWELL) and of LVPWELL edge (for inside DNWELL case).
logger.info("Executing rule NP.11")
np11_l1 = np_11_in_dnwell.or(np_11_out_dnwell)
np11_l1.output("NP.11", "NP.11 : Butting Nplus and PCOMP is forbidden within 0.43um of Nwell edge (for outside DNWELL) and of LVPWELL edge (for inside DNWELL case).")
np11_l1.forget
np_11_in_dnwell.forget
np_11_out_dnwell.forget
# Rule NP.12: Overlap with P-channel poly2 gate extension is forbidden within 0.32um of P-channel gate.
logger.info("Executing rule NP.12")
np12_l1 = nplus.interacting(nplus.edges.separation(pgate.edges.and(pcomp.edges), 0.32.um, euclidian).polygons(0.001))
np12_l1.output("NP.12", "NP.12 : Overlap with P-channel poly2 gate extension is forbidden within 0.32um of P-channel gate.")
np12_l1.forget
end #FEOL
exec_end_time = Time.now
run_time = exec_end_time - exec_start_time
logger.info("DRC Run time %f seconds" % [run_time])