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 () { 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 () { 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 () { 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 () { 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 () { 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 () { 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; @