Files
tt-support-tools/precheck/tech-files/sky130A_mr.drc
T

1630 lines
52 KiB
Plaintext

# 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-6-22 : 2022.6.30_01.07 release
#
# 2023-6-14 : 2023.6.14_01.08 release
#
# 2024-2-11 : 2024.2.11_01.09 release
#
# 2024-5-26 : Update rectMCON_peri to use outside instead of not
# 2024-8-15 :
# * Avoid assigning to constant variables
# * Fix defaults for arguments when they are not passed in the CLI
#
# 2024-8-18 :
# * Add new rules:
# * `MR_lvtn.OVL.2`
# * `MR_tunm.CON.1`
# * `rdl.1`
# * `rdl.2`
# * `MR_thkox.CON.1`
# * `MR_rdl.CON.1`
# * `MR_li.WID.4`
# * `moduleCut.1`
# * Modify `licon` checks to account for ("non-bar" | exempt prec_resistor)
# * Rename `licon` checks
# 2024-9-1 :
# * Change the default of sram_exclude to false
##########################################################################################
release = "2024.2.11_01.09"
require "time"
require "logger"
exec_start_time = Time.now
logger = Logger.new(STDOUT)
logger.formatter =
proc do |severity, datetime, progname, msg|
"#{msg}
"
end
# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=sky130_drc.txt -r drc_sky130.drc
source($input, $top_cell) if $input
if $report
report("SKY130 DRC runset", $report)
else
report(
"SKY130 DRC runset",
File.join(File.dirname(RBA::CellView.active.filename), "sky130_drc.txt")
)
end
if not defined? $feol
$feol = "false"
end
if not defined? $beol
$beol = "false"
end
if not defined? $offgrid
$offgrid = "false"
end
if not defined? $floating_met
$floating_met = "false"
end
if not defined? $sram_exclude
$sram_exclude = "false"
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 == "0" || $feol == "false"
FEOL = false
else
FEOL = true # front-end-of-line checks
end
if $beol == "0" || $beol == "false"
BEOL = false
else
BEOL = true # back-end-of-line checks
end
if $offgrid == "0" || $offgrid == "false"
OFFGRID = false
else
OFFGRID = true # manufacturing grid/angle checks
end
if $seal == "0" || $seal == "false"
SEAL = false
else
SEAL = true # SEAL RING checks
end
if $floating_met == "0" || $floating_met == "false"
FLOATING_MET = false
else
FLOATING_MET = true # back-end-of-line checks
end
if $sram_exclude == "0" || $sram_exclude == "false"
SRAM_EXCLUDE = false # back-end-of-line checks
else
SRAM_EXCLUDE = true
end
logger.info("Args:")
logger.info("\tsram_exclude: #{$sram_exclude}")
logger.info("\tfeol: #{$feol}")
logger.info("\tbeol: #{$beol}")
logger.info("\tfloating_met: #{$floating_met}")
logger.info("\toffgrid: #{$offgrid}")
logger.info("\tseal: #{$seal}")
# 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
$thr ? threads($thr) : threads(4)
# 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"
li_res_wildcard = "67/13"
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"
nsdm_wildcard = "93/44"
psdm_wildcard = "94/20"
nwell_wildcard = "64/20"
diff = input(65, 20)
tap = polygons(65, 44)
nwell = polygons(nwell_wildcard)
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(nsdm_wildcard)
psdm = polygons(psdm_wildcard)
rpm = polygons(86, 20)
urpm = polygons(79, 20)
npc = polygons(95, 20)
licon = polygons(66, 44)
li = polygons(li_wildcard)
li_res = polygons(li_res_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)
rdl = polygons(74, 20)
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)
poly_fill = polygons(66, 99)
diff_rs = polygons(65, 13)
pwell_rs = polygons(64, 13)
li_rs = polygons(67, 13)
cfom = polygons(22, 20)
thkox = polygons(75, 21)
areaid_ce_merged = areaid_ce.merged
# 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|
new_data.insert(p) if p.holes >= (min || 0) && (!max || p.holes <= max)
end
DRC::DRCLayer.new(@engine, new_data)
end
end
# DRC section
########################
log("DRC section")
if FEOL
log("FEOL section")
# dnwell
log("START: 64/18 (dnwell)")
dnwell.width(3.0, euclidian).output(
"dnwell.1",
"dnwell.1: min. dnwell width : 3.0um"
)
dnwell
.not(uhvi.or(vhvi))
.space(6.3, euclidian)
.output("dnwell.2", "dnwell.2 : min. dnwell spacing : 6.3um")
log("END: 64/18 (dnwell)")
not_sram = layout(source.cell_obj).select("-*sky130_sram_*kbyte_*")
not_sram_nsdm = not_sram.input(nsdm_wildcard)
not_sram_psdm = not_sram.input(psdm_wildcard)
not_sram_nwell = not_sram.input(nwell_wildcard)
# This is a hack, should be reverted
not_io =
layout(source.cell_obj).select(
"-*sky130_fd_io__gpiov2_amux",
"-*sky130_fd_io__simple_pad_and_busses"
)
not_io_nwell = not_io.input(nwell_wildcard)
# nwell
log("START: 64/20 (nwell)")
nwell.width(0.84, euclidian).output(
"nwell.1",
"nwell.1 : min. nwell width : 0.84um"
)
nwell.space(1.27, euclidian).output(
"nwell.2a",
"nwell.2a : min. nwell spacing (merged if less) : 1.27um"
)
nwell_interact = not_sram_nwell.and(not_io_nwell).merge
dnwell.enclosing(nwell_interact.holes, 1.03, euclidian).output(
"nwell.6",
"nwell.6 : min enclosure of nwellHole by dnwell : 1.03um"
)
hvmarker = hvi.or(rdl).or(uhvi).or(vhvi)
nwell
.interacting(nwell.and(hvmarker))
.not(hvmarker)
.output("nwell.9", "nwell.9 : HVnwell must be enclosed by hv marker")
log("END: 64/20 (nwell)")
# hvtp
log("START: 78/44 (hvtp)")
hvtp.width(0.38, euclidian).output(
"hvtp.1",
"hvtp.1 : min. hvtp width : 0.38um"
)
hvtp.space(0.38, euclidian).output(
"hvtp.2",
"hvtp.2 : min. hvtp spacing : 0.38um"
)
log("END: 78/44 (hvtp)")
# pwde
log("START: 124/20 (pwde)")
pwde.width(0.84, euclidian).output(
"pwde.1",
"pwde.1 : min. pwde width : 0.84um"
)
pwde
.and(uhvi.or(vhvi))
.space(1.27, euclidian)
.output("pwde.2", "pwde.2 : min. pwde inside v20 spacing : 1.27um")
log("END: 124/20 (pwde)")
# hvtr
log("START: 18/20 (htvr)")
hvtr.width(0.38, euclidian).output(
"hvtr.1",
"hvtr.1 : min. hvtr width : 0.38um"
)
hvtr.separation(hvtp, 0.38, euclidian).output(
"hvtr.2",
"hvtr.2 : min. hvtr spacing : 0.38um"
)
hvtr.and(hvtp).output("hvtr.2_a", "hvtr.2_a : hvtr must not overlap hvtp")
log("END: 18/20 (htvr)")
# lvtn
log("START: 25/44 (lvtn)")
lvtn.width(0.38, euclidian).output(
"lvtn.1a",
"lvtn.1a : min. lvtn width : 0.38um"
)
lvtn.space(0.38, euclidian).output(
"lvtn.2",
"lvtn.2 : min. lvtn spacing : 0.38um"
)
lvtn
.interacting(nwell)
.not_inside(nwell)
.edges
.and(nwell)
.output("MR_lvtn.OVL.2", "MR_lvtn.OVL.2 : lvtn must not straddle nwell")
log("END: 25/44 (lvtn)")
# ncm
log("START: 92/44 (ncm)")
ncm.width(0.38, euclidian).output("ncm.1", "ncm.1 : min. ncm width : 0.38um")
ncm.space(0.38, euclidian).output(
"ncm.2a",
"ncm.2a : min. ncm spacing : 0.38um"
)
log("END: 92/44 (ncm)")
# diff-tap
log("START: 65/20 (diff)")
difftap = diff.or(tap)
diff_width = diff.rectangles.width(0.15, euclidian).polygons
diff_cross_areaid_ce =
diff_width
.edges
.outside_part(areaid_ce)
.not(diff_width.outside(areaid_ce).edges)
diff_cross_areaid_ce.output(
"difftap.1",
"difftap.1 : min. diff width across areaid:ce : 0.15um"
)
diff
.outside(areaid_ce)
.width(0.15, euclidian)
.output(
"difftap.1_a",
"difftap.1_a : min. diff width in periphery : 0.15um"
)
diff
.inside(areaid_ce)
.width(0.14, euclidian)
.output(
"difftap.2",
"difftap.2 : min. diff width inside areadid:ce : 0.14um"
)
log("END: 65/20 (diff)")
log("START: 65/44 (tap)")
tap_width = tap.rectangles.width(0.15, euclidian).polygons
tap_cross_areaid_ce =
tap_width
.edges
.outside_part(areaid_ce)
.not(tap_width.outside(areaid_ce).edges)
tap_cross_areaid_ce.output(
"difftap.1_b",
"difftap.1_b : min. tap width across areaid:ce : 0.15um"
)
tap
.not(areaid_ce)
.width(0.15, euclidian)
.output("difftap.1_c", "difftap.1_c : min. tap width in periphery : 0.15um")
log("END: 65/44 (tap)")
difftap.space(0.27, euclidian).output(
"difftap.3",
"difftap.3 : min. difftap spacing : 0.27um"
)
# tunm
log("START: 80/20 (tunm)")
tunm.width(0.41, euclidian).output(
"tunm.1",
"tunm.1 : min. tunm width : 0.41um"
)
tunm.space(0.5, euclidian).output(
"tunm.2",
"tunm.2 : min. tunm spacing : 0.5um"
)
tunm.output(
"MR_tunm.CON.1",
"MR_tunm.CON.1 : use of layer tunm is prohibited"
)
log("END: 80/20 (tunm)")
# thkox
log("START: 80/20 (thkox)")
thkox_peri = thkox.not(areaid_ce)
thkox_peri.width(0.6, euclidian).output(
"thkox.1",
"thkox.1 : min. thkox width inside periphery : 0.6um"
)
thkox_peri.space(0.7, euclidian).output(
"thkox.2",
"thkox.2 : min. thkox spacing inside periphery : 0.7um"
)
thkox
.interacting(diff)
.not_inside(diff)
.edges
.and(diff)
.output("MR_thkox.CON.1", "MR_thkox.CON.1 : thkox must not straddle diff")
log("END: 80/20 (thkox)")
# poly
log("START: 66/20 (poly)")
poly.width(0.15, euclidian).output(
"poly.1a",
"poly.1a : min. poly width : 0.15um"
)
poly
.not(areaid_ce)
.space(0.21, euclidian)
.output("poly.2", "poly.2 : min. poly spacing : 0.21um")
core_poly_gap = poly.inside(areaid_ce).drc(width(projection) <= 0.15).polygons
poly
.interacting(core_poly_gap)
.isolated(0.16, projection)
.output("poly.3", "poly.3 : min. poly spacing inside areaid:core : 0.16um")
log("END: 66/20 (poly)")
# ldntm
log("START: 80/20 (ldntm)")
ldntm_core = ldntm.and(areaid_ce)
ldntm_core.width(0.7, euclidian).output(
"ldntm.1",
"ldntm.1 : min. ldntm width inside areaid:core : 0.7um"
)
ldntm_core.space(0.7, euclidian).output(
"ldntm.2",
"ldntm.2 : min. ldntm spacing inside areaid:core : 0.7um"
)
log("END: 80/20 (ldntm)")
# rpm
log("START: 86/20 (rpm)")
rpm.width(1.27, euclidian).output(
"rpm.1a",
"rpm.1a : min. rpm width : 1.27um"
)
rpm.space(0.84, euclidian).output(
"rpm.2",
"rpm.2 : min. rpm spacing : 0.84um"
)
log("END: 86/20 (rpm)")
# rdl
log("START: 74/20 (rdl)")
rdl.width(10.um, euclidian).output("rdl.1", "rdl.1 : min. rdl width : 10um")
rdl.space(10.um, euclidian).output("rdl.2", "rdl.2 : min. rdl spacing : 10um")
rdl.output("MR_rdl.CON.1", "MR_rdl.CON.1 : use of rdl layer is prohibited")
log("END: 74/20 (rdl)")
# urpm
log("START: 79/20 (urpm)")
urpm.width(1.27, euclidian).output(
"urpm.1a",
"urpm.1a : min. rpm width : 1.27um"
)
urpm.space(0.84, euclidian).output(
"urpm.2",
"urpm.2 : min. rpm spacing : 0.84um"
)
log("END: 79/20 (urpm)")
# npc
log("START: 95/20 (npc)")
npc.width(0.27, euclidian).output("npc.1", "npc.1 : min. npc width : 0.27um")
npc.space(0.27, euclidian).output(
"npc.2",
"npc.2 : min. npc spacing, should be manually merged if less than : 0.27um"
)
log("END: 95/20 (npc)")
# nsdm
log("START: 93/44 (nsdm)")
if SRAM_EXCLUDE
not_sram_nsdm
.not(areaid_ce)
.space(0.38, euclidian)
.output("nsdm.1", "nsdm.1 : min. nsdm spacing in periphery : 0.38um")
not_sram_nsdm
.outside(areaid_ce)
.width(0.38, euclidian)
.output("nsdm.2", "nsdm.2 : min. nsdm width in periphery : 0.38um")
not_sram_nsdm_width =
not_sram_nsdm
.width(0.38, euclidian)
.polygons
.interacting(areaid_ce_merged)
not_sram_nsdm_width.interacting(
not_sram_nsdm_width.edges.outside_part(areaid_ce_merged)
).output("nsdm.3", "nsdm.3 : min. diff width across areaid:ce : 0.38um")
nsdm_space =
not_sram_nsdm
.space(0.38, euclidian)
.polygons
.interacting(areaid_ce_merged)
nsdm_space.interacting(
nsdm_space.edges.outside_part(areaid_ce_merged)
).output("nsdm.4", "nsdm.4 : min. spacing across areaid:ce : 0.38um")
not_sram_nsdm
.inside(areaid_ce)
.width(0.29, euclidian)
.output("nsdm.5", "nsdm.5 : min. nsdm width in areaid:ce : 0.29um")
not_sram_nsdm
.inside(areaid_ce)
.space(0.29, euclidian)
.output("nsdm.6", "nsdm.6 : min. nsdm spacing in areaid:ce : 0.29um")
not_sram_nsdm
.inside(areaid_ce)
.space(0.38, projection)
.with_internal_angle(0)
.output(
"nsdm.6a",
"nsdm.6a : min. nsdm spacing on parallel edges in areaid:ce : 0.38um"
)
else
nsdm
.not(areaid_ce)
.space(0.38, euclidian)
.output("nsdm.1", "nsdm.1 : min. nsdm spacing in periphery : 0.38um")
nsdm
.outside(areaid_ce)
.width(0.38, euclidian)
.output("nsdm.2", "nsdm.2 : min. nsdm width in periphery : 0.38um")
nsdm_width =
nsdm.width(0.38, euclidian).polygons.interacting(areaid_ce_merged)
nsdm_width.interacting(
nsdm_width.edges.outside_part(areaid_ce_merged)
).output("nsdm.3", "nsdm.3 : min. diff width across areaid:ce : 0.38um")
nsdm_space =
nsdm.space(0.38, euclidian).polygons.interacting(areaid_ce_merged)
nsdm_space.interacting(
nsdm_space.edges.outside_part(areaid_ce_merged)
).output("nsdm.4", "nsdm.4 : min. spacing across areaid:ce : 0.38um")
nsdm
.inside(areaid_ce)
.width(0.29, euclidian)
.output("nsdm.5", "nsdm.5 : min. nsdm width in areaid:ce : 0.29um")
nsdm
.inside(areaid_ce)
.space(0.29, euclidian)
.output("nsdm.6", "nsdm.6 : min. nsdm spacing in areaid:ce : 0.29um")
nsdm
.inside(areaid_ce)
.space(0.38, projection)
.with_internal_angle(0)
.output(
"nsdm.6a",
"nsdm.6a : min. nsdm spacing on parallel edges in areaid:ce : 0.38um"
)
end # SRAM_EXCLUDE
log("END: 93/44 (nsdm)")
# psdm
log("START: 94/20 (psdm)")
if SRAM_EXCLUDE
not_sram_psdm
.not(areaid_ce)
.space(0.38, euclidian)
.output("psdm.1", "psdm.1 : min. psdm spacing in periphery : 0.38um")
not_sram_psdm
.outside(areaid_ce)
.width(0.38, euclidian)
.output("psdm.2", "psdm.2 : min. psdm width in periphery : 0.38um")
not_sram_psdm_width =
not_sram_psdm
.width(0.38, euclidian)
.polygons
.interacting(areaid_ce_merged)
not_sram_psdm_width.interacting(
not_sram_psdm_width.edges.outside_part(areaid_ce_merged)
).output("psdm.3", "psdm.3 : min. diff width across areaid:ce : 0.38um")
psdm_space =
not_sram_psdm
.space(0.38, euclidian)
.polygons
.interacting(areaid_ce_merged)
psdm_space.interacting(
psdm_space.edges.outside_part(areaid_ce_merged)
).output("psdm.4", "psdm.4 : min. spacing across areaid:ce : 0.38um")
not_sram_psdm
.inside(areaid_ce)
.width(0.29, euclidian)
.output("psdm.5", "psdm.5 : min. psdm width in areaid:ce : 0.29um")
not_sram_psdm
.inside(areaid_ce)
.space(0.29, euclidian)
.output("psdm.6", "psdm.6 : min. psdm spacing in areaid:ce : 0.29um")
not_sram_psdm
.inside(areaid_ce)
.space(0.38, projection)
.with_internal_angle(0)
.output(
"psdm.6a",
"psdm.6a : min. psdm spacing on parallel edges in areaid:ce : 0.38um"
)
not_sram_psdm
.and(not_sram_nsdm)
.and(diff)
.output(
"nsdm_psdm_overlap",
"nsdm_psdm_overlap : nsdm overlaps psdm over active"
)
else
psdm
.not(areaid_ce)
.space(0.38, euclidian)
.output("psdm.1", "psdm.1 : min. psdm spacing in periphery : 0.38um")
psdm
.outside(areaid_ce)
.width(0.38, euclidian)
.output("psdm.2", "psdm.2 : min. psdm width in periphery : 0.38um")
psdm_width =
psdm.width(0.38, euclidian).polygons.interacting(areaid_ce_merged)
psdm_width.interacting(
psdm_width.edges.outside_part(areaid_ce_merged)
).output("psdm.3", "psdm.3 : min. diff width across areaid:ce : 0.38um")
psdm_space =
psdm.space(0.38, euclidian).polygons.interacting(areaid_ce_merged)
psdm_space.interacting(
psdm_space.edges.outside_part(areaid_ce_merged)
).output("psdm.4", "psdm.4 : min. spacing across areaid:ce : 0.38um")
psdm
.inside(areaid_ce)
.width(0.29, euclidian)
.output("psdm.5", "psdm.5 : min. psdm width in areaid:ce : 0.29um")
psdm
.inside(areaid_ce)
.space(0.29, euclidian)
.output("psdm.6", "psdm.6 : min. psdm spacing in areaid:ce : 0.29um")
psdm
.inside(areaid_ce)
.space(0.38, projection)
.with_internal_angle(0)
.output(
"psdm.6a",
"psdm.6a : min. psdm spacing on parallel edges in areaid:ce : 0.38um"
)
psdm
.and(nsdm)
.and(diff)
.output(
"nsdm_psdm_overlap",
"nsdm_psdm_overlap : nsdm overlaps psdm over active"
)
end # SRAM_EXCLUDE
log("END: 94/20 (psdm)")
# licon
log("START: 66/44 (licon)")
polyi = poly_fill.and(poly)
poly_licon = (polyi.and(licon)).and(areaid_ce)
licon_peri = licon.outside(areaid_ce)
if SEAL
ringLICON = licon.drc(with_holes > 0)
rectLICON = licon.not(ringLICON)
else
rectLICON = licon
end
rectLICON.non_rectangles.output(
"licon.1_c",
"licon.1_c : licon should be rectangle"
)
prec_resistor = (rpm | urpm) & psdm & (poly.interacting(poly_rs))
licon_peri.not(prec_resistor).space(0.17, euclidian).output(
"MR_licon.SP.1",
"MR_licon.SP.1: min. licon spacing in periphery : 0.17um"
)
licon_not_prec_resistor = licon.not(prec_resistor)
licon_not_prec_resistor.drc(length != 0.17).output(
"licon.1",
"licon.1: min/max. licon length : 0.17um"
)
licon_peri
.and(difftap)
.separation(npc, 0.09, euclidian)
.output(
"licon.13",
"licon.13: min. licon on diff spacing to npc in periphery : 0.09um"
)
licon_peri
.and(difftap)
.and(npc)
.output(
"licon.13_a",
"licon.13_a: licon on diff in periphery can't overlap npc"
)
licon
.and(poly)
.and(difftap)
.output(
"licon.17",
"licon.17 : Licons may not overlap both poly and (diff or tap)"
)
xfom = difftap.not(poly)
licon1ToXfom = licon.interacting(licon.and(xfom))
polyLicon1 =
(licon.not(licon1ToXfom)).interacting((licon.not(licon1ToXfom)).and(poly))
polyLicon1_CORE = polyLicon1.and(areaid_ce)
npc.enclosing(polyLicon1_CORE, 0.045, euclidian).output(
"licon.6",
"licon.6 : npc min enclosure of poly_licon inside areaid:core : 0.045um"
)
polyLicon1_CORE.not(npc).output(
"licon.6",
"licon.6 : npc min enclosure of poly_licon inside areaid:core : 0.045um"
)
log("END: 66/44 (licon)")
#nsm
log("START: 61/20 (nsm)")
nsm.space(4.0, euclidian).output("nsm.1", "nsm.1 : nsm min. spacing : 4.0um")
nsm.width(3.0, euclidian).output("nsm.2", "nsm.2 : nsm min. width : 3.0um")
log("END: 61/20 (nsm)")
# CAPM
log("START: 89/44 (capm)")
capm.width(1.0, euclidian).output(
"capm.1",
"capm.1 : min. capm width : 1.0um"
)
capm.space(0.84, euclidian).output(
"capm.2a",
"capm.2a : min. capm spacing : 0.84um"
)
m3_bot_plate = ((capm.and(m3)).sized(0.14))
m3_bot_plate
.isolated(1.2, euclidian)
.polygons
.not(m3)
.output("capm.2b", "capm.2b : min. spacing between met3_bot_plate : 1.2um")
(m3.not_interacting(m3_bot_plate)).separation(
m3_bot_plate,
1.2,
euclidian
).output(
"capm.2b_a",
"capm.2b_a : min. spacing between met3_bot_plate and met3 : 1.2um"
)
# capm.and(m3).enclosing(m3, 0.14, euclidian).output("capm.3", "capm.3 : min. capm and m3 enclosure of m3 : 0.14um")
m3.enclosing(capm, 0.14, euclidian).output(
"capm.3",
"capm.3 : min. m3 enclosure of capm : 0.14um"
)
capm.enclosing(via3, 0.14, euclidian).output(
"capm.4",
"capm.4 : min. capm enclosure of via3 : 0.14um"
)
capm.separation(via3, 0.14, euclidian).output(
"capm.5",
"capm.5 : min. capm spacing to via3 : 0.14um"
)
(m3.not_interacting(capm)).separation(capm, 0.5, euclidian).output(
"capm.11",
"capm.11 : Min spacing of capm and met3 not overlapping capm : 0.5um"
)
log("END: 89/44 (capm)")
# CAP2M
log("START: 97/44 (cap2m)")
cap2m.width(1.0, euclidian).output(
"cap2m.1",
"cap2m.1 : min. cap2m width : 1.0um"
)
cap2m.space(0.84, euclidian).output(
"cap2m.2a",
"cap2m.2a : min. cap2m spacing : 0.84um"
)
m4
.interacting(cap2m)
.isolated(1.2, euclidian)
.output("cap2m.2b", "cap2m.2b : min. cap2m spacing : 1.2um")
(m4.interacting(cap2m)).isolated(1.2, euclidian).output(
"cap2m.2b_a",
"cap2m.2b_a : min. spacing of m4_bot_plate : 1.2um"
)
cap2m
.and(m4)
.enclosing(m4, 0.14, euclidian)
.output("cap2m.3", "cap2m.3 : min. m4 enclosure of cap2m : 0.14um")
m4.enclosing(cap2m, 0.14, euclidian).output(
"cap2m.3_a",
"cap2m.3_a : min. m4 enclosure of cap2m : 0.14um"
)
cap2m.enclosing(via4, 0.2, euclidian).output(
"cap2m.4",
"cap2m.4 : min. cap2m enclosure of via4 : 0.2um"
)
cap2m.separation(via4, 0.2, euclidian).output(
"cap2m.5",
"cap2m.5 : min. cap2m spacing to via4 : 0.2um"
)
(m4.not_interacting(cap2m)).separation(cap2m, 0.5, euclidian).output(
"cap2m.11",
"cap2m.11 : Min spacing of cap2m and met4 not overlapping cap2m : 0.5um"
)
log("END: 97/44 (cap2m)")
end #FEOL
if BEOL
log("BEOL section")
# li
log("START: 67/20 (li)")
li_outside_or_touching_areaidce =
(li.outside(areaid_ce)).or(
li.interacting(areaid_ce).not(li.inside(areaid_ce))
)
li_outside_or_touching_areaidce.width(0.17, euclidian).output(
"li.1",
"li.1 : min. li width outside or crossing areaid:ce : 0.17um"
)
li_outside_or_touching_areaidce.space(0.17, euclidian).output(
"li.3",
"li.3 : min. li spacing outside or crossing areaid:ce : 0.17um"
)
licon_peri = licon.not(areaid_ce)
li_edges_with_less_enclosure =
li.enclosing(licon_peri, 0.08, projection).second_edges
error_corners = li_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu)
li_interact = licon_peri.interacting(error_corners.polygons(1.dbu))
li_interact.output(
"li.5",
"li.5 : min. li enclosure of licon of 2 adjacent edges : 0.08um"
)
linotace = li.not(li.interacting(areaid_ce))
linotace.with_area(nil, 0.0561).output(
"li.6",
"li.6 : min. li area : 0.0561um²"
)
li_core = li.and(areaid_ce)
li_core.space(0.14, euclidian).output(
"li.7",
"li.7 : min. li core spacing : 0.14um"
)
li_core.width(0.14, euclidian).output(
"li.8",
"li.8 : min. li core width : 0.14um"
)
log("END: 67/20 (li)")
# li res
log("START: 67/13 (li_res)")
li_res.width(0.29, euclidian).output(
"MR_li.WID.4",
"MR_li.WID.4 : li:res minimum width : 0.29um"
)
log("END: 67/13 (li_res)")
# ct
log("START: 67/44 (mcon)")
mconnotace = mcon.not(areaid_ce)
if SEAL
ringMCON = mcon.drc(with_holes > 0)
rectMCON = mcon.not(ringMCON)
else
rectMCON = mcon
end
rectMCON_peri = rectMCON.outside(areaid_ce)
rectMCON.non_rectangles.output(
"ct.1",
"ct.1: non-ring mcon should be rectangular"
)
# rectMCON_peri.edges.without_length(0.17).output("ct.1_a/b", "ct.1_a/b : minimum/maximum width of mcon : 0.17um")
rectMCON_peri.drc(width < 0.17).output(
"ct.1_a",
"ct.1_a : minimum width of mcon : 0.17um"
)
rectMCON_peri.drc(length > 0.17).output(
"ct.1_b",
"ct.1_b : maximum length of mcon : 0.17um"
)
mcon.space(0.19, euclidian).output(
"ct.2",
"ct.2 : min. mcon spacing : 0.19um"
)
if SEAL
ringMCON.width(0.17, euclidian).output(
"ct.3",
"ct.3 : min. width of ring-shaped mcon : 0.17um"
)
ringMCON.drc(width >= 0.175).output(
"ct.3_a",
"ct.3_a : max. width of ring-shaped mcon : 0.175um"
)
ringMCON.not(areaid_sl).output(
"ct.3_b",
"ct.3_b: ring-shaped mcon must be enclosed by areaid_sl"
)
end
mconnotace.not(li).output("ct.4", "ct.4 : mcon should covered by li")
log("END: 67/44 (mcon)")
# m1
log("START: 68/20 (m1)")
m1.width(0.14, euclidian).output("m1.1", "m1.1 : min. m1 width : 0.14um")
huge_m1 = m1.sized(-1.5).sized(1.5).snap(0.005) & m1
non_huge_m1 = m1.edges - huge_m1
huge_m1 = huge_m1.edges.outside_part(m1.merged)
non_huge_m1.space(0.14, euclidian).output(
"m1.2",
"m1.2 : min. m1 spacing : 0.14um"
)
(
huge_m1.separation(non_huge_m1, 0.28, euclidian) +
huge_m1.space(0.28, euclidian)
).output("m1.3ab", "m1.3ab : min. 3um.m1 spacing m1 : 0.28um")
#not_in_cell6 = layout(source.cell_obj).select("-s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b", "-s8fpls_pl8", "-s8fs_cmux4_fm")
not_in_cell6 =
layout(source.cell_obj).select(
"-s8cell_ee_plus_sseln_a",
"-s8cell_ee_plus_sseln_b",
"-s8cell_ee_plus_sselp_a",
"-s8cell_ee_plus_sselp_b",
"-s8fs_cmux4_fm"
)
not_in_cell6_m1 = not_in_cell6.input(m1_wildcard)
not_in_cell6_m1.enclosing(mconnotace, 0.03, euclidian).output(
"791_m1.4",
"791_m1.4 : min. m1 enclosure of mcon : 0.03um"
)
mconnotace.not(m1).output(
"m1.4",
"m1.4 : mcon periphery must be enclosed by m1"
)
in_cell6 =
layout(source.cell_obj).select(
"-*",
"+s8cell_ee_plus_sseln_a",
"+s8cell_ee_plus_sseln_b",
"+s8cell_ee_plus_sselp_a",
"+s8cell_ee_plus_sselp_b",
"+s8fpls_pl8",
"+s8fs_cmux4_fm"
)
in_cell6_m1 = in_cell6.input(m1_wildcard)
in_cell6_m1.enclosing(mcon, 0.005, euclidian).output(
"m1.4a",
"m1.4a : min. m1 enclosure of mcon for specific cells : 0.005um"
)
in_cell6_m1.not(m1).output(
"m1.4a_a",
"m1.4a_a : mcon periph must be enclosed by met1 for specific cells"
)
m1.with_area(0..0.083).output("m1.6", "m1.6 : min. m1 area : 0.083um²")
m1
.holes
.with_area(0..0.14)
.output("m1.7", "m1.7 : min. m1 with holes area : 0.14um²")
if FLOATING_MET
m1.not_interacting(via.or(mcon)).output(
"m1.x",
"floating met1, must interact with via1"
)
end
if backend_flow = AL
#Could flag false positive, fix would be to add .rectangles for m1
mconnotace_edges_with_less_enclosure_m1 =
m1.enclosing(mconnotace, 0.06, projection).second_edges
error_corners_m1 =
mconnotace_edges_with_less_enclosure_m1.width(angle_limit(100.0), 1.dbu)
mconnotace_interact_m1 =
mconnotace.interacting(error_corners_m1.polygons(1.dbu))
mconnotace_interact_m1.output(
"m1.5",
"m1.5 : min. m1 enclosure of mcon of 2 adjacent edges : 0.06um"
)
end
log("END: 68/20 (m1)")
# via
log("START: 68/44 (via)")
if backend_flow = AL
if SEAL
ringVIA = via.drc(with_holes > 0)
rectVIA = via.not(ringVIA)
else
rectVIA = via
end
via_not_mt = rectVIA.not(areaid_mt)
via_not_mt.non_rectangles.output(
"via.1a",
"via.1a : via outside of moduleCut should be rectangular"
)
via_not_mt.width(0.15, euclidian).output(
"via.1a_a",
"via.1a_a : min. width of via outside of moduleCut : 0.15um"
)
# via_not_mt.edges.without_length(nil, 0.15 + 1.dbu).output("via.1a_b", "via.1a_b : maximum length of via : 0.15um")
via_not_mt.drc(length > 0.15).output(
"via.1a_b",
"via.1a_b : maximum length of via : 0.15um"
)
via.space(0.17, euclidian).output(
"via.2",
"via.2 : min. via spacing : 0.17um"
)
if SEAL
ringVIA.width(0.2, euclidian).output(
"via.3",
"via.3 : min. width of ring-shaped via : 0.2um"
)
ringVIA.drc(width >= 0.205).output(
"via.3_a",
"via.3_a : max. width of ring-shaped via : 0.205um"
)
ringVIA.not(areaid_sl).output(
"via.3_b",
"via.3_b: ring-shaped via must be enclosed by areaid_sl"
)
end
m1
.edges
.enclosing(rectVIA.drc(width == 0.15), 0.055, euclidian)
.output("via.4a", "via.4a : min. m1 enclosure of 0.15um via : 0.055um")
rectVIA
.squares
.drc(width == 0.15)
.not(m1)
.output("via.4a_a", "via.4a_a : 0.15um via must be enclosed by met1")
via1_edges_with_less_enclosure_m1 =
m1
.edges
.enclosing(rectVIA.drc(width == 0.15), 0.085, projection)
.second_edges
error_corners_via1 =
via1_edges_with_less_enclosure_m1.width(angle_limit(100.0), 1.dbu)
via2_interact = via.interacting(error_corners_via1.polygons(1.dbu))
via2_interact.output(
"via.5a",
"via.5a : min. m1 enclosure of 0.15um via of 2 adjacent edges : 0.085um"
)
end
log("END: 68/44 (via)")
# m2
log("START: 69/20 (m2)")
via_inside_periphery = via.and(areaid_ce)
m2.width(0.14, euclidian).output("m2.1", "m2.1 : min. m2 width : 0.14um")
huge_m2 = m2.sized(-1.5).sized(1.5).snap(0.005) & m2
non_huge_m2 = m2.edges - huge_m2
huge_m2 = huge_m2.edges.outside_part(m2.merged)
via_outside_periphery = via.not(areaid_ce)
non_huge_m2.space(0.14, euclidian).output(
"m2.2",
"m2.2 : min. m2 spacing : 0.14um"
)
(
huge_m2.separation(non_huge_m2, 0.28, euclidian) +
huge_m2.space(0.28, euclidian)
).output("m2.3ab", "m2.3ab : min. 3um.m2 spacing m2 : 0.28um")
m2.with_area(0..0.0676).output("m2.6", "m2.6 : min. m2 area : 0.0676um²")
m2
.holes
.with_area(0..0.14)
.output("m2.7", "m2.7 : min. m2 holes area : 0.14um²")
if FLOATING_MET
m2.not_interacting(via.or(via2)).output(
"m2.x",
"floating met2, must interact with via1 or via2"
)
end
if backend_flow = AL
m2.enclosing(via_outside_periphery, 0.055, euclidian).output(
"m2.4",
"m2.4 : min. m2 enclosure of via : 0.055um"
)
via_outside_periphery.not(m2).output(
"m2.4_a",
"m2.4_a : via in periphery must be enclosed by met2"
)
m2.enclosing(via_inside_periphery, 0.045, euclidian).output(
"m2.4_b",
"m2.4_B : min. m2 enclosure of via inside areaid:core : 0.045um"
)
via_edges_with_less_enclosure_m2 =
m2.enclosing(via_outside_periphery, 0.085, projection).second_edges
error_corners =
via_edges_with_less_enclosure_m2.width(angle_limit(100.0), 1.dbu)
via_interact = via.interacting(error_corners.polygons(1.dbu))
via_interact.output(
"m2.5",
"m2.5 : min. m2 enclosure of via of 2 adjacent edges : 0.085um"
)
end
log("END: 69/20 (m2)")
# via2
log("START: 69/44 (via2)")
if backend_flow = AL
if SEAL
ringVIA2 = via2.drc(with_holes > 0)
rectVIA2 = via2.not(ringVIA2)
else
rectVIA2 = via2
end
via2_not_mt = rectVIA2.not(areaid_mt)
via2_not_mt.non_rectangles.output(
"via2.1a",
"via2.1a : via2 outside of moduleCut should be rectangular"
)
via2_not_mt.width(0.2, euclidian).output(
"via2.1a_a",
"via2.1a_a : min. width of via2 outside of moduleCut : 0.2um"
)
via2_not_mt
.edges
.without_length(nil, 0.2 + 1.dbu)
.output("via2.1a_b", "via2.1a_b : maximum length of via2 : 0.2um")
via2.space(0.2, euclidian).output(
"via2.2",
"via2.2 : min. via2 spacing : 0.2um"
)
if SEAL
ringVIA2.width(0.2, euclidian).output(
"via2.3",
"via2.3 : min. width of ring-shaped via2 : 0.2um"
)
ringVIA2.drc(width >= 0.205).output(
"via2.3_a",
"via2.3_a : max. width of ring-shaped via2 : 0.205um"
)
ringVIA2.not(areaid_sl).output(
"via2.3_b",
"via2.3_b: ring-shaped via2 must be enclosed by areaid_sl"
)
end
m2.enclosing(via2, 0.04, euclidian).output(
"via2.4",
"via2.4 : min. m2 enclosure of via2 : 0.04um"
)
via2.not(m2).output("via2.4_a", "via2.4_a : via must be enclosed by met2")
via2_edges_with_less_enclosure =
m2.enclosing(via2, 0.085, projection).second_edges
error_corners =
via2_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu)
via2_interact = via2.interacting(error_corners.polygons(1.dbu))
via2_interact.output(
"via2.5",
"via2.5 : min. m3 enclosure of via2 of 2 adjacent edges : 0.085um"
)
end
log("END: 69/44 (via2)")
# m3
log("START: 70/20 (m3)")
m3.width(0.3, euclidian).output("m3.1", "m3.1 : min. m3 width : 0.3um")
huge_m3 = m3.sized(-1.5).sized(1.5).snap(0.005) & m3
non_huge_m3 = m3.edges - huge_m3
huge_m3 = huge_m3.edges.outside_part(m3.merged)
non_huge_m3.space(0.3, euclidian).output(
"m3.2",
"m3.2 : min. m3 spacing : 0.3um"
)
(
huge_m3.separation(non_huge_m3, 0.4, euclidian) +
huge_m3.space(0.4, euclidian)
).output("m3.3cd", "m3.3cd : min. 3um.m3 spacing m3 : 0.4um")
if FLOATING_MET
m3.not_interacting(via2.or(via3)).output(
"m3.x",
"floating met3, must interact with via2 or via3"
)
end
if backend_flow = AL
m3.enclosing(via2, 0.065, euclidian).output(
"m3.4",
"m3.4 : min. m3 enclosure of via2 : 0.065um"
)
via2.not(m3).output("m3.4_a", "m3.4_a : via2 must be enclosed by met3")
end
m3.with_area(0..0.240).output("m3.6", "m3.6 : min. m3 area : 0.240um²")
m3
.holes
.with_area(0..0.2)
.output("m3.7", "m3.7 : min. m3 holes area : 0.2um²")
log("END: 70/20 (m3)")
# via3
log("START: 70/44 (via3)")
if backend_flow = AL
if SEAL
ringVIA3 = via3.drc(with_holes > 0)
rectVIA3 = via3.not(ringVIA3)
else
rectVIA3 = via3
end
via3_not_mt = rectVIA3.not(areaid_mt)
via3_not_mt.non_rectangles.output(
"via3.1",
"via3.1 : via3 outside of moduleCut should be rectangular"
)
via3_not_mt.width(0.2, euclidian).output(
"via3.1_a",
"via3.1_a : min. width of via3 outside of moduleCut : 0.2um"
)
via3_not_mt
.edges
.without_length(nil, 0.2 + 1.dbu)
.output("via3.1_b", "via3.1_b : maximum length of via3 : 0.2um")
via3.space(0.2, euclidian).output(
"via3.2",
"via3.2 : min. via3 spacing : 0.2um"
)
m3.enclosing(via3, 0.06, euclidian).output(
"via3.4",
"via3.4 : min. m3 enclosure of via3 : 0.06um"
)
rectVIA3.not(m3).output(
"via3.4_a",
"via3.4_a : non-ring via3 must be enclosed by met3"
)
via_edges_with_less_enclosure =
m3.enclosing(via3, 0.09, projection).second_edges
error_corners =
via_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu)
via3_interact = via3.interacting(error_corners.polygons(1.dbu))
via3_interact.output(
"via3.5",
"via3.5 : min. m3 enclosure of via3 of 2 adjacent edges : 0.09um"
)
end
log("END: 70/44 (via3)")
# m4
log("START: 71/20 (m4)")
m4.width(0.3, euclidian).output("m4.1", "m4.1 : min. m4 width : 0.3um")
huge_m4 = m4.sized(-1.5).sized(1.5).snap(0.005) & m4
non_huge_m4 = m4.edges - huge_m4
huge_m4 = huge_m4.edges.outside_part(m4.merged)
non_huge_m4.space(0.3, euclidian).output(
"m4.2",
"m4.2 : min. m4 spacing : 0.3um"
)
m4.with_area(0..0.240).output("m4.4a", "m4.4a : min. m4 area : 0.240um²")
(
huge_m4.separation(non_huge_m4, 0.4, euclidian) +
huge_m4.space(0.4, euclidian)
).output("m4.5ab", "m4.5ab : min. 3um.m4 spacing m4 : 0.4um")
if FLOATING_MET
m4.not_interacting(via3.or(via4)).output(
"m4.x",
"floating met3, must interact with via3 or via4"
)
end
if backend_flow = AL
m4.enclosing(via3, 0.065, euclidian).output(
"m4.3",
"m4.3 : min. m4 enclosure of via3 : 0.065um"
)
via3.not(m4).output("m4.3_a", "m4.3_a : via3 must be enclosed by met4")
end
m4
.holes
.with_area(0..0.2)
.output("m4.7", "m4.7 : min. m4 holes area : 0.2um²")
log("END: 71/20 (m4)")
# via4
log("START: 71/44 (via4)")
if SEAL
ringVIA4 = via4.drc(with_holes > 0)
rectVIA4 = via4.not(ringVIA4)
else
rectVIA4 = via4
end
via4_not_mt = rectVIA4.not(areaid_mt)
via4_not_mt.non_rectangles.output(
"via4.1",
"via4.1 : via4 outside of moduleCut should be rectangular"
)
rectVIA4.width(0.8, euclidian).output(
"via4.1_a",
"via4.1_a : min. width of via4 outside of moduleCut : 0.8um"
)
rectVIA4.drc(length > 0.8).output(
"via4.1_b",
"via4.1_b : maximum length of via4 : 0.8um"
)
via4
.space(0.8, euclidian)
.polygons
.output("via4.2", "via4.2 : min. via4 spacing : 0.8um")
if SEAL
ringVIA4.width(0.8, euclidian).output(
"via4.3",
"via4.3 : min. width of ring-shaped via4 : 0.8um"
)
ringVIA4.drc(width >= 0.805).output(
"via4.3_a",
"via4.3_a : max. width of ring-shaped via4 : 0.805um"
)
ringVIA4.not(areaid_sl).output(
"via4.3_b",
"via4.3_b: ring-shaped via4 must be enclosed by areaid_sl"
)
end
m4.enclosing(via4, 0.19, euclidian).output(
"via4.4",
"via4.4 : min. m4 enclosure of via4 : 0.19um"
)
rectVIA4.not(m4).output("via4.4_a", "via4.4_a : m4 must enclose all via4")
log("END: 71/44 (via4)")
# m5
log("START: 72/20 (m5)")
m5.width(1.6, euclidian).output("m5.1", "m5.1 : min. m5 width : 1.6um")
m5.space(1.6, euclidian).output("m5.2", "m5.2 : min. m5 spacing : 1.6um")
m5.enclosing(via4, 0.31, euclidian).output(
"m5.3",
"m5.3 : min. m5 enclosure of via4 : 0.31um"
)
via4.not(m5).output("m5.3_a", "m5.3_a : via must be enclosed by m5")
if FLOATING_MET
m5.not_interacting(via4).output(
"m5.x",
"floating met5, must interact with via4"
)
end
m5.with_area(0..4.0).output("m5.4", "m5.4 : min. m5 area : 4.0um²")
m5
.holes
.with_area(0..0.14)
.output("m5.7", "m5.7 : min. m5 holes area : 0.14um²")
log("END: 72/20 (m5)")
# pad
log("START: 76/20 (pad)")
pad.space(1.27, euclidian).output(
"pad.2",
"pad.2 : min. pad spacing : 1.27um"
)
log("END: 76/20 (pad)")
log("START: 81/10 (moduleCut)")
areaid_mt.output(
"moduleCut.1",
"moduleCut.1 : moduleCut layer is for SkyWater use only"
)
log("END: 81/10 (moduleCut)")
#areaid_mt = polygons(81, 10)
end #BEOL
if FEOL
log("FEOL section")
# hvi
log("START: 75/20 (hvi)")
hvi_peri = hvi.not(areaid_ce)
hvi_peri.width(0.6, euclidian).output(
"hvi.1",
"hvi.1 : min. hvi width : 0.6um"
)
hvi_peri.space(0.7, euclidian).output(
"hvi.2a",
"hvi.2a : min. hvi spacing : 0.7um"
)
log("END: 75/20 (hvi)")
# hvntm
log("START: 125/20 (hvntm)")
hvntm_peri = hvntm.not(areaid_ce)
hvntm_peri.width(0.7, euclidian).output(
"hvntm.1",
"hvntm.1 : min. hvntm width : 0.7um"
)
hvntm_peri.space(0.7, euclidian).output(
"hvntm.2",
"hvntm.2 : min. hvntm spacing : 0.7um"
)
log("END: 125/20 (hvntm)")
end #FEOL
if OFFGRID
log("OFFGRID-ANGLES section")
dnwell.ongrid(0.005).output(
"dnwell_OFFGRID",
"x.1b : OFFGRID vertex on dnwell"
)
dnwell.with_angle(0..45).output(
"dnwell_angle",
"x.3a : non 45 degree angle dnwell"
)
nwell.ongrid(0.005).output("nwell_OFFGRID", "x.1b : OFFGRID vertex on nwell")
nwell.with_angle(0..45).output(
"nwell_angle",
"x.3a : non 45 degree angle nwell"
)
pwbm.ongrid(0.005).output("pwbm_OFFGRID", "x.1b : OFFGRID vertex on pwbm")
pwbm.with_angle(0..45).output("pwbm_angle", "x.3a : non 45 degree angle pwbm")
pwde.ongrid(0.005).output("pwde_OFFGRID", "x.1b : OFFGRID vertex on pwde")
pwde.with_angle(0..45).output("pwde_angle", "x.3a : non 45 degree angle pwde")
hvtp.ongrid(0.005).output("hvtp_OFFGRID", "x.1b : OFFGRID vertex on hvtp")
hvtp.with_angle(0..45).output("hvtp_angle", "x.3a : non 45 degree angle hvtp")
hvtr.ongrid(0.005).output("hvtr_OFFGRID", "x.1b : OFFGRID vertex on hvtr")
hvtr.with_angle(0..45).output("hvtr_angle", "x.3a : non 45 degree angle hvtr")
lvtn.ongrid(0.005).output("lvtn_OFFGRID", "x.1b : OFFGRID vertex on lvtn")
lvtn.with_angle(0..45).output("lvtn_angle", "x.3a : non 45 degree angle lvtn")
ncm.ongrid(0.005).output("ncm_OFFGRID", "x.1b : OFFGRID vertex on ncm")
ncm.with_angle(0..45).output("ncm_angle", "x.3a : non 45 degree angle ncm")
diff.ongrid(0.005).output("diff_OFFGRID", "x.1b : OFFGRID vertex on diff")
tap.ongrid(0.005).output("tap_OFFGRID", "x.1b : OFFGRID vertex on tap")
diff
.not(areaid_en.and(uhvi))
.with_angle(0..90)
.output("diff_angle", "x.2 : non 90 degree angle diff")
diff
.and(areaid_en.and(uhvi))
.with_angle(0..45)
.output("diff_angle", "x.2c : non 45 degree angle diff")
tap
.not(areaid_en.and(uhvi))
.with_angle(0..90)
.output("tap_angle", "x.2 : non 90 degree angle tap")
tap
.and(areaid_en.and(uhvi))
.with_angle(0..45)
.output("tap_angle", "x.2c : non 45 degree angle tap")
tunm.ongrid(0.005).output("tunm_OFFGRID", "x.1b : OFFGRID vertex on tunm")
tunm.with_angle(0..45).output("tunm_angle", "x.3a : non 45 degree angle tunm")
poly.ongrid(0.005).output("poly_OFFGRID", "x.1b : OFFGRID vertex on poly")
poly.with_angle(0..90).output("poly_angle", "x.2 : non 90 degree angle poly")
rpm.ongrid(0.005).output("rpm_OFFGRID", "x.1b : OFFGRID vertex on rpm")
rpm.with_angle(0..45).output("rpm_angle", "x.3a : non 45 degree angle rpm")
npc.ongrid(0.005).output("npc_OFFGRID", "x.1b : OFFGRID vertex on npc")
npc.with_angle(0..45).output("npc_angle", "x.3a : non 45 degree angle npc")
nsdm.ongrid(0.005).output("nsdm_OFFGRID", "x.1b : OFFGRID vertex on nsdm")
nsdm.with_angle(0..45).output("nsdm_angle", "x.3a : non 45 degree angle nsdm")
psdm.ongrid(0.005).output("psdm_OFFGRID", "x.1b : OFFGRID vertex on psdm")
psdm.with_angle(0..45).output("psdm_angle", "x.3a : non 45 degree angle psdm")
licon.ongrid(0.005).output("licon_OFFGRID", "x.1b : OFFGRID vertex on licon")
licon.with_angle(0..90).output(
"licon_angle",
"x.2 : non 90 degree angle licon"
)
li.ongrid(0.005).output("li_OFFGRID", "x.1b : OFFGRID vertex on li")
li.with_angle(0..45).output("li_angle", "x.3a : non 45 degree angle li")
mcon.ongrid(0.005).output("ct_OFFGRID", "x.1b : OFFGRID vertex on mcon")
mcon.with_angle(0..90).output("ct_angle", "x.2 : non 90 degree angle mcon")
vpp.ongrid(0.005).output("vpp_OFFGRID", "x.1b : OFFGRID vertex on vpp")
vpp.with_angle(0..45).output("vpp_angle", "x.3a : non 45 degree angle vpp")
m1.ongrid(0.005).output("m1_OFFGRID", "x.1b : OFFGRID vertex on m1")
m1.with_angle(0..45).output("m1_angle", "x.3a : non 45 degree angle m1")
via.ongrid(0.005).output("via_OFFGRID", "x.1b : OFFGRID vertex on via")
via.with_angle(0..90).output("via_angle", "x.2 : non 90 degree angle via")
m2.ongrid(0.005).output("m2_OFFGRID", "x.1b : OFFGRID vertex on m2")
m2.with_angle(0..45).output("m2_angle", "x.3a : non 45 degree angle m2")
via2.ongrid(0.005).output("via2_OFFGRID", "x.1b : OFFGRID vertex on via2")
via2.with_angle(0..90).output("via2_angle", "x.2 : non 90 degree angle via2")
m3.ongrid(0.005).output("m3_OFFGRID", "x.1b : OFFGRID vertex on m3")
m3.with_angle(0..45).output("m3_angle", "x.3a : non 45 degree angle m3")
via3.ongrid(0.005).output("via3_OFFGRID", "x.1b : OFFGRID vertex on via3")
via3.with_angle(0..90).output("via3_angle", "x.2 : non 90 degree angle via3")
nsm.ongrid(0.005).output("nsm_OFFGRID", "x.1b : OFFGRID vertex on nsm")
nsm.with_angle(0..45).output("nsm_angle", "x.3a : non 45 degree angle nsm")
m4.ongrid(0.005).output("m4_OFFGRID", "x.1b : OFFGRID vertex on m4")
m4.with_angle(0..45).output("m4_angle", "x.3a : non 45 degree angle m4")
via4.ongrid(0.005).output("via4_OFFGRID", "x.1b : OFFGRID vertex on via4")
via4.with_angle(0..90).output("via4_angle", "x.2 : non 90 degree angle via4")
m5.ongrid(0.005).output("m5_OFFGRID", "x.1b : OFFGRID vertex on m5")
m5.with_angle(0..45).output("m5_angle", "x.3a : non 45 degree angle m5")
pad.ongrid(0.005).output("pad_OFFGRID", "x.1b : OFFGRID vertex on pad")
pad.with_angle(0..45).output("pad_angle", "x.3a : non 45 degree angle pad")
mf.ongrid(0.005).output("mf_OFFGRID", "x.1b : OFFGRID vertex on mf")
mf.with_angle(0..90).output("mf_angle", "x.2 : non 90 degree angle mf")
hvi.ongrid(0.005).output("hvi_OFFGRID", "x.1b : OFFGRID vertex on hvi")
hvi.with_angle(0..45).output("hvi_angle", "x.3a : non 45 degree angle hvi")
hvntm.ongrid(0.005).output("hvntm_OFFGRID", "x.1b : OFFGRID vertex on hvntm")
hvntm.with_angle(0..45).output(
"hvntm_angle",
"x.3a : non 45 degree angle hvntm"
)
vhvi.ongrid(0.005).output("vhvi_OFFGRID", "x.1b : OFFGRID vertex on vhvi")
vhvi.with_angle(0..45).output("vhvi_angle", "x.3a : non 45 degree angle vhvi")
uhvi.ongrid(0.005).output("uhvi_OFFGRID", "x.1b : OFFGRID vertex on uhvi")
uhvi.with_angle(0..45).output("uhvi_angle", "x.3a : non 45 degree angle uhvi")
pwell_rs.ongrid(0.005).output(
"pwell_rs_OFFGRID",
"x.1b : OFFGRID vertex on pwell_rs"
)
pwell_rs.with_angle(0..45).output(
"pwell_rs_angle",
"x.3a : non 45 degree angle pwell_rs"
)
areaid_re.ongrid(0.005).output(
"areaid_re_OFFGRID",
"x.1b : OFFGRID vertex on areaid.re"
)
end #OFFGRID
logger.info(" ")
logger.info("Cell exclusion list:")
logger.info(" rule | cell")
if SRAM_EXCLUDE
logger.info(
" nwell.6 | sky130_fd_io__gpiov2_amux, sky130_fd_io__simple_pad_and_busses, sram"
)
logger.info(" nsd.1 | sram")
logger.info(" nsd.2 | sram")
logger.info(" psd.1 | sram")
logger.info(" psd.2 | sram")
else
logger.info(
" nwell.6 | sky130_fd_io__gpiov2_amux, sky130_fd_io__simple_pad_and_busses"
)
end #SRAM_EXCLUDE
logger.info(" ")
logger.info("release #{release}")