【自用向 刷题笔记/答案】HDLBITS: Circuits - Sequential Logic(不包括FSM

Circuits - Sequential Logic

Latches and Flip-Flops

1 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.

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

2 D Flip-Flops

Create 8 D flip-flops. All DFFs should be triggered by the positive edge of clk.

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

    always @(posedge clk ) begin
        q <= d;
    end

endmodule

3 DFF with reset

Create 8 D flip-flops with active high synchronous reset. All DFFs should be triggered by the positive edge of clk.

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

    always @(posedge clk ) begin
        if (reset) begin
            q <= '0;
        end
        else begin
            q <= d;
        end
    end

endmodule

4 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.

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

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

5 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.

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

    always @(posedge clk or posedge areset ) begin
        if (areset) begin
            q <= '0;
        end
        else begin
            q <= d;
        end    
    end

endmodule

6 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 byte d[7:0].

resetn is a synchronous, active-low reset.

All DFFs should be triggered by the positive edge of 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) begin
            q <= '0;
        end
        else begin
            q[7:0]<= byteena[0]?d[7:0]:q[7:0];
            q[15:8]<= byteena[1]?d[15:8]:q[15:8];
        end
    end

endmodule

写法2:

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) begin
            q <= '0;
        end
        else begin
            if (byteena[0]) begin
                q[7:0] <= d[7:0];
            end
            if (byteena[1]) begin
                q[15:8] <= d[15:8];
            end
        end
    end

endmodule

也可以用一个case语句遍历 00 10 01 11:

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) begin
            q <= '0;
        end
        else begin
            case (byteena)
                2'b 00: q <= q ;
                2'b 01: q[7:0] <= d[7:0] ;
                2'b 10: q[15:8] <= d[15:8] ;
                2'b 11: q <= d ;
                default: q <= '0;
            endcase
        end
    end

endmodule

7 D latch

Implement the following circuit:

在这里插入图片描述

Note that this is a latch, so a Quartus warning about having inferred a latch is expected.

module top_module (
    input d, 
    input ena,
    output q);

    always @(*) begin
        if (ena) begin
            q <= d;
        end
    end

endmodule

8 DFF

Implement the following circuit:

在这里插入图片描述

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

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

endmodule

9 DFF

Implement the following circuit:

在这里插入图片描述

module top_module (
    input clk,
    input d, 
    input r,   // synchronous reset
    output q);

    always @(posedge clk) begin
        if (r) begin
            q <= 0;
        end
        else begin
            q <= d;
        end
    end

endmodule

同步复位和异步复位 synchronous reset / asynchronous reset

同步复位

同步复位就是指复位信号只有在时钟上升沿到来时,才能有效

 always @(posedge clk) begin
     if (r) begin
         //
     end
 end

由于大多数寄存器没有单独的同步复位端口,综合出来的RTL一般是数据输入(data_in)和复位信号(rst_n)取与操作/如图的MUX(即只要rst_n和data_in其中一个为0,则输入端为0)。相比于异步复位,会额外消耗电路的组合逻辑资源。

优点:

1、可以使所设计的系统成为 100% 的同步时序电路,有利于时序分析,而且可综合出较高的 Fmax;
2、由于只在时钟有效电平到来时才有效,所以可以滤除高于时钟频率的复位毛刺。

缺点:

1、复位信号的有效时长必须大于时钟周期,才能真正被系统识别并完成复位任务。同时还要考虑诸如 clk skew 、组合逻辑路径延时 、复位延时等因素(所以复位信号有时需要脉冲展宽,用以保证时钟有效期间有足够的复位宽度);

2、由于大多数的逻辑器件的目标库内的 DFF 都只有异步复位端口,所以,倘若采用同步复位的话,综合器就会在寄存器的数据输入端口插入组合逻辑,这样就会一方面额外增加FPGA内部的逻辑资源,另一方面也增加了相应的组合逻辑门时延。

异步复位

异步复位是指无论时钟沿是否到来,只要复位信号有效,就对系统进行复位

 always @(posedge clk or posedge ar) begin
     if (ar) begin
         //
     end
 end

异步复位触发器则是在设计触发器的时候加入了一个复位引脚,也就是说复位逻辑集成在触发器里面。低电平的复位信号到达触发器的复位端时,触发器进入复位状态,直到复位信号撤离。

虽然异步复位没有占用额外的组合逻辑资源,但是其对复位信号的要求较高,假如复位信号中出现毛刺,会使整个寄存器执行复位操作。

优点:

1、使用异步复位的最大好处就是复位路径上没有延时,如上面的图所示,复位信号一直连接到触发器的复位端口,而不是像同步复位那样需要经过一个复位控制逻辑(如与门),这样子就减少了外界信号的影响。

