做网站合同范本,企业网站制作公司盈利,网站开发排行,湖南正规网络营销哪家便宜前言
在FPGA设计中#xff0c;几乎没人会主动使用锁存器Latch#xff0c;但有时候不知不觉中你的设计莫名其妙地就生成了一堆Latch#xff0c;而这些Latch可能会给你带来巨大的麻烦。
什么是锁存器Latch#xff1f;
Latch#xff0c;锁存器#xff0c;一种可以存储电路…前言
在FPGA设计中几乎没人会主动使用锁存器Latch但有时候不知不觉中你的设计莫名其妙地就生成了一堆Latch而这些Latch可能会给你带来巨大的麻烦。
什么是锁存器Latch
Latch锁存器一种可以存储电路状态信息的组合逻辑元件和同样可以保存电路状态的时序逻辑元件–触发器Flip-FlopFF不同锁存器只在其使能端口有效时将输入传递给输出而在其使能端口无效时输出则保持不变就像被“锁住储存”起来了一样。
下图是一个典型的Latch的门电路结构。当使能信号E无效时两个与门的输出均为0对后面的SR锁存器即或非门无影响所以无论输入D的值为1或0输出Q的值都不会改变就像被“锁住”了。 当使能信号E有效且输入D为1时两个与门的输出分别为0和1、此时的输出Q值为1与输入D一致。 当使能信号E有效且输入D为0时两个与门的输出分别为1和0、此时的输出Q值为0同样与输入D一致。
Latch有什么危害
当Latch的使能信号有效时直接让输入信号通过使得输出完全等于输入。这一特性无疑会很容易地引入毛刺使得设计不稳定其次Latch没有时钟信号是一个异步电路元件这就使得综合工具对Latch的静态时序分析十分困难。
而同步逻辑所使用的触发器FF它的典型结构是这样的由2个Latch1个反相器组成。 当时钟信号Clock为高电平时第1个Latch的使能有效输入数据直接通过由于反向器的存在第2个Latch的使能端无效所以其输出保持不变。 当时钟信号Clock为低电平时第1个Latch使能无效其输出保持不变而这个输出也就是在时钟信号处于下降沿时的输入信号由于反向器的存在第2个Latch的使能端有效输入直接传递到输出此时最终输出的是在时钟下降沿时采集的输入信号。 可以看到在同步电路中FF的输出只在时钟边沿这里是下降沿变化而在其他时间是保持不变的这样一来即使某些时刻在输入上出现了毛刺但只要这个毛刺不发生在时钟边沿那它就不会传递到输出进而影响后面的电路。
显然同一个时钟周期比起来时钟边沿持续的时间实在是微不足道所以这大大降低了毛刺影响电路的概率。这也是同步电路相对于异步电路的一个大优点。
什么样的代码会生成Latch
下面的一些代码风格是会生成Latch的
if-else语句不完整的组合逻辑
在组合逻辑中如果if-else语句没有写完整的话是会生成Latch的不管你是有意还是无意的因为缺失掉的条件会被综合工具理解成不变即锁存。
module test(input data,input en,output reg q
);always(*)beginif(en)q data;
endendmoduleVivado中生成的RTL电路如下–一个Latch。 生成Latch的时候Vivado也会报警告所以设计的时候请务必多多关注这些信息 有些时候尽管你的if-else语句已经很完整了也还是会生成Latch就像这样
module test(input data,input en,output reg q
);always(*)beginif(en)q data;else q q; //输出反馈给了输入相当于没变
endendmodule这是因为输出直接反馈给了输入使得输出等于输入相当于没变化依然是被锁存住了。
消除Latch的方法有两种
1、补全if-else语句。注意不能将输出反馈给输入而是应该给输入赋一个其他值例如0、1或其他变量。
module test(input data,input en,output reg q
);always(*)beginif(en)q data;else q 1b0; //q 1b1也可以
endendmodule2、赋初值。在条件语句之前给输出一个初始值。
module test(input data,input en,output reg q
);always(*)beginq 1b0; //q 1b1也可以if(en)q data;
endendmodule两种方法中推荐第一种方法因为比较规范代码风格容易统一。这样的代码不会生成Latch而是生成一个组合逻辑用的2选1MUX
case语句不完整的组合逻辑
与if-else句类似如果case语句的分支没有列举完全也是会生成Latch的比如这样
module test(input data0,data1,input sel,output reg q
);always(*)begincase(sel)1b0: q data0;endcase
endendmoduleVivado中生成的RTL电路会有Latch 类似的有些时候尽管你的case语句已经很完整了但因为出现了反馈语句即输出反馈给输入也还是会生成Latch就像这样
module test(input data0,data1,input sel,output reg q
);always(*)begincase(sel)1b0: q data0;1b1: q q; //反馈语句endcase
endendmodule消除锁存器的方法有三种
1、补全case语句。注意不能将输出反馈给输入而是应该赋一个其他值例如0、1或其他变量。
module test(input data0,data1,input sel,output reg q
);always(*)begincase(sel)1b0: q data0;1b1: q data1; endcase
endendmodule2、赋初值。在case语句之前给输出一个初始值。
module test(input data0,data1,input sel,output reg q
);always(*)beginq data1; case(sel)1b0: q data0; endcase
endendmodule3、使用default语句作为默认语句。default语句用来补充其他所有没有列举出来的结果。
module test(input data0,data1,input sel,output reg q
);always(*)begincase(sel)1b0: q data0;default: q data1;endcase
endendmodule在实践中最推荐第三种写法。风格比较规范和统一。有时候编码的时候可能会把case语句的所有分支都列举出来这种情况下依然建议保留default语句。
这样的代码就不会生成Latch了而是生成一个组合逻辑用的2选1MUX
时序逻辑电路会生成Latch吗
如果以上出现Latch的写法转换成时序逻辑是否也会生成Latch比如这样
module test(input data,input en,input clk,output reg q
);always(posedge clk)beginif(en)q data;
endendmodule答案是不会。只会生成一个寄存器reg实际上就是一个FF。 因为在时序逻辑中即使不补全if-else语句由于FF/REG的特性它本身就可以在非时钟边沿存储数据所以像这样的语句 else q q; //保存值 写或不写在功能上都是一样的。但是在实践中还是建议补全目的是养成风格统一、良好的编码习惯。
Latch在FPGA中是什么情况
网上有种说法在FPGA设计中不使用Latch的一个很大原因是FPGA中没有现成的Latch资源如果要用则需要消耗非常多的资源来构建Latch。
**这种说法是错的。**以Xilinx的7系列FPGA为例Latch实际上是其内部存在的固定资源。一个Slice中有一半的逻辑资源可以被配置为Latch或FF另一半只能被配置成FF。但是需要注意的是如果Silice中的FF被配置成了Latch那么剩余的4个FF就不能用了这样确实是会造成资源的浪费。 Xilinx的7系列FPGA中的FF可以被配置成两种类型的Latch LDCE和LDPE。
异步复位的LDCE比我们熟知的Latch多了一个异步复位端口。 异步置位的LDPE比我们熟知的Latch多了一个异步置位端口。 所以听起来似乎毫无用处的Latch为什么还存在于FPGA中 首先Latch是被做成了和部分FF二选一的一个器件而不是独立器件这确实也说明在FPGA设计中确实需求不高不然肯定就做成了FF这种固定的底层器件了。但这样一来也增加了FPGA底层资源的灵活性保留了更多的设计可能。 其次Latch在某些特定应用还是需要的比如IC设计中的time borrowing来提高时序性能、门控时钟、某些总线接口用来锁存数据等。
总之Latch的用武之地确实有但不多。 不是特殊需求请尽量避免使用Latch 您有任何问题都可以在评论区和我交流本文由 孤独的单刀 原创首发于CSDN平台博客主页wuzhikai.blog.csdn.net您的支持是我持续创作的最大动力如果本文对您有帮助还请多多点赞、评论和收藏⭐