blob: 0a0bc7879f9774b214dfa13cfb0f47fdf7372319 [file] [log] [blame]
# DRC for SKY130 according to :
# https://skywater-pdk.readthedocs.io/en/latest/rules/periphery.html
# https://skywater-pdk.readthedocs.io/en/latest/rules/layers.html
#
# Distributed under GNU GPLv3: https://www.gnu.org/licenses/
#
# History :
# 2022-01-13 : 2022.1.13_01.01 initial release
#
##########################################################################################
# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=sky130_drc.txt -r drc_sky130.drc
if $input
source($input, $top_cell)
end
if $report
report("SKY130 DRC runset", $report)
else
report("SKY130 DRC runset", File.join(File.dirname(RBA::CellView::active.filename), "sky130_drc.txt"))
end
AL = true # do not change
CU = false # do not change
# choose betwen only one of AL or CU back-end flow here :
backend_flow = AL
# enable / disable rule groups
if $feol == "1" || $feol == "true"
FEOL = true # front-end-of-line checks
else
FEOL = false
end
if $beol == "1" || $beol == "true"
BEOL = true # back-end-of-line checks
else
BEOL = false
end
if $offgrid == "1" || $offgrid == "true"
OFFGRID = true # manufacturing grid/angle checks
else
OFFGRID = false
end
if $seal == "1" || $seal == "true"
SEAL = true # SEAL RING checks
else
SEAL = false
end
if $floating_met == "1" || $floating_met == "true"
FLOATING_MET = true # back-end-of-line checks
else
FLOATING_MET = false
end
# klayout setup
########################
# use a tile size of 1mm - not used in deep mode-
# tiles(1000.um)
# use a tile border of 10 micron:
# tile_borders(1.um)
#no_borders
# hierachical
deep
if $thr
threads($thr)
else
threads(4)
end
# if more inof is needed, set true
# verbose(true)
verbose(true)
# layers definitions
########################
# all except purpose (datatype) 5 -- label and 44 -- via
li_wildcard = "67/20"
mcon_wildcard = "67/44"
m1_wildcard = "68/20"
via_wildcard = "68/44"
m2_wildcard = "69/20"
via2_wildcard = "69/44"
m3_wildcard = "70/20"
via3_wildcard = "70/44"
m4_wildcard = "71/20"
via4_wildcard = "71/44"
m5_wildcard = "72/20"
diff = input(65, 20)
tap = polygons(65, 44)
nwell = polygons(64, 20)
dnwell = polygons(64, 18)
pwbm = polygons(19, 44)
pwde = polygons(124, 20)
natfet = polygons(124, 21)
hvtr = polygons(18, 20)
hvtp = polygons(78, 44)
ldntm = polygons(11, 44)
hvi = polygons(75, 20)
tunm = polygons(80, 20)
lvtn = polygons(125, 44)
poly = polygons(66, 20)
hvntm = polygons(125, 20)
nsdm = polygons(93, 44)
psdm = polygons(94, 20)
rpm = polygons(86, 20)
urpm = polygons(79, 20)
npc = polygons(95, 20)
licon = polygons(66, 44)
li = polygons(li_wildcard)
mcon = polygons(mcon_wildcard)
m1 = polygons(m1_wildcard)
via = polygons(via_wildcard)
m2 = polygons(m2_wildcard)
via2 = polygons(via2_wildcard)
m3 = polygons(m3_wildcard)
via3 = polygons(via3_wildcard)
m4 = polygons(m4_wildcard)
via4 = polygons(via4_wildcard)
m5 = polygons(m5_wildcard)
pad = polygons(76, 20)
nsm = polygons(61, 20)
capm = polygons(89, 44)
cap2m = polygons(97, 44)
vhvi = polygons(74, 21)
uhvi = polygons(74, 22)
npn = polygons(82, 20)
inductor = polygons(82, 24)
vpp = polygons(82, 64)
pnp = polygons(82, 44)
lvs_prune = polygons(84, 44)
ncm = polygons(92, 44)
padcenter = polygons(81, 20)
mf = polygons(76, 44)
areaid_sl = polygons(81, 1)
areaid_ce = polygons(81, 2)
areaid_fe = polygons(81, 3)
areaid_sc = polygons(81, 4)
areaid_sf = polygons(81, 6)
areaid_sw = polygons(81, 7)
areaid_sr = polygons(81, 8)
areaid_mt = polygons(81, 10)
areaid_dt = polygons(81, 11)
areaid_ft = polygons(81, 12)
areaid_ww = polygons(81, 13)
areaid_ld = polygons(81, 14)
areaid_ns = polygons(81, 15)
areaid_ij = polygons(81, 17)
areaid_zr = polygons(81, 18)
areaid_ed = polygons(81, 19)
areaid_de = polygons(81, 23)
areaid_rd = polygons(81, 24)
areaid_dn = polygons(81, 50)
areaid_cr = polygons(81, 51)
areaid_cd = polygons(81, 52)
areaid_st = polygons(81, 53)
areaid_op = polygons(81, 54)
areaid_en = polygons(81, 57)
areaid_en20 = polygons(81, 58)
areaid_le = polygons(81, 60)
areaid_hl = polygons(81, 63)
areaid_sd = polygons(81, 70)
areaid_po = polygons(81, 81)
areaid_it = polygons(81, 84)
areaid_et = polygons(81, 101)
areaid_lvt = polygons(81, 108)
areaid_re = polygons(81, 125)
areaid_ag = polygons(81, 79)
poly_rs = polygons(66, 13)
diff_rs = polygons(65, 13)
pwell_rs = polygons(64, 13)
li_rs = polygons(67, 13)
cfom = polygons(22, 20)
# Define a new custom function that selects polygons by their number of holes:
# It will return a new layer containing those polygons with min to max holes.
# max can be nil to omit the upper limit.
class DRC::DRCLayer
def with_holes(min, max)
new_data = RBA::Region::new
self.data.each do |p|
if p.holes >= (min || 0) && (!max || p.holes <= max)
new_data.insert(p)
end
end
DRC::DRCLayer::new(@engine, new_data)
end
end
# DRC section
########################
log("DRC section")
if FEOL
log("FEOL section")
# nsdm
log("START: 93/44 (nsdm)")
nsdm.and(psdm).output("nsd.1", "nsd.1 : nsdm should not overlap psdm")
log("END: 93/44 (nsdm)")
end #FEOL