博客
关于我
Verilog十大基本功8 (flipflop和latch以及register的区别)
阅读量:211 次
发布时间:2019-02-28

本文共 3967 字,大约阅读时间需要 13 分钟。

来自1:

第一次接触Latch是在大二学习数电的时候,那时候Latch被翻译成锁存器,当时还纠结着锁存器和寄存器的区别(要是当时我知道他俩的英文名叫latch和register我还纠结个P)。

扯远了,话不多说,该说说Latch与Verilog的联系。

首先,关于Latch的定义和解释。ALTERA 的recommended HDL coding中提到:

A latch is a small combinational loop that holds the value of a signal until a new value is assigned。

从定义来看,Latch是一个记忆元件或者说是存储单元,他能保持信号的值。

同时在网上找了找关于Latch的中文定义。

锁存器是电平触发的存储单元,数据存储的动作取决于输入时钟(或者使能)信号的电平值,仅当锁存器处于使能状态时,输出才会随着数据输入发生变化。

从一般情况来看,锁存器多数是有电平锁存的。当电平无效时,输出信号随输入信号变化,就像通过了缓冲器;当电平有效时,输出信号被锁存。

看了很多关于Verilog的语法资料,大多其中并没有谈到Latch,Latch和Verilog发生联系是在用Verilog进行FPGA或者ASIC设计时。而在此由于本人正式学习用Verilog进行FPGA设计,涉及到的书中均提到要采用同步设计,避免采用Latch。从网上找了找为什么不使用Latch的原因:

不要锁存器的原因有二:1、锁存器容易产生毛刺,2、锁存器在ASIC设计中应该说比FF要简单,但是在FPGA的资源中,大部分器件没有锁存器这个东西,所以需要用一个逻辑门和FF来组成锁存器,这样就浪费了资源。3、锁存器的出现使得静态时序分析变得更加复杂。

所以又可以得出一条指导性的原则:

在能使用DFF或者寄存器的时候,坚决不使用Latch。

说了Latch的定义和Latch的危害,现在要来说说Latch的产生和避免。

查阅资料,结合自己的理解,总结出无意生成Latch的三大原因:

1、不完整的if或者case结构

2、不完整的敏感信号列表

Latch的出现总是与不完整有关,组合电路本应该是完整的,最理想的写法可能是一个输入对应一个输出,当一个输入没有相应的输出或者引起输出信号没有作为输入的时候,Latch产生了!

先解释第一点不完整的if结构,例如:

if(a)

begin

out = 1'b1;

end

当a为1时输出为1,当a为0时由于没有相应的译码语句,所以输出将保持,此时将生成Latch而不是原来想要的组合电路。

而对于不完整的case语句,例如:

always@( * )

case(a)

3'b000: b = 8'd1;

3'b001: b = 8'd5;

3'b010: b = 8'd8;

3'b011: b = 8'd17;

endcase

此时语句中没有default,当a为4、5、6、7时没有响应的译码语句,输出将保持,此时将生成Latch。

对于第二点不完整的敏感信号表,夏雨闻老师的书中有提到:

如是说道:在赋值表达式右边参与赋值的信号都必须在always@(敏感电平列表)中列出。

如果在赋值表达式右端引用了敏感电平列表中没有列出的信号,那么在综合时,将会为该没有列出的信号隐含地产生一个透明锁存器。

所以得出指导性的原则:

务必写好if和case所有的分支,务必写全敏感信号列表!

来自2:

关于硬件中常见的基本存储元件的定义、中英文对应的名字会模糊,今天特地查明具体定义。

触发器:flip-flop

锁存器:latch

寄存器:register

锁存器是电平触发的存储单元,数据存储的动作取决于输入时钟(或者使能)信号的电平值,仅当锁存器处于使能状态时输出才会随着数据输入发生变化。

触发器是边沿敏感的存储单元,数据存储的动作由某一信号的上升或者下降沿进行同步的。

寄存器用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。其实寄存器就是一种常用的时序逻辑电路,但这种时序逻辑电路只包含存储电路。寄存器的存储电路是由锁存器或触发器构成的,因为一个锁存器或触发器能存储1位二进制数,所以由N个锁存器或触发器可以构成N位寄存器。

触发器是在时钟的沿进行数据的锁存的,而锁存器是用电平使能来锁存数据的。所以触发器的Q输出端在每一个时钟沿都会被更新,而锁存器只能在使能电平有效时才会被更新。

钟控D触发器其实就是D锁存器,边沿D触发器才是真正的D触发器,钟控D触发器在使能情况下输出随输入变化,边沿触发器只有在边沿跳变的情况下输出才变化。

20、D触发器和D锁存器的区别。

两个锁存器可以构成一个触发器,归根到底还是dff是边沿触发的,而latch是电平触发的。锁存器的输出对输入透明的,输入是什么,输出就是什么,这就是锁存器不稳定的原因,而触发器是由两个锁存器构成的一个主从触发器,输出对输入是不透明的,必须在时钟的上升/下降沿才会将输入体现到输出,所以能够消除输入的毛刺信号。

21、Latch和filp-flop的异同

都是时序逻辑,但Latch受所有的输入信号控制,只要输入信号变化,Latch就变化。也正因为如此,Latch很容易出毛刺。