2、与时钟没有关系,不管时钟上升沿有没有到来,只要复位信号一有效,触发器就会复位,也就是基本上做到实时性;

缺点:

异步复位信号在释放时容易出现问题(当复位信号从低拉高即为复位信号的释放)。异步复位信号在结束的时候,可能会不满足recovery和removal time,可能使电路进入亚稳态。

10 DFF+gate

Implement the following circuit:
在这里插入图片描述

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

    wire d;

    always @(*) begin
        d <= in ^ out;
    end

    always @(posedge clk ) begin
        out <= d;
    end

endmodule

11 MUX and DFF

Taken from ECE253 2015 midterm question 5

Consider the sequential circuit below:
在这里插入图片描述

Assume that you want to implement hierarchical Verilog code for this circuit, using three instantiations of a submodule that has a flip-flop and multiplexer in it. Write a Verilog module (containing one flip-flop and multiplexer) named top_module for this submodule.

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

    wire D;
    assign  D = L ? r_in : q_in;

    always @(posedge clk ) begin
        Q <= D;
    end

endmodule

12 MUX and DFF

Consider the n-bit shift register circuit shown below:

在这里插入图片描述

Write a Verilog module named top_module for one stage of this circuit, including both the flip-flop and multiplexers.

module top_module (
    input clk,
    input w, R, E, L,
    output Q
);

    wire temp;
    wire D;
    assign temp = E ? w : Q;
    assign D = L ? R : temp;
    
    always @(posedge clk ) begin
        Q <= D;
    end

endmodule

13 DFFs and gates

Given the finite state machine circuit as shown, assume that the D flip-flops are initially reset to zero before the machine begins.

Build this circuit.

在这里插入图片描述

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

    wire D1,D2,D3;
    wire Q1,Q2,Q3;

    assign D1 = x ^ Q1;
    assign D2 = x & ~Q2;
    assign D3 = x | ~Q3;

    always @(posedge clk ) begin
        Q1 <= D1;
        Q2 <= D2;
        Q3 <= D3;
    end

    assign z = ~(Q1 | Q2 | Q3);

endmodule

14 Create circuit from truth table

A JK flip-flop has the below truth table. Implement a JK flip-flop with only a D-type flip-flop and gates. Note: Qold is the output of the D flip-flop before the positive clock edge.

JKQ
00Qold
010
101
11~Qold
module top_module (
    input clk,
    input j,
    input k,
    output Q); 

    always @(posedge clk) begin
        case ({j,k})
            2'b 00: Q <= Q;
            2'b 01: Q <= 0;
            2'b 10: Q <= 1;
            2'b 11: Q <= ~Q;
            default: Q <= 0;
        endcase
    end

endmodule

15 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.

Here are some examples. For clarity, in[1] and pedge[1] are shown separately.
在这里插入图片描述

module top_module (
    input clk,
    input [7:0] in,
    output [7:0] pedge
);

    wire [7:0] cmp;

    always @(posedge clk ) begin
        cmp = in;
    end

    always @(posedge clk ) begin
        integer i;
        for (i = 0; i < 8 ; i++ ) begin
            if (cmp[i] != in[i] & in[i]) begin
                pedge[i] <= 1;
            end
            else pedge[i] <= 0;
        end            
    end

endmodule

另外一种更简便的写法:

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

16 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.

Here are some examples. For clarity, in[1] and anyedge[1] are shown separately

在这里插入图片描述

module top_module (
    input clk,
    input [7:0] in,
    output [7:0] anyedge
);

    wire [7:0] cmp;

    always @(posedge clk ) begin
        cmp <= in;
        anyedge <= in ^ cmp;
    end

endmodule

17 Edge capture 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.

In the example waveform below, reset, in[1] and out[1] are shown again separately for clarity.

在这里插入图片描述

module top_module (
    input clk,
    input reset,
    input [31:0] in,
    output [31:0] out
);

    reg [31:0] cmp;

    
    always @(posedge clk ) begin
        integer i;
        cmp <= in;
        
        if (reset) begin
            out <= '0;
        end

        else begin
            for (i = 0; i < 32 ; i++ ) begin
                if ((cmp[i] ^ in[i]) & cmp[i]) begin
                    out[i] <= 1;
                end
                
                else begin
                    out[i] <= out[i];
                end
            end
        end

    end

endmodule

要注意cmp <= in;要在reset前,或者单独拎出来做一个always block,这是因为在reset的期间,你in值可能会更新,但是如果把cmp<=in放在reset后,在reset时cmp会是reset以前的值。在reset结束的那一拍,你的cmp可能会是错误的值。

找资料时看到的一个简便写法:

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

18 Dual-edge triggered filp-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:

在这里插入图片描述

