• FPGA结构:LATCH(锁存器)和 FF(触发器)介绍


    FPGA 系列文章



    一、LATCH(锁存器)是什么

    一句话概括,能够存储一个状态的数字电路叫做锁存器。

    以下是最为基本的一个RS锁存器的具体结构:

    请添加图片描述

    以下是它的真值表,其中X表示不确定/无效:

    R {R} R(清零) S {S} S(置位) Q ( t ) {Q(t)} Q(t) (上一时刻的输出 ) Q ( t + 1 ) {Q(t+1)} Q(t+1) (这一时刻的输出A) Q ‾ \overline{Q} Q(这一时刻的输出B)
    00QQ!Q
    10Q01
    01Q10
    11XXX

    这张真值表的前三行如下图所示,能够使得输出的结果和定义一致。
    第一种情况,电路能够维持输出为Q:
    第一种情况
    第二种情况,上面的NOR门输出一定为0,进而使得整个电路达到稳态:

    请添加图片描述
    第三种情况,下面的NOR门输出一定为0,进而使得整个电路达到稳态:
    请添加图片描述
    唯独这张真值表的第四行输出结果和定义不一致:
    请添加图片描述
    看起来这张电路图是一个稳定的状态,但当我们把这个状态切换到S=R=0的状态时,就会产生两种可能的稳态:

    1.上面R对应的或非门电路延迟较低,这时候Q先被置为1:

    请添加图片描述

    2.下面S对应的或非门电路延迟较低,这时候!Q先被置为1:

    请添加图片描述

    在这种情况下,输出结果完全随机(与电路延迟相关),由于这种现象很玄学。因此我们在使用RS锁存器时,一般不会将R和S同时置1。

    为了解决RS锁存器带来的问题(RS不能同时为1),我们需要在它的输入之前添加一些逻辑电路,进化版本的RS锁存器被叫做D锁存器。

    D锁存器的具体结构如下:

    请添加图片描述

    D锁存器在RS锁存器的输入之前添加了一个非门,排除了RS同时为1的情况。同时,上图中的D锁存器将使能输入(E)设置为clock,使得该电路只有在时钟信号为1的时候才能够工作(设置为时钟信号为0时工作也很简单)

    D锁存器的真值表如下:

    D {D} D(置位) E {E} E(使能) Q ( t ) {Q(t)} Q(t) (上一时刻的输出 ) Q ( t + 1 ) {Q(t+1)} Q(t+1) (这一时刻的输出A) Q ‾ ( t + 1 ) \overline{Q}(t+1) Q(t+1)(这一时刻的输出B)
    00QQ!Q
    10QQ!Q
    01Q10
    11Q01

    D锁存器足够完美了吗?

    当然不,D锁存器同样存在问题,那就是无法去除输入的毛刺/抖动。当E为1的时候,D 和 !Q 的值永远是相等的 (哪怕输入存在毛刺/抖动)。为了进一步的改进,人们在D锁存器的基础上提出了触发器的概念。触发器的具体结构会在第二章进行介绍。

    二、FF(触发器)是什么

    一句话概括:触发器是能在指定的事件发生时存储状态的数字电路。

    触发器是时序逻辑电路的基本单元,用来存储1位2进制信息,具有记忆和存储功能。常见的触发器包括D触发器,J-K触发器等。

    D触发器

    D触发器可以由两个D锁存器级联构成,它的具体结构如下,其中FF1和FF2都代表上文提到的D锁存器:
    请添加图片描述
    以下是两个D锁存器级联构成的D触发器的真值表:

    D {D} D C L K {CLK} CLK Q ( t ) {Q(t)} Q(t) (上一时刻的输出 ) Q ( t + 1 ) {Q(t+1)} Q(t+1) (这一时刻的输出A) Q ‾ ( t + 1 ) \overline{Q}(t+1) Q(t+1)(这一时刻的输出B)
    00QQ!Q
    10QQ!Q
    00->1Q01
    10->1Q10
    01QQ!Q
    11QQ!Q
    01->0QQ!Q
    11->0QQ!Q

    从真值表中可以看出,输出的改变只可能发生在时钟信号的上升沿。接下来让我们按CLK依次分析这四种情况:

    • 第一种情况,CLK为0,这时候FF2的CLK输入为0,因此电路的输出保持不变。

    • 第二种情况,CLK处于上升沿(0->1)到达的瞬间,由于电路内部的延迟,这时候FF1会先取上升沿到达之前瞬间D的状态,之后将该状态保存。

    • 第三种情况,CLK为1,这时候FF1的CLK输入为0,因此Q1的输出保持不变,进而使整个电路的输出保持不变。

    • 第四种情况,CLK处于下降沿(1->0)到达的瞬间,由于电路内部的延迟,这时候FF2会先取下降沿到达之前瞬间Q1的状态,之后将该状态保存。

    JK触发器

    JK触发器弥补了RS锁存器的缺陷,能够在输入为1时将状态翻转。JK触发器的具体结构如下图:

    请添加图片描述

    蓝框中的电路结构将或非门换为了与非门,同样也是RS锁存器的一种表现方式。感兴趣的同学可以自己推导一下真值表。

    这里先直接给出与非门实现RS锁存器的真值表:

    S {S} S(置位) R {R} R(清零) Q ( t ) {Q(t)} Q(t) (上一时刻的输出 ) Q ( t + 1 ) {Q(t+1)} Q(t+1) (这一时刻的输出A) Q ‾ \overline{Q} Q(这一时刻的输出B)
    00XXX
    01Q10
    10Q01
    11QQ!Q

    JK触发器通过红框实现上升沿读取数据。当CLK处于上升沿(0->1)时,由于非门的延迟,会有一瞬间出现CLK变为1的情况,这时候读取数据,剩下的时候CLK均为0。

    在时钟上升沿信号未到来时,与非门G3和G4将J与K端的输入信号屏蔽,触发器状态不受输入信号的影响,维持不变。在时钟上升沿信号到来时,触发器的状态将会随着J与K的输入产生相应的变化。

    • 时钟上升沿信号到来时,J=0,K=0,触发器状态维持不变。

    • 时钟上升沿信号到来时,J=1,K=0,这时候S和R的值分别为Q和1,JK触发器会将这一时刻的输出A置为1。(无论Q为0或1,根据上面的真值表,这一时刻的输出A都一定为1)

    • 时钟上升沿信号到来时,J=0,K=1,这时候S和R的值分别为1和!Q,JK触发器会将这一时刻的输出A置为0。(无论Q为0或1,根据上面的真值表,这一时刻的输出A都一定为0)

    • 时钟上升沿信号到来时,J=K=1,这时候S和R的值分别为Q和!Q,根据上面的真值表,这一时刻的输出A与这一时刻的输出B一定为!Q和Q,实现翻转。

    JK触发器的真值表如下图:

    J {J} J K {K} K C L K {CLK} CLK Q ( t ) {Q(t)} Q(t) (上一时刻的输出 ) Q ( t + 1 ) {Q(t+1)} Q(t+1) (这一时刻的输出1) Q ‾ ( t + 1 ) \overline{Q}(t+1) Q(t+1)(这一时刻的输出2)
    000QQ!Q
    010QQ!Q
    100QQ!Q
    110QQ!Q
    000->1QQ!Q
    010->1Q01
    100->1Q10
    110->1Q!QQ
    001QQ!Q
    011QQ!Q
    101QQ!Q
    111QQ!Q
    001->0QQ!Q
    011->0QQ!Q
    101->0QQ!Q
    111->0QQ!Q

    将J和K合并成一个信号,它就有了一个新名称:T触发器。

    三、牛刀小试:避免使用Verilog综合出LATCH

    因为LATCH的种种缺点,它是我们在写Verilog代码的时候唯恐避之不及的。然而,我们常常会遇到由于逻辑定义不完整综合出LATCH的情况。在代码包含always@(*)时,一般情况下会综合出LUT,但假如没有将if/else中所有case的赋值情况写完整,编译器就会综合出LATCH,以下是一段综合出LATCH的Verilog代码:

    module top_module (
        input [15:0] scancode,
        output reg left,
        output reg down,
        output reg right,
        output reg up  ); 
        always @(*) begin 
           case(scancode)
               16'he06b:
                    left=1;
               16'he072:
                    down=1;
               16'he074:
                    right=1;
               16'he075:
                    up=1;
           endcase
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这段代码与人物上下左右移动有关。例如16’he06b这个case,如果我们在其中没有指定down,right和up的值,那么它就会自动保存原来的值(信号接收之前的值),综合出锁存器。

    如何让上面的电路不综合出LATCH呢?

    非常简单,只要在每一次 always @(*) begin 的最开始指定left,down,right和up的值就可以了,更改后的代码如下所示:

    module top_module (
        input [15:0] scancode,
        output reg left,
        output reg down,
        output reg right,
        output reg up  ); 
        always @(*) begin 
        left=0;down=0;right=0;up=0;// 给up,down,left,right赋初始值
           case(scancode)
               16'he06b:
                    left=1;
               16'he072:
                    down=1;
               16'he074:
                    right=1;
               16'he075:
                    up=1;
           endcase
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    需要注意的是,对于always@(posedge clk),即使case不完整,也不会综合出LATCH,综合器会将这些不执行的情况视为不需要进行任何操作。

    参考文档

    FPGA中LUT、LATCH、FF的概念

    RS锁存器,D锁存器、D触发器简介

    数字电路学习笔记(九):初识锁存器

    D触发器 (D-FF)详解

    数字电路中的锁存器(latch)和各种触发器(flip-flop)

    从CMOS到触发器(二)

  • 相关阅读:
    融合注意力机制和BSRU的工业互联网安全态势预测方法
    JavaScript:实现JSON高亮代码块
    小米华为,化干戈为玉帛!
    通用CI/CD软件平台TeamCity推出代理终端功能,谁能从中获益?
    HashMap设计原理与实现(下篇)200行带你写自己的HashMap!!!
    基于TCP Socket和Websocket实现的相互即时通信系统
    进程的状态以及进程的优先级
    泰克示波器控制scpi,程序读取波形数据并显示
    C. To Add or Not to Add
    systemd 强大的初始化系统和服务管理器
  • 原文地址:https://blog.csdn.net/w1ndowsZzz__/article/details/132614065