setup_hold.pl,v #1

  • //
  • guest/
  • robert_yu/
  • autochar-1.5.3/
  • src/
  • RCS/
  • setup_hold.pl,v
  • View
  • Commits
  • Open Download .zip Download (70 KB)
head	1.33;
access;
symbols;
locks; strict;
comment	@# @;


1.33
date	99.06.07.15.02.39;	author ryu;	state Exp;
branches;
next	1.32;

1.32
date	99.02.03.07.26.56;	author ryu;	state Exp;
branches;
next	1.31;

1.31
date	99.01.26.18.22.02;	author ryu;	state Exp;
branches;
next	1.30;

1.30
date	99.01.22.19.04.46;	author ryu;	state Exp;
branches;
next	1.29;

1.29
date	99.01.22.18.50.10;	author ryu;	state Exp;
branches;
next	1.28;

1.28
date	99.01.22.18.25.17;	author ryu;	state Exp;
branches;
next	1.27;

1.27
date	99.01.20.07.44.59;	author ryu;	state Exp;
branches;
next	1.26;

1.26
date	99.01.14.10.19.02;	author ryu;	state Exp;
branches;
next	1.25;

1.25
date	99.01.13.07.18.42;	author ryu;	state Exp;
branches;
next	1.24;

1.24
date	98.09.13.04.14.38;	author ryu;	state Exp;
branches;
next	1.23;

1.23
date	98.09.12.19.54.02;	author ryu;	state Exp;
branches;
next	1.22;

1.22
date	98.09.11.06.19.45;	author ryu;	state Exp;
branches;
next	1.21;

1.21
date	98.09.08.13.16.49;	author ryu;	state Exp;
branches;
next	1.20;

1.20
date	98.09.06.20.43.23;	author ryu;	state Exp;
branches;
next	1.19;

1.19
date	98.09.05.22.10.32;	author ryu;	state Exp;
branches;
next	1.18;

1.18
date	98.09.01.04.49.20;	author ryu;	state Exp;
branches;
next	1.17;

1.17
date	98.08.30.19.24.00;	author ryu;	state Exp;
branches;
next	1.16;

1.16
date	98.08.23.22.11.24;	author ryu;	state Exp;
branches;
next	1.15;

1.15
date	98.08.23.21.59.07;	author ryu;	state Exp;
branches;
next	1.14;

1.14
date	98.08.23.21.16.02;	author ryu;	state Exp;
branches;
next	1.13;

1.13
date	98.08.23.12.03.44;	author ryu;	state Exp;
branches;
next	1.12;

1.12
date	98.08.23.10.13.32;	author ryu;	state Exp;
branches;
next	1.11;

1.11
date	98.08.23.07.19.07;	author ryu;	state Exp;
branches;
next	1.10;

1.10
date	98.08.23.06.56.57;	author ryu;	state Exp;
branches;
next	1.9;

1.9
date	98.08.18.09.33.00;	author ryu;	state Exp;
branches;
next	1.8;

1.8
date	98.08.17.16.58.24;	author ryu;	state Exp;
branches;
next	1.7;

1.7
date	98.08.17.04.25.02;	author ryu;	state Exp;
branches;
next	1.6;

1.6
date	98.08.17.03.34.11;	author ryu;	state Exp;
branches;
next	1.5;

1.5
date	98.08.17.02.54.12;	author ryu;	state Exp;
branches;
next	1.4;

1.4
date	98.08.17.02.49.06;	author ryu;	state Exp;
branches;
next	1.3;

1.3
date	98.08.17.02.41.17;	author ryu;	state Exp;
branches;
next	1.2;

1.2
date	98.08.16.13.37.29;	author ryu;	state Exp;
branches;
next	1.1;

1.1
date	98.08.15.11.38.54;	author ryu;	state Exp;
branches;
next	;


desc
@#! /usr/local/bin/perl
@


1.33
log
@Optional space in measure results
@
text
@#	$Id: setup_hold.pl,v 1.32 1999/02/03 07:26:56 ryu Exp ryu $

#	Copyright (C) 1999 Robert K. Yu
#	email: robert@@yu.org

#	This file is part of Autochar.

#	Autochar is free software; you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation; either version 2, or (at your option)
#	any later version.

#	Autochar is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.

#	You should have received a copy of the GNU General Public License
#	along with Autochar; see the file COPYING.  If not, write to the
#	Free Software Foundation, Inc., 59 Temple Place - Suite 330,
#	Boston, MA 02111-1307, USA.

#   sh_run --
#	Top-level function setup/hold characterization.
#	Generate the spice netlists, run hspice, and extract
#	data.
#
sub sh_run {
    local($d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list) = @@_;

    printf OUT "### SETUP/HOLD #############################################################\n\n";
    printf OUT "Cellname:\t\"$cellname\"\n";
    printf OUT "D Input:\t\"$d\"\n";
    printf OUT "Clock Input:\t\"$clk\"\t($clktype)\n";
    printf OUT "Q Output:\t\"$q\"\t($qtype)\n";
    printf OUT "Critical Node:\t\"$c\"\t($ctype)\n\n";

    &s_run ('lh', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);
    &s_run ('hl', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);

    &h_run ('lh', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);
    &h_run ('hl', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);

    printf OUT "\n\n",
}


#------ SETUP TIME CHARACTERIZATION --------------------------------------------

sub s_run {

    my($out_trans, $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list) = @@_;

    local($run_name, $dtrans);
    local($optmod, $optparam, $optmeasure);

    # check
    if (($clktype ne 'rising') && ($clktype ne 'falling')) {
	die "ERROR: clock type must be either 'rising' or 'falling'\n";
    }
    if (($qtype ne 'inverting') && ($qtype ne 'non_inverting')) {
	die "ERROR: q type must be either 'inverting' or 'non_inverting'\n";
    }

    # give names to these puppies
    $optmod = 'optmod';
    $optparam = 'optsetup';
    $optmeasure = 'optpass';

    $run_name = &run_file_name($cellname, $d, $clk, $q, 's');
    open(SPICEIN,">$run_name") || die "ERROR:  Cannot open file '$run_name'.";

    # Create the hspice netlist(s)
    &print_header(SPICEIN, '*');
    printf SPICEIN "*	Char:	D-Flop Setup Time Characterization\n";
    printf SPICEIN "*	Data:	\"$d\"\n";
    printf SPICEIN "*	Clock:	\"$clk\"\n";
    printf SPICEIN "*	Q:	\"$q\"\n";
    printf SPICEIN "*	C:	\"$c\"\n";
    printf SPICEIN "*	Trans:	\"$out_trans\"\n";

    &s_print_setup (SPICEIN);
    &s_print_source (SPICEIN, $clktype, $out_trans, $qtype);
    &s_print_dut (SPICEIN, $d, $clk, $q, $tie, @@tie_list);
    &s_print_measure (SPICEIN, $clktype, $out_trans, $ctype, $c);
    &s_print_trans (SPICEIN, $clktype, $out_trans);

    printf SPICEIN ".end\n";
    close(SPICEIN);

    &run_spice($run_name);

    &s_report_spice($run_name, $out_trans, $d, $clktype, $clk, $qtype, $q, $ctype, $c);
}


sub s_print_setup {

    my ($fp) = @@_;

    printf $fp "\n*--- SETUP ---------------------------------------------------\n";
    printf $fp ".include '$techpath/$spice_corner'\n";
    printf $fp ".include '$spice_netlist'\n";
    if ($spice_include ne 'none') {
	printf $fp "$spice_include\n";
    }

    if ($spice_type eq 'smartspice') {
	printf $fp "$smartspice_options\n";
	printf $fp ".param isetup = 0\n" ;
	printf $fp ".param setup_hold_scale = '$setup_hold_scale'\n" ;
	printf $fp ".param setup = 'isetup*setup_hold_scale'\n" ;
    } else {
	printf $fp "$optim_options\n";
	printf $fp ".model $optmod opt method=bisection\n";
	printf $fp "+\trelin = $relin\n";
	printf $fp "+\trelout = $relout\n";
	printf $fp ".param setup = $optparam('$setup_range[0]', '$setup_range[0]', '$setup_range[1]')\n" ;
    }

    if ($#slewrate != -1) {
	printf $fp ".param slewrate = '$slewrate[0]'\n" ;
	printf $fp ".param slew_start = '$start_slew_percent'\n" ;
	printf $fp ".param slew_end = '$end_slew_percent'\n" ;
    }
}


#	Modifies dtrans
#
sub s_print_source {

    my ($fp, $clktype, $out_trans, $qtype) = @@_;

    printf $fp "\n*--- INPUTS --------------------------------------------------\n";

    if ($clktype eq 'rising') {
	if ($#slewrate != -1) {
	    printf $fp "vclk vclk $low_value pulse (
+	'$low_value'
+	'$high_value'
+	'$trans_delay+$trans_risetime/2'
+	'0'
+	'0'
+	'$trans_pulse_width+$trans_risetime/2+$trans_falltime/2'
+	'$trans_period')\n";
	} else {
	    printf $fp "vclk vclk $low_value pulse (
+	'$low_value'
+	'$high_value'
+	'$trans_delay'
+	'$trans_risetime'
+	'$trans_falltime'
+	'$trans_pulse_width'
+	'$trans_period')\n";
	}
    } elsif ($clktype eq 'falling') {
	if ($#slewrate != -1) {
	    printf $fp "vclk vclk $low_value pulse (
+	'$high_value'
+	'$low_value'
+	'$trans_delay+$trans_risetime/2'
+	'0'
+	'0'
+	'$trans_pulse_width+$trans_risetime/2+$trans_falltime/2'
+	'$trans_period')\n";
	} else {
	    printf $fp "vclk vclk $low_value pulse (
+	'$high_value'
+	'$low_value'
+	'$trans_delay'
+	'$trans_risetime'
+	'$trans_falltime'
+	'$trans_pulse_width'
+	'$trans_period')\n";
	}
    } else {
	die "ERROR: unknown clock transition type '$clktype'\n";
    }

    if ( (($out_trans eq 'lh') && ($qtype eq 'non_inverting')) ||
	 (($out_trans eq 'hl') && ($qtype eq 'inverting')) ) {

	$dtrans = 'rise';
	printf $fp "vd vd $low_value pulse (
+	'$low_value'
+	'$high_value'
+	'$trans_delay+$trans_risetime+2*$trans_pulse_width+$trans_falltime-setup'
+	'$trans_risetime'
+	'$trans_falltime'
+	'3*$trans_period'
+	'4*$trans_period')\n";

    } elsif ( (($out_trans eq 'hl') && ($qtype eq 'non_inverting')) ||
	      (($out_trans eq 'lh') && ($qtype eq 'inverting')) ) {

	$dtrans = 'fall';
	printf $fp "vd vd $low_value pulse (
+	'$high_value'
+	'$low_value'
+	'$trans_delay+$trans_risetime+2*$trans_pulse_width+$trans_falltime-setup'
+	'$trans_risetime'
+	'$trans_falltime'
+	'3*$trans_period'
+	'4*$trans_period')\n";

    } else {
	die "ERROR: unknown combination of '$out_trans' and '$qtype'\n";
    }
}


