Added a DRC expander
diff --git a/scripts/drcexpander.pl b/scripts/drcexpander.pl
new file mode 100644
index 0000000..8a70d45
--- /dev/null
+++ b/scripts/drcexpander.pl
@@ -0,0 +1,324 @@
+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+/)
+  {
+    $alias{$2}=1;
+    $alias{$3}=1;
+    foreach(split(",",$2))
+    {
+      $alias{$_}=1;
+    }
+    foreach(split(",",$3))
+    {
+      $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(m/(\/\S+)/ && defined($alias{$_}))
+    {    
+      my $image=$1;
+      foreach my $part(split " ",$alias{$_})
+      {
+        $b{$part.(($part =~ m/\//)?"":$image)}=1;
+      }
+    }
+    else
+    {
+      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";
+  }
+  else
+  {
+    print $_;
+  }
+}
+close IN;
+
+print STDERR "".join(",", sort keys %drckind)."\n";