RTL编码风格所造成的仿真和综合的不匹配.docx
《RTL编码风格所造成的仿真和综合的不匹配.docx》由会员分享,可在线阅读,更多相关《RTL编码风格所造成的仿真和综合的不匹配.docx(18页珍藏版)》请在冰豆网上搜索。
RTL编码风格所造成的仿真和综合的不匹配
RTL编码风格所造成的仿真和综合的不匹配
1.0简介
ASIC或者FPGA设计就是把一个想法或者概念转换成物理实现的过程。
这篇文章讨论了
HDL编码风格所造成的RTLGate-level仿真的不一致的几种情况。
它的一个基本的判定规则是,符合以下两种情况的编码风格是坏的编码风格。
・提供给HDL仿真器的关于设计的信息不能传送给综合工具
・综合开关提供给综合工具的信息在仿真器中不可得
如果上犯了上两条禁忌,就会造成综合前的RTL仿真和综合后的门级仿真不匹配的问题。
这些问题很难发现,因为由于门的数量的增多,完备测试是不可能的,而且如果不注意会
最终导致ASIC生产的失败。
解决方法就是了解什么样的编码风格或者综合选项会导致RTL到门级的仿真不一致,并避
免这些问题。
2.0敏感列表
当一个always块中并不包含Verilog的关键字posedge或者negedge的时候综合工具会把它综合成组合或者锁存器逻辑。
对于一个组合逻辑always块,逻辑直接从块中的等
式中推导岀,*而与敏感列表没有关系*。
综合工具读取敏感列表,并把它与always块中
的等式相比较,报告岀可能造成pre-和post-synthesis仿真不一致的疏漏的敏感列表。
若一个信号在敏感列表中岀现而没有在always块用到,它不会对pre-和post-synthesis
造成任何功能上的不同。
多余的敏感信号的唯一的后果就是使仿真变慢了。
2.1不完全敏感信号列表
综合工具总是把always块中的等式按完整敏感信号来综合。
但是pre-synthesis的功能
仿真就会非常不同。
•modulecode1a(o,a,b);
•outputo;
•inputa,b;
•rego;
•always@(aorb)
•o=a&b;
•endmodule
在code1a中敏感列表时完整的,pre-synthesis和post-synthesis都会按一个2输入
and门来仿真
•modulecode1b(o,a,b);
•outputo;
•inputa,b;
•rego;
«always@(a)
«o=a&b;
・endmodule
在codelb中敏感列表不完整,post-synthesis仍然是个2-inputand门,而在
pre-synthesis的仿真中只有在a有变化的时候always块才会执行。
♦modulecode1c(o,a,b);
•outputo;
«inputa,b;
•rego;
«always
«o=a&b;
•endmodule
code1c不包括任何敏感列表,在pre-synthesis的时候仿真器在在always块中陷入无
限循环,而post-synthesis仍然是个2-inputand门
冈一
2.2不同赋值顺序的完整敏感列表
-在pre-synthesis时always块中的赋值语句会按顺序执行。
这样,在always块中有局部临时变量时就会产生问题,临时变量可能在if语句的判断条件部分,case语句,或者赋
值语句的右端中用到。
*如果一个临时变量在被赋值之前用到,就会导致赋值的乱序*。
直
到temp变量的赋值语句被执行,temp将保持之前传送给它的值。
*modulecode2a(o,a,b,c,d);
*outputo;
*inputa,b,c,d;
*rego,temp;
*always@(aorborcord)begin
*o=a&b|temp;
*temp=c&d;
*end
*endmodule
-在code2a中,temp在被赋值之前被用到,temp将保持之前的值。
之后temp被赋新
值。
在pre-synthesis仿真中,temp将像一个锁存器。
而在综合时,它会按正确的顺序
赋值。
此会造成不一致。
*modulecode2b(o,a,b,c,d);
«outputo;
*inputa,b,c,d;
«rego,temp;
«always@(aorborcord)begin
temp=c&d;
o=a&b|temp;
*end
«endmodule
-code2b中pre-和post-synthesis仿真结果是一致的。
3.0function
-function总是被综合成组合电路,由于这个原因,一些工程师把所有的组合逻辑都用
function来实现。
如果function按照组合逻辑来仿真使用function是没有什么问题的。
当工程师在function中的组合逻辑中犯了错误而使它仿真时像一个锁存器,就会产生错误。
当function代码仿真寄存器的行为的时候综合工具是没有警告信息的。
用function
建模组合逻辑是危险的。
*modulecode3a(o,a,nrst,en);
«outputo;
*inputa,nrst,en;
*rego;
«always@(aornrstoren)
*if(!
nrst)o=1'b0;
*elseif(en)o=a;
*endmodule
-code3a是设计锁存器的典型方法。
«modulecode3b(o,a,nrst,en);
«outputo;
«inputa,nrst,en;
*rego;
«always@(aornrstoren)
*o=latch(a,nrst,en);
«functionlatch;
«inputa,nrst,en;
*if(!
nrst)latch=1'bO;
*elseif(en)latch=a;
*endfunction
*endmodule
-code3b中把相同的代码用在了一个if语句中,产生了3-inputand门。
latch的
-如果在function中的代码是用来生成latch的,pre-synthesis仿真将仿真成
行为,为post-synthesis仿真将会仿真成组合逻辑。
从而造成不匹配。
4.0case语句
4.1FullCase
输岀
的仿
这条
*用编译指令〃synopsysfull_case给编译工具更多的关于设计的信息,而不能把这些信
息提供给仿真工具。
这条特别指令是提醒编译工具,case语句是fullydefined的,
对于没用用到的case是"don'tcare"的。
当用此条指令时,pre-和post-synthesis
真可能会不同。
此外,尽管此条指令是告诉编译工具把未用的的情况视为不处理”,
指令有时会使设计比忽略full_case时更大和更慢
•modulecode4a(y,a,en);
«output[3:
0]y;
«input[1:
0]a;
•inputen;
•reg[3:
0]y;
•always@(aoren)begin
y=4'h0;
«case({en,a})
•3'b1_00:
y[a]=1'b1;
•3'b1_01:
y[a]=1'b1;
•3'b1_10:
y[a]=1'b1;
•3'b1_11:
y[a]=1'b1;
«endcase
•end
•endmodule
在code4a中case没有综合指令,结果是三输入与门和一个反相器。
pre-和
post-synthesis仿真是一致的。
•3'b1_01:
y[a]=
=1'b1;
•3'b1_10:
y[a]=
=1'b1;
•3'b1_11:
y[a]=
=1'b1;
•endcase
•end
•endmodule
在code4b中case语句带综合指令full_case,正是因为此,在综合时en输入被优化掉而成为一个悬挂的输入。
code4a和code4b综合前的仿真结果以及code4a综合后的结果都是一致的,而它们是与code4b综合后的结果不同的。
可
4.2ParaelCase
*用编译指令〃synopsysparallel_case给编译工具更多的关于设计的信息,而不能把这
些信息提供给仿真工具*。
这条编译指令是告诉编译器所有的情况是并行执行的,尽管有重
叠的情况(这种情况通常会形成一种优先编码器)。
当设计中有重叠的case时,pre-和
post-synthesis的仿真结果将会不同。
在某些情况,用这条指令会使设计变得更大和更
慢。
添加parallel_case的一个目的是优化面积和速度。
*优先编码器行为的RTL模型通过了
RTL级测试,但是如果在门级测试时忽略了这个漏洞(它其实是没有优先级的并行逻辑),导致的结果就是,设计是错误的,但是bug直到ASIC原型交货前也没有发现,那么在高度的金钱和时间成本下,ASIC必须重新设计。
*
•modulecode5a(y,z,a,b,c,d);
•outputy,z;
•inputa,b,c,d;
•regy,乙
•always@(aorborcord)begin
•{y,z}=2'bo;
•casez({a,b,c,d})
•4'b11?
?
:
z=1;
•4'b?
?
11:
y=1;
endcase
«end
•endmodule
code5a会被被综合成成具有优先编码器的功能的逻辑。
但是code5b却被综合成两个and
门。
•modulecode5b(y,z,a,b,c,d);
•outputy,z;
•inputa,b,c,d;
•regy,乙
•always@(aorborcord)begin
casez({a,b,c,d})//synopsysparallel_case4'b11?
?
:
z=1;
4'b?
?
11:
y=1;
endcase
endendmodule
综合工具指令〃synopsysparallel_case的使用将导致具有优先编码器功能的逻辑实现
成并行逻辑,从而导致综合前后的不匹配。
4.3Casex
casex语句的使用也会导致设计问题。
casex把X视为'don'tcare'(如果它们岀现在case
表达式和case条目里)。
casex所导致的问题会在casex表达式的输入被初始化成不定
值时岀现。
在处理casex语句时,综合前仿真会把不定值视为’don'tcare'。
综合后的仿
真把X在门级的模型中传递。
有个公司在他们的设计中使用了casex语句。
casex语句的输入在复位后成为不定值,因
为综合前RTL仿真把未知的输入视为'don'tcare',casex语句错误地初始化设计在工作
状态,而门级仿真并不够复杂或者说详细以致于没有发现这个错误,从而使递交的ASIC
带着严重的bug。
•modulecode6(memceO,memce1,cs,en,addr);
■
outputmemce0,memce1,cs;
■
■
input
input[31:
30]addr;
en;
■
reg
always@(addroren)begin
memce0,memce1,cs;
{memceO,memce1,cs}casex({addr,en})
=3'b0;
■
3'b101:
memce0=
1'b1;
■
3'b111:
memce1=
1'b1;
•3'b0?
1:
cs
•endcase
•end
•endmodule
=1'b1;
code6是一个带着enable信号的简单的地址解码器,有时外部接口的设计错误会导致
enable信号初始化后在被设置成一个有效状态之前成为不定值。
当enable处于未知状态
时,case选择器基于addr信号错误地匹配case选项。
这个初始化的问题只有在post-synthesis仿真时岀岀现。
一个类似的情况就是,当en有效,地址线的MSB位成
为不定值时。
这将会导致memceO或者memce1有效,而不管片选cs信号是否有效。
4.4casez
casez语句会导致和casex相同的设计问题,只不过它在验证时更容易被发现。
用casez
当输入被初始化成高阻态时就会岀现问题。
但是casez是设计很多结构的一种简洁和有效
的方式,如优先编码器,中断处理器,和地址解码器。
因此当设计工程师再用HDL设计某
些结构时应该考虑用casez语句。
•modulecode7(memceO,memcel,cs,en,addr);
■
outputmemceO,memcel,cs;
■
■
input
input[31:
30]addr;
en;
■
■
reg
always@(addroren)begin
memce0,memcel,cs;
•
{memceO,memcel,cs}casez({addr,en})
=3'b0;
•
3'b101:
memceO=
1'b1;
■
3'b111:
memcel=
1'b1;
•
3'b0?
1:
cs
=1'b1;
■
endcase
■
end
•endmodule
code7是与code6相同的带enable信号的简单地址解码器,只不过它用casez替换了
casex。
当某个输入成为高阻态而不是有效值时,它会与code6产生相同的问题。
同样,
错误的case匹配会发生(取决于case语句输入的状态)。
然而,casez语句的匹配(浮置输入(floatinginput)或者三态驱动信号)比cazex语句匹配(信号成为不定值)可
能性要小得多。
*但是casez语句在设计地址解码器和优先编码器的时候是很有用的*
*使用原则*:
在RTL级谨慎使用casez语句。
5.0初始化
5.1'X'初始化
当在RTL代码中复制时,有时会被赋给X值。
X被Verilog仿真器解释为不定值(casex
例外),但是会被综合工具当做’don'tcare'。
赋值成X会导致综合前后仿真的不一致。
但是赋值成X值也是一种有用的技巧。
在FSM设计中,存在未用到的状态时,把状态变
量赋值成'X'可以帮助调试状态转换。
这是在进入case状态之前把状态寄存器赋值成'X'值
(它是为所有的不正确的状态而准备)。
切记,综合工具将把任何的X值解释为'don't
care'。
•modulecode8a(y,a,b,c,s);
*outputy;
*inputa,b,c;
*input[1:
0]s;
*regy;
*always@(aorborcors)begin
y=1'bx;case(s)
2'b00:
y=a;
2'b01:
y=b;
2'b10:
y=c;endcase
end
endmodulemodulecode8b(y,a,b,c,s);
outputy;
inputa,b,c;
input[1:
0]s;
regy;
always@(aorborcors)case(s)
2'b00:
y=a;
2'b01:
y=b;
2'b10,2'b11:
y=c;
endcase
endmodule
code8a和code8b是3选1选择器的简单的Verilog模型。
如果一旦case的2'b11情况发生,code8a的编码风格会造成仿真的不一致。
而在code8b中则不会发生这种情况。
而这种不匹配在2'b11情况永远不会发生时是有用的,因为一旦2'b11情况发生,y的仿
真输出就会是不定值。
5.2用translate_off/translate_on初始化设计
在translate_off和translate_on,对于综合工具是不可见的,而仿真工具可以。
这样就
会造成综合前后仿真的不一致,有可能在综合前仿真中初始化是正确的,但是在初始化之后,结果就不正确了。
•modulecode9(y1,go,clk,nrst);
«outputy1;
•inputgo,clk,nrst;
•regy1;
•parameterIDLE=1'd0,
BUSY=1'd1;
•reg[0:
0]state,next;
•//Hidingtheinitializationofvariablesfromthe
•//synthesistoolisaverydangerous
practice!
!
•//synopsystranslate_off
initialy1=1'b1;
•//synopsystranslate_on
•always@(posedgeclkornegedgenrst)
«if(!
nrst)state<=IDLE;
«elsestate<=next;
«always@(stateorgo)begin
«next=1'bx;
«y1=1'bO;
«case(state)
*IDLE:
if(go)next=BUSY;
*BUSY:
begin
if(!
go)next=IDLE;
y1=1'b1;
end
«endcase
«end
•endmodule
translate_off/translate_on的初始化部分,会导致综合前后仿真结果的不一致。
6.0translate_off/translate_on的一般用法
translate_off/translate_on综合指令应该谨慎使用。
它们在显示设计的信息时是非常有
用的,但是当它被用来模拟某种功能时是很危险的。
一个例外是异步复位和置位的D触发
器。
他要求用非综合的模型提供正确的综合前仿真模型以和综合后模型匹配。
这种条件按
以下方式创建:
置reset有效,置set有效,置reset无效,使set继续有效。
在这种情
况,D触发器模型需要一点辅助来在综合前阶段正确建模set条件。
这是由于在always
块里只有在set/reset的边沿时才会触发。
当输入是异步的,一旦reset信号被去除,set
就会有效,但是这种情况不会发生,因为always块不能被触发。
为了解决这个问题,可
以用translate_off/translate_on指令强制输岀正确的值。
*最好的方法就是尽可能避免
异步set/reset触发器的使用。
・//GenerallygoodDFFwithasynchronoussetandreset
•modulecode10a(q,d,clk,rstn,setn);
*outputq;
*inputd,clk,rstn,setn;
*regq;
*always@(posedgeclkornegedgerstnornegedgesetn)
if(!
rstn)q<=0;//
asynchronousreset
*elseif(!
setn)q<=1;//asynchronousset
*elseq<=d;
•endmodule
•//synopsystranslate_off
*//BadDFFwithasynchronoussetandreset.Thisdesign
*//willnotcompilefromSynopsys,andthedesign
will
*//notsimulatecorrectly.
•modulecodelOb(q,d,elk,rstn,setn);
•outputq;
•inputd,elk,rstn,setn;
•regq;
•always@(posedgeclkorrstnorsetn)
•if(!
rstn)q<=0;//
asynchronousreset
•elseif(!
setn)q<=1;//asynchronousset
•elseq<=d;
•endmodule
•//synopsystranslate_on
•//GoodDFFwithasynchronoussetandresetandself-
•//correcting
•//set-resetassignment
•modulecode10c(q,d,clk,rstn,setn);
•outputq;
•inputd,clk,rstn,setn;
•regq;
•always@(posedgeclkornegedgerstnornegedgesetn)
•if(!
rstn)q<=0;//
asynchronousreset
•elseif(!
setn)q<=1;//asynchronousset
•elseq<=d;
•//synopsystranslate_off
•always@(rstnorsetn)
•if(rstn&&!
setn)forceq=1;
•elserel
easeq;
•//synopsystranslate_on
•endmodule
code10a在仿真时%99的情况是正确的,但是当rstn的上升沿来到时,如果setn一直是低电平,always块是不被触发的,这导致了仿真的不正确。
而在code10b中不管是综
合前后的仿真,还是综合本身,都会是错误的。
而code10c会100%仿真正确,综合前
后的仿真也会匹配,它使用translate_off/translate_on综合指令,强制使输岀输岀正确
的值。
(这确实是很有意思)。
7.0延