#!/usr/local/bin/perl -w
#!/usr/local/bin/perl -d -w
#============================================================================
# $Id: sim_gen,v 1.17 1999/08/16 13:07:44 duane Exp $
#
# Created by Duane Galbi   <duaneg@iname.com> 
# Copyright 1999 STMicroelectronics, Inc.
# This Software is the property of STMicroelectronics, Inc. ("ST") which
# specifically grants the user the right to use, modify, reproduce, publish,
# display, and distribute this software provided this notice is not removed
# or altered.  All other rights are reserved by ST.
#
# THIS SOFTWARE IS BEING PROVIDED BY ST "AS IS" AND ANY USER OF THIS 
# SOFTWARE WILL DO SO AT ITS OWN RISK. ST MAKES NO PREPRESENTATION OR
# WARRENTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION
# ANY IMPLIED WARRANTY OF MERCHANTABILITY OF FITNESS FOR ANY PARTICULAR
# PURPOSE.  IN ADDTION, IN NO EVENT SHALL ST BE LIABLE FOR ANY DIRECT,
# INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING
# FROM THE FURNISHING, PERFORMANCE, OR USE OF THIS SOFTWARE.
#============================================================================
#
# Search file for control lines and generates appropriate .gs file
# Possible control lines are as follows:
# 1) /*<G: or g> <transition> <table>, <init-pins> */
#      where <transition> = the transition to check (S_U_A_F, etc)
#            <table> = table which lists simulation points
#            <init-pins> = DC values for the pins (ex "A=* B=*")
#                          ex "A=* B=*", "A=* B=!A", "A=1 B=* C=*"
#
# 2) /*<F: or f> <transition> <table>, <other-pins>, <ff-clock> */
#      where <transition> = the transition to check 
#                   (ie CP_R_Q_R ...  -> checks cell delay)
#                   (ie D_1_HOLD_Q    -> check input hold)
#                   (ie D_1_SETUP_Q   -> check input setup)
#                   (ie SD_0_REM_Q    -> check removal rising)
#                   (ie SD_0_REC_Q    -> check recovery rising)
#            <table> = table which lists simulation points
#            <other-pins> = DC values for the pins 
#                           (ex "A=* B=*", "A=* B=!A", "A=1 B=* C=*", etc) 
#                       or values which also specify pin-transitions
#                           (ex "SD=1 D=*/* SI=0", "A=$I B=!$I C=* D=C", etc)
#            <ff-clock> = clock used to initialize FF (ie CP_R)
#
# 3) /*C: <pin>, <init-pins> */
#      measures capacitance of <pin> under the <init-pins> condition
#      (<init-pins> values of "*" will be transformed to "0")
#
# NOTE: 1) If <table>, <init-pins>/<other-pins> or <ff-clock> are not 
#          specified, they will default to the last value specified.
#       2) Input pin under test will be removed from the <init-pins> list  
#       3) Can't have */G: ..*/ and /*F: ... */ stuff in the same file
#
# LIMITS: Does not support multi-line comments 
#         (lines after first will appear as uncommented)
#         Function Statement must be on one line
#=========================================================================
if (@ARGV == 0) {
HELPMSG:
    print <<EOUSAGE;
Version: 1.0
Usage: sim_gen <lib-template> [options]
     
    where [options] are:
       -cell=<name>  -> cell to process (default: first cell encountered)
       -o<file>      -> file to write .gs file to (default: <cell>.gs)
       -rgs          -> run gspice after generate file
       -nlib         -> Don't have .gs automatically run lib_merge
       -nf           -> Don't parse for function statement
       -nfil         -> Don't use function to filter out initial conditions
       -nm           -> Don't do any merging of required simulations
       -h            -> print out this message  

EOUSAGE
    exit(0);
}

$outfile = ""; 
$libfile = ""; 
$do_cellname = "";
$do_function = 1;
$run_gspice = "";
$do_merge_sim = 1;
$do_libmerge = 1;
$do_function_filter = 1;

