drc
false
false
true
drc_scripts
tools_menu.drc.end
dsl
drc-dsl-xml
# Supported variables that can be set using "-rd <name>=<value>" on the command line:
# log_file - path to the log file [default: no log file]
# in_gds - path to the GDS layout to check (required in batch mode)
# cell - name of the cell to check
# report_file - path to the report database [default: sg13g2_minimal.lyrdb in the script directory]
# to set logfile: -rd logfile="sg13g2_minimal.log"
if $log_file
log_file($log_file)
end
application = RBA::Application.instance
main_window = application.main_window
if main_window
curr_layout_view = main_window.current_view()
unless curr_layout_view
layout_path = RBA::FileDialog::ask_open_file_name("Chose your layout file.", ".", "GDSII files (*.GDS *.gds *.GDS.gz *.gds.gz *.GDS2 *.gds2 *.GDS2.gz *.gds2.gz);; All files (*)")
main_window.load_layout(layout_path, 1)
curr_layout_view = main_window.current_view()
end
active_layout = RBA::CellView::active.layout
active_cellname = RBA::CellView::active.cell_name
source(active_layout, active_cellname)
else
log("DRC: batch mode")
# to set input layout: -rd in_gds="path to GDS file"
# to set cell: -rd cell="topcell"
if $cell
active_cellname = $cell
log("Active cell: " + active_cellname)
source($in_gds, active_cellname)
active_layout = source.layout
else
source($in_gds)
active_layout = source.layout
active_cellname = source.cell_name
end
end
unless active_layout or $in_gds
raise("layout file must be defined on command line or via 'in_gds' script variable")
end
if active_layout.dbu != 0.001
puts "WARNING: Layout dbu value (" + active_layout.dbu.to_s + " ) deviates from rule file dbu value (0.001). This will scale the layout and may not be intended."
end
report_file = __dir__ + "/sg13g2_minimal.lyrdb"
# to set report file: -rd report_file="sg13g2_minimal.lyrdb"
if $report_file
report_file = File.expand_path($report_file)
end
report("design rules: sg13g2_minimal | layout cell: " + active_cellname, report_file)
deep
$drc_error_count = 0
class DRC::DRCLayer
unless method_defined?(:original_output)
alias_method :original_output, :output
end
def output(*args)
$drc_error_count += self.count()
original_output(*args)
end
def ext_merged(min_coherence, overlap_count)
args = [min_coherence, overlap_count]
return DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :merged, *args))
end
def ext_merge(min_coherence, overlap_count)
args = [min_coherence, overlap_count]
if @engine.is_tiled?
self.data = @engine._tcmd(self.data, 0, self.data.class, :merged, *args)
else
@engine._tcmd(self.data, 0, self.data.class, :merge, *args)
end
return self
end
end
# Initial definitions of control flow variables
# Strings from the command line have to be converted
if defined? $density
$density = $density.to_s.downcase == "true"
else
$density = true
end
if defined? $sanityRules
$sanityRules = $sanityRules.to_s.downcase == "true"
else
$sanityRules = true
end
class DRC::DRCEngine
def space_width_separation_overlap_check(value,
error_edge_pairs_90,
error_edge_pairs_180,
inverse_error_edge_pairs_90 = nil,
inverse_error_edge_pairs_180 = nil,
options = {})
consider_intersecting_edges = options.fetch(:consider_intersecting_edges, false)
consider_touch_points = options.fetch(:consider_touch_points, false)
ignore_non_axis_aligned_edges = options.fetch(:ignore_non_axis_aligned_edges, false)
min_angle = options.fetch(:min_angle, 0)
max_angle = options.fetch(:max_angle, 90)
include_min_angle = options.fetch(:include_min_angle, true)
include_max_angle = options.fetch(:include_max_angle, false)
area_of_right_angle = value**2/2
errors_ep = RBA::EdgePairs::new()
touch_point_errors_ep = RBA::EdgePairs::new()
intersecting_edges_errors_ep = RBA::EdgePairs::new()
intersecting_edges_error_candidates = Hash.new()
no_touch_point_error = Hash.new()
error_edge_pairs_90.data.each do |edge_pair|
ip = nil
if edge_pair.first.p1 == edge_pair.second.p1 or
edge_pair.first.p1 == edge_pair.second.p2
ip = edge_pair.first.p1
elsif edge_pair.first.p2 == edge_pair.second.p1 or
edge_pair.first.p2 == edge_pair.second.p2
ip = edge_pair.first.p2
end
if ip
intersecting_edges_error_candidates[ip] = edge_pair
if !edge_pair.first.is_degenerate? and !edge_pair.second.is_degenerate?
if (edge_pair.first.contains?(edge_pair.second.p1) and
edge_pair.first.contains?(edge_pair.second.p2)) or
(edge_pair.second.contains?(edge_pair.first.p1) and
edge_pair.second.contains?(edge_pair.first.p2))
no_touch_point_error[ip] = true
end
end
else
errors_ep.insert(edge_pair)
end
end
if consider_intersecting_edges or consider_touch_points
touch_point_candidates = Hash.new()
touch_point_errors = Hash.new()
if inverse_error_edge_pairs_90 and inverse_error_edge_pairs_180
(inverse_error_edge_pairs_90 + inverse_error_edge_pairs_180).data.each do |edge_pair|
ip = edge_pair.first.intersection_point(edge_pair.second)
if ip
if touch_point_candidates[ip]
touch_point_errors[ip] = true
touch_point_candidates.delete(ip)
elsif !no_touch_point_error[ip]
touch_point_candidates[ip] = edge_pair
end
end
end
end
touch_point_candidates = Hash.new()
(error_edge_pairs_90 + error_edge_pairs_180).data.each do |edge_pair|
ip = nil
if edge_pair.first.p1 == edge_pair.second.p1 or
edge_pair.first.p1 == edge_pair.second.p2
ip = edge_pair.first.p1
elsif edge_pair.first.p2 == edge_pair.second.p1 or
edge_pair.first.p2 == edge_pair.second.p2
ip = edge_pair.first.p2
end
if ip
if edge_pair.area == area_of_right_angle or max_angle == 180
intersecting_edges_error_candidates[ip] = edge_pair
end
if touch_point_errors[ip]
touch_point_errors_ep.insert(edge_pair)
intersecting_edges_error_candidates.delete(ip)
elsif touch_point_candidates[ip]
touch_point_errors_ep.insert(edge_pair)
touch_point_errors_ep.insert(touch_point_candidates[ip])
touch_point_candidates.delete(ip)
intersecting_edges_error_candidates.delete(ip)
elsif !no_touch_point_error[ip]
touch_point_candidates[ip] = edge_pair
end
end
end
if consider_intersecting_edges
intersecting_edges_errors_ep = RBA::EdgePairs::new(intersecting_edges_error_candidates.values)
if max_angle != 180
intersecting_edges_errors_ep = intersecting_edges_errors_ep.with_internal_angle(min_angle, max_angle, false, include_min_angle, include_max_angle)
end
errors_ep = errors_ep + intersecting_edges_errors_ep
end
end
if ignore_non_axis_aligned_edges
errors_ep = errors_ep.with_angle_both(RBA::Edges::OrthoEdges, false)
end
if consider_touch_points
errors_ep = errors_ep + touch_point_errors_ep
end
return DRC::DRCLayer::new(self, errors_ep)
end
end
class DRC::DRCLayer
def ext_and(other)
self_min_coherence_state = self.data.min_coherence?
other_min_coherence_state = other.data.min_coherence?
self.data.min_coherence = true
other.data.min_coherence = true
output_layer = self & other
self.data.min_coherence = self_min_coherence_state
other.data.min_coherence = other_min_coherence_state
return output_layer
end
def ext_with_area(constraint)
lower_bound = nil
upper_bound = nil
output_layer = nil
self_min_coherence_state = self.data.min_coherence?
self.data.min_coherence = true
constraint.each do |expression|
relation = expression[0]
value = expression[1]
if relation == ">"
lower_bound = value + 1e-6
elsif relation == "<"
upper_bound = value
elsif relation == "=="
output_layer = self.with_area(value)
elsif relation == "!="
output_layer = self.without_area(value)
elsif relation == ">="
lower_bound = value
elsif relation == "<="
upper_bound = value + 1e-6
else
raise "invalid expression"
end
end
if lower_bound or upper_bound
output_layer = self.with_area(lower_bound, upper_bound)
end
self.data.min_coherence = self_min_coherence_state
return output_layer
end
def ext_constraint_satisfied(value, constraint)
output_bool = true
constraint.each do |expression|
if expression[0] == ">"
output_bool = output_bool && (value > expression[1])
elsif expression[0] == "<"
output_bool = output_bool && (value < expression[1])
elsif expression[0] == "=="
output_bool = output_bool && (value == expression[1])
elsif expression[0] == "!="
output_bool = output_bool && (value != expression[1])
elsif expression[0] == ">="
output_bool = output_bool && (value >= expression[1])
elsif expression[0] == "<="
output_bool = output_bool && (value <= expression[1])
else
raise "invalid expression"
end
end
return output_bool
end
def ext_covering(other)
self_min_coherence_state = self.data.min_coherence?
other_min_coherence_state = other.data.min_coherence?
self.data.min_coherence = true
other.data.min_coherence = true
output_layer = self.covering(other.inside(self))
self.data.min_coherence = self_min_coherence_state
other.data.min_coherence = other_min_coherence_state
return output_layer
end
def ext_separation(other,
value,
metric=RBA::Region::Euclidian,
consider_intersecting_edges=false,
consider_touch_points=false,
ignore_non_axis_aligned_edges=false,
min_angle=0,
max_angle=90,
include_min_angle=true,
include_max_angle=false,
polygons=false)
self_min_coherence_state = self.data.min_coherence?
other_min_coherence_state = other.data.min_coherence?
self.data.min_coherence = true
other.data.min_coherence = true
if metric.is_a?(DRC::DRCMetrics)
metric = metric.value
end
error_edge_pairs_90 = DRC::DRCLayer::new(@engine,
self.data.separation_check(other.data, value, false, metric, 90, 1, nil))
error_edge_pairs_180 = DRC::DRCLayer::new(@engine,
self.data.separation_check(other.data, value, false, metric, 180, nil, 1))
width_error_edge_pairs_90 = DRC::DRCLayer::new(@engine,
self.data.width_check(value, false, metric, 90, 1, nil) +
other.data.width_check(value, false, metric, 90, 1, nil))
width_error_edge_pairs_180 = DRC::DRCLayer::new(@engine,
self.data.width_check(value, false, metric, 180, nil, 1) +
other.data.width_check(value, false, metric, 180, nil, 1))
separation_errors = @engine.space_width_separation_overlap_check(
value,
error_edge_pairs_90,
error_edge_pairs_180,
width_error_edge_pairs_90,
width_error_edge_pairs_180,
{
consider_intersecting_edges: consider_intersecting_edges,
consider_touch_points: consider_touch_points,
ignore_non_axis_aligned_edges: ignore_non_axis_aligned_edges,
min_angle: min_angle,
max_angle: max_angle,
include_min_angle: include_min_angle,
include_max_angle: include_max_angle
}
)
self.data.min_coherence = self_min_coherence_state
other.data.min_coherence = other_min_coherence_state
if polygons
return separation_errors.polygons.merge(true, 0)
else
return separation_errors
end
end
def ext_fast_separation(other,
value,
metric: @engine.euclidian,
consider_intersecting_edges: true,
consider_touch_points: true,
ignore_non_axis_aligned_edges: false,
min_angle: 0,
max_angle: 90,
include_min_angle: true,
include_max_angle: false,
polygon_output: false)
self_min_coherence_state = self.data.min_coherence?
other_min_coherence_state = other.data.min_coherence?
self.data.min_coherence = true
other.data.min_coherence = true
output_layer = self.separation(other, value, metric, @engine.angle_limit(max_angle))
if !consider_intersecting_edges and !consider_touch_points
output_layer = output_layer.with_distance(1, nil)
if ignore_non_axis_aligned_edges
output_layer = output_layer.with_angle(@engine.ortho, @engine.both)
end
elsif consider_intersecting_edges ^ consider_touch_points
candidate_layer1 = self.interacting(output_layer.edges)
candidate_layer2 = other.interacting(output_layer.edges)
output_layer = candidate_layer1.ext_separation(
candidate_layer2,
value,
metric,
consider_intersecting_edges,
consider_touch_points,
ignore_non_axis_aligned_edges,
min_angle,
max_angle,
include_min_angle,
include_max_angle,
false)
end
self.data.min_coherence = self_min_coherence_state
other.data.min_coherence = other_min_coherence_state
if polygon_output
return output_layer.polygons.merge(true, 0)
else
return output_layer
end
end
def ext_not(other)
self_min_coherence_state = self.data.min_coherence?
other_min_coherence_state = other.data.min_coherence?
self.data.min_coherence = true
other.data.min_coherence = true
output_layer = self - other
self.data.min_coherence = self_min_coherence_state
other.data.min_coherence = other_min_coherence_state
return output_layer
end
def ext_or(other, *further_layers)
self_min_coherence_state = self.data.min_coherence?
other_min_coherence_state = other.data.min_coherence?
self.data.min_coherence = true
other.data.min_coherence = true
output_layer = self.join(other)
further_layers.each do |further_layer|
further_layer_min_coherence_state = further_layer.data.min_coherence?
further_layer.data.min_coherence = true
output_layer = output_layer.join(further_layer)
further_layer.data.min_coherence = further_layer_min_coherence_state
end
self.data.min_coherence = self_min_coherence_state
other.data.min_coherence = other_min_coherence_state
return output_layer
end
def ext_rectangles(axis_aligned = false, use_bbox = false, constraint1 = nil, constraint2 = nil, aspect_ratio_constraint = nil, inverted: false)
self_min_coherence_state = self.data.min_coherence?
self.data.min_coherence = true
if ( ( constraint1 && ( !constraint2 || constraint1.length() > 1 || constraint1[0][0] != "==") ) ||
( constraint2 && ( constraint2.length() > 1 || constraint2[0][0] != "==" ) ) ||
( constraint1 && constraint2 && constraint1[0][1] != constraint2[0][1] ) )
raise "ext_rectangle: unsupported options"
end
square = constraint1 ? true : false
shape_filter =
if use_bbox
@engine.extents
elsif axis_aligned
@engine.rectangles
else
@engine.if_all((@engine.corners == 270).count == 4, @engine.corners.count == 4)
end
if square
if use_bbox
shape_filter = @engine.if_all((@engine.extents.length == constraint1[0][1]).count == 4)
else
square_filter = (@engine.length == constraint1[0][1]).count == 4
shape_filter = @engine.if_all(shape_filter, square_filter)
end
end
if inverted
output_layer = self.drc(! shape_filter)
else
output_layer = self.drc(shape_filter)
end
self.data.min_coherence = self_min_coherence_state
return output_layer
end
def ext_space(value,
metric=RBA::Region::Euclidian,
consider_intersecting_edges=false,
consider_touch_points=false,
ignore_non_axis_aligned_edges=false,
min_angle=0,
max_angle=90,
include_min_angle=true,
include_max_angle=false,
polygons=false)
self_min_coherence_state = self.data.min_coherence?
self.data.min_coherence = true
if metric.is_a?(DRC::DRCMetrics)
metric = metric.value
end
error_edge_pairs_90 = DRC::DRCLayer::new(@engine, self.data.space_check(value, false, metric, 90, 1, nil))
error_edge_pairs_180 = DRC::DRCLayer::new(@engine, self.data.space_check(value, false, metric, 180, nil, 1))
width_error_edge_pairs_90 = DRC::DRCLayer::new(@engine, self.data.width_check(value, false, metric, 90, 1, nil))
width_error_edge_pairs_180 = DRC::DRCLayer::new(@engine, self.data.width_check(value, false, metric, 180, nil, 1))
space_errors = @engine.space_width_separation_overlap_check(
value,
error_edge_pairs_90,
error_edge_pairs_180,
width_error_edge_pairs_90,
width_error_edge_pairs_180,
{
consider_intersecting_edges: consider_intersecting_edges,
consider_touch_points: consider_touch_points,
ignore_non_axis_aligned_edges: ignore_non_axis_aligned_edges,
min_angle: min_angle,
max_angle: max_angle,
include_min_angle: include_min_angle,
include_max_angle: include_max_angle
}
)
self.data.min_coherence = self_min_coherence_state
if polygons
return space_errors.polygons.merge(true, 0)
else
return space_errors
end
end
def ext_fast_space(value,
metric: @engine.euclidian,
consider_intersecting_edges: true,
consider_touch_points: true,
ignore_non_axis_aligned_edges: false,
min_angle: 0,
max_angle: 90,
include_min_angle: true,
include_max_angle: false,
polygon_output: false)
self_min_coherence_state = self.data.min_coherence?
self.data.min_coherence = true
output_layer = self.space(value, metric, @engine.angle_limit(max_angle))
if !consider_intersecting_edges and !consider_touch_points
output_layer = output_layer.with_distance(1, nil)
if ignore_non_axis_aligned_edges
output_layer = output_layer.with_angle(@engine.ortho, @engine.both)
end
elsif consider_intersecting_edges ^ consider_touch_points
candidate_layer = self.interacting(output_layer.edges)
output_layer = candidate_layer.ext_space(
value,
metric,
consider_intersecting_edges,
consider_touch_points,
ignore_non_axis_aligned_edges,
min_angle,
max_angle,
include_min_angle,
include_max_angle,
false)
end
self.data.min_coherence = self_min_coherence_state
if polygon_output
return output_layer.polygons.ext_merge(true, 0)
else
return output_layer
end
end
def ext_fast_width(value, polygon_output: false)
self_min_coherence_state = self.data.min_coherence?
self.data.min_coherence = true
output_layer = self.width(value)
self.data.min_coherence = self_min_coherence_state
if polygon_output
return output_layer.polygons.ext_merge(true, 0)
else
return output_layer
end
end
def ext_interacting_with_text(text_layer, text)
if text_layer.is_a? Integer
text_layer = @engine.labels(text_layer)
end
initial_merged_semantics = self.data.merged_semantics?
self.data.merged_semantics = false
result = self.interacting(text_layer.texts(text))
self.data.merged_semantics = initial_merged_semantics
return result
end
def ext_with_density(range, *args)
if self.is_empty?
return DRC::DRCLayer::new(@engine, RBA::Region::new())
end
if self.is_merged?
merged_layer = self
else
merged_layer = self.ext_merged(true, 0)
end
origin = 'cc'
tile_size = nil
tile_step = nil
arguments = [range]
args.each do |a|
if a.is_a?(DRC::DRCTileSize)
tile_size = a
arguments.push(tile_size)
elsif a.is_a?(DRC::DRCTileStep)
tile_step = a
arguments.push(tile_step)
elsif a.is_a?(String)
origin = a
else
raise "argument error"
end
end
bbox = @engine.extent.bbox
if origin == 'll'
origin_x = bbox.left
origin_y = bbox.bottom
if tile_size and tile_step and (tile_size.get[0] != tile_step.get[0] or tile_size.get[1] != tile_step.get[1])
origin_x = bbox.left + tile_step.get[0]/2
origin_y = bbox.bottom + tile_step.get[1]/2
end
tile_origin = DRC::DRCTileOrigin::new(origin_x, origin_y)
arguments.push(tile_origin)
elsif origin != 'cc'
raise "Unknown origin: 'cc' or 'll' expected"
end
if tile_size
boundary_layer = DRC::DRCLayer::new(@engine, RBA::Region::new(bbox.to_itype(@engine.dbu)))
tile_boundary = DRC::DRCTileBoundary::new(boundary_layer)
return merged_layer.with_density(*arguments, tile_boundary, @engine.padding_ignore)
else
tile_size = DRC::DRCTileSize::new(bbox.width, bbox.height)
tile_count = DRC::DRCTileCount::new(1,2)
enlarged_bbox = bbox.enlarged(1.1).to_itype(@engine.dbu)
boundary_layer = DRC::DRCLayer::new(@engine, RBA::Region::new(enlarged_bbox))
tile_boundary = DRC::DRCTileBoundary::new(boundary_layer)
result = merged_layer.with_density(*arguments, tile_size, tile_count, tile_boundary, @engine.padding_ignore)
return result.raw.overlapping(DRC::DRCLayer::new(@engine, RBA::Region::new(bbox.to_itype(@engine.dbu))))
end
end
end
Activ = source.polygons("1/0")
Activ_pin = source.polygons("1/2")
Activ_filler = source.polygons("1/22")
BiWind = source.polygons("3/0")
GatPoly = source.polygons("5/0")
GatPoly_pin = source.polygons("5/2")
GatPoly_filler = source.polygons("5/22")
Cont = source.polygons("6/0")
Metal1 = source.polygons("8/0")
Metal1_pin = source.polygons("8/2")
Metal1_filler = source.polygons("8/22")
Metal1_slit = source.polygons("8/24")
Passiv = source.polygons("9/0")
Metal2 = source.polygons("10/0")
Metal2_pin = source.polygons("10/2")
Metal2_filler = source.polygons("10/22")
Metal2_slit = source.polygons("10/24")
BasPoly = source.polygons("13/0")
Via1 = source.polygons("19/0")
SRAM = source.polygons("25/0")
TRANS = source.polygons("26/0")
Via2 = source.polygons("29/0")
Metal3 = source.polygons("30/0")
Metal3_pin = source.polygons("30/2")
Metal3_filler = source.polygons("30/22")
Metal3_slit = source.polygons("30/24")
DeepCo = source.polygons("35/0")
EdgeSeal = source.polygons("39/0")
ThickGateOx = source.polygons("44/0")
Via3 = source.polygons("49/0")
Metal4 = source.polygons("50/0")
Metal4_pin = source.polygons("50/2")
Metal4_filler = source.polygons("50/22")
Metal4_slit = source.polygons("50/24")
EmPoly = source.polygons("55/0")
TEXT_0 = source.labels("63/0")
Via4 = source.polygons("66/0")
Metal5 = source.polygons("67/0")
Metal5_pin = source.polygons("67/2")
Metal5_filler = source.polygons("67/22")
Metal5_slit = source.polygons("67/24")
TopVia1 = source.polygons("125/0")
TopMetal1 = source.polygons("126/0")
TopMetal1_pin = source.polygons("126/2")
TopMetal1_filler = source.polygons("126/22")
TopMetal1_slit = source.polygons("126/24")
Vmim = source.polygons("129/0")
TopVia2 = source.polygons("133/0")
TopMetal2 = source.polygons("134/0")
TopMetal2_pin = source.polygons("134/2")
TopMetal2_filler = source.polygons("134/22")
TopMetal2_slit = source.polygons("134/24")
ColWind = source.polygons("139/0")
LBE = source.polygons("157/0")
if $sanityRules
PEmWind = source.polygons("11/0")
PEmPoly = source.polygons("53/0")
LDMOS = source.polygons("57/0")
PBiWind = source.polygons("58/0")
Flash = source.polygons("71/0")
end
Activ_Act_a = Activ.ext_fast_width(0.15.um)
Act_density = Activ.ext_or(Activ_filler)
Gat_density = GatPoly.ext_or(GatPoly_filler)
Cont_SQ = Cont.ext_rectangles(true, false, [["==", 0.16.um]], [["==", 0.16.um]], nil)
ContBar = Cont.ext_with_area([[">", (0.16*0.16).um2]])
Act_Nsram = Activ.ext_not(SRAM)
GP_Nsram = GatPoly.ext_not(SRAM)
M1_Nsram = Metal1.ext_not(SRAM)
M2_Nsram = Metal2.ext_not(SRAM)
M3_Nsram = Metal3.ext_not(SRAM)
Via1_edgC1_out = Via1.ext_not(EdgeSeal)
Via2_edgC1_out = Via2.ext_not(EdgeSeal)
Cont_outside_EdgeSeal = Cont.outside(EdgeSeal)
ThickGateOx_TGO_f = ThickGateOx.ext_fast_width(0.86.um, polygon_output: true)
Via3_edgC1_out = Via3.ext_not(EdgeSeal)
M4_Nsram = Metal4.ext_not(SRAM)
Via4_edgC1_out = Via4.ext_not(EdgeSeal)
M5_Nsram = Metal5.ext_not(SRAM)
TopVia1_edgC1_out = TopVia1.ext_not(EdgeSeal)
TopVia1_or_Vmim = TopVia1.ext_or(Vmim)
TopVia2_edgC1_out = TopVia2.ext_not(EdgeSeal)
M1_density = Metal1.ext_or(Metal1_filler).ext_not(Metal1_slit)
M2_density = Metal2.ext_or(Metal2_filler).ext_not(Metal2_slit)
emi2Pin = Metal2_pin.ext_and(TRANS).ext_interacting_with_text(TEXT_0, "E")
M3_density = Metal3.ext_or(Metal3_filler).ext_not(Metal3_slit)
M4_density = Metal4.ext_or(Metal4_filler).ext_not(Metal4_slit)
M5_density = Metal5.ext_or(Metal5_filler).ext_not(Metal5_slit)
TM1_density = TopMetal1.ext_or(TopMetal1_filler).ext_not(TopMetal1_slit)
TM2_density = TopMetal2.ext_or(TopMetal2_filler).ext_not(TopMetal2_slit)
GP_Nsram_Gat_a = GP_Nsram.ext_fast_width(0.13.um, polygon_output: true)
GP_Nsram_Gat_b = GP_Nsram.ext_fast_space(0.18.um, consider_intersecting_edges: false, polygon_output: true)
transG2L = TRANS.ext_interacting_with_text(TEXT_0, "npn13G2L").ext_covering(emi2Pin)
-> do
Activ_Act_a.dup
end.().output("Act.a", "Min. Activ width = 0.15")
-> do
Act_Nsram.ext_fast_space(0.21.um)
end.().output("Act.b", "Min. Activ space or notch = 0.21")
if $density
#-> do
# Act_density.ext_with_density(0.0 .. 0.35, 'll')
#end.().output("AFil.g", "Min. global Activ density [%] = 35.00")
-> do
Act_density.ext_with_density(0.55 .. 1.0, 'll')
end.().output("AFil.g1", "Max. global Activ density [%] = 55.00")
#-> do
# Act_density.ext_with_density(0.0 .. 0.25, 'll', tile_size(800.0.um), tile_step(400.0.um))
#end.().output("AFil.g2", "Min. Activ coverage ratio for any 800 x 800 µm² chip area [%] = 25.00")
-> do
Act_density.ext_with_density(0.65 .. 1.0, 'll', tile_size(800.0.um), tile_step(400.0.um))
end.().output("AFil.g3", "Max. Activ coverage ratio for any 800 x 800 µm² chip area [%] = 65.00")
end
-> do
ThickGateOx_TGO_f.dup
end.().output("TGO.f", "Min. ThickGateOx width = 0.86")
-> do
GP_Nsram_Gat_a.dup
end.().output("Gat.a", "Min. GatPoly width = 0.13")
-> do
GP_Nsram_Gat_b.dup
end.().output("Gat.b", "Min. GatPoly space or notch = 0.18")
-> do
GP_Nsram.ext_fast_separation(Act_Nsram, 0.07.um)
end.().output("Gat.d", "Min. GatPoly space to Activ = 0.07")
if $density
#-> do
# Gat_density.ext_with_density(0.0 .. 0.15, 'll')
#end.().output("GFil.g", "Min. global GatPoly density [%] = 15.00")
end
-> do
Cont_outside_EdgeSeal.ext_not(ContBar.ext_or(Cont_SQ))
end.().output("Cnt.a", "Min. and max. Cont width = 0.16")
-> do
Cont_outside_EdgeSeal.ext_fast_space(0.18.um, consider_intersecting_edges: false)
end.().output("Cnt.b", "Min. Cont space = 0.18")
-> do
Metal1.ext_fast_width(0.16.um)
end.().output("M1.a", "Min. Metal1 width = 0.16")
-> do
M1_Nsram.ext_fast_space(0.18.um, consider_intersecting_edges: false, ignore_non_axis_aligned_edges: true)
end.().output("M1.b", "Min. Metal1 space or notch = 0.18")
if $density
#-> do
# M1_density.ext_with_density(0.0 .. 0.35, 'll')
#end.().output("M1.j", "Min. global Metal1 density [%] = 35.0")
-> do
M1_density.ext_with_density(0.6 .. 1.0, 'll')
end.().output("M1.k", "Max. global Metal1 density [%] = 60.0")
end
-> do
Metal2.ext_fast_width(0.2.um)
end.().output("M2.a", "Min. Metal2 width = 0.20")
-> do
M2_Nsram.ext_fast_space(0.21.um, consider_intersecting_edges: false, ignore_non_axis_aligned_edges: true)
end.().output("M2.b", "Min. Metal2 space or notch = 0.21")
if $density
#-> do
# M2_density.ext_with_density(0.0 .. 0.35, 'll')
#end.().output("M2.j", "Min. global Metal2 density [%] = 35.00")
-> do
M2_density.ext_with_density(0.6 .. 1.0, 'll')
end.().output("M2.k", "Max. global Metal2 density [%] = 60.00")
end
-> do
Metal3.ext_fast_width(0.2.um)
end.().output("M3.a", "Min. Metal3 width = 0.20")
-> do
M3_Nsram.ext_fast_space(0.21.um, consider_intersecting_edges: false, ignore_non_axis_aligned_edges: true)
end.().output("M3.b", "Min. Metal3 space or notch = 0.21")
if $density
#-> do
# M3_density.ext_with_density(0.0 .. 0.35, 'll')
#end.().output("M3.j", "Min. global Metal3 density [%] = 35.00")
-> do
M3_density.ext_with_density(0.6 .. 1.0, 'll')
end.().output("M3.k", "Max. global Metal3 density [%] = 60.00")
end
-> do
Metal4.ext_fast_width(0.2.um)
end.().output("M4.a", "Min. Metal4 width = 0.20")
-> do
M4_Nsram.ext_fast_space(0.21.um, consider_intersecting_edges: false, ignore_non_axis_aligned_edges: true)
end.().output("M4.b", "Min. Metal4 space or notch = 0.21")
if $density
#-> do
# M4_density.ext_with_density(0.0 .. 0.35, 'll')
#end.().output("M4.j", "Min. global Metal4 density [%] = 35.00")
-> do
M4_density.ext_with_density(0.6 .. 1.0, 'll')
end.().output("M4.k", "Max. global Metal4 density [%] = 60.00")
end
-> do
Metal5.ext_fast_width(0.2.um)
end.().output("M5.a", "Min. Metal5 width = 0.20")
-> do
M5_Nsram.ext_fast_space(0.21.um, consider_intersecting_edges: false, ignore_non_axis_aligned_edges: true)
end.().output("M5.b", "Min. Metal5 space or notch = 0.21")
if $density
#-> do
# M5_density.ext_with_density(0.0 .. 0.35, 'll')
#end.().output("M5.j", "Min. global Metal5 density [%] = 35.00")
-> do
M5_density.ext_with_density(0.6 .. 1.0, 'll')
end.().output("M5.k", "Max. global Metal5 density [%] = 60.00")
#-> do
# M1_density.ext_with_density(0.0 .. 0.25, 'll', tile_size(800.0.um), tile_step(400.0.um))
#end.().output("M1Fil.h", "Min. Metal1 and Metal1:filler coverage ratio for any 800 x 800 µm² chip area [%] = 25.00")
-> do
M1_density.ext_with_density(0.75 .. 1.0, 'll', tile_size(800.0.um), tile_step(400.0.um))
end.().output("M1Fil.k", "Max. Metal1 and Metal1:filler coverage ratio for any 800 x 800 µm² chip area [%] = 75.00")
#-> do
# M2_density.ext_with_density(0.0 .. 0.25, 'll', tile_size(800.0.um), tile_step(400.0.um))
#end.().output("M2Fil.h", "Min. Metal2 and Metal2:filler coverage ratio for any 800 x 800 µm² chip area [%] = 25.00")
-> do
M2_density.ext_with_density(0.75 .. 1.0, 'll', tile_size(800.0.um), tile_step(400.0.um))
end.().output("M2Fil.k", "Max. Metal2 and Metal2:filler coverage ratio for any 800 x 800 µm² chip area [%] = 75.00")
#-> do
# M3_density.ext_with_density(0.0 .. 0.25, 'll', tile_size(800.0.um), tile_step(400.0.um))
#end.().output("M3Fil.h", "Min. Metal3 and Metal3:filler coverage ratio for any 800 x 800 µm² chip area [%] = 25.00")
-> do
M3_density.ext_with_density(0.75 .. 1.0, 'll', tile_size(800.0.um), tile_step(400.0.um))
end.().output("M3Fil.k", "Max. Metal3 and Metal3:filler coverage ratio for any 800 x 800 µm² chip area [%] = 75.00")
#-> do
# M4_density.ext_with_density(0.0 .. 0.25, 'll', tile_size(800.0.um), tile_step(400.0.um))
#end.().output("M4Fil.h", "Min. Metal4 and Metal4:filler coverage ratio for any 800 x 800 µm² chip area [%] = 25.00")
-> do
M4_density.ext_with_density(0.75 .. 1.0, 'll', tile_size(800.0.um), tile_step(400.0.um))
end.().output("M4Fil.k", "Max. Metal4 and Metal4:filler coverage ratio for any 800 x 800 µm² chip area [%] = 75.00")
#-> do
# M5_density.ext_with_density(0.0 .. 0.25, 'll', tile_size(800.0.um), tile_step(400.0.um))
#end.().output("M5Fil.h", "Min. Metal5 and Metal5:filler coverage ratio for any 800 x 800 µm² chip area [%] = 25.00")
-> do
M5_density.ext_with_density(0.75 .. 1.0, 'll', tile_size(800.0.um), tile_step(400.0.um))
end.().output("M5Fil.k", "Max. Metal5 and Metal5:filler coverage ratio for any 800 x 800 µm² chip area [%] = 75.00")
end
-> do
Via1_edgC1_out.outside(transG2L).ext_rectangles(false, false, [["==", 0.19.um]], [["==", 0.19.um]], nil, inverted: true)
end.().output("V1.a", "Min. and max. Via1 width = 0.19")
-> do
Via1_edgC1_out.ext_fast_space(0.22.um, consider_intersecting_edges: false)
end.().output("V1.b", "Min. Via1 space = 0.22")
-> do
Via2_edgC1_out.outside(transG2L).ext_rectangles(false, false, [["==", 0.19.um]], [["==", 0.19.um]], nil, inverted: true)
end.().output("V2.a", "Min. and max. Via2 width = 0.19")
-> do
Via2_edgC1_out.ext_fast_space(0.22.um, consider_intersecting_edges: false)
end.().output("V2.b", "Min. Via2 space = 0.22")
-> do
Via3_edgC1_out.outside(transG2L).ext_rectangles(false, false, [["==", 0.19.um]], [["==", 0.19.um]], nil, inverted: true)
end.().output("V3.a", "Min. and max. Via3 width = 0.19")
-> do
Via3_edgC1_out.ext_fast_space(0.22.um, consider_intersecting_edges: false)
end.().output("V3.b", "Min. Via3 space = 0.22")
-> do
Via4_edgC1_out.outside(transG2L).ext_rectangles(false, false, [["==", 0.19.um]], [["==", 0.19.um]], nil, inverted: true)
end.().output("V4.a", "Min. and max. Via4 width = 0.19")
-> do
Via4_edgC1_out.ext_fast_space(0.22.um, consider_intersecting_edges: false)
end.().output("V4.b", "Min. Via4 space = 0.22")
-> do
TopVia1_edgC1_out.ext_or(Vmim).ext_rectangles(false, false, [["==", 0.42.um]], [["==", 0.42.um]], nil, inverted: true)
end.().output("TV1.a", "Min. and max. TopVia1 width = 0.42")
-> do
TopVia1_or_Vmim.ext_fast_space(0.42.um)
end.().output("TV1.b", "Min. TopVia1 space = 0.42")
-> do
TopMetal1.ext_fast_width(1.64.um)
end.().output("TM1.a", "Min. TopMetal1 width = 1.64")
-> do
TopMetal1.ext_fast_space(1.64.um)
end.().output("TM1.b", "Min. TopMetal1 space or notch = 1.64")
if $density
#-> do
# TM1_density.ext_with_density(0.0 .. 0.25, 'll')
#end.().output("TM1.c", "Min. global TopMetal1 density [%] = 25.00")
-> do
TM1_density.ext_with_density(0.7 .. 1.0, 'll')
end.().output("TM1.d", "Max. global TopMetal1 density [%] = 70.00")
end
-> do
TopVia2_edgC1_out.ext_rectangles(false, false, [["==", 0.9.um]], [["==", 0.9.um]], nil, inverted: true)
end.().output("TV2.a", "Min. and max. TopVia2 width = 0.90")
-> do
TopVia2.ext_fast_space(1.06.um)
end.().output("TV2.b", "Min. TopVia2 space = 1.06")
-> do
TopMetal2.ext_fast_width(2.0.um)
end.().output("TM2.a", "Min. TopMetal2 width = 2.00")
-> do
TopMetal2.ext_fast_space(2.0.um)
end.().output("TM2.b", "Min. TopMetal2 space or notch = 2.00")
if $density
#-> do
# TM2_density.ext_with_density(0.0 .. 0.25, 'll')
#end.().output("TM2.c", "Min. global TopMetal2 density [%] = 25.00")
-> do
TM2_density.ext_with_density(0.7 .. 1.0, 'll')
end.().output("TM2.d", "Max. global TopMetal2 density [%] = 70.00")
end
-> do
Passiv.ext_fast_width(2.1.um)
end.().output("Pas.a", "Min. Passiv width = 2.10")
-> do
Passiv.ext_fast_space(3.5.um)
end.().output("Pas.b", "Min. Passiv space or notch = 3.50")
if $sanityRules
-> do
Activ_pin.ext_not(Activ)
end.().output("Pin.a", "Min. Activ enclosure of Activ:pin = 0.00")
-> do
GatPoly_pin.ext_not(GatPoly)
end.().output("Pin.b", "Min. GatPoly enclosure of GatPoly:pin = 0.00")
-> do
Metal1_pin.ext_not(Metal1)
end.().output("Pin.e", "Min. Metal1 enclosure of Metal1:pin = 0.00")
-> do
Metal2_pin.ext_not(Metal2)
end.().output("Pin.f.M2", "Min. Metal2 enclosure of Metal2:pin = 0.00")
-> do
Metal3_pin.ext_not(Metal3)
end.().output("Pin.f.M3", "Min. Metal3 enclosure of Metal3:pin = 0.00")
-> do
Metal4_pin.ext_not(Metal4)
end.().output("Pin.f.M4", "Min. Metal4 enclosure of Metal4:pin = 0.00")
-> do
Metal5_pin.ext_not(Metal5)
end.().output("Pin.f.M5", "Min. Metal5 enclosure of Metal5:pin = 0.00")
-> do
TopMetal1_pin.ext_not(TopMetal1)
end.().output("Pin.g", "Min. TopMetal1 enclosure of TopMetal1:pin = 0.00")
-> do
TopMetal2_pin.ext_not(TopMetal2)
end.().output("Pin.h", "Min. TopMetal2 enclosure of TopMetal2:pin = 0.00")
end
-> do
LBE.ext_fast_width(100.0.um)
end.().output("LBE.a", "Min. LBE width = 100.00")
-> do
LBE.drc((width(projection) > 1500.0.um).polygons)
end.().output("LBE.b", "Max. LBE width = 1500.00")
-> do
LBE.ext_with_area([[">", 250000.0.um2]])
end.().output("LBE.b1", "Max. LBE area (µm²) = 250000.00")
-> do
LBE.ext_fast_space(100.0.um, consider_intersecting_edges: false, ignore_non_axis_aligned_edges: true)
end.().output("LBE.c", "Min. LBE space or notch = 100.00")
-> (;lbe_in_seal) do
lbe_in_seal = LBE.inside(EdgeSeal.holes.merge)
lbe_in_seal.ext_fast_separation(EdgeSeal, 150.0.um, consider_intersecting_edges: false, ignore_non_axis_aligned_edges: true)
end.().output("LBE.d", "Min. LBE space to inner edge of EdgeSeal = 150.00")
-> do
LBE.with_holes.dup
end.().output("LBE.h", "No LBE ring allowed")
if $density
-> do
LBE.ext_with_density(0.2 .. 1.0, 'll')
end.().output("LBE.i", "Max. global LBE density [%] = 20.00")
end
if $sanityRules
-> do
BiWind.dup
end.().output("forbidden.BiWind", "Forbidden drawn layer BiWind on GDS layer 3/0 = 3/0")
-> do
PEmWind.dup
end.().output("forbidden.PEmWind", "Forbidden drawn layer PEmWind on GDS layer 11/0 = 11/0")
-> do
BasPoly.dup
end.().output("forbidden.BasPoly", "Forbidden drawn layer BasPoly on GDS layer 13/0 = 13/0")
-> do
DeepCo.dup
end.().output("forbidden.DeepCo", "Forbidden drawn layer DeepCo on GDS layer 35/0 = 35/0")
-> do
PEmPoly.dup
end.().output("forbidden.PEmPoly", "Forbidden drawn layer PEmPoly on GDS layer 53/0 = 53/0")
-> do
EmPoly.dup
end.().output("forbidden.EmPoly", "Forbidden gen./drawn layer EmPoly on GDS layer 53/0 = 53/0")
-> do
LDMOS.dup
end.().output("forbidden.LDMOS", "Forbidden drawn layer LDMOS on GDS layer 57/0 = 57/0")
-> do
PBiWind.dup
end.().output("forbidden.PBiWind", "Forbidden drawn layer PBiWind on GDS layer 58/0 = 58/0")
-> do
Flash.dup
end.().output("forbidden.Flash", "Forbidden drawn layer Flash on GDS layer 71/0 = 71/0")
-> do
ColWind.dup
end.().output("forbidden.ColWind", "Forbidden drawn layer ColWind on GDS layer 139/0 = 139/0")
end
puts("Number of DRC errors: #{$drc_error_count}")