赞
踩
一句话概括,能够存储一个状态的数字电路叫做锁存器。
以下是最为基本的一个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) |
---|---|---|---|---|
0 | 0 | Q | Q | !Q |
1 | 0 | Q | 0 | 1 |
0 | 1 | Q | 1 | 0 |
1 | 1 | X | X | X |
这张真值表的前三行如下图所示,能够使得输出的结果和定义一致。
第一种情况,电路能够维持输出为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) |
---|---|---|---|---|
0 | 0 | Q | Q | !Q |
1 | 0 | Q | Q | !Q |
0 | 1 | Q | 1 | 0 |
1 | 1 | Q | 0 | 1 |
D锁存器足够完美了吗?
当然不,D锁存器同样存在问题,那就是无法去除输入的毛刺/抖动。当E为1的时候,D 和 !Q 的值永远是相等的 (哪怕输入存在毛刺/抖动)。为了进一步的改进,人们在D锁存器的基础上提出了触发器的概念。触发器的具体结构会在第二章进行介绍。
一句话概括:触发器是能在指定的事件发生时存储状态的数字电路。
触发器是时序逻辑电路的基本单元,用来存储1位2进制信息,具有记忆和存储功能。常见的触发器包括D触发器,J-K触发器等。
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) |
---|---|---|---|---|
0 | 0 | Q | Q | !Q |
1 | 0 | Q | Q | !Q |
0 | 0->1 | Q | 0 | 1 |
1 | 0->1 | Q | 1 | 0 |
0 | 1 | Q | Q | !Q |
1 | 1 | Q | Q | !Q |
0 | 1->0 | Q | Q | !Q |
1 | 1->0 | Q | Q | !Q |
从真值表中可以看出,输出的改变只可能发生在时钟信号的上升沿。接下来让我们按CLK依次分析这四种情况:
第一种情况,CLK为0,这时候FF2的CLK输入为0,因此电路的输出保持不变。
第二种情况,CLK处于上升沿(0->1)到达的瞬间,由于电路内部的延迟,这时候FF1会先取上升沿到达之前瞬间D的状态,之后将该状态保存。
第三种情况,CLK为1,这时候FF1的CLK输入为0,因此Q1的输出保持不变,进而使整个电路的输出保持不变。
第四种情况,CLK处于下降沿(1->0)到达的瞬间,由于电路内部的延迟,这时候FF2会先取下降沿到达之前瞬间Q1的状态,之后将该状态保存。
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) |
---|---|---|---|---|
0 | 0 | X | X | X |
0 | 1 | Q | 1 | 0 |
1 | 0 | Q | 0 | 1 |
1 | 1 | Q | Q | !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) |
---|---|---|---|---|---|
0 | 0 | 0 | Q | Q | !Q |
0 | 1 | 0 | Q | Q | !Q |
1 | 0 | 0 | Q | Q | !Q |
1 | 1 | 0 | Q | Q | !Q |
0 | 0 | 0->1 | Q | Q | !Q |
0 | 1 | 0->1 | Q | 0 | 1 |
1 | 0 | 0->1 | Q | 1 | 0 |
1 | 1 | 0->1 | Q | !Q | Q |
0 | 0 | 1 | Q | Q | !Q |
0 | 1 | 1 | Q | Q | !Q |
1 | 0 | 1 | Q | Q | !Q |
1 | 1 | 1 | Q | Q | !Q |
0 | 0 | 1->0 | Q | Q | !Q |
0 | 1 | 1->0 | Q | Q | !Q |
1 | 0 | 1->0 | Q | Q | !Q |
1 | 1 | 1->0 | Q | Q | !Q |
将J和K合并成一个信号,它就有了一个新名称:T触发器。
因为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
这段代码与人物上下左右移动有关。例如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
需要注意的是,对于always@(posedge clk),即使case不完整,也不会综合出LATCH,综合器会将这些不执行的情况视为不需要进行任何操作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。