题目要求:建立一个 4 位 BCD(二进制编码十进制)计数器。每一位十进制数字用 4 位编码:q[3:0] 用于表示个位数字,q[7:4] 用于表示十位数字,以此类推。对于十百千这三位,还需要输出一个使能信号ena[1]、ena[2]、ena[3],指示上三位中的每一位何时递增。
下面是我第一次写的错误代码。问题出在对于时序逻辑掌握不到位,以个位代码的编写为例,else if语句中,当个位数等于9即q[3:0] == 4'd9时,ena[1]没有立刻被赋值为1,这是因为时序逻辑,需要等待下一个时钟上升沿到来,ena[1] 的值才会被更新。
故下面的代码中,个位数为9时,ena[1]为0;下一个时钟上升沿到来,个位数变为0,ena[1]为1;再下一个时钟上升沿时,十位数才会进行加1操作,此时个位数为1,ena[1]为0;故编译出的结果不满足题目要求。
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:1] ena,
output [15:0] q);
//个位
always @(posedge clk) begin
if(reset) begin
q[3:0] <= 4'd0;
end
else if(q[3:0] == 4'd9) begin
q[3:0] <= 4'd0 ;
ena[1] <= 1'b1 ;
end
else begin
q[3:0] <= q[3:0] + 1'b1 ;
end
end
//十位:ena[1]为1时计数加1,加到9时置为0
always @(posedge clk) begin
if(reset) begin
q[7:4] <= 4'd0;
end
else if (ena[1])begin
if(q[7:4] == 4'd9 ) begin
ena[2] <= 1'b1 ;
q[7:4] <= 4'd0 ;
end
else begin
q[7:4] <= q[7:4] + 1'b1 ;
end
end
end
//百位:ena[2]为1时计数加1,加到9时置为0
always @(posedge clk) begin
if(reset) begin
q[11:8] <= 4'd0;
end
else if (ena[2])begin
if(q[11:8] == 4'd9) begin
ena[3] <= 1'b1 ;
q[11:8] <= 4'd0 ;
end
else begin
q[11:8] <= q[11:8] + 1'b1 ;
end
end
end
//千位:ena[3]为1时计数加1,加到9时置为0
always @(posedge clk) begin
if(reset) begin
q[15:12] <= 4'd0;
end
else if (ena[3])begin
if(q[15:12] == 4'd9) begin
q[15:12] <= 4'd0 ;
end
else begin
q[15:12] <= q[15:12] + 1'b1 ;
end
end
end
endmodule
下面是修改之后的代码。使用组合逻辑为ena赋值,则不存在延后一个时钟沿的问题。
修改后的代码中,仍然以个位为例,当个位数q[3:0]计数到9时,ena[1]同步被赋值为1,故下一个时钟沿到来时,个位数被置为0,十位数进行加一操作,同时ena[1]又重新更新为0。
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:1] ena,
output [15:0] q);
//个位
always @(posedge clk) begin
if(reset) begin
q[3:0] <= 4'd0;
end
else if(q[3:0] == 4'd9) begin
q[3:0] <= 4'd0 ;
//ena[1] <= 1'b1 ;
end
else begin
q[3:0] <= q[3:0] + 1'b1 ;
end
end
assign ena[1] = (q[3:0] == 4'd9)? 1'b1:1'b0 ;
//十位:ena[1]为1时计数加1,加到9时置为0
always @(posedge clk) begin
if(reset) begin
q[7:4] <= 4'd0;
end
else if (ena[1])begin
if(q[7:4] == 4'd9 ) begin
//ena[2] <= 1'b1 ;
q[7:4] <= 4'd0 ;
end
else begin
q[7:4] <= q[7:4] + 1'b1 ;
end
end
end
assign ena[2] = (q[7:4] == 4'd9 && ena[1])? 1'b1:1'b0 ;
//百位:ena[2]为1时计数加1,加到9时置为0
always @(posedge clk) begin
if(reset) begin
q[11:8] <= 4'd0;
end
else if (ena[2])begin
if(q[11:8] == 4'd9) begin
//ena[3] <= 1'b1 ;
q[11:8] <= 4'd0 ;
end
else begin
q[11:8] <= q[11:8] + 1'b1 ;
end
end
end
assign ena[3] = (q[11:8] == 4'd9 && ena[2])? 1'b1:1'b0 ;
//千位:ena[3]为1时计数加1,加到9时置为0
always @(posedge clk) begin
if(reset) begin
q[15:12] <= 4'd0;
end
else if (ena[3])begin
if(q[15:12] == 4'd9) begin
q[15:12] <= 4'd0 ;
end
else begin
q[15:12] <= q[15:12] + 1'b1 ;
end
end
end
endmodule