SOC時(shí)序分析中的跳變點(diǎn)介紹
跳變點(diǎn)是所有重要時(shí)序分析工具中的一個(gè)重要概念。跳變點(diǎn)被時(shí)序分析工具用來計(jì)算設(shè)計(jì)節(jié)點(diǎn)上的時(shí)延與過渡值。跳變點(diǎn)的有些不同含義可能會(huì)被時(shí)序分析工程師忽略。而這在SOC設(shè)計(jì)后期,也就是要對(duì)時(shí)序簽字時(shí)可能會(huì)導(dǎo)致問題。后端設(shè)計(jì)工程師要知道跳變點(diǎn)的概念及其含義,這個(gè)非常重要。這也正是本文目的之所在。
1.跳變點(diǎn)定義:
跳變點(diǎn)可定義為邏輯高電平的百分比,作為測量壓擺率和時(shí)延值的參照。圖1(a)演示的是壓擺率跳變點(diǎn)。
圖1(a)
圖1(b)演示的是時(shí)延跳變點(diǎn)。
圖1(b)
跳變點(diǎn)用來描述標(biāo)準(zhǔn)單元或硬模塊(IP)等的引腳過渡值特征,同時(shí)檢查SoC時(shí)序。通常跳變點(diǎn)的值在時(shí)序模型(自由格式)中提及,時(shí)序分析工具在計(jì)算時(shí)延和壓擺率時(shí)會(huì)使用這些值。
2.如何固定跳變點(diǎn):
在描述標(biāo)準(zhǔn)單元或硬模塊(IP)特征時(shí),跳變點(diǎn)對(duì)于特定的技術(shù)節(jié)點(diǎn)是固定的。將跳變點(diǎn)固定的目的是確保測量的時(shí)延/壓擺率接近實(shí)際(Spice)的波形。如圖2(a)所示,當(dāng)跳變點(diǎn)位于切換波形的線性區(qū)(20%-80%)時(shí),壓擺率值比位于非線性區(qū)(10%-90%)時(shí)要令人樂觀。
圖2(a)
通常情況下,在過渡跳變點(diǎn)位于線性區(qū)時(shí),時(shí)序工具計(jì)算的單元時(shí)延更接近Spice結(jié)果。
同時(shí),晶體管的電壓閾值(Vt)特性對(duì)于決定跳變點(diǎn)發(fā)揮了重要作用,因?yàn)檩敵霾ㄐ卧谳斎腚妷撼^晶體管的Vt值后會(huì)發(fā)生線性化[1]。
時(shí)延閾值在輸入和輸出波形的線性區(qū)是固定的。只要時(shí)延跳變點(diǎn)位于波形的線性部分,那么時(shí)延跳變點(diǎn)是20-80還是50-50都沒有關(guān)系。
3.自由格式提及的跳變點(diǎn)句法[2]
下面給出的是典型時(shí)序模型(.liberty文件)的快照,以指示正在使用的跳變點(diǎn)
input_threshold_pct_rise:50;
input_threshold_pct_fall:50;
output_threshold_pct_rise:50;
output_threshold_pct_fall:50;
slew_lower_threshold_pct_rise:20;
slew_lower_threshold_pct_fall:20;
slew_upper_threshold_pct_rise:80;
slew_upper_threshold_pct_fall:80;
4.時(shí)序工具如何處理跳變點(diǎn)來計(jì)算時(shí)延
a)當(dāng)跳變點(diǎn)對(duì)于界面都相同時(shí):
圖3(a)描述了驅(qū)動(dòng)程序和負(fù)載具有相同時(shí)延閾值時(shí)的情況。
在給出的示例中,兩者都為50%。
圖3(a)[!--empirenews.page--]
此時(shí),,考慮壓擺率降級(jí)(由網(wǎng)絡(luò)引起)后,時(shí)序工具計(jì)算的驅(qū)動(dòng)程序達(dá)到其50%的邏輯高值和負(fù)載達(dá)到其50%的邏輯高值時(shí)兩者之間的時(shí)間差。
類似的解釋對(duì)于特定單元的輸入和輸出產(chǎn)生的下降信號(hào)和時(shí)延同樣適用。壓擺率值根據(jù).lib中提及的變量進(jìn)行計(jì)算。
b)當(dāng)跳變點(diǎn)對(duì)于一個(gè)界面而不同時(shí)
(i)20%比50%:
圖4(a)描述了驅(qū)動(dòng)程序時(shí)延跳變點(diǎn)為20%而對(duì)負(fù)載單元跳變點(diǎn)為50%的情況。
在這種情況下,與負(fù)載信號(hào)相比,驅(qū)動(dòng)程序的信號(hào)會(huì)快速達(dá)到其時(shí)延跳變點(diǎn)值。因此此類界面的網(wǎng)絡(luò)時(shí)延會(huì)大于驅(qū)動(dòng)程序也達(dá)到50%情形下的時(shí)延[圖3(a)]。
圖4(a)
時(shí)序工具可通過線性或非線性擴(kuò)展計(jì)算網(wǎng)絡(luò)上出現(xiàn)的額外時(shí)延。
(ii)50%比20%
圖4(b)描述了驅(qū)動(dòng)程序跳變點(diǎn)為50%而負(fù)載單元的跳變點(diǎn)為20%的情形。
在這種情況下,與驅(qū)動(dòng)信號(hào)相比,負(fù)載的信號(hào)會(huì)更早達(dá)到其時(shí)延跳變點(diǎn)值。這種情況通過時(shí)序工具借助擴(kuò)展(線性或非線性)來進(jìn)行處理。
圖4(b)
這里需要注意的是:在這種情況下,擴(kuò)展會(huì)引起“負(fù)時(shí)延”。
應(yīng)注意:盡管現(xiàn)實(shí)世界不能在時(shí)域中后向穿越,但是時(shí)序工具需要將這種時(shí)延考慮在內(nèi),這樣,從開始點(diǎn)(在本例中為驅(qū)動(dòng)單元的輸入引腳)到終端點(diǎn)(在本例中為負(fù)載單元的輸出引腳)的整體路徑時(shí)延接近現(xiàn)實(shí)世界時(shí)延(Spice)。
5.與跳變點(diǎn)相關(guān)的其他問題:
(i)SDF中的負(fù)時(shí)延:在通過時(shí)序工具完成擴(kuò)展后產(chǎn)生的負(fù)時(shí)延將以標(biāo)準(zhǔn)時(shí)延格式(SDF)進(jìn)行復(fù)制,用于門級(jí)模擬。不希望發(fā)生這種情況,因?yàn)殚T級(jí)模擬器無法處理負(fù)時(shí)延。
它們要么標(biāo)志錯(cuò)誤消息要么表示此類情況的零時(shí)延。作為一種變通方法,可編寫一個(gè)腳本(附錄A),根據(jù)所計(jì)算的負(fù)時(shí)延,增加(或減少)負(fù)載單元(或驅(qū)動(dòng)單元)時(shí)延。
(ii)端口和IO單元之間的附加時(shí)延:
通常時(shí)序工具報(bào)告端口到I/O單元的時(shí)延。在硅片上,該網(wǎng)絡(luò)作為接合線出現(xiàn)在芯片外部。因此,對(duì)于該網(wǎng)絡(luò)物理信息不能進(jìn)行量化。
時(shí)序工具提供此類網(wǎng)絡(luò)的時(shí)延報(bào)告。原因包括:
a)由于沒有時(shí)序模型可用于端口,因此時(shí)序工具采用用戶定義的或默認(rèn)跳變點(diǎn)和電壓電平計(jì)算時(shí)延。
b)由于假定跳變點(diǎn)和端口w.r.tI/O單元跳變點(diǎn)的電壓電平值之間有差額。圖5(a)和圖5(b)描述了此類情況。
圖5(a)
圖5(b)
要克服這種情況,可執(zhí)行以下操作:
1)為與I/O單元的端口相同的端口定義運(yùn)行條件。
2)編寫腳本為此類網(wǎng)注釋零時(shí)延。
(iii)帶有丟失跳變點(diǎn)的庫
如果我們擁有不包含跳變點(diǎn)閾值或電壓電平值的時(shí)序模型,那么來自/到此類模型的界面的時(shí)延可能不正確。因?yàn)闀r(shí)序工具使用跳變點(diǎn)和電壓電平的默認(rèn)值,分析這些路徑。作為一種變通方法,用戶應(yīng)在向負(fù)責(zé)庫的人員進(jìn)行咨詢后,再定義跳變點(diǎn)。
6.如果不通過時(shí)序工具進(jìn)行擴(kuò)展會(huì)怎樣:激烈。這可能會(huì)導(dǎo)致芯片故障,因?yàn)槭褂脮r(shí)序工具計(jì)算的時(shí)延不接近Spice值。如果可以為跳變點(diǎn)不同的界面進(jìn)行Spice分析,應(yīng)當(dāng)是一種很好的操作方法。
如果對(duì)SOC中所使用的所有模型(硬模塊)使用同樣的跳變點(diǎn),應(yīng)當(dāng)是一種很好的操作方法。
這完全可以消除因閾值不同所產(chǎn)生的問題。
7.Spice合作關(guān)系:
對(duì)多閾值路徑進(jìn)行Spice分析,是增強(qiáng)信心并解決時(shí)序問題的好方法。
盡管在Spice世界,閾值實(shí)際并不存在。在時(shí)序模型中使用它們是為了簡化時(shí)序分析工具。
時(shí)序工具提供一個(gè)選項(xiàng),復(fù)制出特定時(shí)序路徑的spice網(wǎng)列表。除了spice網(wǎng)列表外,還復(fù)制出包含輸入矢量的激勵(lì)文件。復(fù)制出的spice網(wǎng)列表可能不包含針對(duì)時(shí)序路徑中標(biāo)準(zhǔn)單元和/或硬模塊的spice網(wǎng)列表。
Spice模擬工具可讀取復(fù)制的spice網(wǎng)列表和標(biāo)準(zhǔn)單元/硬模塊的spice網(wǎng)列表,然后提供激勵(lì)文件來模擬重要路徑。
需要通過分析生成的波形,查看路徑是否滿足時(shí)序要求。測量SPICE中此類路徑的時(shí)延和過渡值時(shí)需要謹(jǐn)記:要采用與時(shí)序模型中所提及的跳變點(diǎn)相同的跳變點(diǎn)。
8.擴(kuò)展類型:
大多數(shù)行業(yè)標(biāo)準(zhǔn)工具使用線性或非線性擴(kuò)展作為其運(yùn)作方式
a)線性擴(kuò)展:在該方法中,工具假定不同閾值的線性斜坡。
該方法使用相似三角形的概念擴(kuò)展驅(qū)動(dòng)程序到負(fù)載單元的時(shí)延。
b)非線性擴(kuò)展:此時(shí),工具使用電流源模型來定義坡道。這需要通過復(fù)雜的數(shù)學(xué)方程來計(jì)算時(shí)延。
總之,本文以跳變點(diǎn)定義開始,然后闡釋如何固定用于特定技術(shù)庫的跳變點(diǎn)。然后本文論述了時(shí)序工具如何解釋跳變點(diǎn),以及當(dāng)驅(qū)動(dòng)程序與負(fù)載單元跳變點(diǎn)不同時(shí)可能會(huì)引發(fā)的問題。[!--empirenews.page--]
附錄 A:在SDF中考慮負(fù)互連時(shí)延的腳本
#!/usr/local/bin/perl
print "n***************RUNNING PERL SCRIPT negaTIvedelinsdf_assarray.pl****nn";
if (!exists $ARGV[0] || !exists $ARGV[1]) { print "USAGE:: negativedelinsdf_assarray.pl
}
open(FILEA,$ARGV[0]) || die ("ERROR:: SDF file $ARGV[0] cannot be opened for reADIngn");
open(file1, ">$ARGV[1]") || die ("ERROR:: file $ARGV[1] cannot be opened for writingn");
while(
{ $line = $_;
$line1 = $line;
$line =~ s/^s+//g ;
if ( $line =~ "INTERCONNECT.*-[0-9]") ######## FINDING NEGATIVE INTERCONNECT ######
{
@array1 = split(/s+/,$line);
$count = @array1;
if ($count == 4){ ## To accont for the fact that only one INTERCONNECT triplet is present
$array1[$count]= $array1[$count-1];
$count = $count + 1;
}
for($i=0;$i<= $count -3;$i++)
{print file1 "$array1[$i] ";}
$value2 = $array1[$count -1];
$value1 = $array1[$count -2];
$instance_name = $array1[2];
@instance = split(///,$instance_name);
$count2 = @instance;
$pin_name = $instance[$count2 -1]; ####### GETTING LOAD INSTANCE PIN NAME ###############
$instance_name =~ s//[^(.*/)][A-Z0-9a-z_[0-9]+]*$//g; ####### GETTING LOAD INSTANCE NAME ###############
if( $value1 =~ "::")
{ $value1 =~ s/[()]//g;
@correct_value1 = split(/::/,$value1);
$load_correct_value1_0{$instance_name} = $correct_value1[0];
$load_correct_value1_1{$instance_name} = $correct_value1[1];
if($correct_value1[0] <= -0.0) #####NEGATIVE CHANGED TO ZERO DELAY######
{$correct_value1[0] = "0.000";}
if($correct_value1[1] <= -0.0)
{$correct_value1[1] = "0.000";}
print file1 "($correct_value1[0]::$correct_value1[1])";
}
elsif( $value1 =~ ":[^:]")
{ $value1 =~ s/[()]//g;
@correct_value1 = split(/:/,$value1);
$load_correct_value1_0{$instance_name} = $correct_value1[0];
$load_correct_value1_1{$instance_name} = $correct_value1[1];
$load_correct_value1_2{$instance_name} = $correct_value1[2];
if($correct_value1[0] <= -0.0) #####NEGATIVE CHANGED TO ZERO DELAY######
{$correct_value1[0] = "0.000";}
if($correct_value1[1] <= -0.0)
{$correct_value1[1] = "0.000";}
if($correct_value1[2] <= -0.0)
{$correct_value1[2] = "0.000";}
print file1 "($correct_value1[0]:$correct_value1[1]:$correct_value1[2])";
}
else{print file1 "$value1 ";}
if( $value2 =~ "::")
{ $value2 =~ s/[()]//g;
@correct_value2 = split(/::/,$value2);
$load_correct_value2_0{$instance_name} = $correct_value2[0]; ########NEGATIVE CHANGED TO ZERO DELAY#####
$load_correct_value2_1{$instance_name} = $correct_value2[1];
if($correct_value2[0] <= -0.0)
{$correct_value2[0] = "0.000";}
if($correct_value2[1] <= -0.0)
{$correct_value2[1] = "0.000";}
if ($correct_value1[0] == $correct_value2[0] && $correct_value1[1] == $correct_value2[1] ) { # Print these values only if they are differnet from the already printed values for the INTERCONNECT
print file1 ")n";
} else {
print file1 " ($correct_value2[0]::$correct_value2[1]))n";
}
}
elsif( $value2 =~ ":[^:]")
{ $value2 =~ s/[()]//g;
@correct_value2 = split(/:/,$value2);
$load_correct_value2_0{$instance_name} = $correct_value2[0]; ########NEGATIVE CHANGED TO ZERO DELAY#####
$load_correct_value2_1{$instance_name} = $correct_value2[1];
$load_correct_value2_2{$instance_name} = $correct_value2[2];
if($correct_value2[0] <= -0.0)
{$correct_value2[0] = "0.000";}
if($correct_value2[1] <= -0.0)
{$correct_value2[1] = "0.000";}
if($correct_value2[2] <= -0.0)
{$correct_value2[2] = "0.000";}
if ($correct_value1[0] == $correct_value2[0] && $correct_value1[1] == $correct_value2[1] && $correct_value1[2] == $correct_value2[2]) { # Print these values only if they are differnet from the already printed values for the INTERCONNECT
print file1 ")n";
} else {
print file1 " ($correct_value2[0]:$correct_value2[1]:$correct_value2[2]))n";
}
}
$load_instance{$instance_name} = $instance_name; ##SAVE ALL LOAD INSTACES FOR NEG DELAY IN THE ASSOCIATIVE ARRAY##
$load_pin{$instance_name.$pin_name} = $pin_name; ##SAVE ALL LOAD PINS FOR NEG DELAY IN THE ASSOCIATIVE ARRAY##
}
elsif ($line =~ "CELL" ) {
print file1 "$line";
$find = 0;
}
elsif($line =~ "INSTANCE ") ##CHECKING CORRESPONDING INSTANCES AND FIND FLAG = 1 IF FOUND######
{
print file1 "$line1";
@array2 = split(/s+/,$line);
$instance_name2 = $array2[1]; ##GETTING THE LOAD INSTANCE NAME FOUND HERE##########
$instance_name2 =~ s/[()]//g;
$instance_definition{$instance_name2} = "$instance_name2" ;
if(exists $load_instance{$instance_name2}) ####COMPARE INSTANCE NAME WITH THAT SAVED IN ASSO ARRAY#####
{
if($load_instance{$instance_name2} eq "$instance_name2")
{$find = 1;}
}
}
elsif($line =~ "IOPATH" && $find == 1) ##AFTER INSTANCES ARE FOUND CHECKING FOR CORRSPONDING PINS######
{
@array4 = split(/s+/,$line);
if ($array4[0] =~ "COND" ) { ## Take care of COND statements
$pin_name2 = $array4[3];
} else {
$pin_name2 = $array4[1];
}
if($line =~ "IOPATH" && exists $load_pin{$instance_name2.$pin_name2} ) {
if ( $load_pin{$instance_name2.$pin_name2} eq "$pin_name2" )
{
@array3 = split(/s+/,$line);
$count3 = @array3 ;
@value_IOPATH = ""; # This is to initialize the array to blank
if ($array3[0] =~ "COND" ) {
for ($j=5; $j<=$count3 ; $j++) {
$value_IOPATH[$j-5] = $array3[$j];
$value_IOPATH_width = @value_IOPATH;
if ($count3 == 6) { #### In case there is only one triplet for COND.*IOPATH
$value_IOPATH[1] = $value_IOPATH[0];
}
#$value1_IOPATH = $array3[5];
#$value2_IOPATH = $array3[6];
}
$constant_fields = 4;
} elsif ($array3[0] =~ "IOPATH") {
for ($k=3; $k<=$count3 ; $k++) {
$value_IOPATH[$k-3] = $array3[$k];
$value_IOPATH_width = @value_IOPATH;
if ($count3 == 4) { #### In case there is only one triplet for IOPATH
$value_IOPATH[1] = $value_IOPATH[0];
}
#$value1_IOPATH = $array3[3];
#$value2_IOPATH = $array3[4];
}
$constant_fields = 2;
}
for($i=0;$i<= $constant_fields;$i++)
{print file1 "$array3[$i] ";}
if( $value_IOPATH[0] =~ "::") ####CORRECT OR ACCOMODATING THE NEG DELAY VALUES HERE #########
{ $value_IOPATH[0] =~ s/[()]//g;
@correct_value1_IOPATH = split(/::/,$value_IOPATH[0]);
if(exists $load_correct_value1_0{$instance_name2}) {
if($load_correct_value1_0{$instance_name2} < 0.0) { # So that only negative delay value triplet is changed in the IOPATH syntax
if ( abs($load_correct_value1_0{$instance_name2}) < $correct_value1_IOPATH[0] ) { ###the absolute value to negative delay is larger than the timing of load arc. ######
$correct_value1_IOPATH[0] = $correct_value1_IOPATH[0] + $load_correct_value1_0{$instance_name2};
} else { print "IOPATH delay for $load_pin{$instance_name2.$pin_name2} of $instance_name2 is smaller than the INTERCONNECT delay n";}
}
}
if(exists $load_correct_value1_1{$instance_name2})
{ if( $load_correct_value1_1{$instance_name2} < 0.0) {
if ( abs($load_correct_value1_1{$instance_name2}) < $correct_value1_IOPATH[1] ) {
$correct_value1_IOPATH[1] = $correct_value1_IOPATH[1] + $load_correct_value1_1{$instance_name2};}
else { print "IOPATH delay for $load_pin{$instance_name2.$pin_name2} of $instance_name2 is smaller than the INTERCONNECT delay n";}}}
print file1 "($correct_value1_IOPATH[0]::$correct_value1_IOPATH[1])";
}
elsif( $value_IOPATH[0] =~ ":[^:]") ####CORRECT OR ACCOMODATING THE NEG DELAY VALUES HERE #########
{ $value_IOPATH[0] =~ s/[()]//g;
@correct_value1_IOPATH = split(/:/,$value_IOPATH[0]);
if(exists $load_correct_value1_0{$instance_name2}) {
if($load_correct_value1_0{$instance_name2} < 0.0) { # So that only negative delay value triplet is changed in the IOPATH syntax
if ( abs($load_correct_value1_0{$instance_name2}) < $correct_value1_IOPATH[0] ) {
$correct_value1_IOPATH[0] = $correct_value1_IOPATH[0] + $load_correct_value1_0{$instance_name2};
} else { print "IOPATH delay for $load_pin{$instance_name2.$pin_name2} of $instance_name2 is smaller than the INTERCONNECT delay n";}
}
}
if(exists $load_correct_value1_1{$instance_name2}) {
if($load_correct_value1_1{$instance_name2} < 0.0) { # So that only negative delay value triplet is changed in the IOPATH syntax
if ( abs($load_correct_value1_1{$instance_name2}) < $correct_value1_IOPATH[1] ) {
$correct_value1_IOPATH[1] = $correct_value1_IOPATH[1] + $load_correct_value1_1{$instance_name2};
} else { print "IOPATH delay for $load_pin{$instance_name2.$pin_name2} of $instance_name2 is smaller than the INTERCONNECT delay n";}
}
}
if(exists $load_correct_value1_2{$instance_name2}) {
if($load_correct_value1_2{$instance_name2} < 0.0) { # So that only negative delay value triplet is changed in the IOPATH syntax
if ( abs($load_correct_value1_2{$instance_name2}) < $correct_value1_IOPATH[2] ) {
$correct_value1_IOPATH[2] = $correct_value1_IOPATH[2] + $load_correct_value1_2{$instance_name2};
} else { print "IOPATH delay for $load_pin{$instance_name2.$pin_name2} of $instance_name2 is smaller than the INTERCONNECT delay n";}
}
}
print file1 "($correct_value1_IOPATH[0]:$correct_value1_IOPATH[1]:$correct_value1_IOPATH[2])";
}
else{print file1 "$value_IOPATH[0] ";} # This is to print empty brackets in case rise and fall triplets are empty
if( $value_IOPATH[1] =~ "::")
{ $value_IOPATH[1] =~ s/[()]//g;
@correct_value2_IOPATH = split(/::/,$value_IOPATH[1]);
if(exists $load_correct_value2_0{$instance_name2}) {
if( $load_correct_value2_0{$instance_name2} < 0.0)
{ if ( abs($load_correct_value2_0{$instance_name2}) < $correct_value2_IOPATH[0] ) {
$correct_value2_IOPATH[0] = $correct_value2_IOPATH[0] + $load_correct_value2_0{$instance_name2};}
else { print "IOPATH delay for $load_pin{$instance_name2.$pin_name2} of $instance_name2 is smaller than the INTERCONNECT delay n";}}}
if(exists $load_correct_value2_1{$instance_name2}) {
if( $load_correct_value2_1{$instance_name2} < 0.0)
{ if ( abs($load_correct_value2_1{$instance_name2}) < $correct_value2_IOPATH[1] ) {
$correct_value2_IOPATH[1] = $correct_value2_IOPATH[1] + $load_correct_value2_1{$instance_name2};}
else { print "IOPATH delay for $load_pin{$instance_name2.$pin_name2} of $instance_name2 is smaller than the INTERCONNECT delay n";}}}
if ($correct_value1_IOPATH[0] == $correct_value2_IOPATH[0] && $correct_value1_IOPATH[1] == $correct_value2_IOPATH[1]) { # Print these values only if they are differnet from the already printed values for the IOPATH
} else {
print file1 " ($correct_value2_IOPATH[0]::$correct_value2_IOPATH[1])";
}
}
elsif( $value_IOPATH[1] =~ ":[^:]")
{ $value_IOPATH[1] =~ s/[()]//g;
@correct_value2_IOPATH = split(/:/,$value_IOPATH[1]);
if(exists $load_correct_value2_0{$instance_name2}) {
if( $load_correct_value2_0{$instance_name2} < 0.0) {
if ( abs($load_correct_value2_0{$instance_name2}) < $correct_value2_IOPATH[0] ) {
$correct_value2_IOPATH[0] = $correct_value2_IOPATH[0] + $load_correct_value2_0{$instance_name2};}
else { print "IOPATH delay for $load_pin{$instance_name2.$pin_name2} of $instance_name2 is smaller than the INTERCONNECT delay n";}}}
if(exists $load_correct_value2_1{$instance_name2}) {
if( $load_correct_value2_1{$instance_name2} < 0.0) {
if ( abs($load_correct_value2_1{$instance_name2}) < $correct_value2_IOPATH[1] ) {
$correct_value2_IOPATH[1] = $correct_value2_IOPATH[1] + $load_correct_value2_1{$instance_name2};}
else { print "IOPATH delay for $load_pin{$instance_name2.$pin_name2} of $instance_name2 is smaller than the INTERCONNECT delay n";}}}
if(exists $load_correct_value2_2{$instance_name2}) {
if( $load_correct_value2_2{$instance_name2} < 0.0) {
if ( abs($load_correct_value2_2{$instance_name2}) < $correct_value2_IOPATH[2] ) {
$correct_value2_IOPATH[2] = $correct_value2_IOPATH[2] + $load_correct_value2_2{$instance_name2};}
else { print "IOPATH delay for $load_pin{$instance_name2.$pin_name2} of $instance_name2 is smaller than the INTERCONNECT delay n";}}}
if ($correct_value1_IOPATH[0] == $correct_value2_IOPATH[0] && $correct_value1_IOPATH[1] == $correct_value2_IOPATH[1] && $correct_value1_IOPATH[2] == $correct_value2_IOPATH[2]) { # Print these values only if they are differnet from the already printed values for the IOPATH
} else {
print file1 " ($correct_value2_IOPATH[0]:$correct_value2_IOPATH[1]:$correct_value2_IOPATH[2])";
}
}
else{print file1 "$value_IOPATH[1] ";} # This is to print empty brackets in case rise and fall triplets are empty
for ($m=2;$m<=$value_IOPATH_width;$m++) {
if (exists $value_IOPATH[$m]) {
$value_IOPATH[$m] =~ s/)+/)/; # To account for the brackets
print file1 " $value_IOPATH[$m]";
}
}
if ($array4[0] =~ "COND" ) { ## Extra bracket for COND statements
print file1 "))n";
} else {print file1 ")n";}
}
}
else
{print file1 "$line1";} #######DUMPING OUT OF SDF IN FILE1######################
}
else
{print file1 "$line1";}
}
close(file1);
close(fileA);
open(FILEA,$ARGV[0]) || die ("ERROR:: SDF file $ARGV[0] cannot be opened for readingn");
print "nn#############REPORTING INSTANCES WHOSE DEFINITION IS NOT THERE IN THE SDF#############n";
while(
{
$line2 = $_;
$line2 =~ s/^s+//g ;
if ( $line2 =~ "INTERCONNECT.*-[0-9]")
{ @array4 = split(/s+/,$line2);
$instance_name3 = $array4[2];
$instance_name3 =~ s//[^(.*/)][A-Z0-9a-z_[0-9]+]*$//g;
if(exists $instance_definition{$instance_name3})
{}
else
{print "$line2";}
}
}
close(fileA);
print "n";