HDLBits的Count clock问题总结
创始人
2024-06-02 01:41:44
  • 模块化设计思想

这是HDLBits的电路->时序逻辑->计数器问题的压轴大题,如果没有从头开始刷起,直接刷12-hour clock对我这种初学者来说是非常吃力的。从这可以看出HDLBits网站出题人的用心良苦,他想告诉我们硬件初学者的是对于复杂的问题不要害怕,复杂的问题是由一个一个简单的小问题组成的,要有将复杂大问题(module)分解成一个一个简单小问题(sub-module)的能力。

对计数器这一章的8个问题从头到尾捋一遍,便于我们理解模块化设计思想。

Four-bit binary counter:

Build a 4-bit binary counter that counts from 0 through 15, inclusive, with a period of 16. The reset input is synchronous, and should reset the counter to 0.重点是从0计数到15,并且是同步复位。

module top_module (input clk,input reset,      // Synchronous active-high resetoutput [3:0] q);always@(posedge clk) beginif(reset)q<=0;elseq<=q+1;end
endmodule

Decade counter:

Build a decade counter that counts from 0 through 9, inclusive, with a period of 10. The reset input is synchronous, and should reset the counter to 0.与上一个问题不同的是计数器是从0计数到9,是人们熟悉的10进制计数法。

module top_module(input clk,input reset,output reg [3:0] q);always @(posedge clk)if (reset || q == 9)    // Count to 10 requires rolling over 9->0 instead of the more natural 15->0q <= 0;elseq <= q+1;endmodule

Decade counter again:

Make a decade counter that counts 1 through 10, inclusive. The reset input is synchronous, and should reset the counter to 1.与上一个不同的是从1计数到10,更符合常理的计数。

module top_module (input clk,input reset,output [3:0] q);always@(posedge clk) beginif(reset | q == 10)q<=1;elseq<=q+1;end
endmodule

Slow decade counter:

Build a decade counter that counts from 0 through 9, inclusive, with a period of 10. The reset input is synchronous, and should reset the counter to 0. We want to be able to pause the counter rather than always incrementing every clock cycle, so the slowena input indicates when the counter should increment.个人任务这个例题是这几个例题中最重要的,也充分展现了使能信号的妙用,学校里教的使我们感觉使能信号是一个很鸡肋的信号,这个例题以及后面的例题会告诉我们使能信号是整个计数时钟的连接枢纽,是整个时钟系统最重要的信号。使用使能信号可以改变计数的快慢,这点与时针分针秒针的计数快慢相联系。因为我们不可能去生成不同频率的时钟信号来实现计数的快慢——这样就不是同步电路了。使能信号就是控制信号,而控制信号才是电路的核心信号。

module top_module (input clk,input slowena,input reset,output [3:0] q);always@(posedge clk) beginif(reset)q<=0;else if(slowena)if(q == 9) q<=0;elseq<=q+1;else q<=q;end
endmodule

Counter 1-12:

The c_enable, c_load, and c_d outputs are the signals that go to the internal counter's enable, load, and d inputs, respectively. Their purpose is to allow these signals to be checked for correctness.该例题为ece241题,主要引入模块化设计思想和三个check信号:使能、装载(包含reset的功能)、和提示一轮计数完成的信号。我在实现Count Clock的时候并没有使用load和d去验证计数的正确性,这是可以改进的一个点。

module top_module (input clk,input reset,input enable,output [3:0] Q,output c_enable,output c_load,output [3:0] c_d
); //assign c_enable = enable;assign c_load = (reset|(Q==4'd12&enable))?1'b1:1'b0;assign c_d = c_load?4'd1:Q;count4 the_counter (clk, c_enable, c_load, c_d, Q);endmodulemodule count4(input clk,input enable,input load,input [3:0] d,output reg [3:0] Q
);

Counter 1000:

将1000HZ通过三个级联的十计数器生成1HZ的信号,这个例题其实是很关键的,很类似Count Clock例题。完成该例题的关键就在于级联的enable信号的设置。

module top_module (input clk,input reset,output OneHertz,output [2:0] c_enable
); //reg [3:0] Q0,Q1,Q2;assign c_enable[0] = 1'b1;assign c_enable[1] = Q0 == 4'd9;assign c_enable[2] = Q1 == 4'd9 && Q0 == 4'd9;assign OneHertz = Q2 == 4'd9 && Q1 == 4'd9 && Q0 == 4'd9;bcdcount counter0 (clk, reset, c_enable[0],Q0);bcdcount counter1 (clk, reset, c_enable[1],Q1);bcdcount counter2 (clk, reset, c_enable[2],Q2);
endmodule

4-digit decimal counter:

