Verilog HDLBits 第十一期:3.2.1 Latches and Flip-Flops

本文详细介绍了Verilog中D触发器的各种变体,如标准DFF、带复位的DFF、异步复位DFF等,并展示了如何创建8位和16位触发器,以及结合多路复用器和锁存器的电路设计。通过实例解析了上升沿、下降沿检测和边缘触发器的设计技巧。
摘要由CSDN通过智能技术生成

 

目录

前言

3.2.1.1 D flip-flop(Dff)

Solution:

3.2.1.2 D flip-flops(Dff8)

Solution:

3.2.1.3 DFF with reset(Dff8r)

Solution:

3.2.1.4 DFF with reset value(Dff8p)

Solution:

3.2.1.5 DFF with asynchronous reset(Dff8ar)

Solution:

3.2.1.6 DFF with byte enable(Dff16e)

Solution:

3.2.1.7 D Latch(Exams/m2014 q4a)

Solution:

3.2.1.8 DFF(Exams/m2014 q4b)

Solution:

3.2.1.9 DFF+gate(Exams/m2014 q4d)

Solution:

3.2.1.10 Mux and DFF(Mt2015 muxdff)

Solution:

3.2.1.11 Mux and DFF(Exams/2014 q4a)

Solution:

3.2.1.12 DFFs and gates(Exams/ece241 2014 q4)

Solution:

3.2.1.13 Creat circuit from truth table(Exams/ece241 2013 q7)

Solution:

3.2.1.14 Detect an edge(Edgedetect)

Solution:

3.2.1.15 Detect both edges(Edgedetect2)

Solution:

3.2.1.16 Edge capture register(Edgecapture)

Solution:

3.2.1.17 Dual-edge triggered flip-flop(Dualedge)

Solution:


前言

HDLbits网站如下

Problem sets - HDLBits (01xz.net)

从本期开始我们继续HDLbits第三章Circuits的学习,本期的内容是3.2.1 Latches and Flip-Flops


3.2.1.1 D flip-flop(Dff)

D触发器是一种存储1位并在时钟信号上升沿定期更新的电路。

D触发器由逻辑综合器在使用时序always块时创建。D触发器是“组合逻辑块后跟触发器”的最简单形式,其中组合逻辑部分只是一个wire信号。 

创建单个D触发器。

Dff.png

Solution:

module top_module(
	input clk,
	input d,
	output reg q);
	
	// Use non-blocking assignment for edge-triggered always blocks
	always @(posedge clk)
		q <= d;

	// Undefined simulation behaviour can occur if there is more than one edge-triggered
	// always block and blocking assignment is used. Which always block is simulated first?
	
endmodule

边沿触发时序akways块采用非阻塞赋值。如果有多个使用阻塞赋值的边沿触发always块,则可能会出现未定义的仿真行为。且哪个always块先仿真呢?


3.2.1.2 D flip-flops(Dff8)

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

Solution:

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

endmodule

3.2.1.3 DFF with reset(Dff8r)

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

Solution:

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

endmodule

3.2.1.4 DFF with reset value(Dff8p)

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

Hint:将寄存器复位为“1”有时称为“预设”

Solution:

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

endmodule

3.2.1.5 DFF with asynchronous reset(Dff8ar)

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

Hint:同步和异步复位触发器之间代码的唯一区别在于敏感列表

Solution:

module top_module (
    input clk,
    input areset,   // active high asynchronous reset
    input [7:0] d,
    output [7:0] q
);
    always@(posedge clk,posedge areset)
        if(areset)
            q<=8'b0;
        else
            q<=d;

endmodule

3.2.1.6 DFF with byte enable(Dff16e)

创建16位D触发器。所有D触发器都应由 clk 的上升沿触发。字节使能输入控制是否应在该周期写入16位寄存器的每个字节。byteena[1]控制高字节d[15:8],而bytenna[0]控制低字节d[7:0]。

restn 低电平有效同步复位。

所有的D触发器由clk的上升沿触发。

Solution:

module top_module (
    input clk,
    input resetn,
    input [1:0] byteena,
    input [15:0] d,
    output [15:0] q
);
    always@(posedge clk)
        if(~resetn)
            q<=0;
        else
            begin
                case(byteena)
                    2'b11:q<=d;
                    2'b10:q[15:8]<=d[15:8];
                    2'b01:q[7:0]<=d[7:0];                   
                endcase
            end

endmodule

3.2.1.7 D Latch(Exams/m2014 q4a)

实现以下电路:

Exams m2014q4a.png

请注意这是一个锁存器,所以Quartus产生会推断latch出现的warning。

Hint:

  • 锁存器是电平敏感电路(不是边缘敏感),所以在always块中,使用电平敏感列表。
  • 然而,这仍然是时序电路,所以使用非阻塞赋值!
  • D 锁存器在启用时就像一个wire(或非反相buffer),并在禁用时保留当前值。

Solution:

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

always@(*)表示缺省,会根据always块内部的内容自动识别敏感变量。


3.2.1.8 DFF(Exams/m2014 q4b)

实现以下电路:

Exams m2014q4b.png

Solution:

module top_module (
    input clk,
    input d, 
    input ar,   // asynchronous reset
    output q);
    always@(posedge clk,posedge ar)
        begin
            if(ar)
                q<=0;
            else
                q<=d;
        end

endmodule

由电路图知,clk和AR都是上升沿触发。