(Note: It’s not necessarily perfectly equivalent: The output of flip-flops have no glitches, but a larger combinational circuit that emulates this behaviour might. But we’ll ignore this detail here.)

module top_module (
    input clk,
    input d,
    output q
);
    reg q1, q2;
    
    always @(negedge clk ) begin
        q1 <= d ^ q2;
    end

    always @(posedge clk ) begin
        q2 <= d ^ q1;
    end

    always @(*) begin
        q = q1 ^ q2;
    end

endmodule

这是一种标准的双边采样的写法,对于他的证明如下:

此外,还可以通过如下写法实现:

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

endmodule

此方法会产生毛刺,其原因主要来自于触发器存在延迟Tcq,也就是说q1和q2相对于clk会有延迟,从而产生毛刺。

Counters

1 Four-bit binary counter

Build a 4-bit binary counter that counts from 0 through 15, inclusive, with a period of 16. The reset input is synchronous, and should reset the counter to 0.
在这里插入图片描述

module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q);

    always @(posedge clk ) begin
        if (reset) begin
            q <= '0;
        end
        else if (q == 4'hf) begin
            q <= 0;
        end
        else begin
            q <= q + 1;
        end
    end

endmodule

实际上,由于q为4位,溢出之后依旧保留低四位的值,不必判定其是否为15:

module top_module(
	input clk,
	input reset,
	output reg [3:0] q);
	
	always @(posedge clk)
		if (reset)
			q <= 0;
		else
			q <= q+1;
	
endmodule

2 Decade counter

Build a decade counter that counts from 0 through 9, inclusive, with a period of 10. The reset input is synchronous, and should reset the counter to 0.

在这里插入图片描述

module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q);

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

endmodule

3 Decade counter again

Make a decade counter that counts 1 through 10, inclusive. The reset input is synchronous, and should reset the counter to 1.

在这里插入图片描述

module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q);

    always @(posedge clk ) begin
        if (reset) begin
            q <= 1;
        end
        else if (q == 10) begin
            q <= 1;
        end
        else begin
            q <= q + 1;
        end
    end

endmodule

4 Slow Decade Counter

Build a decade counter that counts from 0 through 9, inclusive, with a period of 10. The reset input is synchronous, and should reset the counter to 0. We want to be able to pause the counter rather than always incrementing every clock cycle, so the slowena input indicates when the counter should increment.

在这里插入图片描述

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

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

endmodule

5 count 1-12

Design a 1-12 counter with the following inputs and outputs:

  • Reset Synchronous active-high reset that forces the counter to 1
  • Enable Set high for the counter to run
  • Clk Positive edge-triggered clock input
  • Q[3:0] The output of the counter
  • c_enable, c_load, c_d[3:0] Control signals going to the provided 4-bit counter, so correct operation can be verified.

You have the following components available:

  • the 4-bit binary counter (count4) below, which has Enable and synchronous parallel-load inputs (load has higher priority than enable). The count4 module is provided to you. Instantiate it in your circuit.
  • logic gates
module count4(
	input clk,
	input enable,
	input load,
	input [3:0] d,
	output reg [3:0] Q
);

The c_enable, c_load, and c_d outputs are the signals that go to the internal counter’s enable, load, and d inputs, respectively. Their purpose is to allow these signals to be checked for correctness.

module top_module (
    input clk,
    input reset,
    input enable,
    output [3:0] Q,
    output c_enable,
    output c_load,
    output [3:0] c_d
); //

    assign c_enable = enable;

    always @(*) begin
        if (reset) begin
            c_load <= 1;
            c_d <= 1;
        end
        else begin
        	c_load <= 0;
        if ( (enable) && (Q == 12) ) begin
            c_load <= 1;
            c_d <= 1;
        end
        end
    end

    count4 the_counter (clk, c_enable, c_load, c_d , Q);

endmodule

这个题目的重点在于理解4bits的计数器各变量功能:

clk 时钟信号

enable 计数器的使能信号,在enable = 1的时候计数器工作

load 当load = 1的时候载入初始值,令Q = d

d 初始值

因此我们需要在Q=12的时候重新载入d的值,此时需要load操作,同时要使d初始化。

c_load <= 1;
c_d <= 1;

6 count 100

From a 1000 Hz clock, derive a 1 Hz signal, called OneHertz, that could be used to drive an Enable signal for a set of hour/minute/second counters to create a digital wall clock. Since we want the clock to count once per second, the OneHertz signal must be asserted for exactly one cycle each second. Build the frequency divider using modulo-10 (BCD) counters and as few other gates as possible. Also output the enable signals from each of the BCD counters you use (c_enable[0] for the fastest counter, c_enable[2] for the slowest).

The following BCD counter is provided for you. Enable must be high for the counter to run. Reset is synchronous and set high to force the counter to zero. All counters in your circuit must directly use the same 1000 Hz signal.