while ($arg = shift) {
    if ($arg eq "?" || $arg eq "-h"){
	goto HELPMSG;
    }elsif ($arg =~ /^-o(.+)/) {
	$outfile = $1;
    }elsif ($arg =~ /^-cell=(.+)/) {
	$do_cellname = $1;
    }elsif ($arg eq "-rgs"){
        $run_gspice = 1;
    }elsif ($arg eq "-nlib"){
        $do_libmerge = "";
    }elsif ($arg eq "-nfil"){
        $do_function_filter = "";
    }elsif ($arg eq "-nf"){
        $do_function = "";
        $do_function_filter = "";
    }elsif ($arg eq "-nm"){
        $do_merge_sim = "";
    }else{
	if (!$libfile){
	    $libfile = $arg;
	}else{
	    die "ERROR: Bad input argument: $arg";
	}
    }
}

die "ERROR: No <lib-file> was specified" if (!$libfile);
open(LIBFILE,$libfile) || die "ERROR: Cannot open <lib-file> file: $libfile";

$debug = 0;     ## set to 1 for debug

if ($debug){
  print "libfile=$libfile  outfile=$outfile\n";
}

##===============================================================================
##        Merge together required simulation using "_X" fields
##===============================================================================
$debug1 = "";
sub generate_sim_merge{
    local($ipin,$in_name,$in_polar,$out_name,$out_polar);
    local($tpin,$tin_name,$tin_polar,$tout_name,$tout_polar);
    local($i_init,$i_table,$t_init,$t_table,$npin);
    local(@plist,@plist2);

    @plist = sort keys %pin_measure;
    @plist2 = @plist;
    foreach $ipin (@plist){
       shift @plist2;
       if ($debug1){ print "ipin=$ipin\n"; }
       if (!exists $pin_measure{$ipin}) { next; }
       ($in_name,$in_polar,$out_name,$out_polar) = split /_/,$ipin;
       if (!$in_name || !$in_polar || !$out_name || !$out_polar){
	    die "ERROR: Line $pin_measure{$ipin}{LINE}: Bad condition '$ipin'\n";
       }
       $i_init = $pin_measure{$ipin}{INIT};
       $i_table = $pin_measure{$ipin}{TABLE};

       foreach $tpin (@pnew,@plist2){
           if ($debug1){ print "  tpin=$tpin\n"; }
           if (!exists $pin_measure{$tpin}){ next; }
	   ($tin_name,$tin_polar,$tout_name,$tout_polar) = split /_/,$tpin;
	   if (!$tin_name || !$tin_polar || !$tout_name || !$tout_polar){
	       die "ERROR: Line $pin_measure{$tpin}{LINE}: Bad condition '$tpin'\n";
	   }
           $t_init = $pin_measure{$tpin}{INIT};
           $t_table = $pin_measure{$tpin}{TABLE};
           if (($i_init eq $t_init) && ($t_table eq $i_table) &&
               ($in_name eq $tin_name) && ($out_name eq $tout_name)){
	       if ($in_polar ne $tin_polar){ $in_polar = "X"; }
	       if ($out_polar ne $tout_polar){ $out_polar = "X"; }
               $npin = "${in_name}_${in_polar}_${out_name}_${out_polar}";
	       if (!exists $pin_measure{$npin}){
                 push @pnew, $npin;
	         $pin_measure{$npin} = $pin_measure{$ipin};
                 delete $pin_measure{$tpin};
	       }else{
		   if (($pin_measure{$npin}{TABLE} ne $t_table) ||
                       ($pin_measure{$npin}{INIT} ne $t_init)){
		     die "ERROR: Problem with '$npin' TABLE or INIT value\n";
                   }
               }
               delete $pin_measure{$ipin};
               if ($debug1){ print "     Added key: $npin\n"; }
               last;
           }
       }
   } 
}

##===============================================================================
##         Some useful functions
##===============================================================================

