Latch的产生和避免
FPGA
1 人赞同了该文章
在FPGA设计或者IC设计中,latch是一种对脉冲电平敏感的存储单元路径,可以在特定输入脉冲作用下改变电平。但由于往往设计为同步设计,Latch不可避免的毛刺是不愿意看到的;这种毛刺对下一级电路及时序收敛很不利,因而在设计中需要避免。
关于latch的产生,大多说人首先想到的是由于verilog代码中在if-else结构中缺少else或case结构中缺少default所导致,因此也往往在设计中要求if-else结构和case结构要写完整。但完整的if-else结构或case结构就能完全避免latch的产生么?我们看下列两段代码:
always @(*)
begin
if(enable)
data_out1=ina;
else
data_out2=ina;
end
在vivado中进行Synthesis后显示warning:
同样,下述代码综合后也会提示有latch生成:
always @(*)
begin
case(data_in)
0: out1=1'b1;
1,3: out2=1'b1;
2,4,5,6,7: out3=1'b1;
default: out4=1'b1;
endcase
end
上述代码之所以产生latch,个人观点:待赋值变量在个别分支条件下缺少相应赋值,即代码风格的问题。故为避免latch的产生,个人认为应做到如下几点:
1. if-else 和case-default必须配套,也就是出现if 必须出现else与之配套;有case必须在后面写一个default,针对case语句也可以增加综合指令 //synopsys full_case指令省略default语句。
2.在所有条件下,对信号都进行赋值,同时单个always模块尽量只对单一变量进行赋值。
最后就SIRF 2008年面试题为例进行说明
下面哪种写法会产生latch?为什么?
(1)
always @(*)
begin
if(d)
a = b;
end
(2)
always @(*)begin
if(d)
a = b;
else
a = a;
end
(3)
always @ (b or d)
case(d)
2’b00: a=b>>1;
2’b11: c=b>>1;
default:
begin
a=b;
c=b;
end
endcase
(4)
always @(b or d)
begin
a = b;
c = b;
case (d)
2’b00: a = b >> 1;
2’b11: c = b >> 1;
endcase
end
(5)
[email protected](b or d)
begin
case (d) //synopsys full_case
2’b00: a = b >> 1;
2’b11: c = b >> 1;
endcase
end
代码(1)中由于缺少else分支,故而会产生锁存器
代码(2)if-else结构完整但由于为组合逻辑,而组合逻辑要想产生记忆功能,只能综合成锁存器
代码(3)中由于并未在所有情况下对所有信号值赋值故会产生latch
代码(4)中由于在选择语句之前给信号赋一个初值,故不会产生latch。但该种代码风格是按照软件的思维方式书写,故而不推荐使用,针对这种代码风格,针对时序电路也可以应用,下列两种代码综合出的电路没有差别,但不推荐第一种风格
(1)
always @(posedge clk or negedge reset_n)
begin
begin
out1 <= 'd0;
out2 <= 'd0;
end
if (!reset_n)
begin
out1 <= 'd0;
out2 <= 'd0;
end else if (enable)
out1 <= in1;
else
out2 <= in1;
end
(2)
always @(posedge clk or negedge reset_n)
begin
if (!reset_n)
begin
out1 <= 'd0;
out2 <= 'd0;
end else if (enable)
begin
out1 <= in1;
out2 <= 'd0;
end else
begin
out1 <= 0;
out2 <= in1;
end
end
综合电路图
代码(5)中虽然有 //synopsys full_case但是依旧并未在所有情况下对所有信号值赋值故会产生latch( //synopsys full_case只能省掉default)。