Creating .lib file from Verilog netlist

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;
}