#
# returns the value of the pin-name element of the pin-list supplied 
#   1) returns "" if not such pin-name in the pin-list
#   2) pin-list of the form (A=1 B=2)
#
sub find_init_value{
    local ($pin_list,$in_name) = @_;
    local ($pin_pt,$pin_name,$pin_value);

    foreach $pin_pt (split /[\s]+/, $pin_list){
	($pin_name,$pin_value) = split /=/,$pin_pt;
	die "ERROR: Bad Pin-list Data: $pin_pt\n" if (!defined $pin_name || !defined $pin_value);
	die "ERROR: Bad Pin-list Value: $pin_pt\n" if ($pin_name eq "" || $pin_value eq "");

	if ($pin_name eq $in_name){
            return $pin_value;
        } 
    }
    return "";
}


#
# Change form of new_pins ("A=1 B=0" -> "A 1, B 0") and
# removes supplied input-pin and clk-pin from the output pin list
# (note: clk-pin is optional) 
#
sub generate_init{
    local ($pin_list,$in_pin,$clk_pin) = @_;
    local ($pin_pt,$pin_name,$pin_value,$comma_plist);
    local ($new_plist,$in_pin_value);

    ######### Change to comma seperated list #########
    $comma_plist = "";
    $in_pin_value = "";
    foreach $pin_pt (split /[\s]+/, $pin_list){
	($pin_name,$pin_value) = split /=/,$pin_pt;
	die "ERROR: Bad Pin Data: $pin_pt\n" if (!defined $pin_name || !defined $pin_value);

	if ($comma_plist eq ""){ 
	    $comma_plist .= "$pin_name $pin_value";
	}elsif ($comma_plist =~ /;$/){
	    $comma_plist .= " $pin_name $pin_value";
	}else{
	    $comma_plist .= ", $pin_name $pin_value";
	}

	if ($pin_name eq $in_pin){ 
	    $in_pin_value = $pin_value;
	    $in_pin_value =~ s/;$//;
	}
    }

    ######### Remove input and clock pin  #########
    if (!defined $clk_pin){$clk_pin = ""};
    $new_plist = "";
    foreach $pin_pt (split /([,;][\s]*)/, $comma_plist){
	if ($pin_pt =~ /^[,;]/){
	  if ($new_plist ne ""  && !($new_plist =~ /[;](\s)*$/)){ $new_plist .= "$pin_pt";}
	}else{
	  ($pin_name,$pin_value) = split /[\s]+/, $pin_pt;
	  if (($pin_name ne $in_pin) && ($pin_name ne $clk_pin)){
	    if ($pin_value =~ /([\!]{0,1})([a-zA-Z]+)/){   
 		if ($in_pin eq $2){
                    die "ERROR: Bad Init-Pin Data: for '$pin_name' of '$pin_list'\n" if (!$in_pin_value); 
		    $pin_value = "$1$in_pin_value";
		}
	    }
	    $new_plist .= "$pin_name $pin_value";
	  }else{
	    $new_plist =~ s/[,](\s)*$//;
	  }  
        }
    }
    return $new_plist;
}

