blob: 14cedda4971433ed9358f1408a18b9803e9d23ab [file] [log] [blame]
#=============================================================================================================================================================
#----------------------------------------------------------- GF 0.18um MCU DRC RULE DECK (LVPWELL) -----------------------------------------------------------
#=============================================================================================================================================================
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 )
res_mk = polygons(110, 5 )
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.")
#================================================
#--------------------LVPWELL---------------------
#================================================
if FEOL
logger.info("FEOL section")
# Rule LPW.1_3.3V: Min. LVPWELL Width. is 0.6µm
logger.info("Executing rule LPW.1_3.3V")
lpw1_l1 = lvpwell.width(0.6.um, euclidian).polygons(0.001).not_interacting(v5_xtor).not_interacting(dualgate)
lpw1_l1.output("LPW.1_3.3V", "LPW.1_3.3V : Min. LVPWELL Width. : 0.6µm")
lpw1_l1.forget
# Rule LPW.1_5V: Min. LVPWELL Width. is 0.74µm
logger.info("Executing rule LPW.1_5V")
lpw1_l1 = lvpwell.width(0.74.um, euclidian).polygons(0.001).overlapping(dualgate)
lpw1_l1.output("LPW.1_5V", "LPW.1_5V : Min. LVPWELL Width. : 0.74µm")
lpw1_l1.forget
if CONNECTIVITY_RULES
logger.info("CONNECTIVITY_RULES section")
connected_lvpwell_3p3v, unconnected_lvpwell_3p3v = conn_space(lvpwell, 0.86, 1.4, euclidian)
connected_lvpwell_5p0v, unconnected_lvpwell_5p0v = conn_space(lvpwell, 0.86, 1.7, euclidian)
# Rule LPW.2a_3.3V: Min. LVPWELL to LVWELL Space (Inside DNWELL) [Different potential]. is 1.4µm
logger.info("Executing rule LPW.2a_3.3V")
lpw2a_l1 = unconnected_lvpwell_3p3v.not_interacting(v5_xtor).not_interacting(dualgate)
lpw2a_l1.output("LPW.2a_3.3V", "LPW.2a_3.3V : Min. LVPWELL to LVWELL Space (Inside DNWELL) [Different potential]. : 1.4µm")
lpw2a_l1.forget
# Rule LPW.2a_5V: Min. LVPWELL to LVPWELL Space (Inside DNWELL) [Different potential]. is 1.7µm
logger.info("Executing rule LPW.2a_5V")
lpw2a_l1 = unconnected_lvpwell_5p0v.overlapping(dualgate)
lpw2a_l1.output("LPW.2a_5V", "LPW.2a_5V : Min. LVPWELL to LVPWELL Space (Inside DNWELL) [Different potential]. : 1.7µm")
lpw2a_l1.forget
# Rule LPW.2b_3.3V: Min. LVPWELL to LVPWELL Space [Equi potential]. is 0.86µm
logger.info("Executing rule LPW.2b_3.3V")
lpw2b_l1 = connected_lvpwell_3p3v.not_interacting(v5_xtor).not_interacting(dualgate)
lpw2b_l1.output("LPW.2b_3.3V", "LPW.2b_3.3V : Min. LVPWELL to LVPWELL Space [Equi potential]. : 0.86µm")
lpw2b_l1.forget
# Rule LPW.2b_5V: Min. LVPWELL to LVPWELL Space [Equi potential]. is 0.86µm
logger.info("Executing rule LPW.2b_5V")
lpw2b_l1 = connected_lvpwell_5p0v.overlapping(dualgate)
lpw2b_l1.output("LPW.2b_5V", "LPW.2b_5V : Min. LVPWELL to LVPWELL Space [Equi potential]. : 0.86µm")
lpw2b_l1.forget
else
logger.info("CONNECTIVITY_RULES disabled section")
# Rule LPW.2a_3.3V_: Min. LVPWELL to LVWELL Space (Inside DNWELL) [Different potential]. is 1.4µm
logger.info("Executing rule LPW.2a_3.3V_")
lpw2a_l1 = lvpwell.isolated(1.4.um, euclidian).polygons(0.001).not_interacting(v5_xtor).not_interacting(dualgate)
lpw2a_l1.output("LPW.2a_3.3V_", "LPW.2a_3.3V_ : Min. LVPWELL to LVWELL Space (Inside DNWELL) [Different potential]. : 1.4µm")
lpw2a_l1.forget
# Rule LPW.2a_5V_: Min. LVPWELL to LVPWELL Space (Inside DNWELL) [Different potential]. is 1.7µm
logger.info("Executing rule LPW.2a_5V_")
lpw2a_l1 = lvpwell.isolated(1.7.um, euclidian).polygons(0.001).overlapping(dualgate)
lpw2a_l1.output("LPW.2a_5V_", "LPW.2a_5V_ : Min. LVPWELL to LVPWELL Space (Inside DNWELL) [Different potential]. : 1.7µm")
lpw2a_l1.forget
end #CONNECTIVITY_RULES
# Rule LPW.3_3.3V: Min. DNWELL enclose LVPWELL. is 2.5µm
logger.info("Executing rule LPW.3_3.3V")
lpw3_l1 = dnwell.enclosing(lvpwell, 2.5.um, euclidian).polygons(0.001)
lpw3_l2 = lvpwell.not_outside(dnwell).not(dnwell)
lpw3_l = lpw3_l1.or(lpw3_l2).not_interacting(v5_xtor).not_interacting(dualgate)
lpw3_l.output("LPW.3_3.3V", "LPW.3_3.3V : Min. DNWELL enclose LVPWELL. : 2.5µm")
lpw3_l1.forget
lpw3_l2.forget
lpw3_l.forget
# Rule LPW.3_5V: Min. DNWELL enclose LVPWELL. is 2.5µm
logger.info("Executing rule LPW.3_5V")
lpw3_l1 = dnwell.enclosing(lvpwell, 2.5.um, euclidian).polygons(0.001)
lpw3_l2 = lvpwell.not_outside(dnwell).not(dnwell)
lpw3_l = lpw3_l1.or(lpw3_l2).overlapping(dualgate)
lpw3_l.output("LPW.3_5V", "LPW.3_5V : Min. DNWELL enclose LVPWELL. : 2.5µm")
lpw3_l1.forget
lpw3_l2.forget
lpw3_l.forget
# rule LPW.4_3.3V is not a DRC check
# rule LPW.4_5V is not a DRC check
# Rule LPW.5_3.3V: LVPWELL resistors must be enclosed by DNWELL.
logger.info("Executing rule LPW.5_3.3V")
lpw5_l1 = lvpwell.inside(res_mk).not_inside(dnwell).not_interacting(v5_xtor).not_interacting(dualgate)
lpw5_l1.output("LPW.5_3.3V", "LPW.5_3.3V : LVPWELL resistors must be enclosed by DNWELL.")
lpw5_l1.forget
# Rule LPW.5_5V: LVPWELL resistors must be enclosed by DNWELL.
logger.info("Executing rule LPW.5_5V")
lpw5_l1 = lvpwell.inside(res_mk).not_inside(dnwell).overlapping(dualgate)
lpw5_l1.output("LPW.5_5V", "LPW.5_5V : LVPWELL resistors must be enclosed by DNWELL.")
lpw5_l1.forget
# Rule LPW.11: Min. (LVPWELL outside DNWELL) space to DNWELL. is 1.5µm
logger.info("Executing rule LPW.11")
lpw11_l1 = lvpwell.outside(dnwell).separation(dnwell, 1.5.um, euclidian).polygons(0.001)
lpw11_l1.output("LPW.11", "LPW.11 : Min. (LVPWELL outside DNWELL) space to DNWELL. : 1.5µm")
lpw11_l1.forget
# Rule LPW.12: LVPWELL cannot overlap with Nwell.
logger.info("Executing rule LPW.12")
lpw12_l1 = lvpwell.not_outside(nwell)
lpw12_l1.output("LPW.12", "LPW.12 : LVPWELL cannot overlap with Nwell.")
lpw12_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])