blob: c989465d697de74180e935037ffe5356884b6c45 [file] [log] [blame]
#=============================================================================================================================================================
#----------------------------------------------------------- GF 0.18um MCU DRC RULE DECK (DNWELL) ------------------------------------------------------------
#=============================================================================================================================================================
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 )
nat = polygons(5 , 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.")
#================================================
#---------------------DNWELL---------------------
#================================================
if FEOL
logger.info("FEOL section")
# Rule DN.1: Min. DNWELL Width is 1.7µm
logger.info("Executing rule DN.1")
dn1_l1 = dnwell.width(1.7.um, euclidian).polygons(0.001)
dn1_l1.output("DN.1", "DN.1 : Min. DNWELL Width : 1.7µm")
dn1_l1.forget
if CONNECTIVITY_RULES
logger.info("CONNECTIVITY_RULES section")
connected_dnwell, unconnected_dnwell = conn_space(dnwell, 2.5, 5.42, euclidian)
# Rule DN.2a: Min. DNWELL Space (Equi-potential), Merge if the space is less than is 2.5µm
logger.info("Executing rule DN.2a")
dn2a_l1 = connected_dnwell
dn2a_l1.output("DN.2a", "DN.2a : Min. DNWELL Space (Equi-potential), Merge if the space is less than : 2.5µm")
dn2a_l1.forget
# Rule DN.2b: Min. DNWELL Space (Different potential) is 5.42µm
logger.info("Executing rule DN.2b")
dn2b_l1 = unconnected_dnwell
dn2b_l1.output("DN.2b", "DN.2b : Min. DNWELL Space (Different potential) : 5.42µm")
dn2b_l1.forget
else
logger.info("CONNECTIVITY_RULES disabled section")
# Rule DN.2b_: Min. DNWELL Space (Different potential) is 5.42µm
logger.info("Executing rule DN.2b_")
dn2b_l1 = dnwell.isolated(5.42.um, euclidian).polygons(0.001)
dn2b_l1.output("DN.2b_", "DN.2b_ : Min. DNWELL Space (Different potential) : 5.42µm")
dn2b_l1.forget
end #CONNECTIVITY_RULES
dn3_1 = dnwell.not_inside(pcomp.holes.not(pcomp).interacting(dnwell, 1..1).extents)
dn3_2 = dnwell.inside((pcomp.holes.not(pcomp).covering(nat.or(ncomp).or(nwell).not_interacting(dnwell))))
# Rule DN.3: Each DNWELL shall be directly surrounded by PCOMP guard ring tied to the P-substrate potential.
logger.info("Executing rule DN.3")
dn3_l1 = dn3_1.or(dn3_2)
dn3_l1.output("DN.3", "DN.3 : Each DNWELL shall be directly surrounded by PCOMP guard ring tied to the P-substrate potential.")
dn3_l1.forget
dn3_1.forget
dn3_2.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])