Perl在ASIC中的应用——实战篇:网表处理
Posted ExASIC
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Perl在ASIC中的应用——实战篇:网表处理相关的知识,希望对你有一定的参考价值。
今天开始讲Perl语言在网表处理中的一些应用。我们都听说Perl的优势是文本处理,而我们的网表正是有一定语法格式的文本。简单点说,就是用Perl对网表中的内容进行高级查找替换。
我们看一些实际中遇到的需求:
在综合网表的开头插入一些注释,比如网表产生的时间日期。
用buffer替换网表中的assign语句。
把寄存器register file模块的DFF全部替换成同时带复位reset、置位set、输出Q和Q非的DFF。
把网表wire名称大小写敏感转成大小写不敏感。
插入注释
原理:用Perl先读入原网表到内部数组,利用数组的索引确定插入的位置。
例如
#读入原网表
my @netlist;
open(FH_I, "<digital.v");
@netlist = <FH_I>;
close(FH_I);
#定义待插入的内容
my $now = `date +%Y-%m-%d' '%H:%M:%S`;
my $insert = "//this netlist is generated on $now\n";
#插入并写出网表
my $len = $#netlist;
open(FH_O, ">digital_new.v");
my $num = 10; #指定插入的行号
my $i;
for($i=0; $i<$num - 1; $i++){ #先输出插入行之前的内容
print FH_O shift(@netlist);
}
print FH_O "$insert"; #输出新插入的内容
for($i=$num - 1; $i<=$len; $i++){ #最后输出剩下的内容
print FH_O shift(@netlist);
}
上面这段Perl代码实现了在指定行号位置插入文件。如果指定行号为0,就表示插在网表的开头。如果指定行号为$len+1,就表示插在网表末尾。这段代码是不是很简单?有人说“我可以用sed命令一行代码就实现了”。是的,sed命令的确很好用。Perl的优势是灵活、高效,适合较复杂的情形,并且对超大型网表速度也很快。
处理assign语句
在综合或者PR网表里,偶尔会出现assign语句。当然在综合时应该首先尽量用DC或RC去处理through型连线,multiple port net,常量等。我们这里的办法只是没有办法的办法。对于一条assign语句格式通常如下:
assign B = A;
而BUF的例化格式:
BUF0 u_buf_fix_assign_0 (.Z(B), .I(A));
所以我们需要一个高级查找替换,帮我们做这个事情。如果网表中有多处assign,那么BUF0的例化名需要每次加1。
my $netlist = "";
open(FH_I, "<digital.v"); #读入网表
while(<FH_I>){
$netlist .= $_;
}
close(FH_I);
#查找替换
local $i = 0; #子函数里可以修改
$netlist =~ s/^\s*assign\s+(\w+)\s*=\s*(\w+)\s*;/&replace_assign($1, $2)/ge;
open(FH_O, ">digital_new.v");
print FH_O "$netlist";
close(FH_O);
sub replace_assign {
our $i;
my $B = shift;
my $A = shift;
my $ret = "\tBUF0 u_buf_fix_assign_$i (.Z($B), .I($A));\n";
$i++; #用全局变量
return $ret;
}
上面利用正则s///e来调用子函数实现复杂的替换,而s///g用来做全局替换。
DFF换类型
为了方便做ECO把register file的DFF换成同时带复位reset、置位set、输出Q和Q非的DFF。比如有DFFR和DFFSRQ:
DFF u_dff (.Q(Q),
.CLK(CLK),
.R(R),
.D(D));
DFFSRQ u_dff (.Q(Q),
.QN(),
.CLK(CLK),
.R(R),
.S(tiehi_net),
.D(D));
我们就可以查找reg_file中的DFF替换成DFFSRQ。初一看和assign处理的情况有点类似,但又有点不一样。不一样在这里的install写成了多行。我这里就只写出替换部分的代码:
$netlist =~ s/^\s*DFF\s+(\w+)\s+\( #取instance名
\.Q\( (\w+) \), #取Q的wire
\.CLK\( (\w+) \), #取CLK的wire
\.R\( (\w+) \), #取R的wire
\.D\( (\w+) \) #取D的wire
\);/&replace_dff($1, $2, $3, $4, $5)/xge;
sub replace_dff {
my $inst = shift;
my $Q = shift;
...
my $ret = "DFFSRQ u_dff (.Q($Q), \n";
$ret .= " .QN(), \n";
$ret .= " .CLK($CLK), \n";
$ret .= " .R($R), \n";
$ret .= " .S(tiehi_net), \n";
$ret .= " .D($D)); \n";
}
有些童鞋可能已经注意到了s///x,这里的x是为了正则表达式可以换行、加空白字符,还可以加注释。是不是很方便?
大小写敏感变不敏感
在verilog里是大小写敏感的,仅大小写不同的变量,如ABC、abc、Abc是三个不同的变量。但模拟电路里通常不做区别,认为是同一个变量。所以在用calibre做chip层LVS时,需要大小写不敏感的数字电路。我们假设网表里有:
wire n1;
wire n2;
wire N1;
wire N2;
wire n3;
一个简单粗暴的方法是把所有大写的“N加数字”的变量后面加上下划线,即N1->N1_,N2->N2_,N3->N3_,虽然N3不需要转换。
s/^\s*wire\s+N(\d+)\s*;/\twire N$1_;/g
所有instance连线的地方也需要转换。
s/\.(\w+)\s*\(N(d+)\)/.$1(N$2_)/g;
我们接着寻找更好的解决方案:
把网表拆分成若干个单个模块,在每个模块内查找大小写敏感的变量,然后再逐个转换。这个就当作今天的练习题吧!
下一次,我们介绍Perl的图形界面编程在仿真和测试中的应用。
如果觉得本文对你有帮助请转发转载以帮助更多的人。如果有建议或问题也欢迎直接留言讨论。
广告
******************************************
数字后端网表ECO软件:Gates On the Fly(GOF) 5.3
http://www.nandigits.cn
******************************************
--------------------
欢迎关注ExASIC. 分享芯片数字集成电路设计中的经验和方法。Sharing makes work smoother.
以上是关于Perl在ASIC中的应用——实战篇:网表处理的主要内容,如果未能解决你的问题,请参考以下文章
R语言实战应用精讲50篇(二十八)-R语言时空数据分析实战案例-数据处理及可视化