HDLbits day7


Sequential Logic

1、Latches and Flip-Flops

1.1D flip-flop

AD 触发器是一种在时钟信号的(通常)上升沿存储位并定期更新的电路。当使用时钟控制的always块时,逻辑合成器会创建 D 触发器。AD触发器是“组合逻辑块后接触发器”的最简单形式,其中组合逻辑部分只是一条线。

创建一个 D 触发器。

Dff.png
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)
        q<=d;

endmodule

1.2、D flip-flops

创建 8 个 D 触发器。所有 DFF 都应由clk的上升沿触发。

module top_module (
    input clk,
    input [7:0] d,
    output [7:0] q
);
    
    always@(posedge clk)
        q<=d;

endmodule

1.3、DFF with reset

创建 8 个具有高电平有效同步复位的 D 触发器。所有 DFF 都应由clk的上升沿触发。

module top_module (
    input clk,
    input reset,            // Synchronous reset
    input [7:0] d,
    output [7:0] q
);
    always@(posedge clk)
        begin
            if(reset) q<=0;
            else
                q<=d;
        end

endmodule

1.4、DFF with reset value

创建 8 个具有高电平有效同步复位的 D 触发器。触发器必须重置为 0x34 而不是零。所有 DFF 都应由clk的下降沿触发

module top_module (
    input clk,
    input reset,
    input [7:0] d,
    output [7:0] q
);
    always@(negedge clk)
        begin
            if(reset)
                q<=8'h0x34;
            else
                q<=d;
        end

endmodule

1.5、DFF with asynchronous reset

创建 8 个具有高电平有效异步复位的 D 触发器。所有 DFF 都应由clk的上升沿触发。

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)
        if(areset)
            q<=0;
        else
            q<=d;
        

endmodule

1.6、DFF with byte enable

创建 16 个 D 触发器。有时只修改一组触发器的一部分很有用。字节使能输入控制 16 个寄存器中的每个字节是否应在该周期写入。byteena[1]控制高字节d[15:8],而byteena[0]控制低字节d[7:0]

resetn是一个同步的低电平有效复位。

所有 DFF 都应由clk的上升沿触发。

module top_module (
    input clk,
    input resetn,
    input [1:0] byteena,
    input [15:0] d,
    output [15:0] q
);
    always@(posedge clk)
        begin
            if(!resetn)
                q<=0;
            else
                begin
                    q[15:8]<=byteena[1]?d[15:8]:q[15:8];
                    q[7:0]<=byteena[0]?d[7:0]:q[7:0];
                end
        end

endmodule

1.7、D Latch

实现以下电路:

1)请注意,这是一个锁存器,因此预计会出现关于已推断锁存器的 Quartus 警告。

2)锁存器是电平敏感(非边沿敏感)电路,因此在一个始终块中,它们使用电平敏感灵敏度列表。

3)但是,它们仍然是顺序元素,因此应该使用非阻塞赋值。

4)D 锁存器在启用时就像一条线(或非反相缓冲器),在禁用时保留当前值。

Exams m2014q4a.png

module top_module (
    input d, 
    input ena,
    output q);
    
    //always@(ena)
    always@(*)
        if(ena)
            q<=d;

endmodule

1.8、DFF

实现以下电路:

考试 m2014q4b.png

module top_module (
    input clk,
    input d, 
    input ar,   // asynchronous reset异步复位
    output q);

    always@(posedge clk or posedge ar)
        if(ar)
            q<=0;
        else
            q<=d;
endmodule

1.9、DFF

实现以下电路:

考试 m2014q4c.png

module top_module (
    input clk,
    input d, 
    input r,   // synchronous reset同步复位
    output q);
    
    always@(posedge clk)
        if(r)
            q<=0;
        else
            q<=d;

endmodule

1.10、DFF+gate

实现以下电路:

考试 m2014q4d.png

module top_module (
    input clk,
    input in, 
    output out);

    always@(posedge clk)
        begin
            out<=in^out;
        end
endmodule

1.11、Mux and DFF

考虑下面的时序电路:

mt2015 muxdff.png

假设您要为此电路实现分层 Verilog 代码,使用其中具有触发器和多路复用器的子模块的三个实例化。为此子模块编写一个名为top_module的 Verilog 模块(包含一个触发器和多路复用器)。

module top_module (
    input clk,
    input L,
    input r_in,
    input q_in,
    output reg Q);

    always@(posedge clk)
        Q<=L?r_in:q_in;
endmodule

1.12、Mux and DFF

考虑如下所示 的n位移位寄存器电路:

考试 2014q4.png

为该电路的一个阶段编写一个名为 top_module 的 Verilog 模块,包括触发器和多路复用器。

module top_module (
    input clk,
    input w, R, E, L,
    output Q
);
    
    always@(posedge clk)
        begin
         Q<=L?R:E?w:Q;
        end

endmodule

1.13、DFFs and gates

给定如图所示的有限状态机电路,假设 D 触发器在机器开始之前初始复位为零。

建立这个电路。

小心复位状态。确保每个 D 触发器的Q输出确实是其 Q 输出的倒数,即使在模拟的第一个时钟沿之前也是如此。

Ece241 2014 q4.png