#
# Merge new pins with existing default_pins
# (if default_pins is blank or new_pins contains
#  a ";", overwrites default_pins with new_pins)
#
sub generate_pinlist {   
    local ($default_pins,$new_pins,$allow_new) = @_;
    local ($def_pt,$pin_name,$pin_value,$new_plist,$def_pt);
    local ($remain_pins,$pin_pt,$new_name,$new_value);

    if ($debug){
      print "generate_pinlist: updating '$default_pins' with '$new_pins'\n";
    }
    
    if (!defined $allow_new){ $allow_new = 0; }
    $new_pins =~ s/\*\/[\s]*$//;
    $new_pins =~ s/^[\s]+//;
 
    if (($new_pins =~ /;/) || ($default_pins eq "")){
      return $new_pins;
    }
    
    # update default pins
    $new_plist = "";
    foreach $def_pt (split /[\s]+/, $default_pins){
	($pin_name,$pin_value) = split /=/,$def_pt;
	die "ERROR: Bad Pin Data: $new_pins\n" if ($pin_name eq "" || $pin_value eq "");

	$remain_pins = "";
	foreach $pin_pt (split /[\s]+/, $new_pins){
	  ($new_name,$new_value) = split /=/,$pin_pt;
	  die "ERROR: Bad Pin Data: $new_pins\n" if ($new_name eq "" || $new_value eq "");
          if ($pin_name eq $new_name){
	      if ($pin_value =~ /;$/){
                $pin_value = "$new_value;"; 
              }else{
		$pin_value = "$new_value"
              }
	  }else{
	      if ($remain_pins ne ""){ $remain_pins .= " "; }
	      $remain_pins .= "$pin_pt";
	  }
        }
	$new_pins = $remain_pins;

	if ($new_plist ne ""){ $new_plist .= " ";}
	$new_plist .= "$pin_name=$pin_value";
    }
    if ($remain_pins ne ""){
	if ($allow_new){
	  if ($new_plist ne ""){ $new_plist .= " ";}
	  $new_plist .= "$remain_pins";
        }else{
	  die "ERROR: New Pin(s) '$remain_pins' were not already in default pin list\n";
        }
    }
    return $new_plist;
}

##===============================================================================
##                        Main Loop
##===============================================================================
$qt = chr 34;          ## the quote character
$lnum = 0;

$default_table = "";
$default_pins = "";
%pin_measure = ();        ## data indicating what combinatorial delay to measure
$pin_measure_flag = "";   ## set to indicate are measuring combinatorial delay's

$default_ff_clock = "";   ## default flip-flop clock
%ff_measure = ();         ## data indicating what flip-flop delays to measure
$ff_measure_flag = "";    ## set to indicate are measuring FF delays's

$funct_equation = "";     ## function equation from the library
$cellname = "";           ## set to cell name are working on
$cell_flag = "";          ## set when find cell
$cell_done = "";

$icap_flag = "";          ## set to indicate are calculating input capacitances
%ipin_data = ();
$pin_def = "";            ## save pin-name from pin() definition (used in sanity checks)
 