module bcdcount (
	input clk,
	input reset,
	input enable,
	output reg [3:0] Q
);
module top_module (
    input clk,
    input reset,
    output OneHertz,
    output [2:0] c_enable
); //

    reg [3:0] Q0, Q1, Q2;

    bcdcount counter0 (clk, reset, c_enable[0], Q0);
    bcdcount counter1 (clk, reset, c_enable[1], Q1);
    bcdcount counter3 (clk, reset, c_enable[2], Q2);
    
    always @(*) begin
        c_enable[0] <= 1;
        c_enable[1] <= c_enable[0] && (Q0 == 9);
        c_enable[2] <= c_enable[1] && (Q1 == 9);
        OneHertz <= (Q2==9) && (Q1==9) && (Q0==9);
    end

endmodule

7 4-digit decimal counter

Build a 4-digit BCD (binary-coded decimal) counter. Each decimal digit is encoded using 4 bits: q[3:0] is the ones digit, q[7:4] is the tens digit, etc. For digits [3:1], also output an enable signal indicating when each of the upper three digits should be incremented.

You may want to instantiate or modify some one-digit decade counters.

在这里插入图片描述

module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output [15:0] q);

    digit_count digit0 (clk, reset, 1, q[3:0]);
    digit_count digit1 (clk, reset, ena[1], q[7:4]);
    digit_count digit2 (clk, reset, ena[2], q[11:8]);
    digit_count digit3 (clk, reset, ena[3], q[15:12]);

    assign ena[1] = (q[3:0] == 9) ? 1 : 0;
    assign ena[2] = ( (q[7:4] == 9) && ena[1] ) ? 1 : 0;
    assign ena[3] = ( (q[11:8] == 9) && ena[2] ) ? 1 : 0;

endmodule

module digit_count (
    input clk,
    input reset,
    input en,
    output [3:0] q
);
    always @(posedge clk) begin
        if (reset) begin
            q <= 0;
        end
        else begin
            if (en) begin
                if (q == 9) begin
                    q <= 0;
                end
                else begin
                    q ++ ;
                end
            end
        end
    end
        
endmodule

8 12 hour clock

Create a set of counters suitable for use as a 12-hour clock (with am/pm indicator). Your counters are clocked by a fast-running clk, with a pulse on ena whenever your clock should increment (i.e., once per second).

reset resets the clock to 12:00 AM. pm is 0 for AM and 1 for PM. hh, mm, and ss are two BCD (Binary-Coded Decimal) digits each for hours (01-12), minutes (00-59), and seconds (00-59). Reset has higher priority than enable, and can occur even when not enabled.

The following timing diagram shows the rollover behaviour from 11:59:59 AM to 12:00:00 PM and the synchronous reset and enable behaviour.

在这里插入图片描述

