# $Id: model.pl,v 1.26 1999/07/28 14:49:45 ryu Exp $ # 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. sub print_model { my($format, $modelname) = @_; open(MODEL, "> $modelname") || die "ERROR: Cannot create file '$modelname'.\n"; if ($format eq 'synopsys') { &print_synopsys(MODEL); } elsif ($format eq 'pearl') { &print_pearl(MODEL); } else { die "ERROR: unknown model format type '$format'.\n"; } close(MODEL); printf STDERR "Created '$modelname'.\n"; } sub print_synopsys_cellprops { my($fp) = @_; my ($key, $cell, $type, $propname); foreach $key (keys(%celldata)) { ($cell, $type, $propname) = split(':', $key); if (($cell eq $cellname) && ($type eq 'cellprop')) { # treat 'section' properties differently if ($propname eq 'section') { printf $fp "\t%s\n", $celldata{"$cellname:cellprop:$propname"}; } else { printf $fp "\t%s : %s ;\n", $propname, $celldata{"$cellname:cellprop:$propname"}; } } } } sub print_synopsys_termprops { my($fp, $refterm) = @_; my ($key, $cell, $type, $termname, $propname); foreach $key (keys(%celldata)) { ($cell, $type, $termname, $propname) = split(':', $key); if (($cell eq $cellname) && ($type eq 'termprop') && ($termname eq $refterm)) { printf $fp "\t %s : %s ;\n", $propname, $celldata{"$cellname:termprop:$termname:$propname"}; } } } sub print_synopsys { my ($fp) = @_; my ($term); my ($termname, $termtype); printf $fp "/*\n"; &print_header($fp, ' *'); printf $fp " */\n\n"; printf $fp " cell( \"$cellname\" ) {\n"; &print_synopsys_cellprops($fp); # print terms foreach $term (@termlist) { ($termname, $termtype) = split(':', $term); printf $fp "\tpin( \"$termname\" ) {\n"; &print_synopsys_termprops($fp, $termname); if ($termtype eq 'i') { printf $fp "\t direction : input ;\n"; printf $fp "\t capacitance : %.4e ;\n", $celldata{"$cellname:input_cap:$termname"} if $celldata{"$cellname:input_cap:$termname"}; &print_synopsys_input_timing($fp, $termname); printf $fp "\t}\n"; next; } if ($termtype eq 'o') { printf $fp "\t direction : output ;\n"; &print_synopsys_output_timing($fp, $termname); printf $fp "\t}\n"; next; } } printf $fp " }\n"; } sub print_synopsys_input_timing { my($fp, $input) = @_; my ($term); my ($clock, $termtype); my ($i, @wcvalue); foreach $term (@termlist) { ($clock, $termtype) = split(':', $term); if ($termtype eq 'i') { # D SETUP if ($celldata{"$cellname:setup_hold:$input:$clock:setup"}) { printf $fp "\t timing () {\n"; printf $fp "\t\trelated_pin : \"$clock\" ;\n"; if ($celldata{"$cellname:setup_hold:$input:$clock:clktype"} eq 'rising') { printf $fp "\t\ttiming_type : setup_rising ;\n"; } elsif ($celldata{"$cellname:setup_hold:$input:$clock:clktype"} eq 'falling') { printf $fp "\t\ttiming_type : setup_falling ;\n"; } else { printf STDERR "WARNING: unknown clock type '$clktype'.\n"; } if ($#slewrate == -1) { # only one value printf $fp "\t\tintrinsic_rise : %.4e ;\n", $celldata{"$cellname:setup_hold:$input:$clock:setup_lh[0]"} if $celldata{"$cellname:setup_hold:$input:$clock:setup_lh[0]"}; printf $fp "\t\tintrinsic_fall : %.4e ;\n", $celldata{"$cellname:setup_hold:$input:$clock:setup_hl"}[0] if $celldata{"$cellname:setup_hold:$input:$clock:setup_hl"}[0]; printf $fp "\t }\n"; } else { # all values printf $fp "\t\trise_constraint (%s) {\n", $celldata{"$cellname:setup_hold:$input:$clock:lu_table"}; printf $fp "\t\t values (\""; for ($i = 0; $i <= $#slewrate; $i++) { printf $fp "%.4e", $celldata{"$cellname:setup_hold:$input:$clock:setup_lh"}[$i]; printf $fp ", " unless ($i == $#slewrate); } printf $fp "\")\n\t\t}\n"; printf $fp "\t\tfall_constraint (%s) {\n", $celldata{"$cellname:setup_hold:$input:$clock:lu_table"}; printf $fp "\t\t values (\""; for ($i = 0; $i <= $#slewrate; $i++) { printf $fp "%.4e", $celldata{"$cellname:setup_hold:$input:$clock:setup_hl"}[$i]; printf $fp ", " unless ($i == $#slewrate); } printf $fp "\")\n\t\t}\n"; printf $fp "\t }\n"; } } # D HOLD if ($celldata{"$cellname:setup_hold:$input:$clock:hold"}) { printf $fp "\t timing () {\n"; printf $fp "\t\trelated_pin : \"$clock\" ;\n"; if ($celldata{"$cellname:setup_hold:$input:$clock:clktype"} eq 'rising') { printf $fp "\t\ttiming_type : hold_rising ;\n"; } elsif ($celldata{"$cellname:setup_hold:$input:$clock:clktype"} eq 'falling') { printf $fp "\t\ttiming_type : hold_falling ;\n"; } else { printf STDERR "WARNING: unknown clock type '$clktype'.\n"; } if ($#slewrate == -1) { # only one value printf $fp "\t\tintrinsic_rise : %.4e ;\n", $celldata{"$cellname:setup_hold:$input:$clock:hold_lh[0]"} if $celldata{"$cellname:setup_hold:$input:$clock:hold_lh[0]"}; printf $fp "\t\tintrinsic_fall : %.4e ;\n", $celldata{"$cellname:setup_hold:$input:$clock:hold_hl[0]"} if $celldata{"$cellname:setup_hold:$input:$clock:hold_hl[0]"}; printf $fp "\t }\n"; } else { # all values printf $fp "\t\trise_constraint (%s) {\n", $celldata{"$cellname:setup_hold:$input:$clock:lu_table"}; printf $fp "\t\t values (\""; for ($i = 0; $i <= $#slewrate; $i++) { printf $fp "%.4e", $celldata{"$cellname:setup_hold:$input:$clock:hold_lh"}[$i]; printf $fp ", " unless ($i == $#slewrate); } printf $fp "\")\n\t\t}\n"; printf $fp "\t\tfall_constraint (%s) {\n", $celldata{"$cellname:setup_hold:$input:$clock:lu_table"}; printf $fp "\t\t values (\""; for ($i = 0; $i <= $#slewrate; $i++) { printf $fp "%.4e", $celldata{"$cellname:setup_hold:$input:$clock:hold_hl"}[$i]; printf $fp ", " unless ($i == $#slewrate); } printf $fp "\")\n\t\t}\n"; printf $fp "\t }\n"; } } # CE SETUP if ($celldata{"$cellname:clock_enable:$input:$clock:setup"}) { printf $fp "\t timing () {\n"; printf $fp "\t\trelated_pin : \"$clock\" ;\n"; if ($celldata{"$cellname:clock_enable:$input:$clock:clktype"} eq 'rising') { printf $fp "\t\ttiming_type : setup_rising ;\n"; } elsif ($celldata{"$cellname:clock_enable:$input:$clock:clktype"} eq 'falling') { printf $fp "\t\ttiming_type : setup_falling ;\n"; } else { printf STDERR "WARNING: unknown clock type '$clktype'.\n"; } if ($#slewrate == -1) { # only one value if ($celldata{"$cellname:clock_enable:$input:$clock:cetype"} eq 'active_high') { printf $fp "\t\tintrinsic_rise : "; } elsif ($celldata{"$cellname:clock_enable:$input:$clock:cetype"} eq 'active_low') { printf $fp "\t\tintrinsic_fall : "; } else { printf STDERR "WARNING: unknown ce type '$cetype'.\n"; } printf $fp "%.4e ;\n", &max($celldata{"$cellname:clock_enable:$input:$clock:setup_lh[0]"}, $celldata{"$cellname:clock_enable:$input:$clock:setup_hl[0]"}); printf $fp "\t }\n"; } else { # all values @wcvalue = &bigger_avg_list( $celldata{"$cellname:clock_enable:$input:$clock:setup_lh"}, $celldata{"$cellname:clock_enable:$input:$clock:setup_hl"}); if ($celldata{"$cellname:clock_enable:$input:$clock:cetype"} eq 'active_high') { printf $fp "\t\trise_constraint (%s) {\n", $celldata{"$cellname:clock_enable:$input:$clock:lu_table"}; } elsif ($celldata{"$cellname:clock_enable:$input:$clock:cetype"} eq 'active_low') { printf $fp "\t\tfall_constraint (%s) {\n", $celldata{"$cellname:clock_enable:$input:$clock:lu_table"}; } else { printf STDERR "WARNING: unknown ce type '$cetype'.\n"; } printf $fp "\t\t values (\""; for ($i = 0; $i <= $#slewrate; $i++) { printf $fp "%.4e", $wcvalue[$i]; printf $fp ", " unless ($i == $#slewrate); } printf $fp "\")\n\t\t}\n"; printf $fp "\t }\n"; } } # CE HOLD if ($celldata{"$cellname:clock_enable:$input:$clock:hold"}) { printf $fp "\t timing () {\n"; printf $fp "\t\trelated_pin : \"$clock\" ;\n"; if ($celldata{"$cellname:clock_enable:$input:$clock:clktype"} eq 'rising') { printf $fp "\t\ttiming_type : hold_rising ;\n"; } elsif ($celldata{"$cellname:clock_enable:$input:$clock:clktype"} eq 'falling') { printf $fp "\t\ttiming_type : hold_falling ;\n"; } else { printf STDERR "WARNING: unknown clock type '$clktype'.\n"; } if ($#slewrate == -1) { # only one value if ($celldata{"$cellname:clock_enable:$input:$clock:cetype"} eq 'active_high') { printf $fp "\t\tintrinsic_rise : "; } elsif ($celldata{"$cellname:clock_enable:$input:$clock:cetype"} eq 'active_low') { printf $fp "\t\tintrinsic_fall : "; } else { printf STDERR "WARNING: unknown ce type '$cetype'.\n"; } printf $fp "%.4e ;\n", &max($celldata{"$cellname:clock_enable:$input:$clock:hold_lh"}, $celldata{"$cellname:clock_enable:$input:$clock:hold_hl"}); printf $fp "\t }\n"; } else { # all values @wcvalue = &bigger_avg_list( $celldata{"$cellname:clock_enable:$input:$clock:hold_lh"}, $celldata{"$cellname:clock_enable:$input:$clock:hold_hl"}); if ($celldata{"$cellname:clock_enable:$input:$clock:cetype"} eq 'active_high') { printf $fp "\t\trise_constraint (%s) {\n", $celldata{"$cellname:clock_enable:$input:$clock:lu_table"}; } elsif ($celldata{"$cellname:clock_enable:$input:$clock:cetype"} eq 'active_low') { printf $fp "\t\tfall_constraint (%s) {\n", $celldata{"$cellname:clock_enable:$input:$clock:lu_table"}; } else { printf STDERR "WARNING: unknown ce type '$cetype'.\n"; } printf $fp "\t\t values (\""; for ($i = 0; $i <= $#slewrate; $i++) { printf $fp "%.4e", $wcvalue[$i]; printf $fp ", " unless ($i == $#slewrate); } printf $fp "\")\n\t\t}\n"; printf $fp "\t }\n"; } } } } } sub print_synopsys_output_timing { my ($fp, $output) = @_; my ($term); my ($input, $termtype); my ($i, $j, $k); foreach $term (@termlist) { ($input, $termtype) = split(':', $term); if ($termtype eq 'i') { # LOAD DELAY if ($celldata{"$cellname:load_delay:$input:$output"}) { printf $fp "\t timing () {\n"; printf $fp "\t\trelated_pin : \"$input\" ;\n"; if ($#slewrate == -1) { # linear model printf $fp "\t\tintrinsic_rise : %.4e ;\n", $celldata{"$cellname:load_delay:$input:$output:tplha"} if $celldata{"$cellname:load_delay:$input:$output:tplha"}; printf $fp "\t\tintrinsic_fall : %.4e ;\n", $celldata{"$cellname:load_delay:$input:$output:tphla"} if $celldata{"$cellname:load_delay:$input:$output:tphla"}; printf $fp "\t\trise_resistance : %.4e ;\n", $celldata{"$cellname:load_delay:$input:$output:tplhb"} if $celldata{"$cellname:load_delay:$input:$output:tplhb"}; printf $fp "\t\tfall_resistance : %.4e ;\n", $celldata{"$cellname:load_delay:$input:$output:tphlb"} if $celldata{"$cellname:load_delay:$input:$output:tphlb"}; } else { # nonlinear model printf $fp "\t\ttiming_type : combinational ;\n"; if ($celldata{"$cellname:load_delay:$input:$output:tplh"}) { printf $fp "\t\trise_propagation (%s) {", $celldata{"$cellname:load_delay:$input:$output:lu_table"}; if ($output_prop_percent == 0.50) { printf $fp "\n\t\t /* Actual measurement values:"; } printf $fp "\n\t\t values ( \\"; $k = 0; for ($j = 0; $j <= $#slewrate; $j++) { printf $fp "\n\t\t\t\""; for ($i = 0; $i <= $#cload; $i++) { printf $fp "%.4e", $celldata{"$cellname:load_delay:$input:$output:tplh"}[$k++]; printf $fp " " unless ($i == $#cload); } printf $fp "\""; printf $fp "," unless ($j == $#slewrate); printf $fp " \\"; } printf $fp "\n\t\t )"; if ($output_prop_percent == 0.50) { printf $fp "\n\t\t */"; printf $fp "\n\t\t /* Propagation minus rise transition delay: */"; printf $fp "\n\t\t values ( \\"; $k = 0; for ($j = 0; $j <= $#slewrate; $j++) { printf $fp "\n\t\t\t\""; for ($i = 0; $i <= $#cload; $i++) { # subtract the risetime from tplh printf $fp "%.4e", ($celldata{"$cellname:load_delay:$input:$output:tplh"}[$k] - $celldata{"$cellname:load_delay:$input:$output:risetime"}[$k]); $k++; printf $fp " " unless ($i == $#cload); } printf $fp "\""; printf $fp "," unless ($j == $#slewrate); printf $fp " \\"; } printf $fp "\n\t\t )"; } printf $fp "\n\t\t}\n"; } if ($celldata{"$cellname:load_delay:$input:$output:tphl"}) { printf $fp "\t\tfall_propagation (%s) {", $celldata{"$cellname:load_delay:$input:$output:lu_table"}; if ($output_prop_percent == 0.50) { printf $fp "\n\t\t /* Actual measurement values:"; } printf $fp "\n\t\t values ( \\"; $k = 0; for ($j = 0; $j <= $#slewrate; $j++) { printf $fp "\n\t\t\t\""; for ($i = 0; $i <= $#cload; $i++) { printf $fp "%.4e", $celldata{"$cellname:load_delay:$input:$output:tphl"}[$k++]; printf $fp " " unless ($i == $#cload); } printf $fp "\""; printf $fp "," unless ($j == $#slewrate); printf $fp " \\"; } printf $fp "\n\t\t )"; if ($output_prop_percent == 0.50) { printf $fp "\n\t\t */"; printf $fp "\n\t\t /* Propagation minus fall transition delay: */"; printf $fp "\n\t\t values ( \\"; $k = 0; for ($j = 0; $j <= $#slewrate; $j++) { printf $fp "\n\t\t\t\""; for ($i = 0; $i <= $#cload; $i++) { printf $fp "%.4e", ($celldata{"$cellname:load_delay:$input:$output:tphl"}[$k] - $celldata{"$cellname:load_delay:$input:$output:falltime"}[$k]); $k++; printf $fp " " unless ($i == $#cload); } printf $fp "\""; printf $fp "," unless ($j == $#slewrate); printf $fp " \\"; } printf $fp "\n\t\t )"; } printf $fp "\n\t\t}\n"; } if ($celldata{"$cellname:load_delay:$input:$output:risetime"}) { printf $fp "\t\trise_transition (%s) {\n", $celldata{"$cellname:load_delay:$input:$output:lu_table"}; printf $fp "\t\t values ( \\"; $k = 0; for ($j = 0; $j <= $#slewrate; $j++) { printf $fp "\n\t\t\t\""; for ($i = 0; $i <= $#cload; $i++) { printf $fp "%.4e", $celldata{"$cellname:load_delay:$input:$output:risetime"}[$k++]; printf $fp " " unless ($i == $#cload); } printf $fp "\""; printf $fp "," unless ($j == $#slewrate); printf $fp " \\"; } printf $fp "\n\t\t )"; printf $fp "\n\t\t}\n"; } if ($celldata{"$cellname:load_delay:$input:$output:falltime"}) { printf $fp "\t\tfall_transition (%s) {\n", $celldata{"$cellname:load_delay:$input:$output:lu_table"}; printf $fp "\t\t values ( \\"; $k = 0; for ($j = 0; $j <= $#slewrate; $j++) { printf $fp "\n\t\t\t\""; for ($i = 0; $i <= $#cload; $i++) { printf $fp "%.4e", $celldata{"$cellname:load_delay:$input:$output:falltime"}[$k++]; printf $fp " " unless ($i == $#cload); } printf $fp "\""; printf $fp "," unless ($j == $#slewrate); printf $fp " \\"; } printf $fp "\n\t\t )"; printf $fp "\n\t\t}\n"; } } printf $fp "\t }\n"; } # CLOCK Q if ($celldata{"$cellname:clock_q:$input:$output"}) { printf $fp "\t timing () {\n"; printf $fp "\t\trelated_pin : \"$input\" ;\n"; if ($celldata{"$cellname:clock_q:$input:$output:clktype"} eq 'rising') { printf $fp "\t\ttiming_type : rising_edge ;\n"; } elsif ($celldata{"$cellname:clock_q:$input:$output:clktype"} eq 'falling') { printf $fp "\t\ttiming_type : falling_edge ;\n"; } else { printf STDERR "WARNING: unknown clock type '$clktype'.\n"; } if ($timing_model eq 'linear') { printf $fp "\t\tintrinsic_rise : %.4e ;\n", $celldata{"$cellname:clock_q:$input:$output:clk_q_lha"} if $celldata{"$cellname:clock_q:$input:$output:clk_q_lha"}; printf $fp "\t\tintrinsic_fall : %.4e ;\n", $celldata{"$cellname:clock_q:$input:$output:clk_q_hla"} if $celldata{"$cellname:clock_q:$input:$output:clk_q_hla"}; printf $fp "\t\trise_resistance : %.4e ;\n", $celldata{"$cellname:clock_q:$input:$output:clk_q_lhb"} if $celldata{"$cellname:clock_q:$input:$output:clk_q_lhb"}; printf $fp "\t\tfall_resistance : %.4e ;\n", $celldata{"$cellname:clock_q:$input:$output:clk_q_hlb"} if $celldata{"$cellname:clock_q:$input:$output:clk_q_hlb"}; printf $fp "\t }\n"; } elsif ($timing_model eq 'non_linear') { printf $fp "\t\trise_propagation (%s) {\n", $celldata{"$cellname:clock_q:$input:$output:lu_table"}; if ($output_prop_percent == 0.50) { printf $fp "\t\t /* Actual measurement values:\n"; } printf $fp "\t\t values (\""; for ($i = 0; $i <= $#cload; $i++) { printf $fp "%.4e", $celldata{"$cellname:clock_q:$input:$output:clk_q_lh"}[$i]; printf $fp ", " unless ($i == $#cload); } printf $fp "\")\n"; if ($output_prop_percent == 0.50) { printf $fp "\t\t */\n"; printf $fp "\t\t /* Propagation minus rise transition delay: */\n"; printf $fp "\t\t values (\""; for ($i = 0; $i <= $#cload; $i++) { printf $fp "%.4e", ($celldata{"$cellname:clock_q:$input:$output:clk_q_lh"}[$i] - $celldata{"$cellname:clock_q:$input:$output:risetime"}[$i]); printf $fp ", " unless ($i == $#cload); } printf $fp "\")\n"; } printf $fp "\t\t}\n"; printf $fp "\t\trise_transition (%s) {\n", $celldata{"$cellname:clock_q:$input:$output:lu_table"}; printf $fp "\t\t values (\""; for ($i = 0; $i <= $#cload; $i++) { printf $fp "%.4e", $celldata{"$cellname:clock_q:$input:$output:risetime"}[$i]; printf $fp ", " unless ($i == $#cload); } printf $fp "\")\n\t\t}\n"; printf $fp "\t\tfall_propagation (%s) {\n", $celldata{"$cellname:clock_q:$input:$output:lu_table"}; if ($output_prop_percent == 0.50) { printf $fp "\t\t /* Actual measurement values:\n"; } printf $fp "\t\t values (\""; for ($i = 0; $i <= $#cload; $i++) { printf $fp "%.4e", $celldata{"$cellname:clock_q:$input:$output:clk_q_hl"}[$i]; printf $fp ", " unless ($i == $#cload); } printf $fp "\")\n"; if ($output_prop_percent == 0.50) { printf $fp "\t\t */\n"; printf $fp "\t\t /* Propagation minus rise transition delay: */\n"; printf $fp "\t\t values (\""; for ($i = 0; $i <= $#cload; $i++) { printf $fp "%.4e", ($celldata{"$cellname:clock_q:$input:$output:clk_q_hl"}[$i] - $celldata{"$cellname:clock_q:$input:$output:falltime"}[$i]); printf $fp ", " unless ($i == $#cload); } printf $fp "\")\n"; } printf $fp "\t\t}\n"; printf $fp "\t\tfall_transition (%s) {\n", $celldata{"$cellname:clock_q:$input:$output:lu_table"}; printf $fp "\t\t values (\""; for ($i = 0; $i <= $#cload; $i++) { printf $fp "%.4e", $celldata{"$cellname:clock_q:$input:$output:falltime"}[$i]; printf $fp ", " unless ($i == $#cload); } printf $fp "\")\n\t\t}\n"; printf $fp "\t }\n"; } else { printf STDERR "WARNING: unknown timing model type '$timing_model'.\n"; } } } } } 1;