#
#  Parse the input file
#
while (<LIBFILE>) {
   $lnum = $lnum + 1;
   s/^[\s]+//;        # strip leading spaces
   s/[\s]+$//;        # strip trailing spaces
   $iline = $_;
   s/\*\/[\s]*$//;    # strip trailing end of comment

   ($head,$pin_str,$ff_clock,$end_stuff) = split /,[\s]*/;
   if (!defined $head){ $head = "";}
   if (!defined $pin_str){ $pin_str = "";}
   if (!defined $ff_clock){ $ff_clock = "";}
   if (!defined $end_stuff){ $end_stuff = "";}

   $comment = $cond = $table = "";
   if (defined $head){
     ($comment,$cond,$table) = split /[\s]+/, $head;
     if (!defined $comment){ $comment = "";}
     if (!defined $cond){ $cond = "";}
     if (!defined $table){ $table = "";}
     $cond =~ tr/a-z/A-Z/; 
   }

   if ($iline =~ /^[\s]*cell[\s]*\((.*)\)/){
       $cellname = $1;
       if ($debug){print "Found cell: $cellname\n";}
       if ($cell_flag){
	   $cell_done = 1;
	   $cell_flag = "";
       }elsif (($do_cellname eq $cellname || $do_cellname eq "") && !$cell_done){
	   $cell_flag = 1;
	   if (!$outfile){$outfile = $cellname;}
       }
   }elsif ($iline =~ /^[\s]*pin\((.+)\)/){
       $pin_def = $1;
 
   }elsif ($cell_flag && $do_function && ($iline =~ /^[\s]*function[\s]*:[\s](.*)/)){
       $funct_equation = "$1";

   }elsif ($cell_flag && ($comment eq "/*G:" || $comment eq "/*g")){
       if ($debug){print "Found CELL time line = $iline\n";}
       $pin_measure_flag = "1";
       if ($ff_measure_flag){
         die "ERROR: Can't mix cell (/*G:) and Flip-Flop (/*F:) measurements in same file\n";
       }

       if ($table){ $default_table = $table;}
       if ($pin_str){
	   $default_pins = &generate_pinlist($default_pins,$pin_str);
       }
       die "ERROR (Line $lnum): No Default table set on '$iline'\n" if (!$default_table);
       die "ERROR (Line $lnum): No Initial Pins set on '$iline'\n" if (!$default_pins);
       die "ERROR (Line $lnum): No simulation type in '$iline'\n" if ($cond eq "");
       die "ERROR (Line $lnum): Too many fields in '$iline'\n" if ($ff_clock ne "");
       die "ERROR (Line $lnum): Duplicate for '$cond'\n" if (exists $pin_measure{$cond});

       $pin_measure{$cond}{TABLE} = $default_table;
       $pin_measure{$cond}{INIT} = $default_pins;
       $pin_measure{$cond}{LINE} = $lnum;

   }elsif ($cell_flag && ($comment eq "/*F:" || $comment eq "/*f")){
       if ($debug){print "Found FF time line = $iline\n";}
       $ff_measure_flag = "1";
       if ($pin_measure_flag){
         die "ERROR: Can't mix Flip-Flop (/*F:) and Cell (/*G:) measurements in same file\n";
       }

       if ($table){ $default_table = $table;}
       if ($ff_clock) {
	   $ff_clock =~ s/^(\s)+//g;    ## two starting spaces
	   $ff_clock =~ s/(\s)+$//g;    ## remove ending spaces
	   $ff_clock =~ s/_/ /;         ## sperate CP_R into two words
	   $default_ff_clock = $ff_clock;
       }

       if ($pin_str){
	   $default_pins = &generate_pinlist($default_pins,$pin_str);
       }
       die "ERROR (line $lnum): No Default table set for '$iline'\n" if (!$default_table);
       die "ERROR (line $lnum): No Initial Pins set for '$iline'\n" if (!$default_pins);
       die "ERROR (line $lnum): No Clock pin set for '$iline'\n" if (!$default_ff_clock);
       die "ERROR (line $lnum): No simulation type in '$iline'\n" if ($cond eq "");
       die "ERROR (line $lnum): Duplicate for FF '$cond'\n" if (exists $ff_measure{$cond});

       $ff_measure{$cond}{TABLE} = $default_table;
       $ff_measure{$cond}{INIT} = $default_pins;
       $ff_measure{$cond}{CLOCK} = $default_ff_clock;

       $ff_clock = $default_ff_clock;
       $ff_clock =~ s/[\s]+.*//;           ## remove second word (ie R of F) 
       if (&find_init_value($default_pins,$ff_clock) eq ""){
	 $default_pins = &generate_pinlist($default_pins,"$ff_clock=0",1);
       }
       $ff_measure{$cond}{LINE} = $lnum;

   }elsif ($cell_flag && $comment eq "/*C:"){
       if ($debug){print "Found Cap line = $iline\n";}
       $icap_flag = 1;
       if ($pin_str){ 
	 $default_pins = &generate_pinlist($default_pins,$pin_str);
       }

       die "ERROR (Line $lnum): Blank pin-name in /*C:\n" if (!$cond);
       die "ERROR (Line $lnum): Wrong pin-name ($cond vs $pin_def) for /*C\n" if ($cond ne $pin_def);
       die "ERROR (line $lnum): No Initial Pins set for '$iline'\n" if (!$default_pins);
       die "ERROR (Line $lnum): Too many fields in '$iline'\n" if ($ff_clock ne "");

       $ipin_data{$cond}{FOUND} = 1;
       $ipin_data{$cond}{INIT} = $default_pins;
       $ipin_data{$cond}{LINE} = $lnum;
   } 
} 