module top_module (
    input clk,
    input x,
    output z
); 

    reg q1,q2,q3;
    always@(posedge clk)
    begin
        q1<=x^q1;
        q2<=x&(~q2);
        q3<=x|(~q3);
    end
    
    assign z=~(q1|q2|q3);
endmodule

1.14、create circuit from truth table

JK 触发器具有以下真值表。实现一个只有 D 型触发器和门的 JK 触发器。注意:Qold 是正时钟沿之前 D 触发器的输出。

J K Q
0 0 Qold
0 1 0
1 0 1
1 1~ Qold
module top_module (
    input clk,
    input j,
    input k,
    output Q); 

    always@(posedge clk)
        begin
            case({j,k})
                2'b00:Q<=Q;
                2'b01:Q<=0;
                2'b10:Q<=1;
                2'b11:Q<=~Q;
            endcase
        end
endmodule

1.15、Detect an edge

对于 8 位向量中的每一位,检测输入信号何时从一个时钟周期的 0 变为下一个时钟周期的 1(类似于上升沿检测)。输出位应在发生 0 到 1 转换后的周期设置。

这里有些例子。为清楚起见,in[1] 和 pedge[1] 分别显示。

module top_module (
    input clk,
    input [7:0] in,
    output [7:0] pedge
);
    reg [7:0] state_in;
    always@(posedge clk)
        begin
            state_in<=in;
            pedge<=~state_in&in;
            //pedge<=state_in~∈错误写法
            //pedge<=state_in^in;检测输入信号从0跳变到1的位置,用xor门会同时检测到从1变到0的位置
        end

endmodule

1.16、Detect both edges

对于 8 位向量中的每一位,检测输入信号何时从一个时钟周期变为下一个时钟周期(检测任何边沿)。输出位应在发生 0 到 1 转换后的周期设置。

这里有些例子。为清楚起见,in[1] 和 anyedge[1] 分别显示

1)上升沿加下降沿检测。上升沿核心检测逻辑: ~in_last & in。下降沿类似上升沿核心逻辑为: in_last & ~in。最后运用或逻辑组合起来即可。核心代码:anyedge = (~in_last & in) | (in_last & ~in)。

2)异或逻辑检测。边沿检测,从整体来看,即信号发生变化就进行检测输出。因此使用异或逻辑 。核心代码:in ^ in_last 。

module top_module (
    input clk,
    input [7:0] in,
    output [7:0] anyedge
);
    reg [7:0] state_in;
    always@(posedge clk)
        begin
            state_in<=in;
            anyedge<=state_in^in;
        end

endmodule

1.17、Edge capture register

对于 32 位向量中的每一位,在输入信号从一个时钟周期的 1 变为下一个时钟周期的 0 时进行捕捉。“捕获”表示输出将保持为 1,直到寄存器复位(同步复位)。

每个输出位的行为类似于 SR 触发器:输出位应在 1 到 0 转换发生后的周期设置(为 1)。当复位为高电平时,输出位应在正时钟沿复位(为 0)。如果上述两个事件同时发生,则重置优先。在下面示例波形的最后 4 个周期中,“reset”事件比“set”事件早一个周期发生,因此这里不存在冲突。

在下面的示例波形中,为清楚起见,reset、in[1] 和 out[1] 再次分别显示。

1)题意:检测下降沿,检测到后out一直为高,直到reset == 1时,out才为0。
2)方法:先通过边沿检测,得到一个脉冲信号,然后如果这个脉冲信号为高,将其输出给out,输出为低就不管(保持前面状态)。
但是这样做,边沿检测时会延迟一个clk,在将其输出给out时又会延迟一个clk,这样就与题目中给的时序图不符,

3)改正:直接将边沿检测信号与输出信号本身相或赋值给输出信号,就能在一个clk下完成,得到与题目符合的时序图。

4)设初始  in:0000,out:0000

        然后假设in:0001  -> 0000,这时out:0001

               假设in:0001 -> 0101,这时out:0101

module top_module (
    input clk,
    input reset,
    input [31:0] in,
    output [31:0] out
);
    reg [31:0] state_in;
    always@(posedge clk)
        state_in<=in;
    always@(posedge clk)//同步复位
        begin
            if(reset)
                out<=32'h0000;
            else
                out<=(state_in&~in)|out;  
        end

endmodule

 1.18、Dual-edge triggered flip-flop

您熟悉在时钟上升沿或时钟下降沿触发的触发器。在时钟的两个边沿触发双边触发触发器。但是,FPGA 没有双边触发触发器,并且始终不接受 @(posedge clk 或 negedge clk)作为合法的敏感度列表。

构建一个功能类似于双边触发触发器的电路:

(注意:它不一定完全等效:触发器的输出没有毛刺,但模拟这种行为的更大组合电路可能会。但我们将在这里忽略这个细节。)

您无法在 FPGA 上创建双边触发触发器。但是您可以同时创建正沿触发负沿触发触发器。

module top_module (
    input clk,
    input d,
    output q
);
    reg q1,q2;
    always@(posedge clk)
        begin
            q1<=d;
        end
    always@(negedge clk)
        begin
            q2<=d;
        end
    assign q=clk?q1:q2;
endmodule

相关