HDLBits刷题笔记9:Circuits.Sequential Logic.Counters + Shift Registers

文章详细描述了使用Verilog语言设计的各种计数器,包括二进制计数器、十进制计数器、慢速计数器、4位BCD计数器以及12小时制时钟的实现。此外,还涵盖了不同类型的移位寄存器,如4位移位寄存器、循环左/右移寄存器和算术移位寄存器。同时,还讨论了线性反馈移位寄存器(LFSR)的5位和32位实现。
摘要由CSDN通过智能技术生成

Counters

Four-bit binary counter

module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output reg [3:0] q);
    always @(posedge clk) begin
        if(reset)
            q <= 0;
        else
            q <= q + 1;
    end
endmodule

Decade counter

建立一个计数器,从0计数到9

module top_module (
    input clk,
    input reset,        // Synchronous active-high reset
    output reg [3:0] q);
    always @(posedge clk) begin
        if(reset)
            q <= 0;
        else if(q == 9)
            q <= 0;
        else
            q <= q + 1;
    end
endmodule

Decade counter again

建立一个计数器,从1计数到10

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

Slow decade counter

建立一个计数器,从0计数到9,带使能

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

Counter 1-12

提供一个4bit的计数器,接口如下:

module count4(
    input clk,
    input enable,
    input load,
    input [3:0] d,
    output reg [3:0] Q
);

用这个模块实现一个计数器,从1计数到12,并输出上面模块的enable、load、d

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;
    assign c_load = reset | (Q == 12 & enable);
    assign c_d = 4'h1;
    
    count4 the_counter (clk, c_enable, c_load, c_d, Q);
endmodule

Counter 1000

提供一个BCD计数器模块,接口如下

module bcdcount (
    input clk,
    input reset,
    input enable,
    output reg [3:0] Q
);

输入1000hz的时钟,使用该模块输出1hz信号,保证每秒该信号只有一个时钟周期高电平,并输出每个BCD计数器的使能

module top_module (
    input clk,
    input reset,
    output OneHertz,
    output [2:0] c_enable
); //
    wire [3:0] bcd0, bcd1, bcd2;
    assign c_enable[0] = 1'b1;
    assign c_enable[1] = bcd0 == 9;
    assign c_enable[2] = c_enable[1] & bcd1 == 9;
    
    bcdcount counter0 (clk, reset, c_enable[0], bcd0);
    bcdcount counter1 (clk, reset, c_enable[1], bcd1);
    bcdcount counter2 (clk, reset, c_enable[2], bcd2);
    
    assign OneHertz = c_enable[2] & bcd2 == 9;
endmodule

4-digit decimal counter

建立一个四位数的bcd计数器,并输出十位、百位、千位的使能

