[Verilog23]HDLBits习题_Counters

HDLBits习题讲解_Counters

Four-bit binary counter

  • 题目要求,构建一个从0到15的4位二进制计数器,周期为16。采用同步复位,复位时将计数器重置为0。代码如下:
module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q);

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

endmodule

Decade counter

  • 题目要求,构建一个从0到9(包括9)的十进制计数器,其周期为10。采用同步复位,复位时将计数器重置为0。代码如下:
module top_module (
    input clk,
    input reset,        // Synchronous active-high reset
    output [3:0] q);

    always @(posedge clk)begin
        if(reset)begin
            q<= 4'b0;
        end
        else begin
            q<= (q >= 4'd9)? 4'b0 : (q+1'b1);
        end
    end

endmodule

Decade counter again

  • 题目要求,构建一个从1到10的10进制计数器。采用同步复位,复位时将计数器重置为1。代码如下:
module top_module (
    input clk,
    input reset,
    output [3:0] q);

    always @(posedge clk)begin
        if(reset)begin
            q <= 4'b1;
        end
        else begin
            q <= (q>=4'd10) ? 1'b1 : (q+1'b1);
        end
    end
   
endmodule

Slow decade counter

  • 题目要求,构建一个从0到9(包括9)的十进制计数器,其周期为10。采用同步复位,复位时将计数器重置为0。要求可通过slowena输入引脚控制计数器的计数与停止。代码如下:
module top_module (
    input clk,
    input slowena,
    input reset,
    output [3:0] q);

    always @(posedge clk)begin
        if(reset)begin
            q <= 4'b0;
        end
        else if(slowena) begin
            q <= (q == 4'd9) ? 4'b0 : (q+1'b1);
        end
    end

endmodule

Counter 1-12

  • 题目要求,设计一个1-12计数器。采用同步复位,复位时将计数器重置为1。当使能信号为高时,计数器开始运行。采用时钟正边沿作为触发信号,Q为输出结果。c_enable、c_load、c_d[3:0]控制信号发送到提供的4位计数器。4位计数器代码如下:
module count4(
	input clk,
	input enable,
	input load,
	input [3:0] d,
	output reg [3:0] Q
);
  • 编写程序代码如下:
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 == 4'd12) && (enable == 1'b1));
    assign c_d = c_load ? 4'd1 : 4'd0;
    count4 o_count4 (
        .clk (clk),
        .enable (c_enable),
        .load(c_load),
        .d (c_d),
        .Q (Q)
    );

endmodule

Counter 1000

  • 题目要求,从一个1000Hz的时钟中,生成一个1Hz的时钟信号,还可从每个BCD计数器输出启用信号(c_enable[0]表示最快的计数器,c_enable[2]表示最慢的计数器)。使用模10-BCD计数器和尽可能少的其他门构建分频器。BCD计数器的代码如下:
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
); 
	
    wire[3:0] count[2:0];
    assign c_enable = {count[0] == 4'd9 && count[1] == 4'd9, count[0] == 4'd9, 1'b1};
    assign OneHertz = (count[0] == 4'd9 && count[1] == 4'd9 && count[2] == 4'd9);
    generate 
        genvar i;
        for(i=0; i<=2; i=i+1'b1)
        begin: counter
            bcdcount o_bcdcount(
                .clk (clk),
                .reset(reset),
                .enable(c_enable[i]),
                .Q(count[i])
            );
        end
    endgenerate

endmodule

4-digit decimal counter

  • 题目要求,构建一个4位BCD(二进制编码的十进制)计数器。每个十进制数字使用4位进行编码:q[3:0]是个位,q[7:4]是十位,以此类推。各进制上的进位时也需输出一个使能信号,指示三位数字何时应该增加。- 具体代码如下:
module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output [15:0] q);
    
    reg [3:0] ones, tens, hundreds, thousands;
    assign q = {thousands,hundreds,tens,ones};
    assign ena[1] = (ones == 4'd9) ? 1'b1 : 1'b0;
    assign ena[2] = (ena[1] && (tens == 4'd9)) ? 1'b1 : 1'b0;
    assign ena[3] = (ena[2] && (hundreds == 4'd9)) ? 1'b1 : 1'b0;
    always @(posedge clk) begin
        if(reset)begin
            ones <= 4'b0;
        end
        else begin
            ones <=(ena[1]) ? 4'b0 : (ones + 4'd1);
        end
    end
    always @(posedge clk)begin
        if(reset)begin
            tens <= 4'b0;
        end
        else begin
            tens <= (ena[2])? 4'b0 : (ena[1] ? tens + 4'd1 : tens);
        end
    end
    
    always @(posedge clk)begin
        if(reset)begin
            hundreds <= 4'b0;
        end
        else begin
            hundreds <=ena[3] ? 4'b0 : (ena[2] ? hundreds + 4'd1 : hundreds);
        end
    end
    
    always @(posedge clk)begin
        if(reset)begin
            thousands <= 4'b0;
        end
        else begin
            thousands <=(thousands == 4'd9 && ena[3]) ? 4'b0 :(ena[3] ? thousands + 4'd1 : thousands);
        end
    end

endmodule

12-hour clock

  • 题目要求,创建一组适合作为12小时的时钟使用的计数器(带有am/pm指示器)。计数器是由一个快速运行的clk驱动,每次时钟增加时ena必须为1。reset将时钟重置到中午12点。上午时pm=0,下午时pm=0。hh,mm和ss分别是小时(01-12)、分钟(00-59)和秒(00-59)的两个BCD(二进制编码的十进制)数字。Reset比enable具有更高的优先级,并且即使在没有启用时也会发生。上图显示了从11:59:59 AM到12:00:00 PM的翻转行为以及同步的Reset和enable行为。
  • 具体代码如下:
module top_module(
    input clk,
    input reset,
    input ena,
    output pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 
    
    reg pm_temp;
    reg [3:0] ss_ones;
    reg [3:0] ss_tens;
    reg [3:0] mm_ones;
    reg [3:0] mm_tens;
    reg [3:0] hh_ones;
    reg [3:0] hh_tens;
    
    wire		add_ss_ones;
    wire		end_ss_ones;
    wire		add_ss_tens;
    wire		end_ss_tens;
    wire		add_mm_ones;
    wire		end_mm_ones;
    wire		add_mm_tens;
    wire		end_mm_tens;
    wire		add_hh_ones;
    wire		end_hh_ones_0;
    wire		end_hh_ones_1;
    wire		add_hh_tens;
    wire		end_hh_tens_0;
    wire		end_hh_tens_1;
    wire		pm_ding;
    
    assign add_ss_ones = ena;
    assign end_ss_ones = add_ss_ones && (ss_ones == 4'd9);
    always @(posedge clk)begin
        if(reset)begin
            ss_ones <= 4'b0;
        end
        else if(add_ss_ones)begin
            if(end_ss_ones)begin
                ss_ones <= 4'b0;
            end
            else begin
                ss_ones <= ss_ones + 4'b1;
            end
        end
    end
    
    assign add_ss_tens = end_ss_ones;
    assign end_ss_tens = add_ss_tens && (ss_tens == 4'd5);
    always @(posedge clk)begin
        if(reset)begin
            ss_tens <= 4'b0;
        end
        else if(add_ss_tens)begin
            if(end_ss_tens)begin
                ss_tens <= 4'b0;
            end
            else begin
                ss_tens <= ss_tens + 4'b1;
            end
        end
    end
    
    assign add_mm_ones = end_ss_tens;
    assign end_mm_ones = add_mm_ones && (mm_ones == 4'd9);
    always @(posedge clk)begin
        if(reset)begin
            mm_ones <= 4'b0;
        end
        else if(add_mm_ones)begin
            if(end_mm_ones)begin
                mm_ones <= 4'b0;
            end
            else begin
                mm_ones <= mm_ones + 4'b1;
            end
        end
    end
    
    assign add_mm_tens = end_mm_ones;
    assign end_mm_tens = add_mm_tens && (mm_tens == 4'd5);
	always @(posedge clk)begin
        if(reset)begin
            mm_tens <= 4'b0;
        end
        else if(add_mm_tens)begin
            if(end_mm_tens)begin
                mm_tens <= 4'b0;
            end
            else begin
                mm_tens <= mm_tens + 4'b1;
            end
        end
    end
    
    assign add_hh_ones = end_mm_tens;
    assign end_hh_ones_0 = add_hh_ones && (hh_ones == 4'd9);
    assign end_hh_ones_1 = add_hh_ones && ((hh_ones == 4'd2) && (hh_tens == 4'd1));
    always @(posedge clk)begin
        if(reset)begin
            hh_ones <= 4'd2;
        end
        else if(add_hh_ones)begin
            if(end_hh_ones_0)begin
                hh_ones <= 4'b0;
            end
            else if(end_hh_ones_1)begin
                hh_ones <= 4'b1;
            end
            else begin
                hh_ones <= hh_ones+4'b1;
            end
        end
    end

    assign add_hh_tens = end_mm_tens;
    assign end_hh_tens_0 = add_hh_tens && end_hh_ones_1;
    assign end_hh_tens_1 = add_hh_tens && end_hh_ones_0;
    always @(posedge clk)begin
        if(reset)begin
            hh_tens <= 4'b1;
        end
        else if(add_hh_tens)begin
            if(end_hh_tens_0)begin
                hh_tens <= 4'b0;
            end
            else if(end_hh_tens_1)begin
                hh_tens <= hh_tens + 4'b1;
            end
        end
    end
    
    always@(posedge clk)begin
        if(reset)begin
            pm_temp <= 1'b0;
        end
        else if(pm_ding)begin
            pm_temp <= ~pm_temp;
        end
    end
    
    assign pm_ding = hh_tens == 4'd1 && hh_ones == 4'd1 && end_mm_tens;
    
    assign ss = {ss_tens, ss_ones};
    assign mm = {mm_tens, mm_ones};
    assign hh = {hh_tens, hh_ones};
    assign pm = pm_temp;
    
endmodule

参考:
HDLBits
HDLBits答案(11)_Verilog计数器