Build a 4-digit BCD (binary-coded decimal) counter. Each decimal digit is encoded using 4 bits: q[3:0] is the ones digit, q[7:4] is the tens digit, etc. For digits [3:1], also output an enable signal indicating when each of the upper three digits should be incremented.该例题主要展示如何用十进制显示数字,为Count Clock铺垫。主要还是enable信号发挥了关键性的作用。

module top_module (input clk,input reset,   // Synchronous active-high resetoutput [3:1] ena,output [15:0] q);assign ena[1] = q[3:0] == 9;assign ena[2] = q[3:0] == 9 && q[7:4] == 9;assign ena[3] = q[3:0] == 9 && q[7:4] == 9 && q[11:8] == 9;decade_counters d1(clk,1,reset,q[3:0]);decade_counters d2(clk,ena[1],reset,q[7:4]);decade_counters d3(clk,ena[2],reset,q[11:8]);decade_counters d4(clk,ena[3],reset,q[15:12]);
endmodulemodule decade_counters (input clk,input slowena,input reset,output [3:0] q);always@(posedge clk) beginif(reset)q<=0;else if(slowena)if(q == 9) q<=0;elseq<=q+1;else q<=q;end
endmodule

Count clock:

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.

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_m,ena_h;reg pm_reg = 0;assign pm = pm_reg;assign ena_m = (ss[3:0] == 4'd9 && ss[7:4] == 4'd5);assign ena_h = (mm[3:0] == 4'd9 && mm[7:4] == 4'd5) && (ss[3:0] == 4'd9 && ss[7:4] == 4'd5);always@(posedge clk) beginif((hh[3:0] == 1 && hh[7:4] == 1)&&(mm[3:0] == 9 && mm[7:4] == 5) && (ss[3:0] == 9 && ss[7:4] == 5))pm_reg = ~pm_reg;elsepm_reg = pm_reg;endms_counters sc(clk,ena,reset,ss);ms_counters mc(clk,ena_m,reset,mm);cnt_counters_h hc(clk,ena_h,reset,hh);endmodulemodule ms_counters (input clk,input ena,input reset,output [7:0] q);wire ena_g;assign ena_g = q[3:0] == 4'd9 & ena;cnt_counters d1(clk,ena,reset,4'd9,q[3:0]);cnt_counters d2(clk,ena_g,reset,4'd5,q[7:4]);
endmodulemodule cnt_counters (input clk,input ena,input reset,input [3:0] cnt,output [3:0] q);reg [3:0] q_reg;assign q = q_reg;always@(posedge clk) beginif(reset)q_reg<=4'd0;else if(ena)if(q_reg == cnt) q_reg<=4'd0;elseq_reg<=q_reg+1;else q_reg<=q_reg;end
endmodulemodule cnt_counters_h (input clk,input ena,input reset,output [7:0] q_out);reg [7:0] q;assign q_out = q;always@(posedge clk) beginif(reset) beginq[3:0]<=4'd2;q[7:4]<=4'd1;endelse if(ena) beginif(q[3:0] == 4'd2 && q[7:4] == 4'd1) begin q[3:0]<=4'd1;q[7:4]<=4'd0;end else if(q[3:0] == 4'd9 && q[7:4] == 4'd0) begin q[3:0]<=4'd0;q[7:4]<=4'd1;endelse beginq[3:0]<=q[3:0]+4'd1;q[7:4]<=q[7:4];endendelse begin q[3:0]<=q[3:0];q[7:4]<=q[7:4];endend
endmodule

注意以上代码的39行,一开始是assign ena_g = q[3:0] == 4'd9;会导致如下的波形错误:

test bench代码:

`timescale 1ns / 1nsmodule top_tb;
parameter PERIOD  = 10;// top_module Inputs
reg   clk                                  = 0 ;
reg   reset                                = 1 ;
reg   ena                                  = 1 ;// top_module Outputs
wire  pm                                   ;    
wire  [7:0]  hh                            ;    
wire  [7:0]  mm                            ;    
wire  [7:0]  ss                            ;    initial
beginforever #(PERIOD/2)  clk=~clk;
endinitial
begin#(PERIOD*2) reset  =  0;#(PERIOD*4) reset  =  1;#(PERIOD*2) reset  =  0;
endtop_module  u_top_module (.clk                     ( clk          ),  .reset                   ( reset        ),  .ena                     ( ena          ),  .pm                      ( pm           ),  .hh                      ( hh     [7:0] ),  .mm                      ( mm     [7:0] ),  .ss                      ( ss     [7:0] )   
);// initial
// begin//     $finish;
// endendmodule

总结:

模块化为子模块单个解决的思想方法。

相关内容

热门资讯

苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...