flip-flop是触发器,只有在被时钟触发时才采样当前的输入,产生输出。如果使用门电路来搭建Latch和FF,则Latch消耗的门资源比FF要少。但是你用的如果是FPGA,那么内部一般带DFF单元,反而用触发器更好。

22、Latch与register的区别

为什么现在多用register。

行为级描述中Latch如何产生的行为级描述中Latch一般是由于if或case逻辑表述不完全产生的。

异同:

1、Latch由电平触发,非同步控制。在使能信号有效时Latch相当于通路,在使能信号无效时Latch保持输出状态。

DFF由时钟沿触发,同步控制。

2、Latch容易产生毛刺(glitch),DFF则不易产生毛刺。

3、如果使用门电路来搭建Latch和DFF,则Latch消耗的门资源比DFF要少,这是Latch比DFF优越的地方。所以,在ASIC中使用Latch的集成度比DFF高。

但在FPGA中正好相反,因为FPGA中没有标准的Latch单元,但有DFF单元,一个LATCH需要多个LE才能实现。

4、Latch将静态时序分析变得极为复杂。

一般的设计规则是:在绝大多数设计中避免产生Latch。

它会让您设计的时序完蛋,并且它的隐蔽性很强,非老手不能查出。

Latch最大的危害在于不能过滤毛刺。这对于下一级电路是极其危险的。所以,只要能用D触发器的地方,就不用Latch。

有些地方没有时钟,也只能用Latch了。比如现在用一个clk接到Latch的使能端(假设是高电平使能),这样需要的setup时间,就是数据在时钟的下降沿之前需要的时间,但是如果是一个DFF,那么setup时间就是在时钟的上升沿需要的时间。这就说明如果数据晚于控制信号的情况下,只能用Latch,这种情况就是,前面所提到的Latch timing borrow。基本上相当于借了一个高电平时间。也就是说,Latch借的时间也是有限的。

在if语句和case不全很容易产生Latch,需要注意。VIA题目这两个代码哪个综合更容易产生Latch:

代码1

always@(enable or ina or inb)

begin

if(enable)

data_out = ina

else

data_out = inb

end

代码2

input[3:0] data_in;

always@(data_in)

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

答案是代码2在综合时更容易产生Latch。

使用条件语句不当在设计中生成了原本没有想到的锁存器:

例1:

在一个always语句中不正确使用if语句

always@(enable or ina or inb)

begin

if(al)

q <= d

else

q <= 0

end

在这个always块中,if语句只保证了当al=1时q才取d的值。这段程序并没有给出当al=0时q的取值,那么当al=0时q取何值?在always块中在给定的条件下变量没有被赋值,那么变量将保持原值,也就是说将会生成一个锁存器。

如果当设计人员希望当al=0时,q的值为0,则else项就必不可少了。

Verilog HDL程序的另一种偶然生成锁存器是在使用case语句时缺少default项的情况下发生的。

Case语句的功能是:在某个信号取不同的值时,给另一个信号赋不同的值。如下,如果sel=00,q取a值,而sel=11,q取b值。如果sel取00和11以外的值时q将赋予什么值?在这个例子中,默认q保持原值,这就会自动生成锁存器。

always@(sel[1:0] or a or b)

case(sel[1:0])

2’b00: q <= a;

2’b11: q <= b;

default: q <= ‘b0;

endcase

有锁存器 无锁存器

避免生成锁存器的方法:如果用到if语句,最好写上else项;如果用case语句,最好写上default项。遵循上面两条原则,就可以避免发生这种错误,使设计者更加明确设计目标,同时也增强了Verilog程序的可读性。

转载地址:http://jecj.baihongyu.com/

你可能感兴趣的文章
Objective-C实现double sort双重排序算法(附完整源码)
查看>>
Objective-C实现DoublyLinkedList双链表的算法(附完整源码)
查看>>
Objective-C实现DoublyLinkedList双链表算法(附完整源码)
查看>>
Objective-C实现DPLL(davisb putnamb logemannb loveland)算法(附完整源码)
查看>>
Objective-C实现DWT离散小波变换(附完整源码)
查看>>
Objective-C实现Edmonds-Karp算法(附完整源码)
查看>>
Objective-C实现EEMD算法(附完整源码)
查看>>
Objective-C实现elgamal 密钥生成器算法(附完整源码)
查看>>
Objective-C实现EM算法(附完整源码)
查看>>
Objective-C实现EM算法(附完整源码)
查看>>
Objective-C实现entropy熵算法(附完整源码)
查看>>
Objective-C实现euclidean distance欧式距离算法(附完整源码)
查看>>
Objective-C实现Euclidean GCD欧几里得最大公约数算法(附完整源码)
查看>>
Objective-C实现euclideanDistance欧氏距离算法(附完整源码)
查看>>
Objective-C实现euler method欧拉法算法(附完整源码)
查看>>
Objective-C实现euler modified变形欧拉法算法(附完整源码)
查看>>
Objective-C实现eulerianPath欧拉路径算法(附完整源码)
查看>>
Objective-C实现Eulers TotientFunction欧拉函数算法(附完整源码)
查看>>
Objective-C实现eulers totient欧拉方程算法(附完整源码)
查看>>
Objective-C实现EulersTotient欧拉方程算法(附完整源码)
查看>>