HDLbits刷题记录-一个关于非阻塞赋值的问题

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.

在这里插入图片描述
参考了知乎一个大佬的代码(侵删):
https://zhuanlan.zhihu.com/p/128621408

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

    //例化计数器表示秒
    wire ssl_2_ssh,ssh_2_mml;   //地位向高位进位
    cnt cnt_ssl(.clk(clk),.reset(reset),.count_start(ena),.count_end(4'd9),
                .end_cnt(ssl_2_ssh),.count(ss[3:0]));
    cnt cnt_ssh(.clk(clk),.reset(reset),.count_start(ssl_2_ssh),.count_end(4'd5),
                .end_cnt(ssh_2_mml),.count(ss[7:4]));
   
    //例化计数器表示分钟
    wire mml_2_mmh, mmh_2_hh;
    cnt cnt_mml(.clk(clk),.reset(reset),.count_start(ssh_2_mml),
                .count_end(4'd9),.end_cnt(mml_2_mmh),.count(mm[3:0]));
    cnt cnt_mmh(.clk(clk),.reset(reset),.count_start(mml_2_mmh),
                .count_end(4'd5),.end_cnt(mmh_2_hh),.count(mm[7:4]));
    
    //小时计数
    reg a_2_p;
    always @(posedge clk)begin
        if(reset)begin
            a_2_p <= 0;
            hh <= 8'h12;        // 初始条件 12:00:00 AM
        end
        else if(mmh_2_hh)begin
            if(hh == 8'h12)
                hh <= 8'h01;
            else begin
                hh <= hh + 1'b1;
                if(hh == 8'h9)
                    hh <= 8'h10;
                if(hh == 8'h11)
                    a_2_p <= ~ a_2_p;
            end
        end
    end
    assign pm = a_2_p;
endmodule

//计数器子模块,可以设置开始和结束条件
module cnt(
    input clk,
    input reset,
    input count_start,     //开始计数输入
    input [3:0] count_end, //计数到多少停止计数
    output end_cnt,        //一次计数完成标志
    output [3:0] count);
 
    wire add_cnt;
    always @(posedge clk)begin
        if(reset)begin
           count <= 4'd0; 
        end
        else if(add_cnt)begin
            if(end_cnt)
                count <= 4'd0;
            else
                count <= count + 1'b1;
        end
    end
    assign add_cnt = count_start;   //计数开始条件,当满足了开始计数
    assign end_cnt = add_cnt && (count == count_end);    //计数结束产生一个标志
endmodule

首先我觉得这个计数器写的很不错,收藏一下以后可以直接用。
这里我在看代码的时候有两个地方不理解:
①为什么计数器模块的结束时间为5,不是6。如果是5的话,难道50~59就不记了吗?
②在时模块里,有一个部分就更看不懂了:

if(hh == 8'h9)
        hh <= 8'h10;

为啥在9的时候就直接跳到10了?第九个小时不记录了吗?很迷。

针对第一个问题,我把结束标识设为了4’d6,针对把第二个问题把判断条件改为了 8’ha,都不正确。最后我想明白了,这是非阻塞赋值语句的原因,即变量的是不会因为赋值而立马改变的,而是所有语句执行完了后,一起改变。所以第一个问题,就应设置为5,模块会以此记录50~59,在所有的语句执行完了后,发现十位是5,然后重置计数器。如果设置为6的话,那模块就会记60-69,肯定就错了。

针对第二个问题,也是一样的。hh到了8’h9,模块依次记录第九个小时,然后计数执行完了后,所有变量的值一起改变,hh变到了8‘h10。

这样一跑所有的程序就通了,记录一下,如果有写错的地方欢迎纠正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值