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