#
#  Generate the output file
#
if ($outfile eq ""){ $outfile = "unknown"; }
if ($debug){ print "Opening outfile='$outfile'\n"; }
open(OUTFILE,">$outfile.gs") || die "ERROR: Cannot open output file: $outfile.gs";

if ($cell_flag || $cell_done){
   if ($pin_measure_flag || ($icap_flag && !$ff_measure_flag)){
      ##
      ## Measuring combinatorial delays
      ##
      print OUTFILE "\@char_logic.gs;\n\n";
      print OUTFILE "spicec ${qt}.include ${cellname}.netlist${qt};\n";
      print OUTFILE "spicec ${qt}.include setup.mod${qt};\n\n";
      print OUTFILE "spice_deck_options = ${qt}VDD_SOURCE${qt};\n";
      if ($do_function_filter){
	  print OUTFILE "synopsys_function_filter = 1;\n";
      }
      if ($funct_equation){
	print OUTFILE "synopsys_function_equation = $funct_equation\n";
      }
      print OUTFILE "\n";
      if ($do_merge_sim){
	generate_sim_merge();
      }
      print OUTFILE "run_sim() = \n{\n";
      print OUTFILE "  fout = open(${qt}$outfile.sim_stuff${qt});\n";
      print OUTFILE "  pwrite(fout,${qt}//= ${qt},date,";
      print OUTFILE "${qt} VDD=${qt},vdd,${qt} TEMP=${qt},temp);\n\n";

      foreach $ipin (sort keys %pin_measure){
        ($in_name,$in_polar,$out_name,$out_polar) = split /_/,$ipin;
        if (!$in_name || !$in_polar || !$out_name || !$out_polar){
	   die "ERROR: Line $pin_measure{$ipin}{LINE}: Bad condition '$ipin'\n";
        }
        $init_list = &generate_init($pin_measure{$ipin}{INIT},$in_name);
        print OUTFILE "  write_check_cell(${qt}$pin_measure{$ipin}{TABLE}${qt}, ";
        print OUTFILE "${qt}$in_name $in_polar${qt}, ";
        print OUTFILE "${qt}$out_name $out_polar${qt}, ${qt}$init_list${qt});\n";
      }
      print OUTFILE "\n";
   }elsif ($ff_measure_flag){
      ##
      ## Measuring Flip-Flop delays
      ##
      print OUTFILE "\@char_ff.gs;\n";
      if ($icap_flag){
        print OUTFILE "\@char_cap.gs;\n";
      }
      print OUTFILE "\n";
      print OUTFILE "spicec ${qt}.include ${cellname}.netlist${qt};\n";
      print OUTFILE "spicec ${qt}.include setup.mod${qt};\n\n";
      print OUTFILE "spice_deck_options = ${qt}VDD_SOURCE${qt};\n";
      print OUTFILE "\n";
      print OUTFILE "run_sim() = \n{\n";
      print OUTFILE "  fout = open(${qt}$outfile.sim_stuff${qt});\n";
      print OUTFILE "  pwrite(fout,${qt}//= ${qt},date,";
      print OUTFILE "${qt} VDD=${qt},vdd,${qt} TEMP=${qt},temp);\n\n";

      $mode_pflag = 0;
      foreach $ipin (sort keys %ff_measure){
        ($in_name,$in_polar,$out_name,$out_polar,$stuff) = split /_/,$ipin;
	if (!defined $in_name || !defined $in_polar || 
            !defined $out_name || !defined $out_polar || defined $stuff){
	  print "ERROR: Line $ff_measure{$ipin}{LINE}: Bad Condition '$ipin' ... '$mode' '$mode_opin'\n";
	  die;
	}
	$mode = $mode_opin = "";
        if ($in_polar eq "1" || $in_polar eq "0"){
	    $mode = $out_name;
            $mode_opin = $out_polar;
        }
        if (($mode ne "") && ($mode ne "SETUP") && ($mode ne "HOLD") && 
	              ($mode ne "REC") && ($mode ne "REM") ){
	  print "ERROR: Line $ff_measure{$ipin}{LINE}: bad condition '$ipin' ... '$mode' '$mode_opin'\n";
	  die;
        }
	if ($mode eq ""){
	  $mode_pflag = 1;
	  $clock_full = $ff_measure{$ipin}{CLOCK};
	  ($clk_name,$clk_polar) = split /[\s]+/,$clock_full;
          $init_list = &generate_init($ff_measure{$ipin}{INIT},$in_name,$clk_name);

           ## write_check_ff_cell("table_2","CP R","Q R","TE 0, TI 0, D 0/1, SD 1","CP R");
          print OUTFILE "  write_check_ff_cell(${qt}$ff_measure{$ipin}{TABLE}${qt}, "; 
          print OUTFILE "${qt}$in_name $in_polar${qt}, ";
          print OUTFILE "${qt}$out_name $out_polar${qt}, ";
	  print OUTFILE "${qt}$init_list${qt}, ${qt}$ff_measure{$ipin}{CLOCK}${qt});\n";
        }
      }  ## mode not set 
      if ($mode_pflag > 0){ print OUTFILE "\n"; }

      foreach $ipin (sort keys %ff_measure){
        ($in_name,$in_polar,$mode,$mode_opin) = split /_/,$ipin;

	if ($in_polar eq "1" || $in_polar eq "0"){
	  ## write_check_sethold_ff("HOLD","table_13","D 1","SO","TE 0, TI 0, D 0, SD 1","CP R");
	  $prt_mode = sprintf "%-7s", "${qt}$mode${qt}";

	  $clock_full = $ff_measure{$ipin}{CLOCK};
	  ($clk_name,$clk_polar) = split /[\s]+/,$clock_full;
          $init_list = &generate_init($ff_measure{$ipin}{INIT},$in_name,$clk_name);
	  $lnum = $ff_measure{$ipin}{LINE};
##
##        This is now allowed (needed for unencoded mux selects)
##        die "ERROR (line $lnum): Init-List '$init_list' contains /\n" if ($init_list=~/\//);
##
	  print OUTFILE "  write_check_sethold_ff($prt_mode, ";
          print OUTFILE "${qt}$ff_measure{$ipin}{TABLE}${qt}, "; 
          print OUTFILE "${qt}$in_name $in_polar${qt}, ";
          print OUTFILE "${qt}$mode_opin${qt}, ";
	  print OUTFILE "${qt}$init_list${qt}, ${qt}$clock_full${qt});\n";
        }
      } ## mode set

      print OUTFILE "\n";
  }else{
      die "ERROR: No simulation controls detected in input file\n";
  }

  if ($icap_flag){
      foreach $ipin (sort keys %ipin_data){
	  $lnum = $ipin_data{$ipin}{LINE};
	  $init_list = &generate_init($ipin_data{$ipin}{INIT},$ipin);
          $init_list =~ s/([0-9*])\/([0-9*])/$1/g;   ## pick first state from rise/fall stuff */
          $init_list =~ s/([*])/0/g;                 ## change wildcards to 0
	  print OUTFILE "  write_check_icap(${qt}$ipin${qt}, ${qt}$init_list${qt});\n";
      }
      print OUTFILE "\n";
  }
  print OUTFILE "  pwrite(fout,${qt}//= ${qt},date);\n";
  print OUTFILE "  close(fout);\n";
  print OUTFILE "}\n\n";
  if (!$run_gspice){
       print OUTFILE "debug_func = ${qt}CALL${qt};\n";
  }
  print OUTFILE "run_sim();\n";
  if ($do_libmerge){
       print OUTFILE "rval = spawn(${qt}lib_merge $libfile $outfile.sim_stuff ";
       $libfile =~ /(.+).lib/;
       print OUTFILE "-o$1.up_lib${qt}\);\n";
       print OUTFILE "assert(rval==0);\n";
  }
  print OUTFILE "\n";
}

close OUTFILE;
print "\nCreated File: $outfile.gs \n\n";


