#!/usr/bin/perl -w # # File Format Converter from SIS .blif (mapped) to GSRC formats # # # 12/2/04: allow turning off adding "N" prefix to gate names # 12/2/04: allow treating terminals as flops $addPrefix=0; $terminalAsFlop=1; $stdCellHeight=32; $stdTermHeight=8; if (@ARGV < 2) { print " Usage: blif2gsrc blif_file genlib [chip_width]\n"; exit 0; } my $white_space_ratio=1.2; my $file=$ARGV[0]; my $name=substr($file, rindex($file ,"/")+1, 1000); $name=substr($name, 0, rindex($name ,".")); ################################################# # Read in .genlib file, store cell info ################################################# my $lib = $ARGV[1]; open LIB, $lib; @libcells = ; close LIB; @libcells = Connect_Lines(@libcells); my %libcell; my $Num_libcells = 0; foreach $cell(@libcells) { # remove leading space $cell =~ s/^\s+//; if ($cell =~ /^GATE\b/i || $cell =~ /^LATCH\b/i) { my @fields = split /\s+/, $cell; $libcell{$fields[1]} = $fields[2]; if ($fields[1] =~ /(\S+FF)/i) { $defaultFlopName = $1; } $Num_libcells++; } } print "Total library cells: $Num_libcells\n"; ##################################################### $file =~s/\.blif//; #print $file; open BLIF, $file.".blif"; @blifs=; close BLIF; #print "read gate blif\n"; @blifs=Connect_Lines(@blifs); ########################################################################## # Read in the .blif file ########################################################################## my %Nodes; my %I_Nodes; my %O_Nodes; my %Nets; my %Latches; my $Num_Nodes=0; my $Num_Term=0; my $unit_height=$stdCellHeight; # um my $offset = 0; # um my $term_height; if ($terminalAsFlop){ $term_height = $unit_height; } else { $term_height = $stdTermHeight; # um } #my $unit_width=16; #print "read gate blif\n"; foreach $blif(@blifs){ if ( $blif=~/^\.outputs\b/i){ O_nodes_function($blif, $libcell{$defaultFlopName}, $term_height); next; } if ( $blif=~/^\.inputs\b/i){ I_nodes_function($blif, $libcell{$defaultFlopName}, $term_height); next; } if ($blif=~/^\.gate\b/i || $blif=~/^\.mlatch\b/i){ #print "read gate $blif\n"; my @field = split /\s+/, $blif; shift @field; # delete the leading ".name" my $node_name = pop @field; # taking the last field, node fanout # remove ending non-pin parts while ($node_name !~ /^\w+=/) { $node_name = pop @field; } # remove match part $node_name =~ s/^\w+=//; if ($addPrefix){ $node_name = "N".$node_name; } #my $pre_node_name="_".$node_name; if(not $Nodes{$node_name} ){ # $Nodes{$node_name}{'W'}=($#field)*$unit_width; # $Nodes{$node_name}{'A'}=($#field)*$unit_width*$unit_height; # get cell area from library if (not exists $libcell{$field[0]}) { print "cell $field[0] can not be found in the library !!\n"; } else { $Nodes{$node_name}{'W'}=$libcell{$field[0]}/$unit_height; $Nodes{$node_name}{'A'}=$libcell{$field[0]}; $Nodes{$node_name}{'L'}=$field[0]; } } if ((not $Latches{$node_name}) && $blif=~/^\.mlatch\b/i) { $Latches{$node_name} = 1; } } # end of if names } # reading nets foreach $blif(@blifs){ if ($blif!~/^\.gate\b/i && $blif!~/^\.mlatch\b/i){next;} my @node_fanins = split /\s+/, $blif; shift @node_fanins; # remove .gate shift @node_fanins; # remove library instance name my $next_node=pop @node_fanins; while ($next_node !~ /^\w+=/) { $next_node = pop @node_fanins; } $next_node =~ s/^\w+=//; if ($addPrefix){ $next_node = "N".$next_node; } my $index = 0; foreach $fan_in(@node_fanins){ $fan_in =~ s/^(\w+)=//; $pin = $1; if ($addPrefix){ $fan_in = "N".$fan_in; } if(not exists $Nets{$fan_in}){ $Nets{$fan_in}{'I'}=$fan_in; $Nets{$fan_in}{'O_N'}=1; $Nets{$fan_in}{'O'}[0]=$next_node.":".$pin; $Nets{$fan_in}{$next_node.":".$pin}=$index; } else { my $temp; $temp=$Nets{$fan_in}{'O_N'}; $Nets{$fan_in}{'O'}[$temp]=$next_node.":".$pin; $Nets{$fan_in}{$next_node.":".$pin}=$index; $Nets{$fan_in}{'O_N'}+=1; } $index++; } } #foreach $key(sort keys %Nets){ # printf "%10s %4d\n", $key, $Nets{$key}{'O_N'}; #} ########################################################################## # some dummy output pins ########################################################################## foreach $PO_node(sort keys %O_Nodes){ $PO_node =~s/^_//; if(not exists $Nets{$PO_node}){ $Nets{$PO_node}{'I'}=$PO_node; $Nets{$PO_node}{'O_N'}=1; $Nets{$PO_node}{'O'}[0] = "_".$PO_node; $Nets{$PO_node}{"_".$PO_node}=0; } else { my $temp; $temp = $Nets{$PO_node}{'O_N'}; $Nets{$PO_node}{'O'}[$temp] = "_".$PO_node; $Nets{$PO_node}{'O_N'}+=1; $Nets{$PO_node}{"_".$PO_node}=0; } } ########################################################################## # .nodes file ########################################################################## my @temp; @temp= keys %Nodes; my $in_node_num= $#temp+1; @temp= keys %I_Nodes; my $pi_node_num= $#temp+1; @temp= keys %O_Nodes; my $po_node_num= $#temp+1; $Num_Nodes+=$Num_Term; #---- $Num_Nodes = $in_node_num + $pi_node_num + $po_node_num; $Num_Term = $pi_node_num + $po_node_num; #---- open NODES, ">$name.nodes"; print NODES "UCLA nodes 1.0\n"; if ($terminalAsFlop) { print NODES "NumNodes : ".$Num_Nodes."\n"; print NODES "NumTerminals : 0\n"; } else { print NODES "NumNodes : ".$Num_Nodes."\n"; print NODES "NumTerminals : ".$Num_Term."\n"; } foreach $key(sort keys %Nodes){ printf NODES "%20s\t\t%5.1f %5.1f\n", $key,$Nodes{$key}{'W'},$unit_height; } foreach $key(sort keys %I_Nodes){ printf NODES "%20s\t\t%5.1f %5.1f", $key, $I_Nodes{$key}{'W'}, $term_height; if (!$terminalAsFlop){ printf NODES "\t%10s\n", "terminal"; } else { printf NODES "\n"; } } foreach $key(sort keys %O_Nodes){ printf NODES "%20s\t\t%5.1f %5.1f", $key, $O_Nodes{$key}{'W'}, $term_height; if (!$terminalAsFlop){ printf NODES "\t%10s\n", "terminal"; } else { printf NODES "\n"; } } close NODES; ########################################################################## # .node.e file ########################################################################## open NODES, ">$name.nodes.e"; print NODES "UCLA nodes 1.0\n"; if ($terminalAsFlop) { print NODES "NumNodes : ".$Num_Nodes."\n"; print NODES "NumTerminals : 0\n"; } else { print NODES "NumNodes : ".$Num_Nodes."\n"; print NODES "NumTerminals : ".$Num_Term."\n"; } foreach $key(sort keys %Nodes){ printf NODES "%20s\t\t%5.1f %5.1f %s\n", $key,$Nodes{$key}{'W'},$unit_height,$Nodes{$key}{'L'}; } foreach $key(sort keys %I_Nodes){ printf NODES "%20s\t\t%5.1f %5.1f", $key, $I_Nodes{$key}{'W'}, $term_height; if (!$terminalAsFlop) { printf NODES "\t%10s\n", "terminal"; } else { printf NODES " %s\n", $defaultFlopName; } } foreach $key(sort keys %O_Nodes){ printf NODES "%20s\t\t%5.1f %5.1f", $key, $O_Nodes{$key}{'W'}, $term_height; if (!$terminalAsFlop) { printf NODES "\t%10s\n", "terminal"; } else { printf NODES " %s\n", $defaultFlopName; } } close NODES; ########################################################################## # .net file ########################################################################## my $Num_Nets=0; my $Num_Pins=0; @temp = sort keys %Nets; foreach $key (sort keys %Nets){ my %sinks; foreach $i(0..$Nets{$key}{'O_N'}-1){ my $net_pin = $Nets{$key}{'O'}[$i]; my @net_pin_comb; @net_pin_comb = split /:/, $net_pin; $sinks{$net_pin_comb[0]} = 1; } $Num_Nets++; $Num_Pins+= (keys (%sinks)+1); } open NETS, ">$name.nets"; print NETS "UCLA nets 1.0\n"; print NETS "NumNets : ".$Num_Nets."\n"; print NETS "NumPins : ".$Num_Pins."\n"; foreach $key (sort keys %Nets){ my %sinks; foreach $i(0..$Nets{$key}{'O_N'}-1){ my $net_pin = $Nets{$key}{'O'}[$i]; my @net_pin_comb; @net_pin_comb = split /:/, $net_pin; $sinks{$net_pin_comb[0]} = 1; } my $num_sinks = keys (%sinks); printf NETS "NetDegree : %3d\n", $num_sinks + 1; printf NETS "%22s %2s\n", $Nets{$key}{'I'}, "O"; foreach $i(keys (%sinks)){ printf NETS "%22s %2s\n", $i, "I"; } # printf NETS "NetDegree : %3d\n",$Nets{$key}{'O_N'}+1; # printf NETS "%22s %2s\n", $Nets{$key}{'I'}, "O"; # foreach $i(0..$Nets{$key}{'O_N'}-1){ # printf NETS "%22s %2s\n", $Nets{$key}{'O'}[$i], "I"; # } } close NETS; ########################################################################## # latch node file ########################################################################## open LATCHES, ">$name.latch"; printf LATCHES "NumLatches : ".keys(%Latches)."\n"; foreach my $l (sort keys %Latches) { printf LATCHES "%s\n", $l; } close LATCHES; ########################################################################## # enhanced nets file with fanout pin index specified ########################################################################## open NETS, ">$name.nets.e"; print NETS "UCLA nets 1.0\n"; print NETS "NumNets : ".$Num_Nets."\n"; print NETS "NumPins : ".$Num_Pins."\n"; foreach $key (sort keys %Nets){ printf NETS "NetDegree : %3d\n",$Nets{$key}{'O_N'}+1; printf NETS "%22s %2s %d\n", $Nets{$key}{'I'}, "O", 0; foreach $i(0..$Nets{$key}{'O_N'}-1){ my $net_pin = $Nets{$key}{'O'}[$i]; my @net_pin_comb; @net_pin_comb = split /:/, $net_pin; printf NETS "%22s %2s %d\n", $net_pin_comb[0], "I", $Nets{$key}{$Nets{$key}{'O'}[$i]}; } } close NETS; ########################################################################## open WTS, ">$name.wts"; print WTS "UCLA wts 1.0\n"; my $Total_Area=0; my @total_nodes; push @total_nodes, keys %Nodes; push @total_nodes, keys %I_Nodes; push @total_nodes, keys %O_Nodes; foreach $key (sort keys %Nodes){ printf WTS "%20s\t%5.1f\n", $key,$Nodes{$key}{'A'}; $Total_Area+=$Nodes{$key}{'A'}; } foreach $key (sort keys %I_Nodes){ printf WTS "%20s\t%5.1f\n", $key,$I_Nodes{$key}{'A'}; $Total_Area+=$I_Nodes{$key}{'A'}; } foreach $key (sort keys %O_Nodes){ printf WTS "%20s\t%5.1f\n", $key,$O_Nodes{$key}{'A'}; $Total_Area+=$O_Nodes{$key}{'A'}; } # $Total_Area *= 2.5; print "Total area ".$Total_Area."\n"; close WTS; ########################################################################## open SCL, ">$name.scl"; print SCL "UCLA scl 1.0\n"; my $site_width = 1; my $row_number; if ($ARGV[2]) { $row_number= int (($Total_Area/$ARGV[2])/$unit_height+0.5); } else { $row_number = int (sqrt($Total_Area)/$unit_height+0.5); } my $chip_height=int ($row_number*$unit_height+$offset + 0.5); my $row_length; if ($row_number > 1) { $row_length = int ($white_space_ratio*($Total_Area/$unit_height)/($row_number-1)/$site_width + 0.5); } else { $row_length = int ($white_space_ratio*($Total_Area/$unit_height)/$site_width+0.5); } printf SCL "Numrows : %d\n", $row_number; foreach $i(0..$row_number-1){ printf SCL "CoreRow Horizontal\n"; printf SCL " Coordinate : %4.2f\n", $offset/2.0+$unit_height*$i; printf SCL " Height : $unit_height\n"; printf SCL " Sitewidth : $site_width\n"; printf SCL " Sitespacing : $site_width\n"; printf SCL " Siteorient : N\n"; printf SCL " Sitesymmetry : Y\n"; printf SCL " SubrowOrigin : 0 Numsites : %5d\n",$row_length; printf SCL "End\n"; } close SCL; ########################################################################## open PL, ">$name.pl"; print PL "UCLA pl 1.0\n"; my $center_x=int $row_length/2; my $center_y=int $chip_height/2; my @IOPins; @temp= keys %I_Nodes; foreach $word(@temp){$word =~s/^_//;} push @IOPins, @temp; push @IOPins, keys %O_Nodes; #foreach $iopin(@IOPins){ $iopin =~s/^_//;} foreach $key (sort keys %Nodes){ unless ($key =~/^_/){ printf PL "%20s\t%7.1f %7.1f\n", $key,$center_x, $center_y; } } if (@IOPins > 0) { my $side_pin_number = int ($#IOPins/4)+1; my $grid_x = int $row_length/$side_pin_number; my $grid_y = int ( $chip_height/$side_pin_number); foreach $i(0..$side_pin_number-1){ printf PL "%20s\t%7.1f %7.1f\n" ,$IOPins[$i],$grid_x *$i,0; printf PL "%20s\t%7.1f %7.1f\n" ,$IOPins[$side_pin_number+$i],$row_length+$offset,$grid_y*$i; if($IOPins[2*$side_pin_number+$i]){ printf PL "%20s\t%7.1f %7.1f\n" ,$IOPins[2*$side_pin_number+$i],$grid_x *$i,$chip_height; } if($IOPins[3*$side_pin_number+$i]){ printf PL "%20s\t%7.1f %7.1f \n" ,$IOPins[3*$side_pin_number+$i], -$offset/2.0,$grid_y*($i+1); } } } #printf "row number %8d, chip height %8d, row length %8d\n", $row_number,$chip_height,$row_length; #printf "grid_x %8d, grid_y %8d,\n", $grid_x,$grid_y; close PL; ########################################################################## open AUX, ">$name.aux"; print AUX "RowBasedPlacement : "; printf AUX "%s.nodes %s.nets %s.wts %s.pl %s.scl", $name, $name,$name,$name,$name; close AUX; open AUX, ">$name.aux.e"; print AUX "RowBasedPlacement : "; printf AUX "%s.nodes.e %s.nets.e %s.wts %s.pl %s.scl %s.latch", $name, $name, $name, $name, $name, $name; close AUX; ########################################################################## #------------------------------------------------- sub I_nodes_function { my $line =$_[0]; my $area =$_[1]; my $height =$_[2]; my @field = split /\s+/, $line; shift @field; foreach $ionode(@field){ if ($addPrefix){ $ionode =~ s/^/N/; } if ($terminalAsFlop){ $I_Nodes{$ionode}{'W'}=$area/$height; $I_Nodes{$ionode}{'A'}=$area; } else { $I_Nodes{$ionode}{'W'}=1; $I_Nodes{$ionode}{'A'}=2; } } } #------------------------------------------------- sub O_nodes_function { my $line =$_[0]; my $area =$_[1]; my $height =$_[2]; my @field = split /\s+/, $line; shift @field; foreach $ionode(@field){ if ($addPrefix){ $ionode =~ s/^/_N/; } else { $ionode =~ s/^/_/; } if ($terminalAsFlop){ $O_Nodes{$ionode}{'W'}=$area/$height; $O_Nodes{$ionode}{'A'}=$area } else { $O_Nodes{$ionode}{'W'}=1; $O_Nodes{$ionode}{'A'}=2; } } } #------------------------------------------------- # to join those lines with trailing backslash, \ #------------------------------------------------- sub Connect_Lines{ my @lines; @lines=@_; print "total ".$#lines." lines\n"; for($i=0;$i<=$#lines;){ chomp $lines[$i]; if ($lines[$i] =~/\\$/){ print "concatenate $lines[$i]\n"; $lines[$i]=~s/\\$/ /; $lines[$i].=$lines[$i+1]; for($j=$i+1;$j<=$#lines-1;$j++){ $lines[$j]=$lines[$j+1]; } pop @lines; } else{ $i++; } } return @lines; } #-------------------------------------------------