3.2.1.9 DFF+gate(Exams/m2014 q4d)

实现以下电路:

Exams m2014q4d.png

Solution:

module top_module (
    input clk,
    input in, 
    output out);
    always@(posedge clk)
        out<=in^out;
        
endmodule

3.2.1.10 Mux and DFF(Mt2015 muxdff)

考虑下面的时序电路:

假设您要为该电路实现分级 Verilog 代码,使用其中包含触发器和数据选择器的子模块的三个副本。为此子模块编写一个名为 top_module 的 Verilog 模块(包含一个触发器和数据选择器)。 

Solution:

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

本题就是写一个触发器和数据选择器的模块,当L=0,选择q_in为D触发器的输入;当L=1,选择r_in为D触发器的输入。

实现的就是并行输入的3位移位寄存器


3.2.1.11 Mux and DFF(Exams/2014 q4a)

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

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

Solution:

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

3.2.1.12 DFFs and gates(Exams/ece241 2014 q4)

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

创建这个电路。

 

Solution:

module top_module (
    input clk,
    input x,
    output z
);     
    reg q0,q1,q2;
    always@(posedge clk)
    begin
    	q0<=q0^x;
        q1<=~q1&x;
        q2<=~q2|x;        
    end
    assign z=~(q0 | q1 | q2);
endmodule

always块中非阻塞赋值 左边必须是reg型,故声明q0、q1、q2为reg型


3.2.1.13 Creat circuit from truth table(Exams/ece241 2013 q7)

JK 触发器具有以下真值表。仅使用 D 型触发器和门实现 JK 触发器。注:Qold 是时钟上升沿前 D 触发器的输出。

 

Solution:

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
/*
    always@(posedge clk)
        Q <= (j & ~Q) | (~k & Q);
*/
endmodule

根据D触发器和JK触发器的特性方程推出方法二,见代码中注释部分。


3.2.1.14 Detect an edge(Edgedetect)

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

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

Solution:

module top_module(
	input clk,
	input [7:0] in,
	output reg [7:0] pedge);
	
	reg [7:0] d_last;	
			
	always @(posedge clk) begin
		d_last <= in;			// Remember the state of the previous cycle
		pedge <= in & ~d_last;	// A positive edge occurred if input was 0 and is now 1.
	end
	
endmodule

上升沿检测,采用一个D触发器即d_last来存储上一个时钟周期的输入,d_last、in对应位分别为0、1时,则检测到上升沿。


3.2.1.15 Detect both edges(Edgedetect2)

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

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

Solution:

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

边沿检测即输入发生变化,故使用异或来检测。


3.2.1.16 Edge capture register(Edgecapture)

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

每bit输出的行为就像一个SR触发器:输出位应该在1到0转换发生后的周期置位(为1)。当reset为高电平时,输出应在时钟上升沿复位(为0)。如果上述两个事件同时发生,则reset具有高优先级。在下面4个实例波形的最后4个周期中,”reset“比”set“早一个周期发生,因此这里没有发生冲突。

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

Solution:

module top_module (
    input clk,
    input reset,
    input [31:0] in,
    output [31:0] out
);
    reg [31:0]d_last;
    always@(posedge clk) begin
        d_last<=in;
        if(reset)
            out <=0;
        else 
            out <=(d_last&~in)|out;
    end
endmodule

边沿捕获和边沿检测最大的区别在于,捕获是只要出现了一次下降沿,不管再过多少周期输出还是1,只有当reset的时候,out才会复位到0;而检测就是就是检测这一次下降沿,如果下个周期不是下降沿则输出就变为0。

所以本题中,使用if-else语句体现了reset的高优先级,out <=(d_last&~in)|out;  中(d_last&~in)表示下降沿,|out 表示没有下降沿信号的话则继续保持高电平。


3.2.1.17 Dual-edge triggered flip-flop(Dualedge)

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

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

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

Hint:

  • 您无法在 FPGA 上创建双边沿触发触发器。但是您可以创建上升沿触发和下降沿触发触发器。
  • 这个问题是一个中等难度的电路设计问题,但只需要基本的 Verilog 语言特性。 (这是一个电路设计问题,而不是一个编码问题。)在尝试编码之前先手工绘制一个电路可能会有所帮助。

Solution:

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

endmodule

这种方法由于Tcq延迟的存在,输出波形会产生glitch毛刺,即q1、q2的值还没更新,就已经执行了assign q=(clk?q1:q2)

module top_module(
	input clk,
	input d,
	output q);
	
	reg p, n;
	
	// A positive-edge triggered flip-flop
    always @(posedge clk)
        p <= d ^ n;
        
    // A negative-edge triggered flip-flop
    always @(negedge clk)
        n <= d ^ p;
    
    // Why does this work? 
    // After posedge clk, p changes to d^n. Thus q = (p^n) = (d^n^n) = d.
    // After negedge clk, n changes to p^n. Thus q = (p^n) = (p^p^n) = d.
    // At each (positive or negative) clock edge, p and n FFs alternately
    // load a value that will cancel out the other and cause the new value of d to remain.
    assign q = p ^ n;
    
    
	// Can't synthesize this.
	/*always @(posedge clk, negedge clk) begin
		q <= d;
	end*/
    
    
endmodule

第二种方法是通过异或,非常巧妙,且消除了glitch


本节开始,写得非常磕磕绊绊,还是基本功不扎实,不过这也正是我学HDLbits的原因。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值