#   Note: this complete ESNUG has been fully commented so the Perl script
#   in it is ready to use!  Just add water!  - John Cooley, the ESNUG guy


#( ESNUG 137 Item 1 ) -------------------------------------------------- [7/93]
#
#From: uunet!uranus!splinter!flieder (Jeff Flieder)
#Subject: FSV, A Perl Script for Fixing Synopsys' Stinky Verilog Output
#
#John,
#
#   I finally got around to cleaning up my FSV (Fix Synopsys Verilog) script
#so that I could send it to ESNUG users.  I want to strongly state that this
#Perl script comes with no warranty and is used at the users risk.  I will
#not support nor answer questions about this script, but if users want to use
#it, feel free.  I will say that we are using it quite successfully here at
#Ford Microelectronics.  I will try to post all major releases of FSV to you
#so that users can get timely updates.
#
#   The command line to use FSV is:
#
#           "FSV <list of file names>"
#
#FSV will make a copy of the original file in <file_name>.bak and will create
#a new file in place of the old one.  One important note, the bang line says:
#
#            "/apps/fmi/bin/perl411"
#  
#This ain`t gonna work anywhere but here at Ford Microelectronics, so the
#user will have to modify this line to point to wherever their own perl
#executables are. I think that is all the information that anyone should need
#to run the script.
#
#  - Jeff Flieder
#    Senior Engineer, CAE Development
#    Ford Microelectronics, Inc.


#!/apps/fmi/bin/perl411
#
#  Purpose: FSV - a utility program for making good Verilog code 
#           out of "kaa-kaa" Synopsys verilog-out code.
#
#  Performs the following fixes:
#		1. Finds all the busses and makes them into real busses
#		2. Removes all the escaped names
#		3. Creates busses for all multi-bit registers
#
#  Written By: J.W. Flieder  3 Dec 1992
#
#  Modification History:
#   V 1.1:  Added the capability of fixing the 'Q' outputs of
#           all the registers. JWF 14-NOV-1993
#   V 1.2:  Changed the program so that each module is written to
#           a file called module_name.v. This was done because
#           the Synopsys file has the modules in the wrong order
#           so that Verilog won't run correctly. JWF 15-JAN-1993
#  V 1.3:   Added the feature to check if a file already exists prior
#	    to writing a new file over the old one. JWF 25-JAN-1993
#  V 1.4    Changed vectors to little endian [0:n] JWF 14-APR-1993
#  V 1.5    Added the following command line options: JWF  14-APR-1993
#	      -h or -help : shows all command line options
#	      -le : specifies little endian ordering of busses
#	      -be : specifies big endian ordering of busses
#  V 2.0    Decided enough changes have been made to make this a major
#           release of the software. The following changes have been made:
#		1. Files are no longer split up since Synopsys fixed
#			   the problem and lower designs are written first
#		2. Displays help when there are no arguments
#			   JWF 4-20-93	
#  V 2.1    Fixed the little-endian big-endian problem and also fixed another
#           net name problem by changing *cell* to cell and changing
#	    / to _.  JWF 5-5-93
#
#  V 2.2    Fixed a bug that occured if there were no single bit wires
#           in a design. The software would print out a wire declaration
#           with now wires in it before. Now it checks to make sure that
#           there are wires before printing out the wire declaration.

$work_dir = `/bin/pwd`;
chop $work_dir;
$save_index = 0;
$not_in_wire = 1;
$wire_string = ();
$scalar_cnt = 0;
$#vectors = -1;
$endian = "";

#
# opening day niceties
#

system ("/usr/ucb/clear");
print STDOUT "\n\n";
print STDOUT "FSV: Fix Synopsys Verilog Utility Program\n\n";
print STDOUT "Version 2.1 5-MAR-1993\n\n";
if (@ARGV == 0) { 
  die &print_help;
}

print STDOUT "----- Processing ----\n\n";

