Creating a dummy .lib file is something every physical design engineer has done now and then. If you have a verilog model of the block available, your task gets easier. The following script automates .lib generation from your verilog netlist. Use this as a dummy .lib to get your design flow going or use it as a template for your analog blocks for modifying the values.
Customize, edit and use. The script creates a simple Data Structure. So any modification can be done pretty easily. The script parses the verilog for the module name specified, and collects the ports & directions. In the .lib file written out, a default capacitance and transition value is specified. This is a good starting point for your blocks.
Usage: create_lib <verilog_netlist> <module_name> [transition_value] [capacitance_value]
#!/usr/bin/perl
use strict;
if ($#ARGV < 1 ) {
print "usage: create_lib <verilog_netlist> <module_name> \n";
exit;
}
my $netlist = $ARGV[0] ;
my $module = $ARGV[1] ;
my $tran = 2.5 ;
my $cap = 0.001;
my $signal_level = "VDD" ;
if(defined $ARGV[2]) {$tran = $ARGV[2];}
if(defined $ARGV[3]) {$cap = $ARGV[3];}
if(defined $ARGV[4]) {$signal_level = $ARGV[4];}
my $FF;
my $FO;
open $FF, "< $ARGV[0]" or die "Can't open $ARGV[0] : $!";
open $FO, ">$module.lib" or die "Can't open $module.lib for write : $!";
my $db = createTopLevelDB();
createDotLib($db,$FO);
sub createDotLib
{
my $topLevelDBRef = shift;
my $FO = shift ;
### Header
print $FO "library\($topLevelDBRef->{'design'}->{'cell'}\) {\n";
print $FO "\n /* unit attributes */\n";
print $FO " time_unit : \"1ns\"\;\n";
print $FO " voltage_unit : \"1V\"\;\n";
print $FO " current_unit : \"1uA\"\;\n";
print $FO " pulling_resistance_unit : \"1kohm\"\;\n";
print $FO " leakage_power_unit : \"1nW\"\;\n";
print $FO " capacitive_load_unit\(1,pf\)\;\n\n";
foreach my $direction (keys(%{$topLevelDBRef->{'bus'}})) {
foreach my $bus_type (keys %{$topLevelDBRef->{'bus'}->{$direction}}) {
my @bus_width = split(/_/, $bus_type);
my $bus_hi = $bus_width[1] ;
my $bus_lo = $bus_width[2] ;
my $bus_width = $bus_hi+1-$bus_lo;
print $FO " type \($bus_type\) { \n";
print $FO " base_type : array ; \n" ;
print $FO " data_type : bit \n" ;;
print $FO " bit_width : $bus_width \n" ;;
print $FO " bit_from : $bus_hi \n" ;;
print $FO " bit_to : $bus_lo ; \n" ;
print $FO " downto : true ; \n" ;
print $FO " } \n" ;
}
}
print $FO "\n cell\($topLevelDBRef->{'design'}->{'cell'}\) {\n";
foreach my $direction (keys(%{$topLevelDBRef->{'pins'}})) {
foreach my $pin_name (@{$topLevelDBRef->{'pins'}->{$direction}}) {
print $FO (" pin\($pin_name\) { \n");
print $FO ("\tdirection : $direction ;\n");
if($direction eq "input") {
print $FO ("\tmax_transition : $tran;\n");
}
print $FO ("\tcapacitance : $cap; \n");
print $FO (" } \n") ;
}
}
foreach my $direction (keys(%{$topLevelDBRef->{'bus'}})) {
foreach my $bus_type (keys %{$topLevelDBRef->{'bus'}->{$direction}}) {
my @bus_width = split(/_/, $bus_type);
my $bus_hi = $bus_width[1] ;
my $bus_lo = $bus_width[2] ;
foreach my $bus_name (@{$topLevelDBRef->{'bus'}->{$direction}{$bus_type}}) {
chomp($bus_name);
print "BUS $bus_name : $bus_type : $direction \n" ;
print $FO (" bus\($bus_name\) { \n");
print $FO ("\tbus_type : $bus_type ;\n");
print $FO ("\tdirection : $direction ;\n");
if($direction eq "input") {
print $FO ("\tmax_transition : $tran;\n");
}
for(my $i=$bus_lo; $i<=$bus_hi; $i++) {
print $FO ("\tpin\($bus_name\[$i\]\) { \n");
print $FO ("\t\tcapacitance : $cap; \n");
print $FO ("\t} \n") ;
}
print $FO (" } \n") ;
}
}
}
print $FO (" } \n") ;
print $FO ("} \n") ;
}
sub createTopLevelDB
{
my $find_top_module = 0;
my %topLevelDB = () ;
my %pins = () ;
my %bus = () ;
my @input_pins ;
my @output_pins ;
my @inout_pins ;
my @bus_types ;
my %input_bus = () ;
my %output_bus = () ;
my %inout_bus = () ;
my %design = ();
$design{'cell'} = $module;
$design{'tran'} = $tran;
$design{'cap'} = $cap;
$design{'signal_level'} = $signal_level;
while(my $line = <$FF>) {
last if($find_top_module == 1);
if($line=~/module\s+$module/) {
$find_top_module = 1 ;
while(my $line = <$FF>) {
next if($line =~ "\s*//" );
chomp($line);
if ($line =~/input\s+/ ) {
$line=~s/\s*input\s+//;
$line=~s/;//;
if($line =~/\[(\d+):(\d+)\]/) {
my $bus_type = "bus_$1_$2";
$line=~s/\[(\d+):(\d+)\]//;
my @line = split(/,/, $line);
unless(grep {$_ eq $bus_type} @bus_types) {
push(@bus_types,$bus_type);
}
foreach my $pin (@line) {
$pin=~s/\s+//;
push(@{$input_bus{$bus_type}}, $pin );
}
}
else {
my @line = split(/,/, $line);
foreach my $pin (@line) {
$pin=~s/\s+//;
push(@input_pins, $pin);
}
}
}
if ($line =~/output\s+/ ) {
$line=~s/\s*output\s+//;
$line=~s/;//;
if($line =~/\[(\d+):(\d+)\]/) {
my $bus_type = "bus_$1_$2";
$line=~s/\[(\d+):(\d+)\]//;
my @line = split(/,/, $line);
unless(grep {$_ eq $bus_type} @bus_types) {
push(@bus_types,$bus_type);
}
foreach my $pin (@line) {
$pin=~s/\s+//;
push(@{$output_bus{$bus_type}}, $pin );
}
}
else {
my @line = split(/,/, $line);
foreach my $pin (@line) {
$pin=~s/\s+//;
push(@output_pins, $pin);
}
}
}
if ($line =~/inout\s+/ ) {
$line=~s/\s*inout\s+//;
$line=~s/;//;
if($line =~/\[(\d+):(\d+)\]/) {
my $bus_type = "bus_$1_$2";
$line=~s/\[(\d+):(\d+)\]//;
my @line = split(/,/, $line);
unless(grep {$_ eq $bus_type} @bus_types) {
push(@bus_types,$bus_type);
}
foreach my $pin (@line) {
$pin=~s/\s+//;
push(@{$inout_bus{$bus_type}}, $pin );
}
}
else {
my @line = split(/,/, $line);
foreach my $pin (@line) {
$pin=~s/\s+//;
push(@inout_pins, $pin);
}
}
}
last if($line=~/endmodule/);
}
}
}
$pins{'input'} = \@input_pins;
$pins{'output'} = \@output_pins;
$pins{'inout'} = \@inout_pins;
$bus{'input'} = \%input_bus;
$bus{'output'} = \%output_bus;
$bus{'inout'} = \%inout_bus;
$topLevelDB{'pins'} = \%pins;
$topLevelDB{'bus'} = \%bus;
$topLevelDB{'design'} = \%design;
return \%topLevelDB;
}