module top_module(
    input clk,
    input reset,
    input ena,
    output pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 

    reg ens,enm,enh;
	
    //时分秒的进位信号
    assign ens = ena;
    assign enm = ens && (ss[3:0] == 9) && (ss[7:4] == 5);
    assign enh = enm && (mm[3:0] == 9) && (mm[7:4] == 5);
	//调用计数器执行计数
    count60 second(clk,reset,ens,ss);
    count60 minute(clk,reset,enm,mm);
    
    //由于小时制是12-1更新,而非0-11,所以需要另外构建计数器
    count12 hour(clk,reset,enh,hh);

    //单独控制pm信号
    always @(posedge clk ) begin
        if (reset) begin
            pm <= 0;
        end
        else if (enh && (hh[3:0] == 1) && (hh[7:4] == 1)) begin
            pm = !pm;
        end
    end

endmodule

//0-60的BCD计数器
module count60 (
    input clk,
    input rst,
    input en,
    output [7:0] count
);
    always @(posedge clk ) begin
        if (rst) begin
            count <= 0;
        end
        else begin
            if (en) begin
                if (count[3:0] == 9) begin
                    count[3:0] <= 0;
                    if (count[7:4] == 5) begin
                        count[7:4] <= 0;
                    end
                    else begin
                        count[7:4] ++;
                    end
                end
                else begin
                    count[3:0] ++;
                end
            end
        end
    end
endmodule

//1-12的bcd计数器
module count12 (
    input clk,
    input rst,
    input en,
    output [7:0] count
);
    always @(posedge clk ) begin
        if (rst) begin
            count[3:0] <= 2;
            count[7:4] <= 1;
        end
        else begin
            if (en) begin
                if ((count[3:0] == 2) && (count[7:4] == 1)) begin
                    count[3:0] <= 1;
                    count[7:4] <= 0;
                end
                else if(count[3:0] == 9) begin
                    count[3:0] <= 0;
                    count[7:4] <= 1;
                end
                else begin
                    count[3:0] ++;
                end
            end
        end
    end
endmodule

Shift Registers

1 4-bit shift register

Build a 4-bit shift register (right shift), with asynchronous reset, synchronous load, and enable.

  • areset: Resets shift register to zero.
  • load: Loads shift register with data[3:0] instead of shifting.
  • ena: Shift right (q[3] becomes zero, q[0] is shifted out and disappears).
  • q: The contents of the shift register.

If both the load and ena inputs are asserted (1), the load input has higher priority.

module top_module(
    input clk,
    input areset,  // async active-high reset to zero
    input load,
    input ena,
    input [3:0] data,
    output reg [3:0] q); 

    reg tmp;

    always @(posedge clk or posedge areset) begin
        if (areset) begin
            q <= '0;
        end
        else if (load) begin
            q <= data;
        end
        else if (ena) begin
            {q,tmp} <= {1'b0,q};
        end
    end

endmodule

可以用更简单的语句实现:

module top_module(
	input clk,
	input areset,
	input load,
	input ena,
	input [3:0] data,
	output reg [3:0] q);
	
	always @(posedge clk, posedge areset) begin
		if (areset)		// reset
			q <= 0;
		else if (load)	// load
			q <= data;
		else if (ena)	// shift is enabled
			q <= q[3:1];	// Use vector part select to express a shift.
	end
	
endmodule

2 Left/right rotator

Build a 100-bit left/right rotator, with synchronous load and left/right enable. A rotator shifts-in the shifted-out bit from the other end of the register, unlike a shifter that discards the shifted-out bit and shifts in a zero. If enabled, a rotator rotates the bits around and does not modify/discard them.

  • load: Loads shift register with data[99:0] instead of rotating.

  • ena[1:0]
    Chooses whether and which direction to rotate.
    • 2'b01 rotates right by one bit
    • 2'b10 rotates left by one bit
    • 2'b00 and 2'b11 do not rotate.
  • q: The contents of the rotator.

module top_module(
    input clk,
    input load,
    input [1:0] ena,
    input [99:0] data,
    output reg [99:0] q); 

    always @(posedge clk ) begin
        if (load) begin
            q <= data;
        end
        else begin
            case (ena)
                2'b 00, 2'b 11 : q <= q ;
                2'b 01 : q <= {q[0],q[99:1]};
                2'b 10 : q <= {q[98:0],q[99]};
            endcase
        end
    end

endmodule

3 Shift18

Build a 64-bit arithmetic shift register, with synchronous load. The shifter can shift both left and right, and by 1 or 8 bit positions, selected by amount.

An arithmetic right shift shifts in the sign bit of the number in the shift register (q[63] in this case) instead of zero as done by a logical right shift. Another way of thinking about an arithmetic right shift is that it assumes the number being shifted is signed and preserves the sign, so that arithmetic right shift divides a signed number by a power of two.

There is no difference between logical and arithmetic left shifts.

  • load: Loads shift register with data[63:0] instead of shifting.

  • ena: Chooses whether to shift.

  • amount : Chooses which direction and how much to shift.

  • 2'b00: shift left by 1 bit.

  • 2'b01: shift left by 8 bits.

  • 2'b10: shift right by 1 bit.

  • 2'b11: shift right by 8 bits.

  • q: The contents of the shifter.

module top_module(
    input clk,
    input load,
    input ena,
    input [1:0] amount,
    input [63:0] data,
    output reg [63:0] q); 

    always @(posedge clk ) begin
        if (load) begin
            q <= data;
        end
        else if (ena) begin
            case (amount)
                2'b 00: q <= {q[62:0],1'b0};
                2'b 01: q <= {q[55:0],8'b0};
                2'b 10: q <= {q[63],q[63:1]};
                2'b 11: q <= {{8{q[63]}},q[63:8]};
                default: q <= q;
            endcase
        end
    end

endmodule

4 5-bit LFSR

A linear feedback shift register is a shift register usually with a few XOR gates to produce the next state of the shift register. A Galois LFSR is one particular arrangement where bit positions with a “tap” are XORed with the output bit to produce its next value, while bit positions without a tap shift. If the taps positions are carefully chosen, the LFSR can be made to be “maximum-length”. A maximum-length LFSR of n bits cycles through 2n-1 states before repeating (the all-zero state is never reached).

The following diagram shows a 5-bit maximal-length Galois LFSR with taps at bit positions 5 and 3. (Tap positions are usually numbered starting from 1). Note that I drew the XOR gate at position 5 for consistency, but one of the XOR gate inputs is 0.
在这里插入图片描述

Build this LFSR. The reset should reset the LFSR to 1.

