HDLBits 刷题————时序电路

Sequential Logic

Latches and Flip-Flops

D Flip-Flop

A D flip-flop is a circuit that stores a bit and is updated periodically, at the (usually) positive edge of a clock signal.

D flip-flops are created by the logic synthesizer when a clocked always block is used (See alwaysblock2). A D flip-flop is the simplest form of “blob of combinational logic followed by a flip-flop” where the combinational logic portion is just a wire.

Create a single D flip-flop.

D触发器是一种在(通常)时钟信号的正边缘存储位并定期更新的电路。
D触发器由逻辑合成器在使用时钟始终块时创建。D触发器是“组合逻辑的blob后跟一个触发器”的最简单形式,其中组合逻辑部分只是一根导线。
创建一个D触发器。

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

这里没有什么难的,主要是注意在时序电路建模时使用,非阻塞型赋值语句。

D Flip-Flops

Create 8 D flip-flops. All DFFs should be triggered by the positive edge of clk.
建立一个八位的D触发器,使用上升沿触发

module top_module(
	input clk,
	input [7:0] d,
	output reg [7:0] q);
	
	// Because q is a vector, this creates multiple DFFs.
	always @(posedge clk)
		q <= d;
	
endmodule
DFF with reset

Create 8 D flip-flops with active high synchronous reset. All DFFs should be triggered by the positive edge of clk.
创建一个八位D触发器并带有高电平同步置零,D触发器为上升沿触发

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

endmodule

DFF with reset value

Create 8 D flip-flops with active high synchronous reset. The flip-flops must be reset to 0x34 rather than zero. All DFFs should be triggered by the negative edge of clk.
创建带有高电平同步复位的八位D触发器。触发器必须重置为0x34,而不是零。所有DFF都应该由clk的负边缘触发。

module top_module (
    input clk,
    input reset,
    input [7:0] d,
    output [7:0] q
);

    always @(negedge clk)
        if(reset)
            q<=8'h34;
        else
            q<=d;

endmodule

DFF with asynchronous reset

Create 8 D flip-flops with active high asynchronous reset. All DFFs should be triggered by the positive edge of clk.
创建带有高电平异步复位的八位触发器。所有DFF应由clk的正边缘触发。

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<=0;
        else 
            q<=d;
endmodule

这里有几点需要考虑的,大体结构跟前面的D触发器大同小异,主要是这里的复位信号是异步信号,所以在敏感事件表中,我们需要将复位信号areset填加进去,在这里我一开始犯了一个错误,即在敏感事件表中这么写always @(posedge clk,areset),感觉跟组合逻辑电路类似,只要添加进这个信号即可。然后编译的时候系统给我报了这样的一个错误:
mixed single- and double-edge expressions are not supported
意为不支持混合的单边和双边表达式,所以这里我们细想一下,复位信号从0到1后,触发器被置零。当复位信号从1到0时,触发器不会被值零,所以敏感事件表应该写为
always @(posedge clk, posedge areset)

DFF with byte enable

Create 16 D flip-flops. It’s sometimes useful to only modify parts of a group of flip-flops. The byte-enable inputs control whether each byte of the 16 registers should be written to on that cycle. byteena[1] controls the upper byte d[15:8], while byteena[0] controls the lower
resetn is a synchronous, active-low reset.
All DFFs should be triggered by the positive edge of clk.
制作16个D触发器。有时只修改一组触发器的一部分很有用。字节启用输入控制16个寄存器的每个字节是否应在该周期写入。byteena[1]控制高位字节d[15:8],而byteena[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)
        if(!resetn)
            q<=0;
    else if(byteena[0]&byteena[1])
        q<=d;
    else if(byteena[0]&!byteena[1])
        q[7:0]<=d[7:0];
    else if(~byteena[0]&byteena[1])
        q[15:8]<=d[15:8];
    else
        q<=q;
        
endmodule

这里先读题是同步复位信号,所以敏感事件列表中只需要保留 posedge clk,我在一开始写的时候还加上了negedge resetn,编译虽然没有报错,但是仿真的波形不对,如下图
在这里插入图片描述
可以看出这是异步置零的形式,当resetn处于下降沿时,q被迅速拉到0的位置上,此外,在这里我进行尝试的时候还发现了一个问题,当我的代码写成如下形式时,程序报错

 always @(posedge clk, negedge resetn)
        if(resetn)
            q<=0;

Error (10200): Verilog HDL Conditional Statement error at top_module.v(10): cannot match operand(s) in the condition to the corresponding edges in the enclosing event control of the always construct File:
Warning (10240): Verilog HDL Always Construct warning at top_module.v(9): inferring latch(es) for variable “q”, which holds its previous value in one or more paths through the always construct File:
无法将条件中的操作数与“始终构造”文件的封闭事件控件中的相应边匹配:
推断变量“q”的锁存(es),该变量通过始终构造文件在一个或多个路径中保持其以前的值:

