HDL刷题:Count clock

发布时间 2023-08-09 09:39:44作者: Xxaj5

原题链接

要写一个12小时的时钟。

由题目得知,reset信号的优先级最高,其次是enable,这里很好实现。

我的思路:
写了一个4位的bcd计数器,并实例化了4个,对ss与mm的[7:4]与[3:0]分别考虑,低位到8就可以进行发送进位信号即可,高位加1;

hh有两个临界点,11:59:59->12:00:00与12:59:59->1:00:00,其他就是一个8位bcd计数器了;

pm只有在hh11:59:59->12:00:00时进行反转即可,其他时间保持。

还有就是要注意细节了。

代码

module bcd_count
#(
    parameter MOD = 4'd9,
    parameter RESET_VAL = 4'd0
)
(
    input clk,
    input reset,
    input ena,
    input c_in,

    output reg[3:0]q
);
    always @(posedge clk) begin
        if (reset == 1'b1)
            q <= RESET_VAL;
        else if (ena == 1'b1 && c_in == 1'b1) begin
            if (q == MOD)
                q <= RESET_VAL;
            else
                q <= q + 4'd1;
        end
        else
            q <= q;
    end
endmodule

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

    reg c_in_qss_high;
    reg c_in_qmm_low, c_in_qmm_high;
    
    always @(posedge clk) begin
        if (reset == 1'b1) begin
            pm <= 1'b0;
            hh <= 8'b0001_0010;
            c_in_qss_high <= 1'b0;
            c_in_qmm_low <= 1'b0;
            c_in_qmm_high <= 1'b0;
        end
        else if (ena == 1'b1) begin
            if (ss[3:0] == 4'd8) 
                c_in_qss_high <= 1'b1;
            else
                c_in_qss_high <= 1'b0;       

            if (ss[7:4] == 4'd5 && ss[3:0] == 4'd8)
                c_in_qmm_low <= 1'b1;
            else
                c_in_qmm_low <= 1'b0;

            if (mm[3:0] == 4'd9 && ss[7:4] == 4'd5 && ss[3:0] == 4'd8) 
                c_in_qmm_high <= 1'b1;
            else
                c_in_qmm_high <= 1'b0;

            if (mm[7:4] == 4'd5 && mm[3:0] == 4'd9 && ss[7:4] == 4'd5 && ss[3:0] == 4'd9) begin
                if (hh == 8'b0001_0001) begin //11:59:59
                    pm <= ~pm;
                    hh <= 8'b0001_0010;
                end
                else if (hh == 8'b0001_0010) begin //12:59:59
                    pm <= pm;
                    hh <= 8'b0000_0001;
                end
                else begin
                    pm <= pm;
                    if (hh == 8'b0000_1001) //bcd:9
                        hh <= 8'b0001_0000; //->bcd:10
                    else if (hh == 8'b0001_0000) //bcd:10
                        hh <= 8'b0001_0001; //->bcd11
                    else if (hh == 8'b0001_0001) //bcd:11
                        hh <= 8'b0001_0010; //->bcd12
                    else
                        hh <= hh + 8'b0000_0001;
                end
            end
        end   
        else begin
            c_in_qss_high <= c_in_qss_high;
            c_in_qmm_low <= c_in_qmm_low;
            c_in_qmm_high <= c_in_qmm_high;
            pm <= pm;
            hh <= hh;
        end
    end

    //ss
    bcd_count 
    #(
        .MOD(4'd9),
        .RESET_VAL(4'd0)
    ) bcd_count_inst0
    (   
        .clk(clk), 
        .reset(reset), 
        .ena(ena), 
        .c_in(1'b1), 
        .q(ss[3:0])
    );
    
    bcd_count 
    #(
        .MOD(4'd5),
        .RESET_VAL(4'd0)
    )bcd_count_inst1
    (
        .clk(clk), 
        .reset(reset), 
        .ena(ena), 
        .c_in(c_in_qss_high), 
        .q(ss[7:4])
    );

    //mm
    bcd_count 
    #(
        .MOD(4'd9),
        .RESET_VAL(4'd0)
    )bcd_count_inst2
    (
        .clk(clk), 
        .reset(reset), 
        .ena(ena), 
        .c_in(c_in_qmm_low), 
        .q(mm[3:0])
    );

    bcd_count 
    #(
        .MOD(4'd5),
        .RESET_VAL(4'd0)
    )bcd_count_inst3
    (
        .clk(clk), 
        .reset(reset), 
        .ena(ena), 
        .c_in(c_in_qmm_high), 
        .q(mm[7:4])
    );

endmodule