sub s_print_dut {

    my($fp, $d, $clk, $q, $tie, $tie_list) = @@_;
    my($term, $termname, $termtype);
    my($dbuf, $clkbuf, $outload);
    my($vcvs, @@inlist, @@reflist);
    local($term_no, @@vcvs_list, @@output_loads);

    $term_no = 0;

    if ($buffer{$d} ne '') {
	$dbuf = $buffer{$d};
    } else {
	$dbuf = $buffer{'default'};
    }
    if ($buffer{$clk} ne '') {
	$clkbuf = $buffer{$clk};
    } else {
	$clkbuf = $buffer{'default'};
    }
    if ($#slewrate != -1) {
	$clkbuf = 'slewbuffer';
	printf STDERR "INFO: slewbuffer buffer used for slew rate setup_hold at clock input.\n";
    }

    printf $fp "\n*--- TEST CIRCUIT --------------------------------------------\n";

    @@inlist = ($d, $clk);
    @@reflist = ('d', 'clk');

    if ($dbuf eq 'none') {
	printf $fp "vshortd vd d DC 0\n";
    } else {
	printf $fp "xdbuf vd d $dbuf\n";
    }
    if ($clkbuf eq 'none') {
	printf $fp "vshortclk vclk clk DC 0\n";
    } else {
	printf $fp "xclkbuf vclk clk $clkbuf\n";
    }

    printf $fp "xflop\n";
    foreach $term (@@termlist) {
	($termname, $termtype) = split(':', $term);
	if ($termname eq $d) {
	    printf $fp "+\td\t\$ $term\n";
	    next;
	}
	if ($termname eq $clk) {
	    printf $fp "+\tclk\t\$ $term\n";
	    next;
	}
	if ($termname eq $q) {
	    printf $fp "+\t%s\t\$ $term\n", &lookup_output_load($termname, 'q');
	    next;
	}
	if ($termtype eq 'i') {
	    printf $fp "+\t%s\t\$ $term\n",
		&lookup_input($termname, \@@inlist, \@@reflist, $tie, @@tie_list);
	    next;
	}
	if ($termtype eq 'o') {
	    printf $fp "+\t%s\t\$ $term\n", &lookup_output_load($termname);
	    next;
	}
    }
    printf $fp "+\t$cellname\n";

    # if any
    foreach $vcvs (@@vcvs_list) {
	printf $fp "$vcvs\n";
    }

    printf $fp "\n*--- LOADS ---------------------------------------------------\n";
    # if any
    foreach $outload (@@output_loads) {
	printf $fp "$outload\n";
    }
}


sub s_print_measure {

    my($fp, $clktype, $out_trans, $ctype, $c) = @@_;

    printf $fp "\n*--- MEASURE -------------------------------------------------\n";
    printf $fp ".option autostop\n";

    printf $fp "* Measure setup time:\n";

    if ($spice_type eq 'smartspice') {
	printf $fp ".measure tran isetup param='isetup'\n";
	printf $fp ".measure tran setup param='setup'\n";
    }

    printf $fp ".measure tran setup_${out_trans} %s v(d) val='$midpoint_value' cross=1\n",
	&trig_word();
    if ($clktype eq 'rising') {
	printf $fp "+\ttarg=v(clk) val='$midpoint_value' rise=2\n";
    } else {
	printf $fp "+\ttarg=v(clk) val='$midpoint_value' fall=2\n";
    }

    printf $fp "* Measure clock slew rate:\n";
    if ($clktype eq 'rising') {
	printf $fp
	    ".measure tran clkslew %s v(clk) val='$slew_r1' rise=2\n",
	    &trig_word();
	printf $fp
	    "+\ttarg=v(clk) val='$slew_r2' rise=2\n";
    } else {
	printf $fp
	    ".measure tran clkslew %s v(clk) val='$slew_f1' fall=2\n",
	    &trig_word();
	printf $fp
	    "+\ttarg=v(clk) val='$slew_f2' fall=2\n";
    }

    printf $fp "\n* Measure internal criterion node:\n";
    printf $fp ".measure tran vcrit find v(xflop.${c})\n";
    if ($clktype eq 'rising') {
	printf $fp "+\twhen v(clk)='$clock_percent*$high_value' rise=2\n"; 
    } else {
	printf $fp "+\twhen v(clk)='(1-$clock_percent)*$high_value' fall=2\n"; 
    }

    # cnode:
    if ( (($dtrans eq 'rise') && ($ctype eq 'inverting')) ||
	 (($dtrans eq 'fall') && ($ctype eq 'non_inverting')) ) {
	printf $fp ".measure tran $optmeasure param='($high_value-vcrit)/$high_value'\n";
	if ($spice_type ne 'smartspice') {
	    printf $fp "+\tgoal='${criterion_percent}'\n";
	}
    } elsif ( (($dtrans eq 'fall') && ($ctype eq 'inverting')) ||
	      (($dtrans eq 'rise') && ($ctype eq 'non_inverting')) ) {
	printf $fp ".measure tran $optmeasure param='vcrit/$high_value'\n";
	if ($spice_type ne 'smartspice') {
	    printf $fp "+\tgoal='${criterion_percent}'\n";
	}
    }
}


sub s_print_trans {

    my($fp, $clktype, $out_trans) = @@_;
    my($j);

    printf $fp "\n*--- TRANSIENT -----------------------------------------------\n";
    if ($spice_type eq 'smartspice') {

	printf $fp "* Measure final clock->q time:\n";
	if ($clktype eq 'rising') {
	    printf $fp ".measure tran clk_q delay v(clk) val='$midpoint_value' rise=2\n";
	} else {
	    printf $fp ".measure tran clk_q delay v(clk) val='$midpoint_value' fall=2\n";
	}
	if ($out_trans eq 'lh') {
	    printf $fp "+\ttarg=v(q) val='$midpoint_value' rise=1\n";
	} elsif ($out_trans eq 'hl') {
	    printf $fp "+\ttarg=v(q) val='$midpoint_value' fall=1\n";
	} else {
	    die "ERROR: unknown output transition '$out_trans'\n";
	}
	printf $fp ".trans $trans_timestep '$trans_timestop'\n";

    } else {
	printf $fp ".trans $trans_timestep '$trans_timestop' sweep
+	optimize=$optparam
+	results=$optmeasure
+	model=$optmod\n";

	# Have to put this here in order for bisect to work. A
	# failed measurement during bisect causes bisect to abort.
	printf $fp ".trans $trans_timestep '$trans_timestop'\n";
	printf $fp "\n* Measure final clock->q time:\n";
	if ($clktype eq 'rising') {
	    printf $fp ".measure tran clk_q trig=v(clk) val='$midpoint_value' rise=2\n";
	} else {
	    printf $fp ".measure tran clk_q trig=v(clk) val='$midpoint_value' fall=2\n";
	}
	if ($out_trans eq 'lh') {
	    printf $fp "+\ttarg=v(q) val='$midpoint_value' rise=1\n";
	} elsif ($out_trans eq 'hl') {
	    printf $fp "+\ttarg=v(q) val='$midpoint_value' fall=1\n";
	} else {
	    die "ERROR: unknown output transition '$out_trans'\n";
	}
    }

    if ($spice_type eq 'smartspice') {
	&s_print_control($fp, $out_trans);
    }

    printf $fp "\n* Alter slewrate:\n";
    for ($j = 1; $j <= $#slewrate; $j++) {
	printf $fp ".alter\n";
	printf $fp ".param slewrate = '$slewrate[$j]'\n" ;
    }
}


