#!/usr/bin/perl
# Nelson Hu
# EE464H
# 08/07/03

#######################################################
# This program "Spectre2Hspice.pl" generates Hspice code from
#  Spectre netlist (si.inp)
#  The ouput of this program will then be able to run in Hspice
#  for timing analysis

#######################################################
# how to use this program:
# in the folder where si.inp is found, type
#    perl /home/projects/abraham/vlsi464/spicetest/FinalTOOLS/Spectre2Hspice.pl si.inp 3
# the number 3 at the end is the resolution for the timing analysis. it there is a longer delay, a larger number is used
# so that when running Hspice, the code will not fail.

#######################################################
# Input:
#  si.inp
#  a number for resolution.

#######################################################
# Output:
#  %CELLNAME%.sp

#######################################################
# Transition Time and Output Capacitance
# Hspice will use these two column to generate a matrix of timing analysis
#######################################################

#transition time
@a = qw *5ps 50ps 100ps 150ps 200ps 250ps 300ps*;
#capacitance
@b = qw *0ff 3.5ff 17.5ff 35ff 87.5ff 105ff 231ff*;

#before 07/19/03
#@a = qw *0 10.695ps 40.71ps 70.75ps 156.49ps 301.6ps 591.8ps*;
#@b = qw *0 2FF 8FF 20FF 50FF 100FF 200FF* ;

#seokjin suggested
#@a = qw *0.03ps 0.1ps 0.4ps 0.9ps 1.5ps 2.2ps 3ps*;
#@b = qw *0.00035pf 0.021pf 0.0385pf 0.084pf 0.147pf 0.231pf 0.3115pf*;

#######################################################
# get the file name (usually si.inp)
#######################################################
open LALA, "$ARGV[0]";
@line = <LALA>;
close LALA;

#######################################################
# get the second argument, the resolution
#######################################################
$hp = $ARGV[1];

