.. counter.rst --- .. .. Description: .. Author: Hongyi Wu(吴鸿毅) .. Email: wuhongyi@qq.com .. Created: 六 8月 10 21:36:04 2019 (+0800) .. Last-Updated: 六 8月 10 22:05:18 2019 (+0800) .. By: Hongyi Wu(吴鸿毅) .. Update #: 4 .. URL: http://wuhongyi.cn ################################################## 计数器 ################################################## ============================================================ 计数器规则 ============================================================ ---------------------------------------------------------------------- 计数器规则1: 计数器逐一考虑三要素--初值、加1条件、结束条件 ---------------------------------------------------------------------- 任何计数器都有三个要素:初值、加1条件、结束值 - 初值:计数器的默认值或者开始计数的值 - 加1条件:计数器执行加1条件 - 结束值:计数器计数周期的最后一个值 设计计数器,要逐一考虑这三个要素,一般是先考虑初值,再考虑加1条件,最后再考虑结束值。 ---------------------------------------------------------------------- 计数器规则2:计数初值必须为0 ---------------------------------------------------------------------- 计数器的默认值和开始值一定要为0。这是我们规范的统一要求。我们知道一般编程语言计数都是从0开始的,0表示第1个,1表示第2个,。。。这里我们也参考这种做法,计数器都从0开始计数。 所有计数器都统一从0开始计数,有助于我们阅读理解、方便使用,从而不用从头看具体代码,就能清楚这个数值的含义。 ---------------------------------------------------------------------- 计数器规则3:使用某一计数值,必须同时满足加1条件 ---------------------------------------------------------------------- 计数器从0开始计数,计数器的默认值,也就是复位值也是0。当计数器值为0时,如何判断这是计数器的第一个值还是还没开始计数的默认值呢? 可以通过加1条件来判断。当加1条件无效时,计数器值为0表示未开始计数的默认值;当加1条件有效时,计数器值为0表示计数器的第1个值。以此类推,当cnt==x-1时,不表示数到x;只有当cnt==x-1时,并且加1条件有效时,才表示数到x。 例如:当加1条件为add_cnt,且 add_cnt && cnt==4时,表示计数到5个;而当 add_cnt==0 && cnt==4时,不表示计数到5个。 ---------------------------------------------------------------------- 计数器规则4:结束条件必须同时满足加1条件,且结束值必须是 x-1 的形式。 ---------------------------------------------------------------------- 计数器的结束条件必须同时满足加1条件。例如假设要计数5个,那么结束值是4,但是结束条件不是 cnt==4 而是 add_cnt && cnt==4。因为 cnt==4 不表示计数到5个,只有 add_cnt && cnt==4 时,才表示计数到 5 个。 为了更好地阅读代码,我们这里规定结束值必须是 x-1 的形式,即 add_cnt && cnt==4 要写成 add_cnt && cnt==5-1。这里的“5”表示希望计算的个数,“-1”则是固定格式。有了这个约定后,计数的边界就很明确了。 -------------------------------------------------------------------------------- 计数器规则5:当取某个数时,assign 形式必须为:(加1条件) && (cnt==计数值-1) -------------------------------------------------------------------------------- 当要从计数器取某个数时,例如要取计数器的第5个点,就很容易写成cnt==5-1,这是不正确的。正确的写法时:(加1条件)&&(cnt==计数值-1),如 add_cnt && cnt==5-1。 ---------------------------------------------------------------------- 计数器规则6:结束后必须回到0 ---------------------------------------------------------------------- 每轮计数周期结束后,计数器变回0,这是为了使计数器能够循环重复计数。 ---------------------------------------------------------------------- 计数器规则7:若需要限定范围,则推荐使用“>=”和“<”两种符号 ---------------------------------------------------------------------- 设计时,考虑边界值通常要花费一些心思,而且容易出错。为此,我们约定:若需要限定范围,则推荐使用“>=”和“<”两种符号。例如要取前8个数,那么就取 cnt>=0 && cnt<8。注意,一定是“大与或等于”和“小于”符号,而不使用“大与”和“小于或等于”符号。 该规则参考编程里的for循环语句。假如要循环 8 次,for 循环的条件通常会写成“i==0; i<8; i++”,前面的0表示开始值,后面的8表示循环次数。当然,也可以写成“i==0; i<=7; i++”,但是这数字的意义就实在令人费解了,虽然知道7是从8-1得来的,但多一个“-1”的思考,就纯属画蛇添足了。 ---------------------------------------------------------------------- 计数器规则8:设计步骤 ---------------------------------------------------------------------- **设计步骤: 先写计数器的always段,条件用名字代替;然后用assign写出加1条件;最后用assign写出结束条件** 我们的计数器模版代码包括三段。 第一段,写出计数器的 process/always 段 **VHDL** .. code-block:: vhdl process(clk,rst_n) begin if(rst_n = '0')then cnt <= 0; elsif(clk'event and clk = '1')then if(加1条件)then if(结束条件)then cnt <= 0; else cnt <= cnt + 1; end if; end if; end if; end process; **verilog** .. code-block:: verilog always @(posedge clk or negedge rst_n) begin if(!rst_n) begin cnt <= 0; end else if(加1条件) begin if(结束条件) cnt <= 0; else cnt <= cnt + 1; end end 大家有没有发现上述模版的特点?这个模版只需要填两项内容:加一条件和结束条件。如果为加1条件和结束条件定义一个信号名,例如 add_cnt 和 end_cnt,则代码变成: **VHDL** .. code-block:: vhdl process(clk,rst_n) begin if(rst_n = '0')then cnt <= 0; elsif(clk'event and clk = '1')then if(add_cnt )then if(end_cnt)then cnt <= 0; else cnt <= cnt + 1; end if; end if; end if; end process; **verilog** .. code-block:: verilog always @(posedge clk or negedge rst_n) begin if(!rst_n) begin cnt <= 0; end else if(add_cnt) begin if(end_cnt) cnt <= 0; else cnt <= cnt + 1; end end 第二段,用组合逻辑写出加1条件 在此阶段,只需要想好一个点,就是计数器的加1条件。假设计数器的加1条件为 a==2,则代码如下: **VHDL** .. code-block:: vhdl add_cnt <= a=2;--add 1 **verilog** .. code-block:: verilog assign add_cnt = a==2;//add 1 第三段,用组合逻辑写出结束条件 在此阶段,只需要想好一个点,就是计数器的结束值。参考计数器规则5的要求,结束条件的形式一定是:(加1条件)&&(cnt==计数值-1).假设计数器要计数10个,则代码如下: **VHDL** .. code-block:: vhdl end_cnt <= add_cnt and (cnt = 10-1);--end **verilog** .. code-block:: verilog assign end_cnt = add_cnt && cnt == 10-1; //end 至此,就完成了计数器代码的设计。总结一下这段代码的特点:每次值考虑一件事,按这要求去做,就非常容易完成代码设计。 以下是我们完整的模版: **VHDL** .. code-block:: vhdl signal cnt : integer range 0 to ;--max number signal add_cnt : boolean; signal end_cnt : boolean; process(clk,rst_n) begin if(rst_n = '0')then cnt <= 0; elsif(clk'event and clk = '1')then if(add_cnt )then if(end_cnt)then cnt <= 0; else cnt <= cnt + 1; end if; end if; end if; end process; add_cnt <= ;--add 1 dout_tmp='1' end_cnt <= add_cnt and (cnt = -1);--end 以上模版中,只需要补充三个地方, .. code-block:: vhdl signal cnt : integer range 0 to ;--在 to 后面补充计数器的最大计数范围 add_cnt <= ;--补充加1条件 end_cnt <= add_cnt and (cnt = -1);--补充计数器数多少数 **verilog** .. code-block:: verilog reg [ :0] cnt ; wire add_cnt; wire end_cnt; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin cnt <= 0; end else if(add_cnt) begin if(end_cnt) cnt <= 0; else cnt <= cnt + 1; end end assign add_cnt = ;//condition: add 1 assign end_cnt = add_cnt && cnt == -1; //End condition, last value 以上模版中,只需要补充三个地方, .. code-block:: verilog reg [ :0] cnt ;//补充计数器的最大计数范围 assign add_cnt = ;//补充加1条件 assign end_cnt = add_cnt && cnt == -1; //补充计数器数多少数 ---------------------------------------------------------------------- 计数器规则9:加1条件必须与计数器严格对齐,其它信号一律向计数器对齐 ---------------------------------------------------------------------- 我们设计出计数器,但一般计数器不是最终的目的,最终的目的是输出各种信号。设计计数器是为了方便产生这些输出信号(包括中间信号),并能从计数器获取变化条件。例如:信号dout在计数到6时拉高,则其变1的条件是:add_cnt && cnt==6-1。 假设有两个信号:dout0在计数到6时拉高;dout1在计数到7时拉高。一种做法是dout0变1的条件是add_cnt && cnt==6-1,dout1变1的条件是dout0==1。这个dout1就是间接与计数器对齐。这是非常不好的方法。这里我们建议一律向计数器对齐,dout1变1的条件应该为add_cnt && cnt==7-1。 ---------------------------------------------------------------------- 计数器规则10:命名必须符合规范 ---------------------------------------------------------------------- **比如:add_cnt 表示加1条件;end_cnt 表示结束条件** 如无特别说明,计数器的命名都要符合规范,加1条件的前缀为 "\add_",结束条件的前缀为 "\end_"。 .. .. counter.rst ends here