module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output [15:0] q);
    assign ena[1] = q[3:0] == 9;
    assign ena[2] = ena[1] & q[7:4] == 9;
    assign ena[3] = ena[2] & q[11:8] == 9;
    
    bcd_counter u0(clk, reset, 1'b1, q[3:0]);
    bcd_counter u1(clk, reset, ena[1], q[7:4]);
    bcd_counter u2(clk, reset, ena[2], q[11:8]);
    bcd_counter u3(clk, reset, ena[3], q[15:12]);
endmodule

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

12-hour-clock

建立一个12小时制的时钟,带一个am/pm指示器,复位将时钟设定为12:00AM,指示器pm为0时,表示AM,为1时,表示PM。

注意:11点过后为12:00,而不是0:00

下面波形展示了从11:59:59AM翻转到12:00:00PM和复位的波形。

在这里插入图片描述

解题思路:

秒、分的计时范围为00-59,用bcd计数器实现,个位数计数范围为0-9,直接用bcd计数器即可,十位数计数范围0-5,需要在溢出时用reset清零

时钟的计时范围为01-12,不太好用bcd计数器实现,所以单独写always解决

pm只需在11点跳转到12点时翻转即可

module top_module(
    input clk,
    input reset,
    input ena,
    output reg pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 
    
    wire [1:0] h_ena, m_ena, s_ena;
    
    assign s_ena[0] = ena;
    assign s_ena[1] = s_ena[0] & ss[3:0] == 9;
    assign m_ena[0] = s_ena[1] & ss[7:4] == 5;
    assign m_ena[1] = m_ena[0] & mm[3:0] == 9;
    assign h_ena[0] = m_ena[1] & mm[7:4] == 5;
    assign h_ena[1] = h_ena[0] & (hh == 8'h09 || hh == 8'h12);
    
    bcd_counter s0(clk, reset, s_ena[0], ss[3:0]);
    bcd_counter s1(clk, reset | m_ena[0], s_ena[1], ss[7:4]);
    bcd_counter m0(clk, reset, m_ena[0], mm[3:0]);
    bcd_counter m1(clk, reset | h_ena[0], m_ena[1], mm[7:4]);
    
    // h0
    always @(posedge clk) begin
        if(reset)
            hh[3:0] <= 2;
        else if(h_ena[0]) begin
            if(hh == 8'h12)
                hh[3:0] <= 1;
            else if(hh == 8'h09)
                hh[3:0] <= 0;
            else
                hh[3:0] <= hh[3:0] + 1;
        end
    end
    
    // h1
    always @(posedge clk) begin
        if(reset)
            hh[4] <= 1;
        else if(h_ena[1])
            hh[4] <= ~hh[4];
    end
    
    // pm
    always @(posedge clk) begin
        if(reset)
            pm <= 0;
        else if(h_ena[0] && hh == 8'h11)
            pm <= ~pm;
    end
endmodule

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

Shift Registers

4-bit shift register

建立一个4bit的移位寄存器,右移,带异步复位、load、ena

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); 
    always @(posedge clk, posedge areset) begin
        if(areset)
            q <= 0;
        else if(load)
            q <= data;
        else if(ena)
            q <= {1'b0, q[3:1]};
    end
endmodule

Left/right rotator

建立一个循环左移/右移寄存器,带load、移位使能,当ena为2'b01时右移,当ena为2'b10时左移,其他情况不移位

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)
            q <= data;
        else if(ena == 2'b01) // right
            q <= {q[0], q[99:1]};
        else if(ena == 2'b10) // left
            q <= {q[98:0], q[99]};
    end
endmodule

Left/right arithmetic shift by 1 or 8

建立一个64bit的算数移位寄存器,带load,该移位寄存器可以左移、右移1bit或8bit,算数右移时,左侧填充的是符号位,而不是0。左移时和逻辑左移没有区别,移位方向、移位多少是有amount决定的:

  • 2’b00: 左移1bit
  • 2’b01: 左移8bit
  • 2’b10: 右移1bit
  • 2’b11: 右移8bit
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)
            q <= data;
        else if(ena) begin
            case(amount)
                2'b00: q <= {q[62:0], 1'b0};
                2'b01: q <= {q[55:0], 8'h00};
                2'b10: q <= {q[63], q[63:1]};
                2'b11: q <= {{8{q[63]}}, q[63:8]};
            endcase
        end
    end
endmodule

5-bit LFSR

LFSR: (linear feedback shift register),线性反馈移位寄存器,通常有几个异或门来产生移位寄存器的下一个状态。实现如下图所示的5bit位宽LFSR,其在5和3位置处添加了taps(tap即表示该寄存器D端和q[0]进行异或,tap位置从1开始):

在这里插入图片描述

module top_module(
    input clk,
    input reset,    // Active-high synchronous reset to 5'h1
    output reg [4:0] q
); 
    always @(posedge clk) begin
        if(reset)
            q <= 5'h1;
        else
            q <= {q[0], q[4], q[3] ^ q[0], q[2:1]};
    end
endmodule

3-bit LFSR

实现如下电路:

在这里插入图片描述

module top_module (
	input [2:0] SW,      // R
	input [1:0] KEY,     // L and clk
    output reg [2:0] LEDR);  // Q
    always @(posedge KEY[0]) begin
        LEDR[0] <= KEY[1] ? SW[0] : LEDR[2];
        LEDR[1] <= KEY[1] ? SW[1] : LEDR[0];
        LEDR[2] <= KEY[1] ? SW[2] : (LEDR[1] ^ LEDR[2]);
    end
endmodule

32-bit LFSR

实现一个32bit的LFSR,在第32、22、2、1位置添加taps,参考5-bit LFSR题目

module top_module(
    input clk,
    input reset,    // Active-high synchronous reset to 32'h1
    output reg [31:0] q
); 
    always @(posedge clk) begin
        if(reset)
            q <= 32'h1;
        else
            q <= {q[0], q[31:23], q[0] ^ q[22], q[21:3], q[0] ^ q[2], q[0] ^ q[1]};
    end
endmodule

Shift register

实现如下电路:

在这里插入图片描述

module top_module (
    input clk,
    input resetn,   // synchronous reset
    input in,
    output out);
    reg [3:0] taps;
    always @(posedge clk) begin
        if(~resetn)
            taps <= 0;
        else
            taps <= {in, taps[3:1]};
    end
    assign out = taps[0];
endmodule

Shift register

如下为n-bit的Shift Register:

在这里插入图片描述

编写一个模块实现上述电路,假设n=4,编写MUXDFF模块,在顶层实例化4个MUXDFF子模块,假设你要在DE2开发板上实现,端口对应如下:

  • R to SW
  • clk to KEY[0]
  • E to KEY[1]
  • L to KEY[2] and
  • w to KEY[3]
  • Q to LEDR
module top_module (
    input [3:0] SW,
    input [3:0] KEY,
    output [3:0] LEDR
); //
    MUXDFF u0(KEY[0], KEY[1], SW[0], KEY[2], LEDR[1], LEDR[0]);
    MUXDFF u1(KEY[0], KEY[1], SW[1], KEY[2], LEDR[2], LEDR[1]);
    MUXDFF u2(KEY[0], KEY[1], SW[2], KEY[2], LEDR[3], LEDR[2]);
    MUXDFF u3(KEY[0], KEY[1], SW[3], KEY[2], KEY[3], LEDR[3]);
endmodule

module MUXDFF (
	input clk,
    input E,
    input R,
    input L,
    input W,
    output reg Q
);
    always @(posedge clk) begin
        Q <= L ? R : (E ? W : Q);
    end
endmodule
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值