题目
创建一组适合用作12小时时钟的计数器(带有上午/下午指示器)。你的计数器由一个快速运行的clk计时,每当你的时钟增加时(即每秒一次),ena上就会有一个脉冲。
reset将时钟重置为12:00 AM。AM的pm为0,pm为1。hh、mm和ss是两个BCD(二进制编码的十进制)数字,分别表示小时(01-12)、分钟(00-59)和秒(00-59。重置的优先级高于启用,即使未启用也可能发生重置。
以下时序图显示了从上午11:59:59到下午12:00:00的翻转行为以及同步重置和启用行为。
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.
思路
创建十进制和六进制模块
创建十进制和六进制模块,来计算mm和ss的个位和十位,hh的计算放在顶部模块里
module bcdcnt_l(
input clk,
input reset,
input ena,
output [3:0]q);
always @(posedge clk)
begin
if(reset) q= 4'h0;
else if (ena)
q <= (q == 4'h9) ? 4'h0 : q + 1;
else q <= q;
end
endmodule
module bcdcnt_h(
input clk,
input reset,
input ena,
output [3:0]q);
always @(posedge clk)
begin
if(reset) q = 4'h0;
else if (ena)
q <= (q == 4'h5) ? 4'h0 : q + 1;
else q <= q;
end
endmodule
assign语句,计算模块的使能位
wire ena_sh,ena_ml,ena_mh,ena_hl,ena_hh,am_pm_c;//定义导线
assign ena_sh = ena && (ss[3:0] == 4'h9);//秒个位使能位
assign ena_ml = ena && (ss[7:0] == 8'h59);//秒十位使能位
assign ena_mh = ena_ml && (mm[3:0] == 4'h9);//分钟个位使能位
assign ena_hl = ena_ml && (mm[7:0] == 8'h59);//分钟十位使能位
assign ena_hh = ena_hl && (hh[3:0] == 4'h9);//小时个位使能位
assign am_pm_c = ena_hl &&(hh[7:0] == 8'h11);//am,pm转换位,这个不知道为什么12点就变为下午了
子模块实例化
分别计算分、秒的个位和十位
bcdcnt_l s_cnt_l(clk, reset, ena, ss[3:0]);
bcdcnt_h s_cnt_h(clk, reset, ena_sh, ss[7:4]);
bcdcnt_l m_cnt_l(clk, reset, ena_ml, mm[3:0]);
bcdcnt_h m_cnt_h(clk, reset, ena_mh, mm[7:4]);
always块处理最复杂的小时位
always @(posedge clk)
begin
if(reset) begin
hh[7:0] <= 8'h12;
pm <= 0;
end
else if(ena_hl &&(hh[7:0] == 8'h12))
begin
hh[7:0] <= 8'h01;
end
else if(ena_hh) hh[7:0] <= 8'h10;
else if(ena_hl) hh <= hh + 1;
else hh <= hh;
if(am_pm_c)pm <= ~pm;
end
总的代码
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
wire ena_sh,ena_ml,ena_mh,ena_hl,ena_hh,am_pm_c;
assign ena_sh = ena && (ss[3:0] == 4'h9);
assign ena_ml = ena && (ss[7:0] == 8'h59);
assign ena_mh = ena_ml && (mm[3:0] == 4'h9);
assign ena_hl = ena_ml && (mm[7:0] == 8'h59);
assign ena_hh = ena_hl && (hh[3:0] == 4'h9);
assign am_pm_c = ena_hl &&(hh[7:0] == 8'h11);
bcdcnt_l s_cnt_l(clk, reset, ena, ss[3:0]);
bcdcnt_h s_cnt_h(clk, reset, ena_sh, ss[7:4]);
bcdcnt_l m_cnt_l(clk, reset, ena_ml, mm[3:0]);
bcdcnt_h m_cnt_h(clk, reset, ena_mh, mm[7:4]);
always @(posedge clk)
begin
if(reset) begin
hh[7:0] <= 8'h12;
pm <= 0;
end
else if(ena_hl &&(hh[7:0] == 8'h12))
begin
hh[7:0] <= 8'h01;
end
else if(ena_hh) hh[7:0] <= 8'h10;
else if(ena_hl) hh <= hh + 1;
else hh <= hh;
if(am_pm_c)pm <= ~pm;
end
endmodule
module bcdcnt_l(
input clk,
input reset,
input ena,
output [3:0]q);
always @(posedge clk)
begin
if(reset) q= 4'h0;
else if (ena)
q <= (q == 4'h9) ? 4'h0 : q + 1;
else q <= q;
end
endmodule
module bcdcnt_h(
input clk,
input reset,
input ena,
output [3:0]q);
always @(posedge clk)
begin
if(reset) q = 4'h0;
else if (ena)
q <= (q == 4'h5) ? 4'h0 : q + 1;
else q <= q;
end
endmodule
反思即错误总结
刚开始写的时候出来了重复赋值的错误提示,看了下确实我给hh向量赋值了很多次导致冲突。
改正方法是将这些给hh向量复制的语句放在always块下的一个if语句下面,根据优先级来给hh向量赋值。