#######################################################
# aquire the name of the cell from si.inp and use the
# name of the cell to create %CELLNAME%.sp
#######################################################
foreach (@line){
	if ($_ =~ /Design cell name:/){
		@temp = split / /,$_;
		$filename = $temp[$#temp];
		chomp $filename;}}

open HSPICE, ">$filename.sp";

#######################################################
# look for gate and number of input
# $OtherInput is either "gnd" or "vdd".
#    it specifies for multiple inputs to tie all to gnd or vdd
# $Inverted is either "T" or "F".
#    it tells the program that the gate is inverted
# this section needs to be added for new type of logic cells
#######################################################

$NumberOfInput = $filename;
if ($filename =~ /inv/){
    $NumberOfInput = 1;
    $output = "Z";
    $inverted = "T";}
elsif ($filename =~ /buf/){
    $NumberOfInput = 1;
    $output = "Z";
    $inverted = "F";}
elsif ($filename =~ /mux/){   #might not work
    $NumberOfInput = 3;
    $OtherInput = " vdd";
    $output = "Z";
    $inverted = "F";}
elsif ($filename =~ /nand/){
    $NumberOfInput =~ s/nand//g;
    $NumberOfInput =~ s/x[\d]+//g;
    $OtherInput = " vdd";
    $output = "Z";
    $inverted = "T";}
elsif ($filename =~ /nor/){
    $NumberOfInput =~ s/nor//g;
    $NumberOfInput =~ s/x[\d]+//g;
    $OtherInput = " gnd";
    $output = "Z";
    $inverted = "T";}
elsif ($filename =~ /xor/){
    $NumberOfInput =~ s/xor//g;
    $NumberOfInput =~ s/x[\d]+//g;
    $OtherInput = " gnd";
    $output = "Z";
    $inverted = "F";}
elsif ($filename =~ /and/){
    $NumberOfInput =~ s/and//g;
    $NumberOfInput =~ s/x[\d]+//g;
    $OtherInput = " vdd";
    $output = "Z";
    $inverted = "F";}
elsif ($filename =~ /or/){
    $NumberOfInput =~ s/or//g;
    $NumberOfInput =~ s/x[\d]+//g;
    $OtherInput = " gnd";
    $output = "Z";
    $inverted = "F";}

if ($NumberOfInput == 1){
    $input = "A";}
if ($NumberOfInput == 2){
    $input = "A B";}
if ($NumberOfInput == 3){
    $input = "A B C";}
if ($NumberOfInput == 4){
    $input = "A B C D";}
if ($NumberOfInput == 5){
    $input = "A B C D E";}

$inout = $input." ".$output;

#######################################################
# to replace the "\" and carriage return (if the line is too long)
# with carriage return and a "+" in HSPICE format
#######################################################
for ($n = 0; $n <= $#line; $n++){
	if ($line[$n] =~ /\\\n/){
		chomp $line[$n];
		chop $line[$n];
		$line[$n] .= $line[($n + 1)];
		$line[$n] =~ s/  //g;}
		}

#######################################################
# to discard all the lines except the one starts with
# _inst
#######################################################
$n = 0;
foreach (@line) {
	if ($_ =~ /_inst\d+/){
		$new[$n] = $_;
		$n++;}
		}
#######################################################
# replace _inst with C* or M* and take out the word
# capacitor and region=sat. also take out "(", ")", "!"
#######################################################
$M = 1; $C = 1;
foreach (@new) {
	if (($_ =~ /tsmc20P/) or ($_ =~ /tsmc20N/)){
		$_ =~ s/_inst[\d]+/M$M/g;
		$M++;}
	if ($_ =~ /capacitor/){
		$_ =~ s/_inst[\d]+/C$C/g;
		$C++;
		$_ =~ s/capacitor//g;}
	$_ =~ s/ region\=sat//g;
	$_ =~ s/\(//g;
	$_ =~ s/\)//g;
	$_ =~ s/\!//g;
	$_ =~ s/  / /g;}

#######################################################
# duplicate m if m is greater than 2
#######################################################

foreach (@new) {
	@values = split / /,$_;
	$values[$#values] =~ s/m=//g;
	$temp = $values[$#values];
	chomp $temp;
	$values[$#values] = "\n";
	$_ = join " ",@values;
	$temp--;
	$copy = $_;
	for (1..$temp) {
		$new[$#new + 1] = $copy;
		@change = split / /,$new[$#new];
		if ($change[0] =~ s/M[\d]+/M$M/g){;
		$M++;}
		if ($change[0] =~ s/C[\d]+/C$C/g){;
		$C++;}
		$new[$#new] = join " ",@change;
		}}

#######################################################
# exchange w,l; as,ad; ps,pd
#######################################################

foreach (@new) {
	@values = split / /,$_;
	if ($values[0] =~ /M(\d)/){
		($values[7], $values[6]) = ($values[6], $values[7]);
		($values[9], $values[8]) = ($values[8], $values[9]);
		($values[11], $values[10]) = ($values[10], $values[11]);}
	$_ = join " ",@values;}

#######################################################
# adding the beginning of the file
#######################################################

$middle = join " ",@new;
$middle =~ s/\n /\n/g;

$top_middle = "\*".$filename.".sp\n.options SPICE NOMOD AUTOSTOP LVLTIM=3\n.param ttra=0.1n LV=0.1e-12\n.temp 27\n\n.include \"/usr/local/packages/cadence/local/models/hspice/standalone/tsmc20P.m\"\n.include \"/usr/local/packages/cadence/local/models/hspice/standalone/tsmc20N.m\"\n.global vdd\n.global gnd\n\n\n.subckt $filename $inout\n". $middle.".ends\n";

#######################################################
# find number of input
#######################################################
@input = split / /,$input;
$n_input = $#input;		#number of input - 1
$G = " gnd";
$V = " vdd";
$I = " input";
$O = " output";

chomp $hp;
$period = $hp + $hp;
$wholeperiod = $period + $hp;
$resolution = (($period + 1) / 10000);

print "the resolution is ".$resolution."\n";

$lastpart = "X".$filename.$I.$OtherInput x $n_input.$O." ".$filename."\nCLOAD".$O.$G." LV\n\nVa".$I.$G." PULSE\(0,3.3,1p,Ttra,Ttra,".$hp."n,".$period."n\)\n\nvdd".$V.$G." 3.3\n\n";

#######################################################
# middie-last part
#######################################################
if ($inverted eq "T"){
    $abc = ".MEAS TRAN cell_rise TRIG V($I) val=1.65 TD=0n fall=1\n+\tTARG V($O) val=1.65 rise=1\n".
	   ".MEAS TRAN cell_fall TRIG V($I) val=1.65 TD=0n rise=1\n+\tTARG V($O) val=1.65 fall=1\n".
	   ".MEAS TRAN rise_slew TRIG V($O) val=0.33 TD=0n rise=1\n+\tTARG V($O) val=2.97 rise=1\n".
	   ".MEAS TRAN fall_slew TRIG V($O) val=2.97 TD=0n fall=1\n+\tTARG V($O) val=0.33 fall=1\n".
	   ".TRAN ".$resolution."N ".$wholeperiod."N sweep DATA=DATNM\n";}
elsif ($inverted eq "F"){
    $abc = ".MEAS TRAN cell_rise TRIG V($I) val=1.65 TD=0n rise=1\n+\tTARG V($O) val=1.65 rise=1\n".
	   ".MEAS TRAN cell_fall TRIG V($I) val=1.65 TD=0n fall=1\n+\tTARG V($O) val=1.65 fall=1\n".
	   ".MEAS TRAN rise_slew TRIG V($O) val=0.33 TD=0n rise=1\n+\tTARG V($O) val=2.97 rise=1\n".
	   ".MEAS TRAN fall_slew TRIG V($O) val=2.97 TD=0n fall=1\n+\tTARG V($O) val=0.33 fall=1\n".
	   ".TRAN ".$resolution."N ".$wholeperiod."N sweep DATA=DATNM\n";}

#######################################################
# vary capacitance and delay time
# change @a, @b on top
#######################################################
@c;
$#c = 0;
foreach $a (@a) {
	foreach $b (@b) {
		$c[$#c++] = ($a."\t".$b."\n");}}
$c = join " ",@c;
$c =~ s/\n /\n/g;

$datnm = ".DATA DATNM\nTtra\tLV\n$c.ENDDATA\n";

#print $datnm;

#######################################################
# change .alter
#######################################################
@last;
$count = 2;
for (1..$n_input){
	$last[0] = "X$filename";
	$last[1] = $OtherInput;
	for (1..$n_input){
		$last[$_ + 1] = $OtherInput;}
	$last[$count++] = $I;
	$last .= ".alter\n@last $O $filename\n";
	}
$last .= ".end\n";

#######################################################
# combine all
#######################################################

$final = "$top_middle"."\n"."$lastpart"."$abc\n"."$datnm"."\n"."$last";
print HSPICE $final;

close HSPICE;






