题解 | #可置位计数器#
可置位计数器
https://www.nowcoder.com/practice/b96def986e29475e8100c213178b73a8
思路
这道题的思路很简单。就是一个简单的16进制计数器,如果计数到0则zero拉高。同时还带个置位功能,当set拉高时,计数器的输出值就是set_num的值。
但是仔细观察这道题的波形图,就会发现两个需要注意的地方:
- num从0开始计数。这里的意思是,当rst_n为高电平的第一个clk上升沿,num是0而不是1。
always @(posedge clk or negedge rst_n) begin if (!rst_n)number<=0; else begin number<=number+1; end end
如果我们像上面一样写代码,最开始rst_n为0时number为0,而当rst_n为1时的第一个clk上升沿,number会马上变成1。这显然不符合题意,因为题目要求rst_n为1后,number是从0计数的。
如何解决上面这个问题呢?很简单,如果按照我们上面的代码,我们会发现,正确的技术总是比上面的number慢一拍。也就是,上面代码的number延迟一拍就是我们想要的结果。so,一个D触发器就搞定了:
always @(posedge clk or negedge rst_n) begin if (!rst_n)num<=0; else begin if (set)num<=set_num; else num<=num+1; end end //把number延迟一个周期输出 always @(posedge clk or negedge rst_n) begin if (!rst_n)number<=0; else number<=num; end
- 再次观察波形图,发现,zero拉高是和number为0一起的。也就是zero拉高的这段时间,number恰好为0.如果按照下面的代码:
always @(posedge clk or negedge rst_n) begin if (!rst_n)zero<=0; else begin if (number==0)zero<=1; else zero<=0; end end
是不行的,按照上面的代码,zero为高的过程中number是为1的【不懂的小伙伴可以想想clk上升沿检测number是检测哪个时间的值】所以要想让zero为高的过程中number为1,就需要让zero提前一拍拉高。让zero提前一拍拉高,所以zero是否拉高检测的不是number,而是num,这样就能保证zero相对于number提前了一拍。
//zero信号变化 always @(posedge clk or negedge rst_n) begin if (!rst_n)zero<=0; else begin if (num==0)zero<=1; else zero<=0; end end
代码
完整代码如下:
`timescale 1ns/1ns module count_module( input clk, input rst_n, input set, input [3:0] set_num, output reg [3:0]number, output reg zero ); reg [3:0]num; //置位 always @(posedge clk or negedge rst_n) begin if (!rst_n)num<=0; else begin if (set)num<=set_num; else num<=num+1; end end //zero信号变化 always @(posedge clk or negedge rst_n) begin if (!rst_n)zero<=0; else begin if (num==0)zero<=1; else zero<=0; end end //把number延迟一个周期输出 always @(posedge clk or negedge rst_n) begin if (!rst_n)number<=0; else number<=num; end endmodule