这里后来搜了其他人的博客才知道,大概意思是不能匹配操作条件中的边沿事件和always语句中的控制事件,主要原因出在敏感信号列表上导致FPGA底层无法生成相应的电路所以报错。
PS:解答中的else if语句也可以用case语句替代

D Latch

Implement the following circuit:
Note that this is a latch, so a Quartus warning about having inferred a latch is expected.
执行以下电路:

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

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

endmodule
DFF
module top_module (
    input clk,
    input d, 
    input ar,   // asynchronous reset
    output q);

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

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

endmodule

第一个为异步置零,第二个为同步置零

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

endmodule
Mux and DFF
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

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

endmodule

这里用了两种方式描写数据选择器

DFFs ang gates
module top_module (
    input clk,
    input x,
    output z
); 
    wire q1,q2,q3;
    always @(posedge clk)
        begin
            q1<=x^q1;
            q2<=x&~q2;
            q3<=x|~q3;
        end
    assign z = ~(q1|q2|q3);

endmodule
Create circuit from truth table
module top_module (
    input clk,
    input j,
    input k,
    output Q); 
    
    always @(posedge clk)
        Q <= (j&~Q)|(~k&Q);

endmodule

这个JK触发器可以用数电知识直接写了

Detect an edge

For each bit in an 8-bit vector, detect when the input signal changes from 0 in one clock cycle to 1 the next (similar to positive edge detection). The output bit should be set the cycle after a 0 to 1 transition occurs.

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
Detect both edge

For each bit in an 8-bit vector, detect when the input signal changes from one clock cycle to the next (detect any edge). The output bit should be set the cycle after a 0 to 1 transition occurs.

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

For each bit in a 32-bit vector, capture when the input signal changes from 1 in one clock cycle to 0 the next. “Capture” means that the output will remain 1 until the register is reset (synchronous reset).

Each output bit behaves like a SR flip-flop: The output bit should be set (to 1) the cycle after a 1 to 0 transition occurs. The output bit should be reset (to 0) at the positive clock edge when reset is high. If both of the above events occur at the same time, reset has precedence. In the last 4 cycles of the example waveform below, the ‘reset’ event occurs one cycle earlier than the ‘set’ event, so there is no conflict here.

module top_module (
    input clk,
    input reset,
    input [31:0] in,
    output [31:0] out
);
    reg [31:0]	in_reg;
    
    always@(posedge clk)begin
        in_reg <= in;
    end
    
    always@(posedge clk)begin
        if(reset)begin
            out <= 32'd0;
        end
        else begin
            out <= ~in & in_reg | out;
        end
    end
 
endmodule
Dual-edge triggered flip-flop

You’re familiar with flip-flops that are triggered on the positive edge of the clock, or negative edge of the clock. A dual-edge triggered flip-flop is triggered on both edges of the clock. However, FPGAs don’t have dual-edge triggered flip-flops, and always @(posedge clk or negedge clk) is not accepted as a legal sensitivity list.

Build a circuit that functionally behaves like a dual-edge triggered flip-flop

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

这里的大体思路主要如下,首先always @(posedge clk or negedge clk)不可被综合,所以打算采用两个D触发器,一个为上升沿触发,一个为下降沿触发,然后根据结果的波形我们可以看出来,时钟信号为高电平时采样上升沿D触发器,时钟信号为低电平时采样下降沿D触发器,所以在后面加了一个二选一数据选择器。
这种方法比较容易理解,但是其他博主说在实际情况中容易产生毛刺,所以答案给了另一种电路,形式如下

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

Counters

Four-bit binary counter
module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q);
    
    reg [3:0]cout;
    always @(posedge clk)
        if(reset)
            cout <= 0;
   	    else
            cout <= cout+1;
    
    assign q = cout;
        

endmodule
Decade counter
module top_module(
	input clk,
	input reset,
	output reg [3:0] q);
	
	always @(posedge clk)
		if (reset || q == 9)	// Count to 10 requires rolling over 9->0 instead of the more natural 15->0
			q <= 0;
		else
			q <= q+1;
	
endmodule

Decade counter again
module top_module (
    input clk,
    input reset,
    output [3:0] q);
    
    always @(posedge clk)
        if(reset||q==10)
            q<=1;
        else
            q<=q+1'b1;

endmodule

在之前写的代码中直接写成q<=q+1,编译器会报出一个警告:truncated value with size 32 to match size of target (4)
意思就是+1中的没有指定位宽,比较浪费资源,所以在这里的代码中改成了+1’b1就好了

Slow decade counter
module top_module (
    input clk,
    input slowena,
    input reset,
    output [3:0] q);

    always @(posedge clk)
        if(reset)
            q<=0;
    else if(slowena)begin
        if(q<9)
            q<=q+1'b1;
        else
            q<=0;
    end
			
endmodule

这里的slowena相当于一个使能信号,只有当其为高电平的时候,计数器的值才能发生跳变

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值