blob: 060f38fa503e63dd72399194339f69a5cbdecbe0 [file] [log] [blame]
print STDERR "DRC Expander - expands the DRC rules in MAGIC tech files and annotates the layers that might cause the DRC issues\n";
# Original tech file:
my $tech=$ARGV[0] || "/usr/local/lib/magic/sys/sky130A.tech";
my $expand=0;
my $debug=0;
my $createrules=0; # Create code for rules instead of expanding the tech file
print STDERR "Processing the original tech file: $tech\n";
#our %contacts=();
our %alias=();
# Required DRC rules for SKY130: area,cifmaxwidth,edge4way,exact_overlap,extend,overhang,rect_only,spacing,surround,width
my $rules=<<EOF
surround types1 types2 distance presence error
widespacing types1 wwidth types2 distance flavor error
spacing types1 types2 distance adjacency error
width type-list width error
overhang types1 types2 distance error
extend types1 types2 distance error
rect_only types error
angles types allowed why
edge types1 types2 d OKTypes cornerTypes cornerDist error [plane]
edge4way types1 types2 d OKTypes cornerTypes cornerDist error [plane]
exact_overlap type-list
no_overlap type-list1 type-list2
off_grid types pitch why
area types minarea minedge why
maxwidth layers mwidth [bends] why
cifwidth layer width why
cifspacing layer1 layer2 separation adjacency why
cifarea layer minarea minedge why
cifmaxwidth layer mwidth [bends] why
EOF
;
print STDERR "Extracting optional arguments:\n";
my @erules=();
foreach my $line(split "\n",$rules)
{
if($line=~m/\[/)
{
my $a=$line; $a=~s/\[\w+\]//;
my $b=$line; $b=~s/\[//; $b=~s/\]//;
#print "A: $a\nB: $b\n";
push @erules,$a;
push @erules,$b;
}
else
{
#print "R: $line\n";
push @erules,$line;
}
}
print STDERR "Handling rules:\n";
foreach my $rule (@erules)
{
print STDERR " # Rule: $rule\n";
my @a=split " ",$rule;
my $kind=shift @a;
#print "Kind:$kind\n";
my $regexp="^\\s*($kind)";
my @types=("zero","other");
my @typelists=();
foreach(@a)
{
$regexp.="\\s+";
if($_=~m/^(types|type-list|layer|OKTypes)/)
{
$regexp.="(\\S+)";
push @types,"type-list";
}
elsif($_=~m/^(why|error)/)
{
$regexp.="\"([^\"]*)\"";
push @types,"why";
}
else
{
$regexp.="(\\S+)";
push @types,"other";
}
}
next unless($createrules);
$regexp.="\\s*\$";
print " if(m/$regexp/)\n {\n";
print ' print " # ORIGINAL RULE:$oneline\n";'."\n";
foreach(2 .. scalar(@types)-1)
{
print " my \$vl$_=\$$_;\n" if($types[$_] eq "type-list");
print " my \$l$_=join \" \",allLayers(\$vl$_);\n" if($types[$_] eq "type-list");
# print " print STDERR \"L$_: \$vl$_ -> \$l$_\n\" if(\$debug);\n" if($types[$_] eq "type-list");
print " my \$text=\$$_;\n" if($types[$_] eq "why");
push @typelists,$_ if($types[$_] eq "type-list");
}
print " print \" ";
foreach(1 .. scalar(@types)-1)
{
print "\$$_ " if($types[$_] eq "other");
print "\$vl$_ " if($types[$_] eq "type-list");
if($types[$_] eq "why")
{
print "\\\"\$$_ ";
#print "[erase ".join(",",@typelists)."]";
foreach my $tl (@typelists)
{
print "[erase \$l$tl]";
}
print "\\\"";
}
}
print "\\n\";\n";
print " }\n";
print "\n";
# $1 $vl1 $vl2 $4 $5 \"$6 [erase $l1]".(($vl1 eq $vl2)?"":"[erase $l2]")."\"\n";
}
exit if($createrules);
#magic: tech layers allli
# At first we are reading through the original tech file to search for all the virtual layers that need to be expanded
open IN,"<$tech";
while(<IN>)
{
s/\\//g;
if(m/^\s*(spacing|surround)\s+(\S+)\s+(\S+)\s+/)
{
my $a2=$2;
my $a3=$3;
$alias{$a2}=1;
$alias{$a3}=1;
foreach(split(",",$a2))
{
$alias{$_}=1;
$alias{$1}=1 if(m/^([^\/]+)/);
}
foreach(split(",",$a3))
{
$alias{$_}=1;
$alias{$1}=1 if(m/^([^\/]+)/);
}
}
# Rule: width type-list width error
if(m/^\s*(width)\s+(\S+)\s+(\S+)\s+"([^"]*)"\s*$/)
{
$alias{$2}=1;
foreach(split(",",$2))
{
$alias{$_}=1;
}
}
}
close IN;
if($debug)
{
print STDERR "BEFORE:\n";
foreach(sort keys %alias)
{
print STDERR "$_ -> $alias{$_}\n";
}
}
# No we are asking magic what those virtual layers actually mean
if(open OUT,"|magic -dnull -noconsole -T $tech >magic.layers.out")
{
print OUT "puts \"CUT HERE -------- CUT HERE\"\n";
foreach(sort keys %alias)
{
print OUT "puts \"EXPANDING: $_\"\n";
print OUT "puts [tech layers $_]\n";
}
print OUT "puts \"CUT HERE -------- CUT HERE\"\n";
print OUT "quit -noprompt\n";
close OUT;
# Now we are retrieving the answer from Magic:
if(open IN,"<magic.layers.out")
{
while(<IN>)
{
if(m/^EXPANDING: (\S+)/)
{
my $next=<IN>;
chomp $next;
$alias{$1}=$next;
}
}
close IN;
}
else
{
die "Could not get the results from magic!\n";
}
}
else
{
die "Could not run magic!\n";
}
if($debug)
{
print STDERR "\n\nAFTER:\n";
foreach(sort keys %alias)
{
print STDERR "$_ -> $alias{$_}\n";
}
exit;
}
open IN,"<$tech";
# This function expands a single layer-list into all the physical layers it means
sub allLayers($)
{
#if($_[0] !~ m/\//) # If we do not look for "images" (which are signalled by / in the typelist and are currently not supported by magic), then we can just use the whole typelist which is more efficient.
#{
#return split " ",$alias{$_[0]} ;
#}
my @a=split ",",$_[0];
my %b=();
foreach(@a)
{
print STDERR "piece: $_\n" if($debug);
if(m/(\/\S+)/ && defined($alias{$_}) && $alias{$_})
{
print STDERR "WE FOUND A SLASH AND AN ALIAS\n" if($debug);
my $image=$1;
foreach my $part(split " ",$alias{$_})
{
print STDERR "PART: $part\n" if($debug);
$b{$part.(($part =~ m/\//)?"":$image)}=1;
}
}
elsif(m/^([^\/]+)(\/\S+)/) # This is a workaround for bugs in magic that hopefully get fixed
{
print STDERR "WE FOUND A SLASH BUT NO ALIAS\n" if($debug);
my $image=$2;
my $short=$1;
foreach my $part(split " ",$alias{$short})
{
print STDERR "PART: $part\n" if($debug);
$b{$part.$image}=1;
}
}
else
{
print STDERR "NO SLASH OR ALIAS\n" if($debug);
foreach my $part(split " ",$alias{$_})
{
$b{$part}=1;
}
}
}
return sort keys %b;
}
my $section="";
our %drckind=();
# Finally we are processing the whole tech file and annotating the rules:
while(<IN>)
{
while($_=~m/\\$/)
{
$_.=<IN>;
}
if(m/^(\w+)/)
{
$section=$1;
}
# if($section eq "contact" && m/^\s+(\w+)/)
#{
# my $a=$_;
# $a=~s/^\s+//; $a=~s/\s+$//;
# my @a=split(/\s+/,$a);
# my $cont=shift(@a);
# foreach my $cnt(@a)
# {
# print STDERR "CONTACT: $cont -> $cnt\n";
# $contacts{$cont}{$cnt}=1;
# $contacts{$cnt}{$cont}=1;
# }
#}
#if($section eq "aliases" && m/^\s+(\w+)/)
#{
# my $a=$_;
# $a=~s/^\s+//; $a=~s/\s+$//;
# my @a=split(/\s+/,$a);
# my $cont=shift(@a);
# foreach my $cnt(@a)
# {
# print STDERR "ALIAS: $cont -> $cnt\n";
# $alias{$cont}=$cnt;
# }
#}
my $oneline=$_;
$oneline=~s/\n//sg;
tr/\\//;
if($section eq "drc")
{
if(m/^\s*(\w+)/)
{
$drckind{$1}=1;
}
}
if(m/^\s*(spacing|surround)\s+(\S+)\s+(\S+)\s+(\d+)\s+\\?\s*(\w+)\s+\\?\s*"([^"]+)"/)
{
#print " # ORIGINAL RULE:$oneline\n";
my $vl1=$2;
my $vl2=$3;
my $text=$6;
my $l1=join " ",allLayers($vl1);
print STDERR "L1: $vl1 -> $l1\n" if($debug);
my $l2=join " ",allLayers($vl2);
print STDERR "L2: $vl2 -> $l2\n" if($debug);
if($expand)
{
foreach my $layer1(allLayers($vl1))
{
foreach my $layer2(allLayers($vl2))
{
#print " $1 $layer1 $layer2 $4 $5 \"$6 [erase $layer1]".(($layer1 eq $layer2)?"":"[erase $layer2]")."\"\n";
}
}
}
else
{
print " $1 $vl1 $vl2 $4 $5 \"$6 [erase $l1".(($vl1 eq $vl2)?"":",$l2")."]\"\n";
}
#print "\n";
}
# Rule: width type-list width error
elsif(m/^\s*(width)\s+(\S+)\s+(\S+)\s+"([^"]*)"\s*$/)
{
print " # ORIGINAL RULE:$oneline\n";
my $vl2=$2;
print STDERR "ALLLAYERS $vl2\n" if($debug);
my $l2=join ",",allLayers($vl2); # For painting we need a different strategy to try each layer individually
print STDERR "INFO: vl2=$vl2 l2=$l2\n" if($debug);
my $text=$4;
print " $1 $vl2 $3 \"$4 [paint $l2]\"\n";
}
else
{
print $_;
}
}
close IN;
print STDERR "".join(",", sort keys %drckind)."\n";