blob: c09453d0e62d45d10ee6348b522eb7b1ed236023 [file] [log] [blame]
#=============================================================================================================================================================
#--------------------------------------------------------- GF 0.18um MCU DRC RULE DECK (10V LDPMOS) ----------------------------------------------------------
#=============================================================================================================================================================
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 )
sab = polygons(49 , 0 )
contact = polygons(33 , 0 )
metal1 = polygons(34 , 0 )
mvpsd = polygons(11 , 39)
ldmos_xtor = polygons(226, 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])
#================================================
#------------- LAYERS CONNECTIONS ---------------
#================================================
if CONNECTIVITY_RULES
logger.info("Construct connectivity for the design.")
connect(dnwell, ncomp)
connect(ncomp, contact)
connect(pcomp, contact)
connect(lvpwell, ncomp)
connect(nwell, ncomp)
connect(natcompsd, contact)
connect(mvsd, ncomp)
connect(mvpsd, pcomp)
connect(contact, metal1)
connect(metal1, via1)
connect(via1, metal2)
connect(metal2, via2)
connect(via2, metal3)
connect(metal3, via3)
connect(via3, metal4)
connect(metal4, via4)
connect(via4, metal5)
connect(metal5, via5)
connect(via5, metaltop)
end #CONNECTIVITY_RULES
#================================================
#------------ 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
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_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)
if !net1 || !net2
puts "Should not happen ..."
elsif net1.circuit != net2.circuit || net1.cluster_id != net2.cluster_id
# unconnected
unconnected_errors.data.insert(ep)
end
end
unconnected_output = unconnected_errors.polygons.or(singularity_errors.polygons(0.001))
return 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
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_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)
if !net1 || !net2
puts "Should not happen ..."
elsif net1.circuit != net2.circuit || net1.cluster_id != net2.cluster_id
# unconnected
unconnected_errors.data.insert(ep)
end
end
unconnected_output = unconnected_errors.polygons(0.001)
return connected_output, unconnected_output
end
# === IMPLICIT EXTRACTION ===
if CONNECTIVITY_RULES
logger.info("Connectivity rules enabled, Netlist object will be generated.")
netlist
end #CONNECTIVITY_RULES
# === LAYOUT EXTENT ===
CHIP = extent.sized(0.0)
logger.info("Total area of the design is #{CHIP.area()} um^2.")
#================================================
#-------------------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)
# 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.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.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.output("MDP.2", "MDP.2 : Minimum transistor channel width. : 4µm")
mdp2_l1.forget
mdp3_1 = ldpmos.or(mvpsd).or(mdp_source).not_interacting(ncomp.holes).inside(dualgate).inside(ldmos_xtor)
mdp3_2 = ncomp.holes.not_interacting(ncomp.interacting(mdp_source)).not_interacting(mvpsd,1,1).inside(dualgate).inside(ldmos_xtor)
# Rule MDP.3: Each LDPMOS shall be surrounded by non-broken Nplus guard ring inside DNWELL
logger.info("Executing rule MDP.3")
mdp3_l1 = mdp3_1.or(mdp3_2)
mdp3_l1.output("MDP.3", "MDP.3 : Each LDPMOS shall be surrounded by non-broken Nplus guard ring inside DNWELL")
mdp3_l1.forget
ncomp_mdp3ai = ncomp.not_interacting(pcomp).inside(ldmos_xtor).inside(dualgate)
# Rule MDP.3ai: Min NCOMP (Nplus AND COMP) space to MVPSD (source and body tap non-butted). NCOMP (Nplus AND COMP) intercept with MVPSD is not allowed.
logger.info("Executing rule MDP.3ai")
mdp3ai_l1 = ncomp_mdp3ai.separation(mvpsd, 1.um, euclidian).polygons(0.001).or(mvpsd.interacting(ncomp_mdp3ai))
mdp3ai_l1.output("MDP.3ai", "MDP.3ai : Min NCOMP (Nplus AND COMP) space to MVPSD (source and body tap non-butted). NCOMP (Nplus AND COMP) intercept with MVPSD is not allowed.")
mdp3ai_l1.forget
ncomp_mdp3ai.forget
ncomp_mdp3aii = ncomp.interacting(pcomp).inside(ldmos_xtor).inside(dualgate)
# Rule MDP.3aii: Min NCOMP (Nplus AND COMP) space to MVPSD (source and body tap butted). NCOMP (Nplus AND COMP) intercept with MVPSD is not allowed.
logger.info("Executing rule MDP.3aii")
mdp3aii_l1 = ncomp_mdp3aii.separation(mvpsd, 0.92.um, euclidian).polygons(0.001).or(mvpsd.interacting(ncomp_mdp3aii))
mdp3aii_l1.output("MDP.3aii", "MDP.3aii : Min NCOMP (Nplus AND COMP) space to MVPSD (source and body tap butted). NCOMP (Nplus AND COMP) intercept with MVPSD is not allowed.")
mdp3aii_l1.forget
ncomp_mdp3aii.forget
ncomp_mdp3b = ncomp.inside(ldmos_xtor).inside(dualgate)
pcomp_mdp3b = pcomp.inside(dnwell).inside(ldmos_xtor).inside(dualgate)
# Rule MDP.3b: Min NCOMP (Nplus AND COMP) space to PCOMP in DNWELL (Pplus AND COMP AND DNWELL). Use butted source and DNWELL contacts otherwise and that is best for Latch-up immunity as well. is 0.4µm
logger.info("Executing rule MDP.3b")
mdp3b_l1 = ncomp_mdp3b.not(poly2).not(mvpsd).separation(pcomp_mdp3b.not(poly2).not(mvpsd), 0.4.um, euclidian).polygons(0.001)
mdp3b_l1.output("MDP.3b", "MDP.3b : Min NCOMP (Nplus AND COMP) space to PCOMP in DNWELL (Pplus AND COMP AND DNWELL). Use butted source and DNWELL contacts otherwise and that is best for Latch-up immunity as well. : 0.4µm")
mdp3b_l1.forget
ncomp_mdp3b.forget
pcomp_mdp3b.forget
# Rule MDP.3c: Maximum distance of the nearest edge of the DNWELL tab (NCOMP inside DNWELL) from PCOMP edge (PCOMP inside DNWELL). is 15µm
logger.info("Executing rule MDP.3c")
mdp3c_l1 = ncomp.inside(dnwell).inside(ldmos_xtor).inside(dualgate).not_interacting(ncomp.inside(dnwell).drc(separation(pcomp.inside(dnwell)) <= 15.um).first_edges,4)
mdp3c_l1.output("MDP.3c", "MDP.3c : Maximum distance of the nearest edge of the DNWELL tab (NCOMP inside DNWELL) from PCOMP edge (PCOMP inside DNWELL). : 15µm")
mdp3c_l1.forget
# Rule MDP.3d: The metal connection for the Nplus guard ring recommended to be continuous. The maximum gap between this metal if broken. Note: To put maximum number of contact under metal for better manufacturability and reliability. is 10µm
logger.info("Executing rule MDP.3d")
mdp3d_l1 = ncomp.interacting(ldmos_xtor.interacting(mvpsd)).interacting(dualgate).not(metal1).edges.not(metal1).with_length(10.001.um, nil)
mdp3d_l1.output("MDP.3d", "MDP.3d : The metal connection for the Nplus guard ring recommended to be continuous. The maximum gap between this metal if broken. Note: To put maximum number of contact under metal for better manufacturability and reliability. : 10µm")
mdp3d_l1.forget
mdp4_metal = pcomp.not_interacting(mvpsd).interacting(ldmos_xtor.interacting(mvpsd)).interacting(dualgate).not(metal1).edges.not(metal1).with_length(10.001.um, nil)
# Rule MDP.4: DNWELL covering LDPMOS shall be surrounded by non broken Pplus guard. The metal connection for the Pplus guard ring recommended to be continuous, The maximum gap between this metal if broken. Note: To put maximum number of contact under metal for better manufacturability and reliability.
logger.info("Executing rule MDP.4")
mdp4_l1 = pcomp.interacting(metal1).not_interacting(pcomp.holes).edges.and(ldmos_xtor).and(dualgate).or(mdp4_metal)
mdp4_l1.output("MDP.4", "MDP.4 : DNWELL covering LDPMOS shall be surrounded by non broken Pplus guard. The metal connection for the Pplus guard ring recommended to be continuous, The maximum gap between this metal if broken. Note: To put maximum number of contact under metal for better manufacturability and reliability.")
mdp4_l1.forget
mdp4_metal.forget
# Rule MDP.4a: Min PCOMP (Pplus AND COMP) space to DNWELL. is 2.5µm
logger.info("Executing rule MDP.4a")
mdp4a_l1 = pcomp.inside(ldmos_xtor).inside(dualgate).separation(dnwell.inside(ldmos_xtor).inside(dualgate), 2.5.um, euclidian).polygons(0.001)
mdp4a_l1.output("MDP.4a", "MDP.4a : Min PCOMP (Pplus AND COMP) space to DNWELL. : 2.5µm")
mdp4a_l1.forget
mdp4b_dnwell_edges = dnwell.inside(ldmos_xtor).inside(dualgate).edges.centers(0, 0.99)
mdp4b_not_error = dnwell.drc(separation(pcomp.inside(ldmos_xtor.interacting(mvpsd)).inside(dualgate).not_interacting(mvpsd), euclidian) <= 15.um).polygons(0.001)
# Rule MDP.4b: Maximum distance of the nearest edge of the DNWELL from the PCOMP Guard ring outside DNWELL. is 15µm
logger.info("Executing rule MDP.4b")
mdp4b_l1 = mdp4b_dnwell_edges.not_interacting(mdp4b_not_error).and(pcomp.holes).extended(0, 0, 0.001, 0.001)
mdp4b_l1.output("MDP.4b", "MDP.4b : Maximum distance of the nearest edge of the DNWELL from the PCOMP Guard ring outside DNWELL. : 15µm")
mdp4b_l1.forget
mdp4b_dnwell_edges.forget
mdp4b_not_error.forget
# Rule MDP.5: Each LDPMOS shall be covered by Dualgate layer.
logger.info("Executing rule MDP.5")
mdp5_l1 = pcomp.not(poly2).not(mvpsd).or(pgate.not(mvpsd)).or(pcomp.and(mvpsd)).inside(ldmos_xtor).not_inside(dualgate)
mdp5_l1.output("MDP.5", "MDP.5 : Each LDPMOS shall be covered by Dualgate layer.")
mdp5_l1.forget
# Rule MDP.5a: Minimum Dualgate enclose Plus guarding ring PCOMP (Pplus AND COMP). is 0.5µm
logger.info("Executing rule MDP.5a")
mdp5a_l1 = dualgate.interacting(ldmos_xtor).enclosing(pcomp.inside(ldmos_xtor), 0.5.um, euclidian).polygons(0.001)
mdp5a_l2 = pcomp.inside(ldmos_xtor).not_outside(dualgate.interacting(ldmos_xtor)).not(dualgate.interacting(ldmos_xtor))
mdp5a_l = mdp5a_l1.or(mdp5a_l2)
mdp5a_l.output("MDP.5a", "MDP.5a : Minimum Dualgate enclose Plus guarding ring PCOMP (Pplus AND COMP). : 0.5µm")
mdp5a_l1.forget
mdp5a_l2.forget
mdp5a_l.forget
# Rule MDP.6: Each LDPMOS shall be covered by LDMOS_XTOR (GDS#226) layer.
logger.info("Executing rule MDP.6")
mdp6_l1 = mvpsd.not_inside(ldmos_xtor)
mdp6_l1.output("MDP.6", "MDP.6 : Each LDPMOS shall be covered by LDMOS_XTOR (GDS#226) layer.")
mdp6_l1.forget
# Rule MDP.6a: Minimum LDMOS_XTOR enclose Dualgate.
logger.info("Executing rule MDP.6a")
mdp6a_l1 = ldmos_xtor.not_covering(dualgate)
mdp6a_l1.output("MDP.6a", "MDP.6a : Minimum LDMOS_XTOR enclose Dualgate.")
mdp6a_l1.forget
# Rule MDP.7: Minimum LDMOS_XTOR layer space to Nwell outside LDMOS_XTOR. is 2µm
logger.info("Executing rule MDP.7")
mdp7_l1 = ldmos_xtor.separation(nwell.outside(ldmos_xtor), 2.um, euclidian).polygons(0.001)
mdp7_l1.output("MDP.7", "MDP.7 : Minimum LDMOS_XTOR layer space to Nwell outside LDMOS_XTOR. : 2µm")
mdp7_l1.forget
# Rule MDP.8: Minimum LDMOS_XTOR layer space to NCOMP outside LDMOS_XTOR. is 1.5µm
logger.info("Executing rule MDP.8")
mdp8_l1 = ldmos_xtor.separation(ncomp.outside(ldmos_xtor), 1.5.um, euclidian).polygons(0.001)
mdp8_l1.output("MDP.8", "MDP.8 : Minimum LDMOS_XTOR layer space to NCOMP outside LDMOS_XTOR. : 1.5µm")
mdp8_l1.forget
# Rule MDP.9a: Min LDPMOS POLY2 width. is 1.2µm
logger.info("Executing rule MDP.9a")
mdp9a_l1 = poly2.inside(dnwell.and(dualgate).and(ldmos_xtor)).width(1.2.um, euclidian).polygons(0.001)
mdp9a_l1.output("MDP.9a", "MDP.9a : Min LDPMOS POLY2 width. : 1.2µm")
mdp9a_l1.forget
mdp9b_1 = poly2.inside(dnwell.and(dualgate).and(ldmos_xtor)).edges.interacting(mvpsd).not(mvpsd).enclosing(comp.edges,0.4.um).edges
mdp9b_2 = poly2.inside(dnwell.and(dualgate).and(ldmos_xtor)).edges.interacting(mvpsd).not(mvpsd).interacting(pcomp)
# Rule MDP.9b: Min POLY2 extension beyond COMP in the width direction of the transistor (other than the LDMOS drain direction). is 0.4µm
logger.info("Executing rule MDP.9b")
mdp9b_l1 = mdp9b_1.or(mdp9b_2).extended(0,0,0.001,0.001)
mdp9b_l1.output("MDP.9b", "MDP.9b : Min POLY2 extension beyond COMP in the width direction of the transistor (other than the LDMOS drain direction). : 0.4µm")
mdp9b_l1.forget
mdp9b_1.forget
mdp9b_2.forget
# Rule MDP.9c: Min/Max POLY2 extension beyond COMP on the field towards LDPMOS drain (MVPSD AND COMP AND Pplus NOT POLY2) direction.
logger.info("Executing rule MDP.9c")
mdp9c_l1 = poly2.edges.in(poly2.inside(dnwell.and(dualgate).and(ldmos_xtor)).edges.inside_part(mvpsd)).not_interacting(poly2.drc(enclosing(comp,projection) == 0.2.um))
mdp9c_l1.output("MDP.9c", "MDP.9c : Min/Max POLY2 extension beyond COMP on the field towards LDPMOS drain (MVPSD AND COMP AND Pplus NOT POLY2) direction.")
mdp9c_l1.forget
# Rule MDP.9d: Min/Max POLY2 on field to LDPMOS drain COMP (MVPSD AND COMP AND Pplus NOT POLY2) space.
logger.info("Executing rule MDP.9d")
mdp9d_l1 = poly2.inside(dualgate).inside(ldmos_xtor).overlapping(mvpsd.and(pcomp).not(poly2).sized(0.16.um)).or(poly2.inside(dualgate).inside(ldmos_xtor.interacting(mvpsd)).not_interacting(mvpsd.and(pcomp).not(poly2).sized(0.16.um)))
mdp9d_l1.output("MDP.9d", "MDP.9d : Min/Max POLY2 on field to LDPMOS drain COMP (MVPSD AND COMP AND Pplus NOT POLY2) space.")
mdp9d_l1.forget
ldpmos_poly2_gate = poly2.interacting(pgate.and(dualgate).not(mvpsd))
ncomp_not_butted = ncomp.not(pplus).not_interacting(pcomp.not(nplus)).or(ncomp.not(pplus).overlapping(pcomp.not(nplus)))
mdp9ei_1 = ldpmos_poly2_gate.inside(dualgate).inside(ldmos_xtor).separation(ncomp_not_butted, 0.4.um).polygons(0.001)
mdp9ei_2 = ldpmos_poly2_gate.inside(dualgate).inside(ldmos_xtor).and(ncomp_not_butted)
# Rule MDP.9ei: Min LDMPOS gate Poly2 space to Nplus guardring (source and body tap non-butted).
logger.info("Executing rule MDP.9ei")
mdp9ei_l1 = mdp9ei_1.or(mdp9ei_2)
mdp9ei_l1.output("MDP.9ei", "MDP.9ei : Min LDMPOS gate Poly2 space to Nplus guardring (source and body tap non-butted).")
mdp9ei_l1.forget
ncomp_not_butted.forget
mdp9ei_1.forget
mdp9ei_2.forget
ncomp_butted = ncomp.not(pplus).interacting(pcomp.not(nplus)).not_overlapping(pcomp.not(nplus))
mdp9eii_1 = ldpmos_poly2_gate.inside(dualgate).inside(ldmos_xtor).separation(ncomp_butted, 0.32.um).polygons(0.001)
mdp9eii_2 = ldpmos_poly2_gate.inside(dualgate).inside(ldmos_xtor).and(ncomp_butted)
# Rule MDP.9eii: Min LDMPOS gate Poly2 space to Nplus guardring (source and body tap butted).
logger.info("Executing rule MDP.9eii")
mdp9eii_l1 = mdp9eii_1.or(mdp9eii_2)
mdp9eii_l1.output("MDP.9eii", "MDP.9eii : Min LDMPOS gate Poly2 space to Nplus guardring (source and body tap butted).")
mdp9eii_l1.forget
ncomp_butted.forget
mdp9eii_1.forget
mdp9eii_2.forget
# Rule MDP.9f: Poly2 interconnect is not allowed in LDPMOS region (LDMOS_XTOR marked region). is -µm
logger.info("Executing rule MDP.9f")
mdp9f_l1 = poly2.not(pplus).inside(dualgate).inside(ldmos_xtor).interacting(poly2.and(pplus).inside(dualgate).inside(ldmos_xtor),2)
mdp9f_l1.output("MDP.9f", "MDP.9f : Poly2 interconnect is not allowed in LDPMOS region (LDMOS_XTOR marked region). : -µm")
mdp9f_l1.forget
# Rule MDP.10: Min/Max MVPSD overlap onto the channel (LDMOS_XTOR AND COMP AND POLY2 AND Pplus).
logger.info("Executing rule MDP.10")
mdp10_l1 = mvpsd.inside(dualgate).inside(ldmos_xtor).not_interacting(mvpsd.drc(overlap(ldmos_xtor.and(comp).and(poly2).and(pplus),projection) == 0.4))
mdp10_l1.output("MDP.10", "MDP.10 : Min/Max MVPSD overlap onto the channel (LDMOS_XTOR AND COMP AND POLY2 AND Pplus).")
mdp10_l1.forget
if CONNECTIVITY_RULES
logger.info("CONNECTIVITY_RULES section")
connected_mdp_10b, unconnected_mdp_10a = conn_space(mvpsd, 1, 2, euclidian)
# Rule MDP.10a: Min MVPSD space within LDMOS_XTOR marking [diff potential]. is 2µm
logger.info("Executing rule MDP.10a")
mdp10a_l1 = unconnected_mdp_10a
mdp10a_l1.output("MDP.10a", "MDP.10a : Min MVPSD space within LDMOS_XTOR marking [diff potential]. : 2µm")
mdp10a_l1.forget
# Rule MDP.10b: Min MVPSD space [same potential]. Merge if space less than 1um. is 1µm
logger.info("Executing rule MDP.10b")
mdp10b_l1 = connected_mdp_10b
mdp10b_l1.output("MDP.10b", "MDP.10b : Min MVPSD space [same potential]. Merge if space less than 1um. : 1µm")
mdp10b_l1.forget
else
logger.info("CONNECTIVITY_RULES disabled section")
# Rule MDP.10a: Min MVPSD space within LDMOS_XTOR marking [diff potential]. is 2µm
logger.info("Executing rule MDP.10a")
mdp10a_l1 = mvpsd.space(2.um, euclidian).polygons(0.001)
mdp10a_l1.output("MDP.10a", "MDP.10a : Min MVPSD space within LDMOS_XTOR marking [diff potential]. : 2µm")
mdp10a_l1.forget
end #CONNECTIVITY_RULES
# Rule MDP.11: Min MVPSD enclosing PCOMP in the drain (MVPSD AND COMP NOT POLY2) direction and in the direction along the transistor width.
logger.info("Executing rule MDP.11")
mdp11_l1 = mvpsd.edges.not_interacting(pcomp.edges).enclosing(pcomp.edges, 0.8.um, euclidian).polygons(0.001).or(mvpsd.interacting(mvpsd.edges.and(pcomp.edges)))
mdp11_l1.output("MDP.11", "MDP.11 : Min MVPSD enclosing PCOMP in the drain (MVPSD AND COMP NOT POLY2) direction and in the direction along the transistor width.")
mdp11_l1.forget
# Rule MDP.12: Min DNWELL enclose Nplus guard ring (NCOMP). is 0.66µm
logger.info("Executing rule MDP.12")
mdp12_l1 = dnwell.inside(dualgate).inside(ldmos_xtor).enclosing(ncomp.inside(dualgate).inside(ldmos_xtor), 0.66.um, euclidian).polygons(0.001)
mdp12_l2 = ncomp.inside(dualgate).inside(ldmos_xtor).not_outside(dnwell.inside(dualgate).inside(ldmos_xtor)).not(dnwell.inside(dualgate).inside(ldmos_xtor))
mdp12_l = mdp12_l1.or(mdp12_l2)
mdp12_l.output("MDP.12", "MDP.12 : Min DNWELL enclose Nplus guard ring (NCOMP). : 0.66µm")
mdp12_l1.forget
mdp12_l2.forget
mdp12_l.forget
# rule MDP.13 is not a DRC check
# Rule MDP.13a: Max single finger width. is 50µm
logger.info("Executing rule MDP.13a")
mdp13a_l1 = poly2.and(pcomp).not(mvpsd).inside(dualgate).inside(ldmos_xtor).edges.with_length(50.001.um,nil).extended(0, 0, 0.001, 0.001)
mdp13a_l1.output("MDP.13a", "MDP.13a : Max single finger width. : 50µm")
mdp13a_l1.forget
# Rule MDP.13b: Layout shall have alternative source & drain.
logger.info("Executing rule MDP.13b")
mdp13b_l1 = ldpmos.not_interacting(mdp_source,1,1).or(ldpmos.not_interacting(mvpsd,1,1)).or(mdp_source.interacting(mvpsd))
mdp13b_l1.output("MDP.13b", "MDP.13b : Layout shall have alternative source & drain.")
mdp13b_l1.forget
mdp_13c_source_side = ldpmos.interacting(mdp_source.interacting(ldpmos, 2, 2).or(mdp_source.interacting(ncomp.interacting(mdp_source, 2, 2))))
# Rule MDP.13c: Both sides of the transistor shall be terminated by source.
logger.info("Executing rule MDP.13c")
mdp13c_l1 = mvpsd.covering(pcomp.not_interacting(poly2)).interacting(pcomp, 2, 2).interacting(mdp_13c_source_side)
mdp13c_l1.output("MDP.13c", "MDP.13c : Both sides of the transistor shall be terminated by source.")
mdp13c_l1.forget
mdp_13c_source_side.forget
# rule MDP.14 is not a DRC check
# Rule MDP.15: Min DNWELL enclosing MVPSD to any DNWELL spacing. is 6µm
logger.info("Executing rule MDP.15")
mdp15_l1 = dnwell.separation(dnwell.covering(mvpsd).inside(dualgate).inside(ldmos_xtor), 6.um, euclidian).polygons(0.001)
mdp15_l1.output("MDP.15", "MDP.15 : Min DNWELL enclosing MVPSD to any DNWELL spacing. : 6µm")
mdp15_l1.forget
# Rule MDP.16a: Min LDPMOS drain COMP width. is 0.22µm
logger.info("Executing rule MDP.16a")
mdp16a_l1 = comp.inside(mvpsd).inside(dualgate).inside(ldmos_xtor).width(0.22.um, euclidian).polygons(0.001)
mdp16a_l1.output("MDP.16a", "MDP.16a : Min LDPMOS drain COMP width. : 0.22µm")
mdp16a_l1.forget
# Rule MDP.16b: Min LDPMOS drain COMP enclose contact. is 0µm
logger.info("Executing rule MDP.16b")
mdp16b_l1 = contact.interacting(pcomp.inside(mvpsd).inside(dualgate).inside(ldmos_xtor)).not_inside(pcomp.inside(mvpsd))
mdp16b_l1.output("MDP.16b", "MDP.16b : Min LDPMOS drain COMP enclose contact. : 0µm")
mdp16b_l1.forget
mdp17_a1 = mvpsd.inside(dnwell).inside(ldmos_xtor)
mdp17_a2 = ncomp.outside(dnwell).outside(nwell)
# Rule MDP.17a: For better latch up immunity, it is necessary to put DNWELL guard ring between MVPSD Inside DNWELL covered by LDMOS_XTOR and NCOMP (outside DNWELL and outside Nwell) when spacing between them is less than 40um.
logger.info("Executing rule MDP.17a")
mdp17a_l1 = mdp17_a1.separation(mdp17_a2,transparent,40.um).polygons(0.001).not_interacting(ncomp.and(dnwell).holes)
mdp17a_l1.output("MDP.17a", "MDP.17a : For better latch up immunity, it is necessary to put DNWELL guard ring between MVPSD Inside DNWELL covered by LDMOS_XTOR and NCOMP (outside DNWELL and outside Nwell) when spacing between them is less than 40um.")
mdp17a_l1.forget
mdp17_a1.forget
mdp17_a2.forget
# Rule MDP.17c: DNWELL guard ring shall have NCOMP tab to be connected to highest potential
logger.info("Executing rule MDP.17c")
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
exec_end_time = Time.now
run_time = exec_end_time - exec_start_time
logger.info("DRC Run time %f seconds" % [run_time])