sub s_print_control {
    my($fp, $out_trans) = @@_;

    printf $fp "\n*--- CONTROL -------------------------------------------------\n";
    printf $fp ".control
# find fail
modif loop=${iterations} stop ${optmeasure} le ${criterion_percent} isetup -= (0)${window} prtbl
set fail = \$isetup
# find pass
modif loop=${iterations} stop ${criterion_percent} le ${optmeasure} isetup += (0)${window} prtbl
set pass = \$isetup

set i = 0
set window = \`expr \$pass - \$fail\`

# Save measurements
set save_setup = \$setup_${out_trans}
set save_clkslew = \$clkslew
set save_clk_q = \$clk_q
set save_vcrit = \$vcrit
set save_${optmeasure} = \$${optmeasure}

echo Iteration \$i: Pass = \$pass, Fail = \$fail, Window = \$window, Setup = \$save_setup, Criterion = \$save_${optmeasure}
";

    printf $fp "
# Binary search
while (\$window > ${resolution}) 
    set i = \`expr \$i + 1\`
    set sum = \`expr \$pass + \$fail\`
    set midpoint = \`expr \$sum / 2\`

    modif loop=1 isetup = \$midpoint prtbl

    if (\$${optmeasure} > ${criterion_percent} or \$${optmeasure} eq ${criterion_percent})
	set pass = \$midpoint

	# Save measurements
	set save_setup = \$setup_${out_trans}
	set save_clkslew = \$clkslew
	set save_clk_q = \$clk_q
	set save_vcrit = \$vcrit
	set save_${optmeasure} = \$${optmeasure}

    else
	set fail = \$midpoint
    end
    set window = \`expr \$pass - \$fail\`

    echo Iteration \$i: Pass = \$pass, Fail = \$fail, Window = \$window, Setup = \$save_setup, Criterion = \$save_${optmeasure}
end

echo Final setup_${out_trans} = \$save_setup
echo Final clkslew = \$clkslew
echo Final clk_q = \$clk_q
echo Final vcrit = \$vcrit
echo Final ${optmeasure} = \$${optmeasure}

.endc\n";

}

sub s_report_spice {

    my($run_name, $out_trans, $d, $clktype, $clk, $qtype, $q, $ctype, $c) = @@_;

    my($base,$dir,$ext,$spiceout);
    my(@@setup, @@clkslew, @@clk_q, @@vcrit, @@pass);
    my(@@scaled_setup, @@scaled_clkslew, @@scaled_clk_q, $i);

    ($base,$dir,$ext) = fileparse($run_name, '\.sp');
    $spiceout = $base . '.out';

    printf STDERR "Extracting results from '$spiceout' ...\n";

    # grab the last values
    open(SPICEOUT, $spiceout) || die "ERROR: Cannot find '$spiceout'.\n";

    if ($spice_type eq 'smartspice') {
	while (<SPICEOUT>) {
	    if (($name, $value) = /^Final (setup_${out_trans}) *= +([0-9\+\-eE\.]+)/) {
		push(@@setup, $value);
		next;
	    }
	    if (($name, $value) = /^Final (clkslew) *= +([0-9\+\-eE\.]+)/) {
		push (@@clkslew, $value);
		next;
	    }
	    if (($name, $value) = /^Final (clk_q) *= +([0-9\+\-eE\.]+)/) {
		push (@@clk_q, $value);
		next;
	    }
	    if (($name, $value) = /^Final (vcrit) *= +([0-9\+\-eE\.]+)/) {
		push (@@vcrit, $value);
		next;
	    }
	    if (($name, $value) = /^Final ($optmeasure) *= +([0-9\+\-eE\.]+)/) {
		push (@@pass, $value);
		next;
	    }
	}
    } else {
	while (<SPICEOUT>) {
	    if (($name, $value) = /^ +(setup_${out_trans}) *= +([0-9\+\-eE\.]+)/) {
		push(@@setup, $value);
		next;
	    }
	    if (($name, $value) = /^ +(clkslew) *= +([0-9\+\-eE\.]+)/) {
		push (@@clkslew, $value);
		next;
	    }
	    if (($name, $value) = /^ +(clk_q) *= +([0-9\+\-eE\.]+)/) {
		push (@@clk_q, $value);
		next;
	    }
	    if (($name, $value) = /^ +(vcrit) *= +([0-9\+\-eE\.]+)/) {
		push (@@vcrit, $value);
		next;
	    }
	    if (($name, $value) = /^ +($optmeasure) *= +([0-9\+\-eE\.]+)/) {
		push (@@pass, $value);
		next;
	    }
	}
    }

    @@setup = &halve_list(@@setup);
    @@clkslew = &halve_list(@@clkslew);
    @@vcrit = &halve_list(@@vcrit);
    @@pass = &halve_list(@@pass);

    printf OUT "\n";
    printf OUT "    InputSlew\tSetup_${out_trans}\tClock-Q\t\tCritNode\tCritPercent\n";
    printf OUT "    [s]\t\t[s]\t\t[s]\t\t[V]\n";
    printf OUT "    ----------\t----------\t----------\t----------\t----------\n";

    for ($i = 0; $i <= $#setup; $i++) {
	printf OUT "    %.4e\t%.4e\t%.4e\t%.4e\t%.4e\n",
	    $clkslew[$i], $setup[$i], $clk_q[$i], $vcrit[$i], $pass[$i];
    }

    @@scaled_setup = &div_list($scale_delay, @@setup);
    @@scaled_clk_q = &div_list($scale_delay, @@clk_q);
    @@scaled_clkslew = &div_list($scale_delay, @@clkslew);

    printf OUT "\n";
    printf OUT "    InputSlew\tSetup_${out_trans}\tClock-Q\t\tCritNode\tCritPercent\n";
    printf OUT "    [scaled]\t[scaled]\t[scaled]\t[V]\n";
    printf OUT "    ----------\t----------\t----------\t----------\t----------\n";

    for ($i = 0; $i <= $#setup; $i++) {
	printf OUT "    %.4e\t%.4e\t%.4e\t%.4e\t%.4e\n",
	    $scaled_clkslew[$i], $scaled_setup[$i],
	    $scaled_clk_q[$i], $vcrit[$i], $pass[$i];
    }

    &s_save_data($cellname, $d, $clk, $clktype, ('setup_' . $out_trans), \@@scaled_setup);

    close SPICEOUT;
}

#------ HOLD TIME CHARACTERIZATION ---------------------------------------------

sub h_run {

    my($out_trans, $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list) = @@_;

    local($run_name, $dtrans);
    local($optmod, $optparam, $optmeasure);

    # check
    if (($clktype ne 'rising') && ($clktype ne 'falling')) {
	die "ERROR: clock type must be either 'rising' or 'falling'\n";
    }
    if (($qtype ne 'inverting') && ($qtype ne 'non_inverting')) {
	die "ERROR: q type must be either 'inverting' or 'non_inverting'\n";
    }

    # give names to these puppies
    $optmod = 'optmod';
    $optparam = 'opthold';
    $optmeasure = 'optpass';

    $run_name = &run_file_name($cellname, $d, $clk, $q, 'h');
    open(SPICEIN,">$run_name") || die "ERROR:  Cannot open file '$run_name'.";

    # Create the hspice netlist(s)
    &print_header(SPICEIN, '*');
    printf SPICEIN "*	Char:	D-Flop Hold Time Characterization\n";
    printf SPICEIN "*	Data:	\"$d\"\n";
    printf SPICEIN "*	Clock:	\"$clk\"\n";
    printf SPICEIN "*	Q:	\"$q\"\n";
    printf SPICEIN "*	C:	\"$c\"\n";
    printf SPICEIN "*	Trans:	\"$out_trans\"\n";

    &h_print_setup (SPICEIN);
    &h_print_source (SPICEIN, $clktype, $out_trans, $qtype);
    &h_print_dut (SPICEIN, $d, $clk, $q, $tie, @@tie_list);
    &h_print_measure (SPICEIN, $clktype, $out_trans, $ctype, $c);
    &h_print_trans (SPICEIN, $clktype, $out_trans);

    printf SPICEIN ".end\n";
    close(SPICEIN);

    &run_spice($run_name);

    &h_report_spice($run_name, $out_trans, $d, $clktype, $clk, $qtype, $q, $ctype, $c);
}


sub h_print_setup {

    my ($fp) = @@_;

    printf $fp "\n*--- SETUP ---------------------------------------------------\n";
    printf $fp ".include '$techpath/$spice_corner'\n";
    printf $fp ".include '$spice_netlist'\n";
    if ($spice_include ne 'none') {
	printf $fp "$spice_include\n";
    }

    if ($spice_type eq 'smartspice') {
	printf $fp "$smartspice_options\n";
	printf $fp ".param ihold = 0\n" ;
	printf $fp ".param setup_hold_scale = '$setup_hold_scale'\n" ;
	printf $fp ".param hold = 'ihold*setup_hold_scale'\n" ;
    } else {
	printf $fp "$optim_options\n";
	printf $fp ".model $optmod opt method=bisection\n";
	printf $fp "+\trelin=$relin\n";
	printf $fp "+\trelout=$relout\n";
	printf $fp ".param hold = $optparam('$hold_range[0]', '$hold_range[0]', '$hold_range[1]')\n" ;
    }

    if ($#slewrate != -1) {
	printf $fp ".param slewrate = '$slewrate[0]'\n" ;
	printf $fp ".param slew_start = '$start_slew_percent'\n" ;
	printf $fp ".param slew_end = '$end_slew_percent'\n" ;
    }
}


#	Modifies dtrans
#
sub h_print_source {

    my ($fp, $clktype, $out_trans, $qtype) = @@_;

    printf $fp "\n*--- INPUTS --------------------------------------------------\n";

    if ($clktype eq 'rising') {
	if ($#slewrate != -1) {
	    printf $fp "vclk vclk $low_value pulse (
+	'$low_value'
+	'$high_value'
+	'$trans_delay+$trans_risetime/2'
+	'0'
+	'0'
+	'$trans_pulse_width+$trans_risetime/2+$trans_falltime/2'
+	'$trans_period')\n";
	} else {
	    printf $fp "vclk vclk $low_value pulse (
+	'$low_value'
+	'$high_value'
+	'$trans_delay'
+	'$trans_risetime'
+	'$trans_falltime'
+	'$trans_pulse_width'
+	'$trans_period')\n";
	}
    } elsif ($clktype eq 'falling') {
	if ($#slewrate != -1) {
	    printf $fp "vclk vclk $low_value pulse (
+	'$high_value'
+	'$low_value'
+	'$trans_delay+$trans_risetime/2'
+	'0'
+	'0'
+	'$trans_pulse_width+$trans_risetime/2+$trans_falltime/2'
+	'$trans_period')\n";
	} else {
	    printf $fp "vclk vclk $low_value pulse (
+	'$high_value'
+	'$low_value'
+	'$trans_delay'
+	'$trans_risetime'
+	'$trans_falltime'
+	'$trans_pulse_width'
+	'$trans_period')\n";
	}
    } else {
	die "ERROR: unknown clock transition type '$clktype'\n";
    }

    if ( (($out_trans eq 'lh') && ($qtype eq 'non_inverting')) ||
	 (($out_trans eq 'hl') && ($qtype eq 'inverting')) ) {

	$dtrans = 'rise';
	printf $fp "vd vd $low_value pulse (
+	'$low_value'
+	'$high_value'
+	'$trans_delay+$trans_risetime+$trans_pulse_width'
+	'$trans_risetime'
+	'$trans_falltime'
+	'$trans_pulse_width+hold'
+	'4*$trans_period')\n";

    } elsif ( (($out_trans eq 'hl') && ($qtype eq 'non_inverting')) ||
	      (($out_trans eq 'lh') && ($qtype eq 'inverting')) ) {

	$dtrans = 'fall';
	printf $fp "vd vd $low_value pulse (
+	'$high_value'
+	'$low_value'
+	'$trans_delay+$trans_risetime+$trans_pulse_width'
+	'$trans_risetime'
+	'$trans_falltime'
+	'$trans_pulse_width+hold'
+	'4*$trans_period')\n";

    } else {
	die "ERROR: unknown combination of '$out_trans' and '$qtype'\n";
    }
}


sub h_print_dut {

    my($fp, $d, $clk, $q, $tie, $tie_list) = @@_;
    my($term, $termname, $termtype);
    my($dbuf, $clkbuf, $outload);
    my($vcvs, @@inlist, @@reflist);
    local($term_no, @@vcvs_list, @@output_loads);

    $term_no = 0;

    if ($buffer{$d} ne '') {
	$dbuf = $buffer{$d};
    } else {
	$dbuf = $buffer{'default'};
    }
    if ($buffer{$clk} ne '') {
	$clkbuf = $buffer{$clk};
    } else {
	$clkbuf = $buffer{'default'};
    }
    if ($#slewrate != -1) {
	$clkbuf = 'slewbuffer';
	printf STDERR "INFO: slewbuffer buffer used for slew rate setup_hold at clock input.\n";
    }

    printf $fp "\n*--- TEST CIRCUIT --------------------------------------------\n";

    @@inlist = ($d, $clk);
    @@reflist = ('d', 'clk');

    if ($dbuf eq 'none') {
	printf $fp "vshortd vd d DC 0\n";
    } else {
	printf $fp "xdbuf vd d $dbuf\n";
    }
    if ($clkbuf eq 'none') {
	printf $fp "vshortclk vclk clk DC 0\n";
    } else {
	printf $fp "xclkbuf vclk clk $clkbuf\n";
    }

    printf $fp "xflop\n";
    foreach $term (@@termlist) {
	($termname, $termtype) = split(':', $term);
	if ($termname eq $d) {
	    printf $fp "+\td\t\$ $term\n";
	    next;
	}
	if ($termname eq $clk) {
	    printf $fp "+\tclk\t\$ $term\n";
	    next;
	}
	if ($termname eq $q) {
	    printf $fp "+\t%s\t\$ $term\n", &lookup_output_load($termname, 'q');
	    next;
	}
	if ($termtype eq 'i') {
	    printf $fp "+\t%s\t\$ $term\n",
		&lookup_input($termname, \@@inlist, \@@reflist, $tie, @@tie_list);
	    next;
	}
	if ($termtype eq 'o') {
	    printf $fp "+\t%s\t\$ $term\n", &lookup_output_load($termname);
	    next;
	}
    }
    printf $fp "+\t$cellname\n";

    # if any
    foreach $vcvs (@@vcvs_list) {
	printf $fp "$vcvs\n";
    }

    printf $fp "\n*--- LOADS ---------------------------------------------------\n";
    # if any
    foreach $outload (@@output_loads) {
	printf $fp "$outload\n";
    }
}


sub h_print_measure {

    my($fp, $clktype, $out_trans, $ctype, $c) = @@_;

    printf $fp "\n*--- MEASURE -------------------------------------------------\n";
    printf $fp ".option autostop\n";

    if ($spice_type eq 'smartspice') {
	printf $fp ".measure tran ihold param='ihold'\n";
	printf $fp ".measure tran hold param='hold'\n";
    }

    printf $fp "* Measure hold time:\n";
    if ($clktype eq 'rising') {
	printf $fp ".measure tran hold_${out_trans} %s v(clk) val='$midpoint_value' rise=2\n",
	    &trig_word();
    } else {
	printf $fp ".measure tran hold_${out_trans} %s v(clk) val='$midpoint_value' fall=2\n",
	    &trig_word();
    }
    printf $fp "+\ttarg=v(d) val='$midpoint_value' cross=2\n";

    printf $fp "* Measure clock slew rate:\n";
    if ($clktype eq 'rising') {
	printf $fp
	    ".measure tran clkslew %s v(clk) val='$slew_r1' rise=2\n",
	    &trig_word();
	printf $fp
	    "+\ttarg=v(clk) val='$slew_r2' rise=2\n";
    } else {
	printf $fp
	    ".measure tran clkslew %s v(clk) val='$slew_f1' fall=2\n",
	    &trig_word();
	printf $fp
	    "+\ttarg=v(clk) val='$slew_f2' fall=2\n";
    }

    printf $fp "\n* Measure internal criterion node:\n";
    printf $fp ".measure tran vcrit find v(xflop.${c})\n";
    if ($clktype eq 'rising') {
	printf $fp "+\twhen v(clk)='$clock_percent*$high_value' rise=2\n"; 
    } else {
	printf $fp "+\twhen v(clk)='(1-$clock_percent)*$high_value' fall=2\n"; 
    }

    # cnode:
    if ( (($dtrans eq 'rise') && ($ctype eq 'inverting')) ||
	 (($dtrans eq 'fall') && ($ctype eq 'non_inverting')) ) {
	printf $fp ".measure tran $optmeasure param='($high_value-vcrit)/$high_value'\n";
	if ($spice_type ne 'smartspice') {
	    printf $fp "+\tgoal='${criterion_percent}'\n";
	}
    } elsif ( (($dtrans eq 'fall') && ($ctype eq 'inverting')) ||
	      (($dtrans eq 'rise') && ($ctype eq 'non_inverting')) ) {
	printf $fp ".measure tran $optmeasure param='vcrit/$high_value'\n";
	if ($spice_type ne 'smartspice') {
	    printf $fp "+\tgoal='${criterion_percent}'\n";
	}
    }
}


sub h_print_trans {

    my($fp, $clktype, $out_trans) = @@_;

    printf $fp "\n*--- TRANSIENT -----------------------------------------------\n";
    if ($spice_type eq 'smartspice') {

	printf $fp "* Measure final clock->q time:\n";
	if ($clktype eq 'rising') {
	    printf $fp ".measure tran clk_q delay v(clk) val='$midpoint_value' rise=2\n";
	} else {
	    printf $fp ".measure tran clk_q delay v(clk) val='$midpoint_value' fall=2\n";
	}
	if ($out_trans eq 'lh') {
	    printf $fp "+\ttarg=v(q) val='$midpoint_value' rise=1\n";
	} elsif ($out_trans eq 'hl') {
	    printf $fp "+\ttarg=v(q) val='$midpoint_value' fall=1\n";
	} else {
	    die "ERROR: unknown output transition '$out_trans'\n";
	}
	printf $fp ".trans $trans_timestep '$trans_timestop'\n";

    } else {
	printf $fp ".trans $trans_timestep '$trans_timestop' sweep
+	optimize=$optparam
+	results=$optmeasure
+	model=$optmod\n";

	# Have to put this here in order for bisect to work. A
	# failed measurement during bisect causes bisect to abort.
	printf $fp ".trans $trans_timestep '$trans_timestop'\n";
	printf $fp "\n* Measure final clock->q time:\n";
	if ($clktype eq 'rising') {
	    printf $fp ".measure tran clk_q trig=v(clk) val='$midpoint_value' rise=2\n";
	} else {
	    printf $fp ".measure tran clk_q trig=v(clk) val='$midpoint_value' fall=2\n";
	}

	if ($out_trans eq 'lh') {
	    printf $fp "+\ttarg=v(q) val='$midpoint_value' rise=1\n";
	} elsif ($out_trans eq 'hl') {
	    printf $fp "+\ttarg=v(q) val='$midpoint_value' fall=1\n";
	} else {
	    die "ERROR: unknown output transition '$out_trans'\n";
	}
    }

    if ($spice_type eq 'smartspice') {
	&h_print_control($fp, $out_trans);
    }

    printf $fp "\n* Alter slewrate:\n";
    for ($j = 1; $j <= $#slewrate; $j++) {
	printf $fp ".alter\n";
	printf $fp ".param slewrate = '$slewrate[$j]'\n" ;
    }
}

sub h_print_control {
    my($fp, $out_trans) = @@_;

    printf $fp "\n*--- CONTROL -------------------------------------------------\n";
    printf $fp ".control
# find fail
modif loop=${iterations} stop ${optmeasure} le ${criterion_percent} ihold -= (0)${window} prtbl
set fail = \$ihold
# find pass
modif loop=${iterations} stop ${criterion_percent} le ${optmeasure} ihold += (0)${window} prtbl
set pass = \$ihold

set i = 0
set window = \`expr \$pass - \$fail\`

# Save measurements
set save_hold = \$hold_${out_trans}
set save_clkslew = \$clkslew
set save_clk_q = \$clk_q
set save_vcrit = \$vcrit
set save_${optmeasure} = \$${optmeasure}

echo Iteration \$i: Pass = \$pass, Fail = \$fail, Window = \$window, hold = \$save_hold
";

    printf $fp "
# Binary search
while (\$window > ${resolution}) 
    set i = \`expr \$i + 1\`
    set sum = \`expr \$pass + \$fail\`
    set midpoint = \`expr \$sum / 2\`

    modif loop=1 ihold = \$midpoint prtbl

    if (\$${optmeasure} > ${criterion_percent} or \$${optmeasure} eq ${criterion_percent})
	set pass = \$midpoint

	# Save measurements
	set save_hold = \$hold_${out_trans}
	set save_clkslew = \$clkslew
	set save_clk_q = \$clk_q
	set save_vcrit = \$vcrit
	set save_${optmeasure} = \$${optmeasure}

    else
	set fail = \$midpoint
    end
    set window = \`expr \$pass - \$fail\`

    echo Iteration \$i: Pass = \$pass, Fail = \$fail, Window = \$window, hold = \$save_hold
end

echo Final hold_${out_trans} = \$save_hold
echo Final clkslew = \$clkslew
echo Final clk_q = \$clk_q
echo Final vcrit = \$vcrit
echo Final ${optmeasure} = \$${optmeasure}

.endc\n";

}

sub h_report_spice {

    my  ($run_name, $out_trans, $d, $clktype, $clk, $qtype, $q, $ctype, $c) = @@_;

    my($base,$dir,$ext,$spiceout);
    my(@@hold, @@clkslew, @@clk_q, @@vcrit, @@pass);
    my(@@scaled_hold, @@scaled_clkslew, @@scaled_clk_q, $i);

    ($base,$dir,$ext) = fileparse($run_name, '\.sp');
    $spiceout = $base . '.out';

    printf STDERR "Extracting results from '$spiceout' ...\n";

    # grab the last values
    open(SPICEOUT, $spiceout) || die "ERROR: Cannot find '$spiceout'.\n";
    if ($spice_type eq 'smartspice') {
	while (<SPICEOUT>) {
	    if (($name, $value) = /^Final (hold_${out_trans}) *= +([0-9\+\-eE\.]+)/) {
		push(@@hold, $value);
		next;
	    }
	    if (($name, $value) = /^Final (clkslew) *= +([0-9\+\-eE\.]+)/) {
		push (@@clkslew, $value);
		next;
	    }
	    if (($name, $value) = /^Final (clk_q) *= +([0-9\+\-eE\.]+)/) {
		push (@@clk_q, $value);
		next;
	    }
	    if (($name, $value) = /^Final (vcrit) *= +([0-9\+\-eE\.]+)/) {
		push (@@vcrit, $value);
		next;
	    }
	    if (($name, $value) = /^Final ($optmeasure) *= +([0-9\+\-eE\.]+)/) {
		push (@@pass, $value);
		next;
	    }
	}
    } else {
	while (<SPICEOUT>) {
	    if (($name, $value) = /^ +(hold_${out_trans}) *= +([0-9\+\-eE\.]+)/) {
		push(@@hold, $value);
		next;
	    }
	    if (($name, $value) = /^ +(clkslew) *= +([0-9\+\-eE\.]+)/) {
		push (@@clkslew, $value);
		next;
	    }
	    if (($name, $value) = /^ +(clk_q) *= +([0-9\+\-eE\.]+)/) {
		push(@@clk_q, $value);
		next;
	    }
	    if (($name, $value) = /^ +(vcrit) *= +([0-9\+\-eE\.]+)/) {
		push (@@vcrit, $value);
		next;
	    }
	    if (($name, $value) = /^ +($optmeasure) *= +([0-9\+\-eE\.]+)/) {
		push (@@pass, $value);
		next;
	    }
	}
    }

    @@hold = &halve_list(@@hold);
    @@clkslew = &halve_list(@@clkslew);
    @@vcrit = &halve_list(@@vcrit);
    @@pass = &halve_list(@@pass);

    printf OUT "\n";
    printf OUT "    InputSlew\tHold_${out_trans}\t\tClock-Q\t\tCritNode\tCritPercent\n";
    printf OUT "    [s]\t\t[s]\t\t[s]\t\t[V]\n";
    printf OUT "    ----------\t----------\t----------\t----------\t----------\n";

    for ($i = 0; $i <= $#hold; $i++) {
	printf OUT "    %.4e\t%.4e\t%.4e\t%.4e\t%.4e\n",
	    $clkslew[$i], $hold[$i], $clk_q[$i], $vcrit[$i], $pass[$i];
    }

    @@scaled_hold = &div_list($scale_delay, @@hold);
    @@scaled_clk_q = &div_list($scale_delay, @@clk_q);
    @@scaled_clkslew = &div_list($scale_delay, @@clkslew);

    printf OUT "\n";
    printf OUT "    InputSlew\tHold_${out_trans}\t\tClock-Q\t\tCritNode\tCritPercent\n";
    printf OUT "    [scaled]\t[scaled]\t[scaled]\t[V]\n";
    printf OUT "    ----------\t----------\t----------\t----------\t----------\n";

    for ($i = 0; $i <= $#hold; $i++) {
	printf OUT "    %.4e\t%.4e\t%.4e\t%.4e\t%.4e\n",
	    $scaled_clkslew[$i], $scaled_hold[$i],
	    $scaled_clk_q[$i], $vcrit[$i], $pass[$i];
    }

    &h_save_data($cellname, $d, $clk, $clktype, (hold_ . $out_trans), \@@scaled_hold);

    close SPICEOUT;
}

1;
@


1.32
log
@syntax for >= for smartspice control
@
text
@d1 1
a1 1
#	$Id: setup_hold.pl,v 1.31 1999/01/26 18:22:02 ryu Exp ryu $
d495 1
a495 1
	    if (($name, $value) = /^Final (setup_${out_trans}) += +([0-9\+\-eE\.]+)/) {
d499 1
a499 1
	    if (($name, $value) = /^Final (clkslew) += +([0-9\+\-eE\.]+)/) {
d503 1
a503 1
	    if (($name, $value) = /^Final (clk_q) += +([0-9\+\-eE\.]+)/) {
d507 1
a507 1
	    if (($name, $value) = /^Final (vcrit) += +([0-9\+\-eE\.]+)/) {
d511 1
a511 1
	    if (($name, $value) = /^Final ($optmeasure) += +([0-9\+\-eE\.]+)/) {
d518 1
a518 1
	    if (($name, $value) = /^ +(setup_${out_trans}) += +([0-9\+\-eE\.]+)/) {
d522 1
a522 1
	    if (($name, $value) = /^ +(clkslew) += +([0-9\+\-eE\.]+)/) {
d526 1
a526 1
	    if (($name, $value) = /^ +(clk_q) += +([0-9\+\-eE\.]+)/) {
d530 1
a530 1
	    if (($name, $value) = /^ +(vcrit) += +([0-9\+\-eE\.]+)/) {
d534 1
a534 1
	    if (($name, $value) = /^ +($optmeasure) += +([0-9\+\-eE\.]+)/) {
d1021 1
a1021 1
	    if (($name, $value) = /^Final (hold_${out_trans}) += +([0-9\+\-eE\.]+)/) {
d1025 1
a1025 1
	    if (($name, $value) = /^Final (clkslew) += +([0-9\+\-eE\.]+)/) {
d1029 1
a1029 1
	    if (($name, $value) = /^Final (clk_q) += +([0-9\+\-eE\.]+)/) {
d1033 1
a1033 1
	    if (($name, $value) = /^Final (vcrit) += +([0-9\+\-eE\.]+)/) {
d1037 1
a1037 1
	    if (($name, $value) = /^Final ($optmeasure) += +([0-9\+\-eE\.]+)/) {
d1044 1
a1044 1
	    if (($name, $value) = /^ +(hold_${out_trans}) += +([0-9\+\-eE\.]+)/) {
d1048 1
a1048 1
	    if (($name, $value) = /^ +(clkslew) += +([0-9\+\-eE\.]+)/) {
d1052 1
a1052 1
	    if (($name, $value) = /^ +(clk_q) += +([0-9\+\-eE\.]+)/) {
d1056 1
a1056 1
	    if (($name, $value) = /^ +(vcrit) += +([0-9\+\-eE\.]+)/) {
d1060 1
a1060 1
	    if (($name, $value) = /^ +($optmeasure) += +([0-9\+\-eE\.]+)/) {
@


1.31
log
@Hold time seems to work.
@
text
@d1 1
a1 1
#	$Id: setup_hold.pl,v 1.30 1999/01/22 19:04:46 ryu Exp ryu $
d437 1
a437 1
echo Iteration \$i: Pass = \$pass, Fail = \$fail, Window = \$window, Setup = \$save_setup
d449 1
a449 1
    if (\$${optmeasure} > ${criterion_percent})
d464 1
a464 1
    echo Iteration \$i: Pass = \$pass, Fail = \$fail, Window = \$window, Setup = \$save_setup
d976 1
a976 1
    if (\$${optmeasure} > ${criterion_percent})
@


1.30
log
@works.
@
text
@d1 1
a1 1
#	$Id: setup_hold.pl,v 1.29 1999/01/22 18:50:10 ryu Exp ryu $
d635 13
a647 5
    printf $fp "$optim_options\n";
    printf $fp ".model $optmod opt method=bisection\n";
    printf $fp "+\trelin=$relin\n";
    printf $fp "+\trelout=$relout\n";
    printf $fp ".param hold = $optparam('$hold_range[0]', '$hold_range[0]', '$hold_range[1]')\n" ;
d829 5
d871 3
a873 1
	printf $fp "+\tgoal='${criterion_percent}'\n";
d877 3
a879 1
	printf $fp "+\tgoal='${criterion_percent}'\n";
d889 19
a907 1
    printf $fp ".trans $trans_timestep '$trans_timestop' sweep
d912 17
a928 10
    # Have to put this here in order for bisect to work. A
    # failed measurement during bisect causes bisect to abort.
    printf $fp ".trans $trans_timestep '$trans_timestop'\n";
    printf $fp "\n* Measure final clock->q time:\n";
    if ($clktype eq 'rising') {
	printf $fp ".measure tran clk_q %s v(clk) val='$midpoint_value' rise=2\n",
	    &trig_word();
    } else {
	printf $fp ".measure tran clk_q %s v(clk) val='$midpoint_value' fall=2\n",
	    &trig_word();
d931 2
a932 6
    if ($out_trans eq 'lh') {
	printf $fp "+\ttarg=v(q) val='$midpoint_value' rise=1\n";
    } elsif ($out_trans eq 'hl') {
	printf $fp "+\ttarg=v(q) val='$midpoint_value' fall=1\n";
    } else {
	die "ERROR: unknown output transition '$out_trans'\n";
d942 61
d1019 22
a1040 4
    while (<SPICEOUT>) {
	if (($name, $value) = /^ +(hold_${out_trans}) += +([0-9\+\-eE\.]+)/) {
	    push(@@hold, $value);
	    next;
d1042 22
a1063 15
	if (($name, $value) = /^ +(clkslew) += +([0-9\+\-eE\.]+)/) {
	    push (@@clkslew, $value);
	    next;
	}
	if (($name, $value) = /^ +(clk_q) += +([0-9\+\-eE\.]+)/) {
	    push(@@clk_q, $value);
	    next;
	}
	if (($name, $value) = /^ +(vcrit) += +([0-9\+\-eE\.]+)/) {
	    push (@@vcrit, $value);
	    next;
	}
	if (($name, $value) = /^ +($optmeasure) += +([0-9\+\-eE\.]+)/) {
	    push (@@pass, $value);
	    next;
@


1.29
log
@works.
@
text
@d1 1
a1 1
#	$Id: setup_hold.pl,v 1.28 1999/01/22 18:25:17 ryu Exp ryu $
d429 9
a437 2
set best = \$setup_${out_trans}
echo Iteration \$i: Pass = \$pass, Fail = \$fail, Window = \$window, Setup = \$best
d451 8
a458 1
	set best = \$setup_${out_trans}
d464 1
a464 1
    echo Iteration \$i: Pass = \$pass, Fail = \$fail, Window = \$window, Setup = \$best
d467 5
a471 1
echo Final setup_${out_trans} = \$best
d492 46
a537 20
    while (<SPICEOUT>) {
	if (($name, $value) = /^ +(setup_${out_trans}) += +([0-9\+\-eE\.]+)/) {
	    push(@@setup, $value);
	    next;
	}
	if (($name, $value) = /^ +(clkslew) += +([0-9\+\-eE\.]+)/) {
	    push (@@clkslew, $value);
	    next;
	}
	if (($name, $value) = /^ +(clk_q) += +([0-9\+\-eE\.]+)/) {
	    push (@@clk_q, $value);
	    next;
	}
	if (($name, $value) = /^ +(vcrit) += +([0-9\+\-eE\.]+)/) {
	    push (@@vcrit, $value);
	    next;
	}
	if (($name, $value) = /^ +($optmeasure) += +([0-9\+\-eE\.]+)/) {
	    push (@@pass, $value);
	    next;
@


1.28
log
@Use > instead of >=
@
text
@d1 1
a1 1
#	$Id: setup_hold.pl,v 1.27 1999/01/20 07:44:59 ryu Exp ryu $
d451 1
a451 1
end\n";
d453 3
a455 1
    printf $fp ".endc\n";
@


1.27
log
@No perl header
@
text
@d1 1
a1 1
#	$Id: setup_hold.pl,v 1.26 1999/01/14 10:19:02 ryu Exp ryu $
d107 13
a119 5
    printf $fp "$optim_options\n";
    printf $fp ".model $optmod opt method=bisection\n";
    printf $fp "+\trelin=$relin\n";
    printf $fp "+\trelout=$relout\n";
    printf $fp ".param setup = $optparam('$setup_range[0]', '$setup_range[0]', '$setup_range[1]')\n" ;
d302 8
a309 1
    printf $fp ".measure tran setup_${out_trans} trig=v(d) val='$midpoint_value' cross=1\n";
d319 2
a320 1
	    ".measure tran clkslew trig=v(clk) val='$slew_r1' rise=2\n";
d325 2
a326 1
	    ".measure tran clkslew trig=v(clk) val='$slew_f1' fall=2\n";
d343 3
a345 1
	printf $fp "+\tgoal='${criterion_percent}'\n";
d349 3
a351 1
	printf $fp "+\tgoal='${criterion_percent}'\n";
d362 19
a380 1
    printf $fp ".trans $trans_timestep '$trans_timestop' sweep
d385 16
a400 8
    # Have to put this here in order for bisect to work. A
    # failed measurement during bisect causes bisect to abort.
    printf $fp ".trans $trans_timestep '$trans_timestop'\n";
    printf $fp "\n* Measure final clock->q time:\n";
    if ($clktype eq 'rising') {
	printf $fp ".measure tran clk_q trig=v(clk) val='$midpoint_value' rise=2\n";
    } else {
	printf $fp ".measure tran clk_q trig=v(clk) val='$midpoint_value' fall=2\n";
d402 3
a404 6
    if ($out_trans eq 'lh') {
	printf $fp "+\ttarg=v(q) val='$midpoint_value' rise=1\n";
    } elsif ($out_trans eq 'hl') {
	printf $fp "+\ttarg=v(q) val='$midpoint_value' fall=1\n";
    } else {
	die "ERROR: unknown output transition '$out_trans'\n";
d415 42
d459 1
a459 1
    my  ($run_name, $out_trans, $d, $clktype, $clk, $qtype, $q, $ctype, $c) = @@_;
d777 2
a778 1
	printf $fp ".measure tran hold_${out_trans} trig=v(clk) val='$midpoint_value' rise=2\n";
d780 2
a781 1
	printf $fp ".measure tran hold_${out_trans} trig=v(clk) val='$midpoint_value' fall=2\n";
d788 2
a789 1
	    ".measure tran clkslew trig=v(clk) val='$slew_r1' rise=2\n";
d794 2
a795 1
	    ".measure tran clkslew trig=v(clk) val='$slew_f1' fall=2\n";
d836 2
a837 1
	printf $fp ".measure tran clk_q trig=v(clk) val='$midpoint_value' rise=2\n";
d839 2
a840 1
	printf $fp ".measure tran clk_q trig=v(clk) val='$midpoint_value' fall=2\n";
@


1.26
log
@Using /usr/bin/perl
@
text
@d1 1
a1 3
#! /usr/bin/perl

#	$Id: setup_hold.pl,v 1.25 1999/01/13 07:18:42 ryu Exp ryu $
@


1.25
log
@GPL
@
text
@d1 1
a1 1
#! /usr/local/bin/perl
d3 1
a3 1
#	$Id$
@


1.24
log
@Added slew rate check on clock enable
@
text
@d3 1
a3 5
#	Copyright (c) 1998-2001, Robert K. Yu.  All Rights Reserved.
#
#	No part of this program may be used, reproduced, stored in a 
#	retrieval system, or transmitted in any form or by any 
#	means without the prior permission of the author.
d5 2
a6 3
#	$Id: setup_hold.pl,v 1.23 1998/09/12 19:54:02 ryu Exp ryu $
#	Setup/Hold Flop Characterization Functions
#	Author: Robert K. Yu
d8 16
@


1.23
log
@Added slew-rate to setup and hold; support for non-linear models for clock-q
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.22 1998/09/11 06:19:45 ryu Exp ryu $
d430 1
a430 2
    &s_save_data($cellname, $d, $clk, $clktype, ('setup_' . $out_trans),
	\@@scaled_setup, \@@scaled_clkslew, \@@scaled_clk_q);
d826 1
a826 2
    &h_save_data($cellname, $d, $clk, $clktype, (hold_ . $out_trans),
	\@@scaled_hold, \@@scaled_clkslew, \@@scaled_clk_q);
@


1.22
log
@Added slew rate to setup/hold
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.21 1998/09/08 13:16:49 ryu Exp ryu $
d22 1
d34 2
d93 1
a93 1
    printf $fp ".include '$init{'techpath'}/$init{'corner'}'\n";
d95 2
a96 2
    if ($init{'include'} ne 'none') {
	printf $fp "$init{'include'}\n";
d98 1
a98 1
    printf $fp "$optim{'options'}\n";
d106 2
a107 2
	printf $fp ".param slew_start = '$trans{'start_slew_percent'}'\n" ;
	printf $fp ".param slew_end = '$trans{'end_slew_percent'}'\n" ;
d122 4
a125 4
	    printf $fp "vclk vclk $init{'low'} pulse (
+	'$init{'low'}'
+	'$init{'high'}'
+	'$trans{'delay'}+$trans{'risetime'}/2'
d128 2
a129 2
+	'$trans{'pulse_width'}+$trans{'risetime'}/2+$trans{'falltime'}/2'
+	'$trans{'period'}')\n";
d131 8
a138 8
	    printf $fp "vclk vclk $init{'low'} pulse (
+	'$init{'low'}'
+	'$init{'high'}'
+	'$trans{'delay'}'
+	'$trans{'risetime'}'
+	'$trans{'falltime'}'
+	'$trans{'pulse_width'}'
+	'$trans{'period'}')\n";
d142 4
a145 4
	    printf $fp "vclk vclk $init{'low'} pulse (
+	'$init{'high'}'
+	'$init{'low'}'
+	'$trans{'delay'}+$trans{'risetime'}/2'
d148 2
a149 2
+	'$trans{'pulse_width'}+$trans{'risetime'}/2+$trans{'falltime'}/2'
+	'$trans{'period'}')\n";
d151 8
a158 8
	    printf $fp "vclk vclk $init{'low'} pulse (
+	'$init{'high'}'
+	'$init{'low'}'
+	'$trans{'delay'}'
+	'$trans{'risetime'}'
+	'$trans{'falltime'}'
+	'$trans{'pulse_width'}'
+	'$trans{'period'}')\n";
d168 8
a175 8
	printf $fp "vd vd $init{'low'} pulse (
+	'$init{'low'}'
+	'$init{'high'}'
+	'$trans{'delay'}+$trans{'risetime'}+2*$trans{'pulse_width'}+$trans{'falltime'}-setup'
+	'$trans{'risetime'}'
+	'$trans{'falltime'}'
+	'3*$trans{'period'}'
+	'4*$trans{'period'}')\n";
d181 8
a188 8
	printf $fp "vd vd $init{'low'} pulse (
+	'$init{'high'}'
+	'$init{'low'}'
+	'$trans{'delay'}+$trans{'risetime'}+2*$trans{'pulse_width'}+$trans{'falltime'}-setup'
+	'$trans{'risetime'}'
+	'$trans{'falltime'}'
+	'3*$trans{'period'}'
+	'4*$trans{'period'}')\n";
d285 1
a285 1
    printf $fp ".measure tran setup_${out_trans} trig=v(d) val='$init{'midpoint'}' cross=1\n";
d287 1
a287 1
	printf $fp "+\ttarg=v(clk) val='$init{'midpoint'}' rise=2\n";
d289 1
a289 1
	printf $fp "+\ttarg=v(clk) val='$init{'midpoint'}' fall=2\n";
d308 1
a308 1
	printf $fp "+\twhen v(clk)='$clock_percent*$init{'high'}' rise=2\n"; 
d310 1
a310 1
	printf $fp "+\twhen v(clk)='(1-$clock_percent)*$init{'high'}' fall=2\n"; 
d316 1
a316 1
	printf $fp ".measure tran $optmeasure param='($init{'high'}-vcrit)/$init{'high'}'\n";
d320 1
a320 1
	printf $fp ".measure tran $optmeasure param='vcrit/$init{'high'}'\n";
d332 1
a332 1
    printf $fp ".trans $trans{'timestep'} '$trans{'timestop'}' sweep
d339 1
d342 1
a342 1
	printf $fp ".measure tran clk_q trig=v(clk) val='$init{'midpoint'}' rise=2\n";
d344 1
a344 1
	printf $fp ".measure tran clk_q trig=v(clk) val='$init{'midpoint'}' fall=2\n";
d347 1
a347 1
	printf $fp "+\ttarg=v(q) val='$init{'midpoint'}' rise=1\n";
d349 1
a349 1
	printf $fp "+\ttarg=v(q) val='$init{'midpoint'}' fall=1\n";
d400 18
a417 3
    @@scaled_setup = &div_list($init{'scale_delay'}, @@setup);
    @@scaled_clk_q = &div_list($init{'scale_delay'}, @@clk_q);
    @@scaled_clkslew = &div_list($init{'scale_delay'}, @@clkslew);
d420 2
a421 2
    printf OUT "    InputSlew\tSetup_${out_trans}\t\tClock-Q\t\tCritNode\tCritPercent\n";
    printf OUT "    [gates]\t\t[gates]\t\t[gates]\t\t[V]\n";
d431 1
a431 1
	\@@scaled_setup, \@@scaled_clkslew, \@@scaled_clk_q;
d490 1
a490 1
    printf $fp ".include '$init{'techpath'}/$init{'corner'}'\n";
d492 2
a493 2
    if ($init{'include'} ne 'none') {
	printf $fp "$init{'include'}\n";
d495 1
a495 1
    printf $fp "$optim{'options'}\n";
d503 2
a504 2
	printf $fp ".param slew_start = '$trans{'start_slew_percent'}'\n" ;
	printf $fp ".param slew_end = '$trans{'end_slew_percent'}'\n" ;
d519 4
a522 4
	    printf $fp "vclk vclk $init{'low'} pulse (
+	'$init{'low'}'
+	'$init{'high'}'
+	'$trans{'delay'}+$trans{'risetime'}/2'
d525 2
a526 2
+	'$trans{'pulse_width'}+$trans{'risetime'}/2+$trans{'falltime'}/2'
+	'$trans{'period'}')\n";
d528 8
a535 8
	    printf $fp "vclk vclk $init{'low'} pulse (
+	'$init{'low'}'
+	'$init{'high'}'
+	'$trans{'delay'}'
+	'$trans{'risetime'}'
+	'$trans{'falltime'}'
+	'$trans{'pulse_width'}'
+	'$trans{'period'}')\n";
d539 4
a542 4
	    printf $fp "vclk vclk $init{'low'} pulse (
+	'$init{'high'}'
+	'$init{'low'}'
+	'$trans{'delay'}+$trans{'risetime'}/2'
d545 2
a546 2
+	'$trans{'pulse_width'}+$trans{'risetime'}/2+$trans{'falltime'}/2'
+	'$trans{'period'}')\n";
d548 8
a555 8
	    printf $fp "vclk vclk $init{'low'} pulse (
+	'$init{'high'}'
+	'$init{'low'}'
+	'$trans{'delay'}'
+	'$trans{'risetime'}'
+	'$trans{'falltime'}'
+	'$trans{'pulse_width'}'
+	'$trans{'period'}')\n";
d565 8
a572 8
	printf $fp "vd vd $init{'low'} pulse (
+	'$init{'low'}'
+	'$init{'high'}'
+	'$trans{'delay'}+$trans{'risetime'}+$trans{'pulse_width'}'
+	'$trans{'risetime'}'
+	'$trans{'falltime'}'
+	'$trans{'pulse_width'}+hold'
+	'4*$trans{'period'}')\n";
d578 8
a585 8
	printf $fp "vd vd $init{'low'} pulse (
+	'$init{'high'}'
+	'$init{'low'}'
+	'$trans{'delay'}+$trans{'risetime'}+$trans{'pulse_width'}'
+	'$trans{'risetime'}'
+	'$trans{'falltime'}'
+	'$trans{'pulse_width'}+hold'
+	'4*$trans{'period'}')\n";
d683 1
a683 1
	printf $fp ".measure tran hold_${out_trans} trig=v(clk) val='$init{'midpoint'}' rise=2\n";
d685 1
a685 1
	printf $fp ".measure tran hold_${out_trans} trig=v(clk) val='$init{'midpoint'}' fall=2\n";
d687 1
a687 1
    printf $fp "+\ttarg=v(d) val='$init{'midpoint'}' cross=2\n";
d705 1
a705 1
	printf $fp "+\twhen v(clk)='$clock_percent*$init{'high'}' rise=2\n"; 
d707 1
a707 1
	printf $fp "+\twhen v(clk)='(1-$clock_percent)*$init{'high'}' fall=2\n"; 
d713 1
a713 1
	printf $fp ".measure tran $optmeasure param='($init{'high'}-vcrit)/$init{'high'}'\n";
d717 1
a717 1
	printf $fp ".measure tran $optmeasure param='vcrit/$init{'high'}'\n";
d728 1
a728 1
    printf $fp ".trans $trans{'timestep'} '$trans{'timestop'}' sweep
d735 1
d738 1
a738 1
	printf $fp ".measure tran clk_q trig=v(clk) val='$init{'midpoint'}' rise=2\n";
d740 1
a740 1
	printf $fp ".measure tran clk_q trig=v(clk) val='$init{'midpoint'}' fall=2\n";
d744 1
a744 1
	printf $fp "+\ttarg=v(q) val='$init{'midpoint'}' rise=1\n";
d746 1
a746 1
	printf $fp "+\ttarg=v(q) val='$init{'midpoint'}' fall=1\n";
d797 4
a800 3
    @@scaled_hold = &div_list($init{'scale_delay'}, @@hold);
    @@scaled_clk_q = &div_list($init{'scale_delay'}, @@clk_q);
    @@scaled_clkslew = &div_list($init{'scale_delay'}, @@clkslew);
d804 1
a804 1
    printf OUT "    [s]\t\t[gates]\t\t[s]\t\t[gates]\t\t[V]\n";
d807 15
a821 1
    for ($i = 0; $i <= $#setup; $i++) {
d828 1
a828 1
	\@@scaled_hold, \@@scaled_clkslew, \@@scaled_clk_q;
@


1.21
log
@slew rate at the clock input of setup_hold (wip)
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.20 1998/09/06 20:43:23 ryu Exp ryu $
a276 14
    local($input_prop_r, $input_prop_f);	# unused
    local($output_prop_r, $output_prop_f);	# unused
    local($trans_r1, $trans_r2);		# unused
    local($trans_f1, $trans_f2);		# unused
    local($slew_r1, $slew_r2);
    local($slew_f1, $slew_f2);

    &set_measure_values (
	\$input_prop_r, \$input_prop_f,
	\$output_prop_r, \$output_prop_f,
	\$trans_r1, \$trans_r2,
	\$trans_f1, \$trans_f2,
	\$slew_r1, \$slew_r2,
	\$slew_f1, \$slew_f2);
a333 9
    for ($j = 1; $j <= $#slewrate; $j++) {
	printf $fp ".alter\n";
	printf $fp ".param slewrate = '$slewrate[$j]'\n" ;
    }

    printf $fp "\n\n* Final value:\n";
    printf $fp ".alter\n";
    printf $fp ".trans $trans{'timestep'} '$trans{'timestop'}'\n";

a341 1

d349 6
d363 2
a364 3

    # TODO: make these lists, and report/save all values.
    my($setup, $slewrate, $clk_q, $vcrit, $pass);
d375 1
a375 1
	    $setup = $value;
d379 1
a379 1
	    $clkslew = $value;
d383 1
a383 1
	    $clk_q = $value;
d387 1
a387 1
	    $vcrit = $value;
d391 1
a391 1
	    $pass = $value;
d396 4
d401 9
a409 7
    printf OUT "    Setup_${out_trans}\tSetup_${out_trans}\tClock-Q\t\tClock-Q\t\tCritNode\tCritPercent\n";
    printf OUT "    [s]\t\t[gates]\t\t[s]\t\t[gates]\t\t[V]\n";
    printf OUT "    ----------\t----------\t----------\t----------\t----------\t----------\n";
    printf OUT "    %.4e\t%.4e\t%.4e\t%.4e\t%.4e\t%.4e\n",
	$setup, $setup/$init{'scale_delay'},
	$clk_q, $clk_q/$init{'scale_delay'},
	$vcrit, $pass;
d412 1
a412 1
	$setup/$init{'scale_delay'});
d481 6
d499 11
a509 1
	printf $fp "vclk vclk $init{'low'} pulse (
d517 1
d519 11
a529 1
	printf $fp "vclk vclk $init{'low'} pulse (
d537 1
d594 4
d670 13
a713 4
    printf $fp "\n\n* Final value:\n";
    printf $fp ".alter\n";
    printf $fp ".trans $trans{'timestep'} '$trans{'timestop'}'\n";

d730 6
d744 2
a745 1
    my($hold, $clk_q, $vcrit, $pass);
d756 5
a760 1
	    $hold = $value;
d764 1
a764 1
	    $clk_q = $value;
d768 1
a768 1
	    $vcrit = $value;
d772 1
a772 1
	    $pass = $value;
d777 4
d782 1
a782 1
    printf OUT "    Hold_${out_trans}\tHold_${out_trans}\t\tClock-Q\t\tClock-Q\t\tCritNode\tCritPercent\n";
d784 7
a790 5
    printf OUT "    ----------\t----------\t----------\t----------\t----------\t----------\n";
    printf OUT "    %.4e\t%.4e\t%.4e\t%.4e\t%.4e\t%.4e\n",
	$hold, $hold/$init{'scale_delay'},
	$clk_q, $clk_q/$init{'scale_delay'},
	$vcrit, $pass;
d793 1
a793 1
	$hold/$init{'scale_delay'});
@


1.20
log
@clock enable
@
text
@d3 1
a3 1
#	Copyright (c) 1998, Robert K. Yu.  All Rights Reserved.
d9 1
a9 1
#	$Id: setup_hold.pl,v 1.19 1998/09/05 22:10:32 ryu Exp ryu $
d79 1
a79 1
    &s_run_spice($run_name);
d100 6
d118 11
a128 1
	printf $fp "vclk vclk $init{'low'} pulse (
d136 1
d138 11
a148 1
	printf $fp "vclk vclk $init{'low'} pulse (
d156 1
d213 4
d277 14
d303 13
d340 1
d348 5
a375 17
sub s_run_spice {

    my($run_name) = @@_;
    my($base,$dir,$type,$spiceout);

    ($base,$dir,$type) = fileparse($run_name, '\.sp');
    $spiceout = $base . '.out';

    # Run hspice
    if ($skip && (-e $spiceout)) {
	printf STDERR "Found \"%s\", skipping run.\n", $spiceout;
    } else {
	printf STDERR "Running %s on \"%s\" ...\n", $init{'spice_cmd'}, $run_name;
	`$init{'spice_cmd'} $run_name`;
    }
}

d381 3
a383 1
    my($setup, $clk_q, $vcrit, $pass);
d397 4
d473 1
a473 1
    &h_run_spice($run_name);
a703 17

sub h_run_spice {

    my($run_name) = @@_;
    my($base,$dir,$type,$spiceout);

    ($base,$dir,$type) = fileparse($run_name, '\.sp');
    $spiceout = $base . '.out';

    # Run hspice
    if ($skip && (-e $spiceout)) {
	printf STDERR "Found \"%s\", skipping run.\n", $spiceout;
    } else {
	printf STDERR "Running %s on \"%s\" ...\n", $init{'spice_cmd'}, $run_name;
	`$init{'spice_cmd'} $run_name`;
    }
}
@


1.19
log
@Consolidate lookup_input functions into one, using list of names and refnames.
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.18 1998/09/01 04:49:20 ryu Exp ryu $
d206 1
a206 1
	    printf $fp "+\td\n";
d210 1
a210 1
	    printf $fp "+\tclk\n";
d214 1
a214 1
	    printf $fp "+\t%s\n", &lookup_output_load($termname, 'q');
d218 1
a218 1
	    printf $fp "+\t%s\n",
d223 1
a223 1
	    printf $fp "+\t%s\n", &lookup_output_load($termname);
d250 1
a250 1
    printf $fp ".meas tran setup_${out_trans} trig=v(d) val='$init{'midpoint'}' cross=1\n";
d258 1
a258 1
    printf $fp ".meas tran vcrit find v(xflop.${c})\n";
d265 1
a265 1
    # falling cnode:
d268 1
a268 1
	printf $fp ".meas tran $optmeasure param='($init{'high'}-vcrit)/$init{'high'}'\n";
d272 1
a272 1
	printf $fp ".meas tran $optmeasure param='vcrit/$init{'high'}'\n";
d296 1
a296 1
	printf $fp ".meas tran clk_q trig=v(clk) val='$init{'midpoint'}' rise=2\n";
d298 1
a298 1
	printf $fp ".meas tran clk_q trig=v(clk) val='$init{'midpoint'}' fall=2\n";
d546 1
a546 1
	    printf $fp "+\td\n";
d550 1
a550 1
	    printf $fp "+\tclk\n";
d554 1
a554 1
	    printf $fp "+\t%s\n", &lookup_output_load($termname, 'q');
d558 1
a558 1
	    printf $fp "+\t%s\n",
d563 1
a563 1
	    printf $fp "+\t%s\n", &lookup_output_load($termname);
d591 1
a591 1
	printf $fp ".meas tran hold_${out_trans} trig=v(clk) val='$init{'midpoint'}' rise=2\n";
d593 1
a593 1
	printf $fp ".meas tran hold_${out_trans} trig=v(clk) val='$init{'midpoint'}' fall=2\n";
d598 1
a598 1
    printf $fp ".meas tran vcrit find v(xflop.${c})\n";
d605 1
a605 1
    # falling cnode:
d608 1
a608 1
	printf $fp ".meas tran $optmeasure param='($init{'high'}-vcrit)/$init{'high'}'\n";
d612 1
a612 1
	printf $fp ".meas tran $optmeasure param='vcrit/$init{'high'}'\n";
d636 1
a636 1
	printf $fp ".meas tran clk_q trig=v(clk) val='$init{'midpoint'}' rise=2\n";
d638 1
a638 1
	printf $fp ".meas tran clk_q trig=v(clk) val='$init{'midpoint'}' fall=2\n";
@


1.18
log
@Consistent quotes
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.17 1998/08/30 19:24:00 ryu Exp ryu $
d170 1
a170 1
    my($vcvs, $drefname, $clkrefname);
d188 2
a189 2
    $drefname = 'd';
    $clkrefname = 'clk';
d219 1
a219 1
		&lookup_input_2($termname, $d, $clk, $drefname, $clkrefname, $tie, @@tie_list);
d510 1
a510 1
    my($vcvs, $drefname, $clkrefname);
d528 2
a529 2
    $drefname = 'd';
    $clkrefname = 'clk';
d559 1
a559 1
		&lookup_input_2($termname, $d, $clk, $drefname, $clkrefname, $tie, @@tie_list);
@


1.17
log
@Using term instead of port; extract all cell and terminal properties into synopsys model.
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.16 1998/08/23 22:11:24 ryu Exp ryu $
d59 1
a59 1
    open(SPICEIN,">$run_name") || die "ERROR:  Cannot open file \"$run_name\".";
d341 1
a341 1
    open(SPICEOUT, $spiceout) || die "ERROR: Cannot find \"$spiceout\".\n";
d399 1
a399 1
    open(SPICEIN,">$run_name") || die "ERROR:  Cannot open file \"$run_name\".";
d681 1
a681 1
    open(SPICEOUT, $spiceout) || die "ERROR: Cannot find \"$spiceout\".\n";
@


1.16
log
@Robert K. Yu
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.15 1998/08/23 21:59:07 ryu Exp ryu $
d168 1
a168 1
    my($port, $portname, $porttype);
d171 1
a171 1
    local($port_no, @@vcvs_list, @@output_loads);
d173 1
a173 1
    $port_no = 0;
d203 3
a205 3
    foreach $port (@@portlist) {
	($portname, $porttype) = split(':', $port);
	if ($portname eq $d) {
d209 1
a209 1
	if ($portname eq $clk) {
d213 2
a214 2
	if ($portname eq $q) {
	    printf $fp "+\t%s\n", &lookup_output_load($portname, 'q');
d217 1
a217 1
	if ($porttype eq 'i') {
d219 1
a219 1
		&lookup_input_2($portname, $d, $clk, $drefname, $clkrefname, $tie, @@tie_list);
d222 2
a223 2
	if ($porttype eq 'o') {
	    printf $fp "+\t%s\n", &lookup_output_load($portname);
d508 1
a508 1
    my($port, $portname, $porttype);
d511 1
a511 1
    local($port_no, @@vcvs_list, @@output_loads);
d513 1
a513 1
    $port_no = 0;
d543 3
a545 3
    foreach $port (@@portlist) {
	($portname, $porttype) = split(':', $port);
	if ($portname eq $d) {
d549 1
a549 1
	if ($portname eq $clk) {
d553 2
a554 2
	if ($portname eq $q) {
	    printf $fp "+\t%s\n", &lookup_output_load($portname, 'q');
d557 1
a557 1
	if ($porttype eq 'i') {
d559 1
a559 1
		&lookup_input_2($portname, $d, $clk, $drefname, $clkrefname, $tie, @@tie_list);
d562 2
a563 2
	if ($porttype eq 'o') {
	    printf $fp "+\t%s\n", &lookup_output_load($portname);
@


1.15
log
@save_data functions moved into model.pl; pass lists by reference
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.14 1998/08/23 21:16:02 ryu Exp ryu $
d11 1
a11 1
#	Author: Robert Yu
@


1.14
log
@Write out synopsys lib.
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.13 1998/08/23 12:03:44 ryu Exp ryu $
d370 2
a371 4
    $celldata{"$cellname:setup_hold:$d:$clk:setup"} = 1;
    $celldata{"$cellname:setup_hold:$d:$clk:clktype"} = $clktype;
    $celldata{"$cellname:setup_hold:$d:$clk:setup_$out_trans"} =
	$setup/$init{'scale_delay'};
d710 2
a711 4
    $celldata{"$cellname:setup_hold:$d:$clk:hold"} = 1;
    $celldata{"$cellname:setup_hold:$d:$clk:clktype"} = $clktype;
    $celldata{"$cellname:setup_hold:$d:$clk:hold_$out_trans"} =
	$hold/$init{'scale_delay'};
@


1.13
log
@celldata
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.12 1998/08/23 10:13:32 ryu Exp ryu $
d370 4
a373 1
    $celldata{"$cellname:setup_hold:$d:$clk:setup_$out_trans"} = $setup/$init{'scale_delay'};
d712 4
a715 1
    $celldata{"$cellname:setup_hold:$d:$clk:hold_$out_trans"} = $hold/$init{'scale_delay'};
@


1.12
log
@Added writing of DATA
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.11 1998/08/23 07:19:07 ryu Exp ryu $
d370 1
a370 2
    printf DATA "\$data{'$cellname:setup_hold:$d:$clk:setup_$out_trans'} = %.4e;\n",
	$setup/$init{'scale_delay'};
d709 1
a709 2
    printf DATA "\$data{'$cellname:setup_hold:$d:$clk:hold_$out_trans'} = %.4e;\n",
	$hold/$init{'scale_delay'};
@


1.11
log
@Using proper my and local
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.10 1998/08/23 06:56:57 ryu Exp ryu $
d370 3
d709 3
@


1.10
log
@Using my and use instead of local and require.
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.9 1998/08/18 09:33:00 ryu Exp ryu $
d379 2
a380 2
    my($run_name, $dtrans);
    my($optmod, $optparam, $optmeasure);
@


1.9
log
@Debugged clock to q module; changed generated file convention
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.8 1998/08/17 16:58:24 ryu Exp ryu $
d40 1
a40 1
    local($out_trans, $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list) = @@_;
d87 1
a87 1
    local ($fp) = @@_;
d107 1
a107 1
    local ($fp, $clktype, $out_trans, $qtype) = @@_;
d167 5
a171 4
    local($fp, $d, $clk, $q, $tie, $tie_list) = @@_;
    local($port, $portname, $porttype);
    local($dbuf, $clkbuf, $port_no, $outload, @@output_loads);
    local($vcvs, @@vcvs_list, $drefname, $clkrefname);
d244 1
a244 1
    local($fp, $clktype, $out_trans, $ctype, $c) = @@_;
d280 1
a280 1
    local($fp, $clktype, $out_trans) = @@_;
d313 2
a314 2
    local($run_name) = @@_;
    local($base,$dir,$type,$spiceout);
d330 1
a330 1
    local  ($run_name, $out_trans, $d, $clktype, $clk, $qtype, $q, $ctype, $c) = @@_;
d332 2
a333 2
    local($base,$dir,$ext,$spiceout);
    local($setup, $clk_q, $vcrit, $pass);
d377 1
a377 1
    local($out_trans, $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list) = @@_;
d379 2
a380 2
    local($run_name, $dtrans);
    local($optmod, $optparam, $optmeasure);
d424 1
a424 1
    local ($fp) = @@_;
d444 1
a444 1
    local ($fp, $clktype, $out_trans, $qtype) = @@_;
d504 5
a508 4
    local($fp, $d, $clk, $q, $tie, $tie_list) = @@_;
    local($port, $portname, $porttype);
    local($dbuf, $clkbuf, $port_no, $outload, @@output_loads);
    local($vcvs, @@vcvs_list, $drefname, $clkrefname);
d581 1
a581 1
    local($fp, $clktype, $out_trans, $ctype, $c) = @@_;
d617 1
a617 1
    local($fp, $clktype, $out_trans) = @@_;
d650 2
a651 2
    local($run_name) = @@_;
    local($base,$dir,$type,$spiceout);
d658 1
a658 1
	printf STDERR "\"%s\" found, skipping run.\n", $spiceout;
d667 1
a667 1
    local  ($run_name, $out_trans, $d, $clktype, $clk, $qtype, $q, $ctype, $c) = @@_;
d669 2
a670 2
    local($base,$dir,$ext,$spiceout);
    local($hold, $clk_q, $vcrit, $pass);
d674 2
@


1.8
log
@Clean up clock_q module
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.7 1998/08/17 04:25:02 ryu Exp ryu $
d58 1
a58 1
    $run_name = &run_file_name($cellname, $d, $clk, $q);
d320 1
a320 1
	printf STDERR "\"%s\" found, skipping run.\n", $spiceout;
d337 2
d394 1
a394 1
    $run_name = &run_file_name($cellname, $d, $clk, $q);
@


1.7
log
@Measure clock using clock_percent for setup and hold
@
text
@d9 2
a10 2
#	$Id: setup_hold.pl,v 1.6 1998/08/17 03:34:11 ryu Exp ryu $
#	Input Capacitance Characterization Functions
a32 3

    # &sh_min_pulse_width ('lh', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);
    # &sh_min_pulse_width ('hl', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);
@


1.6
log
@Added hold time characterization
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.5 1998/08/17 02:54:12 ryu Exp ryu $
d26 1
a26 1
    printf OUT "Critical Node:\"$c\"\t($ctype)\n\n";
d262 1
a262 1
	printf $fp "+\twhen v(clk)='$init{'midpoint'}' rise=2\n"; 
d264 1
a264 1
	printf $fp "+\twhen v(clk)='$init{'midpoint'}' fall=2\n"; 
d591 1
a591 1
    printf $fp "\ttarg=v(d) val='$init{'midpoint'}' cross=1\n";
d596 1
a596 1
	printf $fp "+\twhen v(clk)='$init{'midpoint'}' rise=2\n"; 
d598 1
a598 1
	printf $fp "+\twhen v(clk)='$init{'midpoint'}' fall=2\n"; 
d696 1
a696 1
    printf OUT "    Hold_${out_trans}\tHold_${out_trans}\tClock-Q\t\tClock-Q\t\tCritNode\tCritPercent\n";
@


1.5
log
@Documentation
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.4 1998/08/17 02:49:06 ryu Exp ryu $
d28 6
a33 4
    &sh_setup ('lh', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);
    &sh_setup ('hl', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);
    # &sh_hold  ('lh', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);
    # &sh_hold  ('hl', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);
d39 4
a42 1
sub sh_setup {
d73 5
a77 5
    &sh_print_setup (SPICEIN);
    &sh_print_source (SPICEIN, $clktype, $out_trans, $qtype);
    &sh_print_dut (SPICEIN, $d, $clk, $q, $tie, @@tie_list);
    &sh_print_measure (SPICEIN, $clktype, $out_trans, $ctype, $c);
    &sh_print_trans (SPICEIN, $clktype, $out_trans);
d82 1
a82 1
    &sh_run_spice($run_name);
d84 1
a84 1
    &sh_report_spice($run_name, $out_trans, $d, $clktype, $clk, $qtype, $q, $ctype, $c);
d88 1
a88 1
sub sh_print_setup {
d108 1
a108 1
sub sh_print_source {
d168 1
a168 1
sub sh_print_dut {
d244 1
a244 1
sub sh_print_measure {
d280 1
a280 1
sub sh_print_trans {
d313 1
a313 1
sub sh_run_spice {
d330 1
a330 1
sub sh_report_spice {
d373 333
@


1.4
log
@Scale results to gate delay
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.3 1998/08/17 02:41:17 ryu Exp ryu $
d289 2
@


1.3
log
@Debuggin
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.2 1998/08/16 13:37:29 ryu Exp ryu $
d355 7
a361 4
    printf OUT "    Setup_${out_trans}\tClock-Q\t\tCritNode\tCritPercent\n";
    printf OUT "    [s]\t\t[s]\t\t[V]\n";
    printf OUT "    ----------\t----------\t----------\t----------\n";
    printf OUT "    %.4e\t%.4e\t%.4e\t%.4e\n", $setup, $clk_q, $vcrit, $pass;
@


1.2
log
@work in progress
@
text
@d9 1
a9 1
#	$Id: setup_hold.pl,v 1.1 1998/08/15 11:38:54 ryu Exp ryu $
d22 6
d30 4
a33 4
    &sh_hold  ('lh', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);
    &sh_hold  ('hl', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);
    &sh_min_pulse_width ('lh', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);
    &sh_min_pulse_width ('hl', $d, $clktype, $clk, $qtype, $q, $ctype, $c, $tie, @@tie_list);
d44 2
a45 2
    if (($clktype ne 'rise') && ($clktype ne 'fall')) {
	die "ERROR: clock type must be either 'rise' or 'fall'\n";
d54 1
a54 1
    $optmeasure = 'optcrit';
d65 1
d71 2
a72 3
    &sh_print_load (SPICEIN);
    &sh_print_measure (SPICEIN, $clktype, $out_trans, $qtype, $ctype, $c);
    &sh_print_trans (SPICEIN);
d79 1
a79 1
    &sh_report_spice($in, $run_name);
d95 2
d109 1
a109 1
    if ($clktype eq 'rise') {
d118 1
a118 1
    } elsif ($clktype eq 'fall') {
d138 1
a138 1
+	'$trans{'delay+risetime+2*pulse_width+falltime-setup'}'
d141 2
a142 2
+	'$trans{'3*period'}'
+	'$trans{'4*period'}')\n";
d151 1
a151 1
+	'$trans{'delay+risetime+2*pulse_width+falltime-setup'}'
d154 2
a155 2
+	'$trans{'3*period'}'
+	'$trans{'4*period'}')\n";
d167 1
a167 1
    local($dbuf, $clkbuf, $port_no, @@output_loads);
d189 1
a189 1
	die "ERROR:  You must specify a D buffer type to characterize setup and hold times.\n";
d194 1
a194 1
	die "ERROR:  You must specify a CLK buffer type to characterize setup and hold times.\n";
d196 1
a196 1
	printf $fp "xclkbuf vclk d $clkbuf\n";
d211 1
a211 1
	    printf $fp "+\t%s\n", &lookup_output_load($portname, $q);
a229 7
}


sub sh_print_load {

    local($fp) = @@_;
    local($outload);
d241 1
a241 1
    local($fp, $clktype, $out_trans, $qtype, $ctype, $c) = @@_;
d248 2
a249 8
    printf $fp "+\ttarg=v(clk) val='$init{'midpoint'}' $clktype=2\n";

    printf $fp "\n* Measure clock->q time:\n";
    printf $fp ".meas tran clk_q trig=v(clk) val='$init{'midpoint'}' $clktype=2\n";
    if ($out_trans eq 'lh') {
	printf $fp "+\ttarg=v(q) val='$init{'midpoint'}' rise=1\n";
    } elsif ($out_trans eq 'hl') {
	printf $fp "+\ttarg=v(q) val='$init{'midpoint'}' fall=1\n";
d251 1
a251 1
	die "ERROR: unknown output transition '$out_trans'\n";
d256 5
a260 1
    printf $fp "+\twhen v(clk)='$init{'midpoint'}' $clktype=2\n"; 
d265 2
a266 2
	printf $fp ".meas tran $optmeasure param='$init{'high'}-vcrit'\n";
	printf $fp "+\tgoal='${criterion_percent}*$init{'high'}'\n";
d269 2
a270 2
	printf $fp ".meas tran $optmeasure param='vcrit'\n";
	printf $fp "+\tgoal='${criterion_percent}*$init{'high'}'\n";
d277 1
a277 1
    local($fp) = @@_;
d288 15
d316 1
a316 1
	printf STDERR "\"%s\" found.\n", $spiceout;
a317 1
	printf STDERR "\"%s\" not found.\n", $spiceout;
d325 2
a326 1
    ($opt_trans, $run_name) = @@_;
d333 1
d336 1
a336 1
	if (($name, $value) = /^ +(setup_${opt_trans}) += +([0-9\+\-eE\.]+)/) {
d338 1
d342 1
d346 1
d350 1
d354 5
a358 4
    printf OUT "Cellname:\t\"$cellname\"\n";
    printf OUT "D Input:\t\"$d\"\n";
    printf OUT "Clock Input:\t\"$clk\"\n";
    printf OUT "Q Output:\t\"$q\"\n";
@


1.1
log
@entered into RCS
@
text
@d9 1
a9 1
#	$Id: setup_hold.c,v 1.1 1998/08/15 11:37:45 ryu Exp $
d13 1
a13 1
#
d15 1
a15 1
#	Top-level function to input cap characterization.
d20 1
d22 6
a27 15
    local($inexp, $tie, @@tie_list) = @@_;
    local($port, $portname, $porttype);

    printf OUT "Cellname:\t\"$cellname\"\n";
    printf OUT "\n";
    printf OUT "    Input\tCeff\t\tTerror\n";
    printf OUT "    \t\t[F]\t\t[s]\n";
    printf OUT "    ----------\t----------\t----------\n";

    foreach $port (@@portlist) {
	($portname, $porttype) = split(':', $port);
	if (($porttype eq 'i') && ($portname =~ /$inexp/)) {
	    &sh_char($portname, $tie, @@tie_list);
	}
    }
d31 2
a32 1
sub sh_char {
d34 1
a34 2
    local($in, $tie, @@tie_list) = @@_;
    local($devices, $run_name);
d37 8
d47 2
a48 2
    $optparam = 'optcap';
    $optmeasure = 'opterror';
d50 1
a50 1
    $run_name = &run_file_name($cellname, $in);
d55 5
a59 2
    printf SPICEIN "*	Char:	Input Capacitance Characterization\n";
    printf SPICEIN "*	Input:	\"$in\"\n";
d62 2
a63 2
    &sh_print_source (SPICEIN);
    &sh_print_dut (SPICEIN, $in, $tie, @@tie_list);
d65 1
a65 1
    &sh_print_measure (SPICEIN);
d88 2
a89 2
    printf $fp ".model $optmod opt\n";
    printf $fp ".param ceq = $optparam('$cstart', '$cmin', '$cmax')\n" ;
d93 2
d97 1
a97 1
    local ($fp) = @@_;
d100 3
a102 1
    printf $fp "vin0 in0 $init{'low'} pulse (
d110 3
a112 5

    # put two of them, in the future, integrate
    # the current going out of the source to
    # figure the charge, if no buffers are used.
    printf $fp "vin1 in1 $init{'low'} pulse (
a113 1
+	'$init{'high'}'
d119 29
d149 3
d157 1
a157 1
    local($fp, $in, $tie, $tie_list) = @@_;
d159 2
a160 2
    local($buf, $port_no, $outload, @@output_loads);
    local($vcvs, @@vcvs_list, $refname);
d164 7
a170 2
    if ($buffer{$in} ne '') {
	$buf = $buffer{$in};
d172 1
a172 1
	$buf = $buffer{'default'};
d177 2
a178 1
    $refname = 'input0';
d180 7
a186 2
    if ($buf eq 'none') {
	die "ERROR:  You must specify a buffer type to characterize input capacitance.\n";
d188 1
a188 2
	printf $fp "xbuf0 in0 input0 $buf\n";
	printf $fp "xbuf1 in1 input1 $buf\n";
d191 1
a191 1
    printf $fp "xdut0\n";
d194 10
a203 2
	if ($portname eq $in) {
	    printf $fp "+\tinput0\n";
d208 1
a208 1
		&lookup_input($portname, $in, $refname, $tie, @@tie_list);
a221 3

    # print the matching cap
    printf $fp "ceff input1 $init{'low'} ceq\n";
d228 1
d240 1
a240 1
    local($fp) = @@_;
d245 13
a257 11
    printf $fp ".meas tran dut_r trig=v(in0) val='$init{'midpoint'}' rise=1\n";
    printf $fp "+\ttarg=v(input0) val='$init{'midpoint'}' rise=1\n";
    printf $fp ".meas tran dut_f trig=v(in0) val='$init{'midpoint'}' fall=1\n";
    printf $fp "+\ttarg=v(input0) val='$init{'midpoint'}' fall=1\n";
    printf $fp ".meas tran dut_delay param='(dut_r + dut_f)/2.0'\n";

    printf $fp ".meas tran cap_r trig=v(in1) val='$init{'midpoint'}' rise=1\n";
    printf $fp "+\ttarg=v(input1) val='$init{'midpoint'}' rise=1\n";
    printf $fp ".meas tran cap_f trig=v(in1) val='$init{'midpoint'}' fall=1\n";
    printf $fp "+\ttarg=v(input1) val='$init{'midpoint'}' fall=1\n";
    printf $fp ".meas tran cap_delay param='(cap_r + cap_f)/2.0'\n";
d259 14
a272 1
    printf $fp ".meas tran $optmeasure param='dut_delay - cap_delay' goal=0\n";
a288 1
    printf $fp ".meas tran ceff param='ceq'\n";
a309 1

d312 1
a312 1
    ($in, $run_name) = @@_;
d314 1
a314 1
    local($ceq,$cerror);
d321 8
a328 2
	if (($name, $value) = /^ +(ceff) += +([0-9\+\-eE\.]+)/) {
	    $ceq = $value;
d331 1
a331 1
	    $cerror = $value;
d335 4
a338 1
    printf OUT "    %10s\t%.4e\t%.4e\n", $in, $ceq, $cerror;
@
# Change User Description Committed
#1 6489 robert_yu Saved here.