HDLBits:在线学习 Verilog (十七 · Problem 80-84)

2021-04-15 11:48:20 浏览数 (1)

本系列内容来自于知乎专栏,链接如下:https://zhuanlan.zhihu.com/c_1131528588117385216 本系列文章将和读者一起巡礼数字逻辑在线学习网站 HDLBits 的教程与习题,并附上解答和一些作者个人的理解,相信无论是想 7 分钟精通 Verilog,还是对 Verilog 和数电知识查漏补缺的同学,都能从中有所收获。

Problem 80 : D flip-flop (Dff)

接下来的题目是属于触发器,锁存器的专题。我们会从用 Verilog 实现基础 D 触发器开始,学习触发器这一数字电路中最重要的电路之一。

D 触发器是一个电路,存储 1bit 数据,并定期地根据触发器的输入(d)更新这 1 bit 数据,更新通常发生在时钟上升沿(clk)。存储的数据会通过输出管脚(q)输出。

t1时刻: d -> 0

t2时刻: clk->1 上升沿到来,触发器存储的数据变成 0,输出 q 保持为存储的值:0,直到下一个时钟上升沿到来。

t3时刻: d -> 1(d:我变了),q 仍保持 0 不动摇(时钟沿还没来呢)

t4时刻: clk->1 上升沿到来,q->1(q:时钟沿来了,我该变身了)

绝大多数时候,我们不会在 Verilog 代码中显示例化一个触发器(作者没这么做过,但应该是可以做的),我们在时钟敏感的 always 块中的语句一般都会被综合工具转换为相应的触发器。

D 触发器可以认为是一个触发器和一段最简单的组合逻辑块(blob :想表达逻辑块的时候用我,别用 block)的组合。其中组合逻辑块仅仅是一段 wire。(q 直接输出了触发器的存储值)

牛刀小试

造个 D 触发器吧。

解答与分析

代码语言:javascript复制
module top_module (
    input clk,    // Clocks are used in sequential circuits
    input d,
    output reg q );//

    // Use a clocked always block
    //   copy d to q at every positive edge of clk
    //   Clocked always blocks should use non-blocking assignments
    always@(posedge clk) begin
        q <= d;
    end
endmodule

在每个时钟上升沿,输出 q 的值变为输入 d 的值。我们在 always 块中的语句就会被综合工具转换为触发器。这里使用 clk,q,d 对应于触发器的三个端口,反应了转换的对应关系。

上图是触发器在 ISE 中的综合结果,fd 是多种触发器中的基础款,我们会在后续的题目中认识更多款式。

Problem 81 : D flip-flops (Dff8)

牛刀小试

本题需要你实现 8 个 D 触发器。

解答与分析

代码语言:javascript复制
module top_module (
    input clk,
    input [7:0] d,
    output [7:0] q
);
    always@(posedge clk) begin
    	q <= d;
    end
endmodule

实现 8 个 D 触发器,听上去好像很累的样子,实则 Verilog 语言的抽象帮助我们省去不少麻烦。输入 a,b 的位宽变为 8 位,但 always 块中的语句与上一题完全相同。

综合工具根据位宽,综合出了 8 个 D 触发器。一般没有八位触发器的说法。这里反映了综合工具能分析代码,生成相应的触发器电路,其实综合器还能将复杂得多的语句转为相应的电路。

Problem 82 : DFF with reset (Dff8r)

牛刀小试

在上题的 8 个 D 触发器基础上,这题我们要给触发器配上同步复位端口。

什么同步复位?当时钟上升沿到来时,如果同步复位端有效(本题中复位高电平有效,即 reset),那么任凭你触发器此前输出或者输入的是 0,是 1,输出一律变为 0。

复位电路对于那些经常需要恢复到初始状态的电路是必要的,复位相较于断电重新加载程序恢复到初始状态的速度要快得多。但也有一些电路则不需要复位设计。(作者也是有所耳闻那些不需要复位的电路,平常自己还是会加上复位电路)

解答与分析

代码语言:javascript复制
module top_module (
    input clk,
    input [7:0] d,
    output [7:0] q
);
    always@(posedge clk) begin
        if(reset)
            q <= 8'b0;
        else
    	    q <= d;
    end
endmodule

从语法的角度来说,reset 实现就是加一个 if 语句判断 reset 是否有效,有效就将输出 q 置为 0 。

但从电路的角度来说,电路的角度往往更加重要,是使用一个带有复位端的 D 触发器 fdr,另一种 D 触发器单元。

Problem 83 : DFF with reset value (Dff8p)

牛刀小试

与上题的不同点在于,复位后的值不再是 0 (那么即为 1,对于 1bit 来说也没别的选择了),另外触发器的触发事件从时钟上升沿变成了时钟下降沿,这些在语法都没什么好提的。

解答与分析

代码语言:javascript复制
module top_module (
    input clk,
    input reset,
    input [7:0] d,
    output [7:0] q
);
    always@(negedge clk) begin
        if(reset)
            q <= 8'h34;
        else
    	    q <= d;
    end
endmodule

从电路的角度来说,时钟下降沿触发,如果仍要使用上升沿触发的触发器,则通过将输入触发器的时钟取反实现。

复位后的值为 1,那么通常我们可以管这种复位为置位,在电路中使用 fds ,带有置位端 s 的触发器实现。

Problem 84 : DFF with asynchronous reset (Dff8ar)

牛刀小试

本题中的触发器引入了异步复位。当异步复位端有效时,触发器的输出复位为 0 。

对于上上题中引入的同步复位来说,存在一个问题。

我们假设一个工作时钟为 1Hz 的系统,比如你的床头闹钟,你按下隆隆叫的闹钟时,就好比按下了闹钟的同步复位键。那么当你清晨 6:30:00 的闹钟响起,不想起床的你拍下闹钟,最糟糕的情况下,闹钟还会再响接近一秒,因为你刚好错过了一个时钟上升沿,真是糟糕,这真是太可怕了!

对于同步复位系统来说,当同步复位事件发生时,等到下一个时钟上升沿才会得到响应,响应的速度比较慢。

与之相对的异步复位的响应就很快,因为在异步复位有效的时刻,复位响应就会发生,好像戳破气球一般。

解答与分析

代码语言:javascript复制
module top_module (
    input clk,
    input areset,   // active high asynchronous reset
    input [7:0] d,
    output [7:0] q
);
    always@(posedge clk or posedge areset) begin
        if(areset)
            q <= 8'b0;
        else
    	    q <= d;
    end
endmodule

多次重复,之后仍然会提及:语法的实现很简单。将异步复位加入 always 块的敏感列表当中,在电路上则又出现了一位新的小伙伴( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ:fdc,它有一个异步复位端 CLR。

0 人点赞