module top_module(
    input clk,
    input reset,    // Active-high synchronous reset to 5'h1
    output [4:0] q
); 

    always @(posedge clk ) begin
        if (reset) begin
            q <= 5'b1;
        end
        else begin
            q[0] <= q[1];
            q[1] <= q[2];
            q[2] <= q[3] ^ q[0];
            q[3] <= q[4];
            q[4] <= q[0] ^ 0;
        end
    end

endmodule

5 3-bit LFSR

aken from 2015 midterm question 5. See also the first part of this question: mt2015_muxdff

在这里插入图片描述

Write the Verilog code for this sequential circuit (Submodules are ok, but the top-level must be named top_module). Assume that you are going to implement the circuit on the DE1-SoC board. Connect the R inputs to the SW switches, connect Clock to KEY[0], and L to KEY[1]. Connect the Q outputs to the red lights LEDR.

module top_module (
	input [2:0] SW,      // R
	input [1:0] KEY,     // L and clk
	output [2:0] LEDR);  // Q

    reg clk;
    reg L;

    always @(*) begin
        clk <= KEY[0];
        L <= KEY[1];
    end

    muxFF muxFF0( SW[0], LEDR[2], L, clk, LEDR[0] );
    muxFF muxFF1( SW[1], LEDR[0], L, clk, LEDR[1] );
    reg Qtmp;
    assign Qtmp = LEDR[1] ^  LEDR[2];
    muxFF muxFF2( SW[2], Qtmp, L, clk, LEDR[2] );

endmodule

module muxFF (
    input r,
    input Q_in,
    input L,
    input clk,
    output Q_out);

    reg D;

    always @(*) begin
        D <= L ? r : Q_in;
    end
    
    always @(posedge clk ) begin
        Q_out <= D;
    end
    
endmodule

6 32-bit LFSR

See Lfsr5 for explanations.

Build a 32-bit Galois LFSR with taps at bit positions 32, 22, 2, and 1.