foreach $file (@ARGV) {
  print STDOUT "arg: $file \n\n";
  if($file =~ /^-.*/) {
    if ($file eq "-le") {
       print STDOUT "Little Endian Ordering Requested ([0:n])\n\n";
       $endian = "big";
    }
    if ($file eq "-be") {
       print STDOUT "Big Endian Ordering Requested ([n:0])\n\n";
       $endian = "little";
    }
    if (($file eq "-h") || ($file eq "-help")) {
      &print_help;
    }
  }    
  else {
    if($endian eq "") {
      print STDOUT 
        "No Endian ordering specified, using Little Endian  ([0:n])\n\n";
      $endian = little;
  }
    open(INFILE, "$work_dir/$file") || die STDOUT 
        "Can't open $work_dir/$file for read: $!\n";
    system("cp $work_dir/$file $work_dir/$file.sav");
    system("rm $work_dir/$file");
    open(OUTFILE, ">$work_dir/$file") || die STDOUT 
        "Can't open $work_dir/$file for write: $!\n";
    while (<INFILE>) {
      if (/endmodule/) {
        &process_wires;
        &process_body;
        &dump_module;
        &reset_arrays;
      }
      else {
        $current_string = $current_string.$_;
#
# look for the semi-colon that terminates the current string
# replace all carraige returns with the string "PutCrHere", I 
# mean what are the odds of a net having that name?
#
        if(!($current_string =~ /\;$/)) {
          chop($current_string);
        $current_string = "$current_string.PutCrHere";
        }
        else {
          $complete_string = $current_string;
          $current_string = "";
#
# Search for the wire declaration so that all busses and wires can be
# identified and processed, and save the module declaration and the
# i/o declarations
#
#
# module declaration
#
          if($complete_string =~ /\s*module\s*([^\s]*).*/) {
            $module_name = $1;
            print "Processing Module $module_name\n";
            $file_names{$module_name} = 0;

            $complete_string =~ s/.PutCrHere/g;
            $module_string = $complete_string;
          }
#
# inout declaration
#
          elsif($complete_string =~ /^\s*inout.*/) {
            $complete_string =~ s/.PutCrHere/g;
            $inout_string = "$inout_string $complete_string";
          }
#
# input declaration
#
          elsif($complete_string =~ /^\s*input.*/) {
            $complete_string =~ s/.PutCrHere/g;
            $input_string = "$input_string $complete_string";
          }
#
# output declaration
#
          elsif($complete_string =~ /^\s*output.*/) {
            $complete_string =~ s/.PutCrHere/g;
            $output_string = "$output_string $complete_string";
          }
#
# wire declaration string
#
          elsif($complete_string =~ /^\s*wire.*/) {
            $complete_string =~ /\s*([^\;]*);/;	# strip leading spaces and CR
            $wire_string = "$wire_string $1";
          }
#
# If none of the above, we must be in the body of the Verilog module.
# The processing of the body lines consists of removing all the backslashes
# that escape all the names, renaming each arrayed instance from name[#] to
# name_# and finding all of the Q inputs to F/F's so that they can later be
# attached to busses like they should have been in the first place.
# 
          else {
            $complete_string =~ s//g;	# strip off the '\'s
            $complete_string =~ s/\*cell\*/cell/g;# replace *cell* with cell
            $complete_string =~ s/\_/g;	# replace / with _
            $_ = $complete_string;
#
# find all of the arrayed instance names and fix them by changing from
# name[#] to name_#
#
# search for instance definitions
  	    if(/(\s+[^\s]+\s*)([^\s]*)(.*)/) {  
              $c_type = $1;
              $i_name = $2;
              $p_list = $3;
#
# find all of the Q inputs of registers and save the name for
# processing later
#
   if($i_name =~ /([^\[]*)\[([^\]]*)\]/) { # parse the instance name
       $i_ident = $1;
       $i_num = $2; 
       $ext = "_Q";
       $under = "_";
       $new_name = "$i_ident$ext[$i_num]";
       $p_list =~ /([^\.]*\.Q\()([^\)]*)(.*)/;
       $old_name = $2;
       $complete_string = "$c_type $i_ident$under$i_num $p_list\n";
#
# Add the new net to the wire_string array so that in can be processed later
# and add the net to the bus_name associative array so that it can be processed
# later. Only add the net if the old_name is not contained in the port list of
# the current module
#
	        $old_name =~ /([^\[]*).*/;
                if(!($module_string =~ /)) {
                  $old_name =~ s//g;		# remove any spaces in the name
                  $bus_name{$new_name} = $old_name;
                  $wire_string = "$wire_string, $i_ident$ext[$i_num]";
                }
              }
              $body_array[$body_index] = $complete_string;
	      $body_index ++;
            }
          }
        }  
      } 
    }
    print STDOUT "\n\n<<<<< PROCESSING COMPLETED >>>>>>\n\n";
    print STDOUT "\t Your original verilog netlist has been preserved\n";
    print STDOUT "\t in a file called $file.sav.\n\n";
    print STDOUT "\t The new netlists is called $file\n\n";
    print STDOUT "\n-------------------------------------------------\n\n";
  }
}
###########################################################
sub process_wires {
  $wire_string = "$wire_string;";
  $wire_string =~ /wire(.*;)/;			# strip the word "wire"
  $wire_string = $1;
  $wire_string =~ s/\.PutCrHere//g;		# remove the ".PutCrHere"
  $wire_string =~ s//g;			# remove the slashes (\) 
  $wire_string =~ s/\*cell\*/cell/g;		# replace *cell* with cell
  $wire_string =~ s/\_/g;			# replace / with _
	
#
# search for the old net names and replace them with the new ones
#
   foreach $element (sort keys(%bus_name)) {
#    print "ON:$bus_name{$element}., NN:$element.\n";    
    $bus_name{$element} =~ /([^\[]*)\[([^\]]*)\]/;
    $old_bus = $1;
    $old_number = $2;
    $element =~ /([^\[]*)\[([^\]]*)\]/;
    $new_bus = $1;
    $new_number = $2;
    $wire_string =~ s/$old_bus\[$old_number\]/$new_bus\[$new_number\]/g;
   }  
  &parse_wire_string();
  &fix_wire_string();
  if (@scalars != "") {
    $wire_array[$wire_index] = "wire\t";
    $wire_index++;
    foreach $wire_name (@scalars) {
      if ($start_flag == 0) {
        $wire_array[$wire_index] = "\t$wire_name";
        $start_flag = 1;
      }
      else {
        $wire_array[$wire_index] = ",\n\t\t$wire_name";
      }
      $wire_index++;
    }
  $wire_array[$wire_index] = ";\n";     
  $wire_index++;
  }     
  foreach $vector_name (sort keys(%vectors)) {
    if ($endian eq "little") {
$wire_array[$wire_index]=
        "wire[0:$vectors{$vector_name}]\t$vector_name\;\n";
    }
    elsif ($endian eq "big") {
$wire_array[$wire_index]=
        "wire[$vectors{$vector_name}:0]\t$vector_name\;\n";
    }    
    $wire_index ++;
  }
}

############################################################
#
# subroutine: process_body
#
# purpose: this subroutine runs through each line in the body
#          of the current module definition and replaces the old
#          net names with new net names
#
###########################################################
sub process_body {
  foreach $body_line (@body_array) {
    foreach $element (sort keys(%bus_name)) {
      $bus_name{$element} =~ /([^\[]*)\[([^\]]*)\]/;
      $old_bus = $1;
      $old_number = $2;
      $element =~ /([^\[]*)\[([^\]]*)\]/;
      $new_bus = $1;
      $new_number = $2;
      $body_line =~ s/$old_bus\[$old_number\]/$new_bus\[$new_number\]/g;
     }  
#
# put the carraige returns back into the strings
#
            $body_line =~ s/.PutCrHere/g;  
  }
}
############################################################
#
# subroutine: dump_module
#
# purpose: writes out the current module arrays to the
#          output file
#
#############################################################

sub dump_module {
  print OUTFILE ($module_string);
  print OUTFILE ($inout_string);
  print OUTFILE ($input_string);
  print OUTFILE ($output_string);
  foreach $line (@wire_array) {
    print OUTFILE $line;
  }
  foreach $line (@body_array) {
    print OUTFILE $line;
  }
  print OUTFILE "endmodule\n";
}

############################################################
#
# subroutine: reset arrays
#
# purpose: resets all arrays, pointers, etc after a module dump
#
############################################################
sub reset_arrays {
  $wire_index = 0;
  $not_in_wire = 1;
  $scalar_cnt = 0;
  $body_index = 0;
  $start_flag = 0;
  $wire_string = "";
  $module_string = "";
  $inout_string = "";
  $input_string = "";
  $output_string = "";
  @scalars = -1;
  @wire_array = "";
  @body_array = "";
  %vectors = -1;
  %bus_name = -1;
  %single_names = -1;
}
############################################################
#
# subroutine: parse_wire_string
#
# purpose: parses the input wire string into individual
#          wires in an array called @parsed_string
#
############################################################
sub parse_wire_string {
  chop($wire_string);
  @parsed_string = split(/,/,$wire_string);
#  print "@parsed_string\n\n";
}
############################################################
#
# subroutine: fix_wire_string
#
# purpose: finds all the vectored and scalar nets in the wire
#          string and puts them in seperate arrays
#
############################################################
sub fix_wire_string {
  foreach $element (@parsed_string) {
    $element =~ s//g;			# remove leading spaces
    if($element =~ /([^\[]*)\[(\d*)\]/) {	# find all the vectored nets
      # by looking for the []`s
      if($vectors{$1} <= $2) {
	$vectors{$1} = $2;        
      }
    }
    else {
      $scalars[$scalar_cnt] = "$element";
      $scalar_cnt++;
    }
  }
}
############################################################
#
# subroutine: print_help
#
# purpose: prints out the help string
#
############################################################
sub print_help {
  print STDOUT "Command line format is:\n\n";
  print STDOUT "fsv [-arg] file_name [file_name]\n\n";
  print STDOUT "Arguments are: \n\n";
  print STDOUT "-le : specified little endian ordering of busses [0:n]\n";
  print STDOUT "-be : specified big endian ordering of busses [n:0]\n";
  print STDOUT " (Note: Default is little endian)\n\n";
  print STDOUT "-h or -help : displays this message\n\n";
}


 Sign up for the DeepChip newsletter.
Email
 Read what EDA tool users really think.


Feedback About Wiretaps ESNUGs SIGN UP! Downloads Trip Reports Advertise

"Relax. This is a discussion. Anything said here is just one engineer's opinion. Email in your dissenting letter and it'll be published, too."
This Web Site Is Modified Every 2-3 Days
Copyright 1991-2024 John Cooley.  All Rights Reserved.
| Contact John Cooley | Webmaster | Legal | Feedback Form |

   !!!     "It's not a BUG,
  /o o\  /  it's a FEATURE!"
 (  >  )
  \ - / 
  _] [_     (jcooley 1991)