module top_module(
    input clk,
    input reset,   
    output [31:0] q
); 
    always@(posedge clk)begin
        if(reset) q<=32'd1;
        else q<={q[0]^1'b0,q[31:23],q[0]^q[22],q[21:3],q[0]^q[2],q[0]^q[1]};
    end
endmodule

7 shift register

Implement the following circuit:

在这里插入图片描述

module top_module (
    input clk,
    input resetn,   // synchronous reset
    input in,
    output out);
    
    reg Q1, Q2, Q3;

    FF ff1(in, clk, resetn, Q1);
    FF ff2(Q1, clk, resetn, Q2);
    FF ff3(Q2, clk, resetn, Q3);
    FF ff4(Q3, clk, resetn, out);

endmodule

module FF (
    input D,
    input clk,
    input rstn,
    output Q);

    always @(posedge clk ) begin
        if (!rstn) begin
            Q <= 0;
        end
        else begin
            Q <= D;
        end
    end
    
endmodule

8 shift register

Consider the n-bit shift register circuit shown below:

在这里插入图片描述

Write a top-level Verilog module (named top_module) for the shift register, assuming that n = 4. Instantiate four copies of your MUXDFF subcircuit in your top-level module. Assume that you are going to implement the circuit on the DE2 board.

  • Connect the R inputs to the SW switches,
  • clk to KEY[0],
  • E to KEY[1],
  • L to KEY[2], and
  • w to KEY[3].
  • Connect the outputs to the red lights LEDR[3:0].
module top_module (
    input [3:0] SW,
    input [3:0] KEY,
    output [3:0] LEDR
); //

    reg clk, E, L, w;

    always @(*) begin
        { w, L, E, clk } <= KEY;
    end

    MUXDFF muxdff3( w, E, SW[3], L, clk, LEDR[3] );
    MUXDFF muxdff2( LEDR[3], E, SW[2], L, clk, LEDR[2] );
    MUXDFF muxdff1( LEDR[2], E, SW[1], L, clk, LEDR[1] );
    MUXDFF muxdff0( LEDR[1], E, SW[0], L, clk, LEDR[0] );

endmodule

module MUXDFF (
    input w,
    input E,
    input R,
    input L,
    input clk,
    output Q
);

    reg D1, D2;

    always @(*) begin
        D1 <= E ? w : Q;
        D2 <= L ? R : D1;
    end

    always @(posedge clk ) begin
        Q <= D2;
    end

endmodule

9 3-input LUT

In this question, you will design a circuit for an 8x1 memory, where writing to the memory is accomplished by shifting-in bits, and reading is “random access”, as in a typical RAM. You will then use the circuit to realize a 3-input logic function.

First, create an 8-bit shift register with 8 D-type flip-flops. Label the flip-flop outputs from Q[0]…Q[7]. The shift register input should be called S, which feeds the input of Q[0] (MSB is shifted in first). The enable input controls whether to shift. Then, extend the circuit to have 3 additional inputs A,B,C and an output Z. The circuit’s behaviour should be as follows: when ABC is 000, Z=Q[0], when ABC is 001, Z=Q[1], and so on. Your circuit should contain ONLY the 8-bit shift register, and multiplexers. (Aside: this circuit is called a 3-input look-up-table (LUT)).

module top_module (
    input clk,
    input enable,
    input S,
    input A, B, C,
    output Z ); 

    reg [7:0]Q;
    
    FF ff0( clk, enable, S, Q[0] );
    FF ff1( clk, enable, Q[0], Q[1] );
    FF ff2( clk, enable, Q[1], Q[2] );
    FF ff3( clk, enable, Q[2], Q[3] );
    FF ff4( clk, enable, Q[3], Q[4] );
    FF ff5( clk, enable, Q[4], Q[5] );
    FF ff6( clk, enable, Q[5], Q[6] );
    FF ff7( clk, enable, Q[6], Q[7] );

    always @(*) begin
        case ({A,B,C})
            3'b 000: Z <= Q[0];
            3'b 001: Z <= Q[1];
            3'b 010: Z <= Q[2];
            3'b 011: Z <= Q[3];
            3'b 100: Z <= Q[4];
            3'b 101: Z <= Q[5];
            3'b 110: Z <= Q[6];
            3'b 111: Z <= Q[7];

            default: Z <= 0;
        endcase
    end

endmodule

module FF (
    input clk,
    input en,
    input D,
    output Q
);

    always @(posedge clk ) begin
        if (en) begin
            Q <= D;
        end
    end
    
endmodule

more circuits

1 rule 90

Rule 90 is a one-dimensional cellular automaton with interesting properties.

The rules are simple. There is a one-dimensional array of cells (on or off). At each time step, the next state of each cell is the XOR of the cell’s two current neighbours. A more verbose way of expressing this rule is the following table, where a cell’s next state is a function of itself and its two neighbours:

LeftCenterRightCenter’s next state
1110
1101
1010
1001
0111
0100
0011
0000

(The name “Rule 90” comes from reading the “next state” column: 01011010 is decimal 90.)

In this circuit, create a 512-cell system (q[511:0]), and advance by one time step each clock cycle. The load input indicates the state of the system should be loaded with data[511:0]. Assume the boundaries (q[-1] and q[512]) are both zero (off).

module top_module(
    input clk,
    input load,
    input [511:0] data,
    output [511:0] q ); 

    reg [512:-1] qtmp;

    always @(posedge clk ) begin
        integer i;
        if (load) begin
            qtmp <= {1'b0,data,1'b0};    
        end
        else
        for (i = 0; i<512 ; i++ ) begin
            qtmp[i] <= qtmp[i-1] ^ qtmp[i+1];
        end
    end
    
    assign q = qtmp[511:0];

endmodule

2 rule 110

Rule 110 is a one-dimensional cellular automaton with interesting properties (such as being Turing-complete).

There is a one-dimensional array of cells (on or off). At each time step, the state of each cell changes. In Rule 110, the next state of each cell depends only on itself and its two neighbours, according to the following table:

LeftCenterRightCenter’s next state
1110
1101
1011
1000
0111
0101
0011
0000

(The name “Rule 110” comes from reading the “next state” column: 01101110 is decimal 110.)

In this circuit, create a 512-cell system (q[511:0]), and advance by one time step each clock cycle. The load input indicates the state of the system should be loaded with data[511:0]. Assume the boundaries (q[-1] and q[512]) are both zero (off).

module top_module(
    input clk,
    input load,
    input [511:0] data,
    output [511:0] q ); 

    reg [512:-1] qtmp;

    always @(posedge clk ) begin
        integer i;

        if (load) begin
            qtmp <= {1'b0,data,1'b0};    
        end
        else for (i = 0; i<512 ; i++ ) begin
            case ( {qtmp[i+1], qtmp[i], qtmp[i-1]} )
                3'b 111: qtmp[i] <= 0;
                3'b 110: qtmp[i] <= 1;
                3'b 101: qtmp[i] <= 1;
                3'b 100: qtmp[i] <= 0;
                3'b 011: qtmp[i] <= 1;
                3'b 010: qtmp[i] <= 1;
                3'b 001: qtmp[i] <= 1;
                3'b 000: qtmp[i] <= 0;
                default:  qtmp[i] <= qtmp[i];
            endcase
        end
    end

    assign q = qtmp[511:0];

endmodule

3 conway’s game of life 16x16

Conway’s Game of Life is a two-dimensional cellular automaton.

The “game” is played on a two-dimensional grid of cells, where each cell is either 1 (alive) or 0 (dead). At each time step, each cell changes state depending on how many neighbours it has:

  • 0-1 neighbour: Cell becomes 0.
  • 2 neighbours: Cell state does not change.
  • 3 neighbours: Cell becomes 1.
  • 4+ neighbours: Cell becomes 0.

The game is formulated for an infinite grid. In this circuit, we will use a 16x16 grid. To make things more interesting, we will use a 16x16 toroid, where the sides wrap around to the other side of the grid. For example, the corner cell (0,0) has 8 neighbours: (15,1), (15,0), (15,15), (0,1), (0,15), (1,1), (1,0), and (1,15). The 16x16 grid is represented by a length 256 vector, where each row of 16 cells is represented by a sub-vector: q[15:0] is row 0, q[31:16] is row 1, etc. (This tool accepts SystemVerilog, so you may use 2D vectors if you wish.)

  • load: Loads data into q at the next clock edge, for loading initial state.
  • q: The 16x16 current state of the game, updated every clock cycle.

The game state should advance by one timestep every clock cycle.

John Conway, mathematician and creator of the Game of Life cellular automaton, passed away from COVID-19 on April 11, 2020.

module top_module(
    input clk,
    input load,
    input [255:0] data,
    output reg [255:0] q ); 

	integer row, col;
    reg [3:0] sum;
    reg [15:0] q_2d [15:0];
    reg [16:-1] q_2d_exp [16:-1];
    reg [15:0] q_next [15:0];
    
    //赋予q的值
    always @(posedge clk ) begin
        if (load) begin
            q <= data;
        end
        else begin
            for ( col = 0 ; col < 16 ; col = col+1 ) begin
                for ( row = 0 ; row < 16 ; row = row+1 ) begin
                    q[col*16 + row] <= q_next[col][row];
                end
            end
        end
    end
    
    //将q的数据导入二维矩阵中
    always @(*) begin
         for ( col = 0 ; col < 16 ; col = col+1 ) begin
            for ( row = 0 ; row < 16 ; row = row+1 ) begin
                	q_2d[col][row] = q[col*16+row ]; 
            end 
        end
    end

    //将二维矩阵转化为球形矩阵
    always @(*) begin
        //中间区域
        for ( col = 0 ; col < 16 ; col = col+1 ) begin
            for ( row = 0 ; row < 16 ; row = row+1 ) begin
                q_2d_exp[col][row] = q_2d[col][row];
            end
        end
        //拓宽区域:上下边角
        for ( col = 0 ; col < 16 ; col = col+1 ) begin
            q_2d_exp[col][-1] = q_2d[col][15];
            q_2d_exp[col][16] = q_2d[col][0];
        end
        //拓宽区域:左右边角
        for ( row = 0 ; row < 16 ; row = row+1 ) begin
            q_2d_exp[-1][row] = q_2d[15][row];
            q_2d_exp[16][row] = q_2d[0][row];
        end
        //拓宽区域:四个顶点
        q_2d_exp[-1][-1] = q_2d[15][15];
        q_2d_exp[-1][16] = q_2d[15][0];
        q_2d_exp[16][-1] = q_2d[0][15];
        q_2d_exp[16][16] = q_2d[0][0];
    end

    //判定q_next的值,使用康威规则
    always @(*) begin
        for ( col = 0 ; col < 16 ; col = col+1 ) begin
            for ( row = 0 ; row < 16 ; row = row+1 ) begin
                sum = q_2d_exp[col+1][row+1] + q_2d_exp[col+1][row] + q_2d_exp[col+1][row-1] + q_2d_exp[col][row+1] + q_2d_exp[col][row-1] + q_2d_exp[col-1][row+1] + q_2d_exp[col-1][row] + q_2d_exp[col-1][row-1];
                
                case (sum)
                    4'b0010: q_next[col][row] = q_2d[col][row];
                    4'b0011: q_next[col][row] = 1;
                    default: q_next[col][row] = 0;
                endcase
            end
        end
    end

endmodule

这道题debug花了很久的时间,因为最初在最后一个always block的for循环内采用的语句是:

 sum <= q_2d_exp[col+1][row+1] + q_2d_exp[col+1][row] + q_2d_exp[col+1][row-1] + q_2d_exp[col][row+1] + q_2d_exp[col][row-1] + q_2d_exp[col-1][row+1] + q_2d_exp[col-1][row] + q_2d_exp[col-1][row-1];
                
                case (sum)
                    4'b0010: q_next[col][row] <= q_2d[col][row];
                    4'b0011: q_next[col][row] <= 1;
                    default: q_next[col][row] <= 0;
                endcase

这里的bug在于采用了非阻塞语句,那么每个for循环内的进程并行,最终sum永远等于最后一个3×3矩阵的和,在这里需要采用阻塞语句,才能保证每一个进入到case语句的sum为当前循环的值,切记!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值