计数器设计

一个计数器通常是由一组触发器构成,该组触发器按照预先给定的顺序改变其状态,
如果所有触发器的状态改变是在同一时钟脉冲的同一时钟沿上发送的,则称该计数器为
同步计数器(Synchronous Counter),如果计数器中的每个触发器的时钟部分或全部不同,则称该计数器为异步计数器(Asynchronous Counter)。

虽然计数器在形式上是简单的,但计数器也是很有内涵的。

计数器设计的三要素

1.初始值是多少
每轮计数的初始值,按照习惯一般可以从0开始计数
有些情况下需要装载值然后做减法计数

2.加1条件是什么
valid信号==1,有效时计数,一般而言,这种+1计数条件会放在条件判断的低优先级上
无valid使能计数的设计中,默认为按时钟节拍计数,此时相当于作为计时器用

3.结束条件
结束本轮计数的条件 一般与累加计数的条件相关,如 valid==1 && cnt==7
如果是循环计数,则记住要恢复初始值
计数结束,清零条件一般处于计数器控制的高优先级级别上

用于统计计数的,一般用自增计数器
用于不定时计数的,一般用自减计数器


常见计数器

二进制计数器

1.以下是一个不带中止条件的同步二进制加法计数器的结构框图
可以根据结构框图直接对计数器进行结构建模


untitled.png

同步二进制计数器两种风格下的写法

2016-10-15 07:59:24屏幕截图.png

计数器进位输出: cout = (cnt_q == 2**N -1) ? 1'b1 : 1'b0;
需使用组合逻辑直接得出计数器进位有效信号;
如果是寄存输出,则无法级联且正确按序计数。

2.异步二进制计数器的简要介绍以及实际使用中的缺陷
Ripple Counter


untitled2.png

这种计数器用前级的输出作为后级的时钟,由触发器的时钟到输出延时Tco可知,到达每个计数器的时钟信号并不是同时的;假设此时刻Q3Q2Q1Q0=0111, 当下一个CP脉冲到来时,从整体上看,这四个寄存器的输出会是0111-->0110-->0100-->0000-->1000其中每次改变的时间间隔都是Tco,也就是从当前状态输出0111,到最终输出稳定为1000,中间有4个Tco的时间输出是不稳定的;如果作为计数器来用,这么长时间的虚假数值会造成严重错误,特别是当计数值作为控制逻辑的判断条件时,可能在同一拍,不同的控制逻辑会收到了不同的计数值,造成系统挂死。

3.同步二进制计数器位数变多后的进位链问题(以加法计数器为例)
二进制同步加法计数器状态方程的一般形式

untitled3.png

考虑现在有一个20位计数器,那么FF间实际最长组合路径为
Q19(n+1) = Q19n ^ (Q18n & Q17n & ... & Q0n)
形式上虽然是2级组合逻辑:用与1个19输入的与门,将 FF18~FF0 的触发器的输出相与,1个2输入的异或门,将与门的输出和FF19的输出异或,接FF19的输入端,就可以实现;但实际FPGA中,需要3级4输入LUT,并且如果这样的逻辑很多,则可能决定次态输入的LE无法和寄存计数值的FF单元排在同一列上,而跨LAB的线延迟明显。假设每个LUT延时0.7ns,线延迟0.7ns+,在FPGA中,Fmax =260MHz左右, 这个速度不能算高。

一般而言,在运算电路中插入流水线寄存器,以消除关键路径,
控制逻辑中关键路径,则设法用寄存器切割组合逻辑链,优化时序性能,
但是这里是计数器,所以流水线是不能恰当解决问题的。(思考脸)

4.用双口ROM设计实现一个20bit二进制加法高速计数器
FPGA中可用片内RAM资源实现的二进制高速计数器,只要管理好地址与地址空间中所存数据之间的对应关系,也就是现态与次态间的对应关系,即可自由的实现二进制码,格雷码,BCD码高速计数器。

在ROM的地址0~1023依次存储
{0MSB,拼接10bit数据1~1023} ,{1MSB,拼接10bit数据0}
这1024个单元的11bit数;
DOUTA[9:0}接地址ADDRA[9:0],cnt[9:0]从输出口DOUTA[9:0]寄存输出,
cnt[9:0]可以循环输出0~1023;
DOUTB[9:0]接地址ADDRB[9:0],
cnt[19:10]从输出口DOUTB[9:0]直接引出(非寄存输出),
DOUTA[10]作为端口B按ADDRB读取数据的使能信号;
从而得到计数器输出cnt[19:0];
使用了11bit数据位宽,深度1024的片内双口ROM,
延时小且固定,实现了不构成系统运行速度瓶颈的高速计数器。

5.在对计数顺序没有要求的场合,可以用LFSR替代传统的二进制计数器,作为高速计数器,对提高性能起关键作用。
LFSR的介绍见《序列产生电路》文章

Gray码计数器

在异步FIFO设计中,常用格雷码对顺序+1增长的地址指针进行编码,然后传递到异步时钟域中进行比较。

1.Gray code counter style #1
设计思路:
按照原始的思路,可以先构建一个二进制计数器,再对二进制的输出做Binary码到Gray码的变换,这样输出就是周期增长的格雷码了,直接法如下图

untitled4.png

但是这种组合输出是有毛刺的,而计数器模块的后级模块常常是对毛刺敏感的,特别是将输出传到异步时钟域,所以计数器输出不能从组合逻辑直接得到。

Gray code counter style #2
于是改进计数器结构,环路法实现闭结点寄存输出如下图


untitled5.png

有了上面的结构框图,按照结构化设计的思路,代码就不难写了;
以4bit格雷码/二进制码为例

将格雷码转换为二进制码(G-->B) 方法是:
B3 = G3
B2 = G3 ^ G2
B1 = B2 ^ G1 = G3 ^ G2 ^ G1
B0 = B1 ^ G0 = G3 ^ G2 ^ G1 ^ G0

考虑到逻辑运算公式 A ^ 0 = A ;所以上面的转换等同下面表达式


untitled6.png

RTL实现


untitled7.png

将二进制结果转换为格雷码(B-->G) 方法是
G3 = B3 ^ 0 = B3
G2 = B3 ^ B2
G1 = B2 ^ B1
G0 = B1 ^ B0

也就是 G = (B>>1) ^ B


untitled8.png

Gray code counter style #2 RTL描述


untitled9.png

其中inc在作为计数器低位进位输入的同时,也作为计数器的计数使能,可控制其是否运行/翻转

3.Gray code counter style #3

untitled10.png

Style #2中
G-->B和B-->G组合逻辑与半加器,共同消耗了一个时钟周期,(Reg2Reg, 212MHz);
Style #3中
只有B-->G Comb 与半加器一起,消耗一个时钟周期,
所以Style #3的格雷码计数器会比Style #2快,(Reg2Reg, 386MHz)。

Gray code counter style #3 RTL描述(Recommend)

untitled11.png

4.Gray code counter style #4
还可以用状态机法建模格雷码计数器,简单的方法是按照格雷码编码次序分别作为状态机状态编码,以output encoding coding style实现一个Moore机,状态机输出直接从Present State 寄存器输出端引出来。

环形计数器

环形计数器又称移位寄存器型计数器,其输出就好像是将一个触发器的输出在时钟脉冲作用下不断循环移位;
如1000-->0100-->0010-->0001-->1000-->......
数码管动态扫描就用到了环形计数器作为数码管的位选信号输出;
下面给出共阳接法8个7段数码管位选产生的环形计数器,低电平选通;此移位寄存器使用了反馈接法,因而这个电路(的输出模式)是可以自恢复的。

untitled12.png

它的输出值按时钟节拍变化规律是:
01111111-->10111111-->11011111-->11101111-->11110111-->
-->11111011-->11111101-->11111110-->01111111...

Johnson计数器

环型计数器(Ring Counter)的一个特例是扭环型计数器(Twisted-ring Counter)
而(Twisted-ring Counter又称Johnson Counter, 其计数行为是:
若当前计数器最高位为1, 则执行最低位补0的左移操作,
若当前计数器最高位为0, 则执行最低位补1的左移操作。
如 000-->001-->011-->111-->110-->100-->000-->001 ...

untitled13.png

注意,以3bit移位寄存器实现的Johnson计数器为例,这个计数器按上面RTL描述的接法,是不可自恢复的;若某时刻,计数器值为010,那么下一拍,会跳变为101;而101在下一时钟有效沿后,又会跳变为010,
这样就在无效态中循环了;思考解决方法。

模M计数器

定义:所谓M进制计数器,是指共有M个状态,计数M次产生一个进位信号的计数器,
也称为模M计数器(Modulo-M Counter).
1.Modulo-M计数器的计数范围是 0 到M-1,之后返回 0 重新开始计数。
简单的模M计数可使用下图注释部分的习惯写法

untitled14.png

模M(加法)计数器是一种非常常见的数字电路基本结构,经常作为一些控制器设计中必不可少的基本部分。

2.WatchDog Timer

看门狗定时器(WDT,Watch Dog Timer)是一种常见的电路,它实际上是一个计数/计时器。
在初始状态时,看门狗电路首先装载一个预置数;当状态机或者程序开始运行后,看门狗开始倒计数;如果状态机或程序运行正常,每隔一段时间应该发出指令或信号让看门狗重新装载一个初始值,并(再次)开始倒计数;如果看门狗减到 0 就认为程序或状态机没有正常工作,需要强制整个系统复位。

(1)下面计数器电路描述就是一个看门狗电路
cnt <= 0 作为看门复位状态, load信号有效则是状态机或软件给出的喂狗动作。


module counter_wdt #(parameter N = 8) (
  input  logic clk,
  input  logic rst_n,
  input  logic load,
  input  logic up_down,
  input  logic [N-1:0] preset,
  output logic [N-1:0] cnt_q
);
  logic [N-1:0] cnt;
  always_ff @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      cnt <= 0;  
    else if(load)
      cnt <= preset;
    else if(up_down)
      cnt <= cnt+1'b1;
    else
      cnt <= cnt-1'b1;
  end

  assign cnt_q = cnt;
endmodule

(2)WDT计数器的另一种写法
控制向量与数据向量正交分离的设计原则,简化设计思路。

untitled15.png

(3)设计一个二进制模M计数器 该计数器含有:异步清零端,同步装载,加减计数控制;其中计数的模(/中止位) 按参数化设计。

module counter_fsmd #(parameter N = 4, M = 10)(
  input  logic rst_n,
  input  logic clk,
  input  logic [N-1:0] preset,
  input  logic [1:0] func, //controls the function
  output logic [N-1:0] q
);

always_ff @(posedge clk or negedge rst_n) begin
  if(!rst_n)
    q <= 0;
  else
    case(func)
      2'b00: q <= preset;
      2'b01: if(q == (M-1)) q <= 0;
             else           q <= q + 1;
      2'b10: if(q == 0) q <= M - 1;
             else       q <= q - 1;
      2'b11: q <= q;
    endcase
end

endmodule

显然,这里的N和M是相关的,可以在预处理时,执行(log2(M)取整 +1) 就可自动得到相关的N;虽然如此,但还是不建议在RTL描述的module里写出不可综合代码,即使在综合时会被预处理掉,看起来也有些混乱;如有必要,可以专门写一个预处理文件,然后用`include嵌入其中。

BCD码计数器

1.区分BCD码(模60)计数器 与(二进制)模60计数器
二进制码计数器和BCD码计数器是不同的,
例如,二进制模60计数器在寄存器各位的输出为5'b111011 表示计数到59,
而BCD码模60计数器在寄存器的输出为8'b0101_1001 表示计数到59;

模10以下的二进制码计数器和BCD码计数器的输出相同,对十进制数0~9,
以BCD码和二进制码对它们编码,得出的值在形式上一致。

BCD码计数器是计数值以BCD码表记的计数器,
BCD码计数器的概念层次与Binary(二进制)码计数器平行

2.设计一个BCD码模60计数器
计数器的值以BCD码值,从0~59依次变化
8421BCD码D(59) 对应的编码为8'h59

利用60进制BCD码计数器,方便数字钟里的秒数分数译码显示;
如00:45:59,分别为模60 BCD码计数器-->模60 BCD码计数器-->模24 BCD码计数器的级联,其中秒数计数器的计数使能cin接1;产生的BCD码可以很方便的译码显示在数码管或12864液晶上。

module counter_bcd (
  input  logic clk,
  input  logic rst_n,
  input  logic cin,          // cnt_en
  output logic [7:0] bcd,
  output logic cout
);

  logic [3:0] low, high;

  always_ff @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      {high, low} <= 8'b0;

    else if(cin==1'b1) begin
      if(low==4'd9)   // 低4位计数到9 下一拍低4位清0
        if(high==4'd5) // 进一步的,如果同时满足高四位为5,则所有位清零
          {high, low} <= 8'b0;
        else
          {high, low} <= {high+1'b1, 4'b0};
      else
        {high, low} <= {high, low+1'b1};
    end
  end

  assign bcd  = {high,low};
  assign cout = (cin==1'b1 && {high,low}==8'h59) ? 1'b1 : 1'b0;

//error cout
/*
  always_ff @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      cout <= 1'b0;
    else if(cin==1'b1 && {high,low}==8'h59)
      cout <= 1'b1;
    else
      cout <= 1'b0;
  end
*/
endmodule

3.BCD码模60计数器的几个注意点
(1)上面的模60和bcd码的位宽8是相关的,这意味着例化BCD码计数模块时,可以只提供计数的模,而bcd码的位宽可以预处理得出。

(2)计数器进位输入cin,同时也扮演了计数器计数使能的角色,为1时才会计数+1,低电平维持计数值,停止计数。

计数使能避免了系统空闲态中计数器仍然空转,降低了动态功耗;

有了进位输入和进位输出端口,这样才可以级联计数器,方便层次化和结构化复用;

在不关心或没必要考虑/使用级联时,可无cin,此时可以用专门的计数使能cnt_en控制计数器计数;如果计数器设计时,没有计数使能或计数停止条件,则无论系统当前需不需要计数,它都会不停的翻转,耗电;

如果计数器是用作某个完整设计的子模块,则最好要有cin或cnt_en计数使能信号,
这样计数器模块才是可控(受控计数)的。

(3)关于上方代码//error注释部分说明
一般可级联的计数器需要有超前进位输出(Cout),这样接到高位计数器模块的计数允许端(Cin),两者组合起来的计数电路整体上会有更宽的计数范围;

所谓超前进位输出,就是计数器的所有位为1时,同时输出进位信号(用组合逻辑),不能延迟一拍/下一拍输出进位;对应高位计数器的Cin==1时,下一拍计数值才会+1,而高位计数器输出1的同一拍,低位计数器刚好为全0,这就实现了无缝连接;

而注释部分的代码描述行为是在{high,low}==8'h59的下一拍才会输出一个高脉冲,如果例化多个模块,直接级联后,输出的值是错位的。

(4)多个计数器模块级联时的进位链问题
设有5个上述模60 BCD码计数器模块被例化并级联,
由assign cout = (cin==1'b1 && {high,low}==8'h59) ? 1'b1 : 1'b0; 这个组合逻辑层层递归展开来看,cin不断的被得出前级cout的与门+MUX结构往下迭代,那么从最低位的计数模块进位cin信号到最高模块cout输出,这个路径上级联的组合逻辑,叠加的延时至少有5个与门5个MUX那么长,考虑极端情况,如果这个叠加的延时超过了同步计数器运行的时钟周期,那么后级计数器模块实际上无法正确得到前级送来的进位信号,所以就无法继续正确计数了。

4.BCD码计数器第二种实现方法
从结构和组合上入手:先构建一个普通的二进制计数器 再接上一个二进制码译码转换BCD码的组合电路;这种搭积木的设计思路比较直观。

下面的BCD码计数器,使用二进制加法计数器计数值译码为BCD码输出;进位输出在计数的第1015次时维持,从而实现了一个计数范围为015的模16 BCD码计数器。

 assign e = bin[3] & ~bin[1];
 assign bcd[3] = e & ~bin[2];
 assign bcd[2] = ~e & bin[2];
 assign bcd[1] = e & bin[2] | ~bin[3] & bin[1];
 assign bcd[0] = bin[0];
 assign cout = bin[3] & (bin[2] | bin[1]);

由毛刺造成的暂态由于人的视觉分辨时间/数字发光管的响应时间,看不出来,
故数字钟的BCD码计数器,对毛刺不敏感;
所以这里组合逻辑译码器(decoder)直接输出计数器计数值可以直接用。

位数比较少的BCD码可以使用组合逻辑转换,但这种方法的局限性比较大

相关问题: 用状态机实现二进制码转BCD码的功能

5.BCD码计数器第三种实现方法
由带进位输入输出的模m~10二进制同步计数器拼接
举个简单的例子,直接级联3个二进制模10计数器,可以实现BCD码 0~D(999) 的计数(最高位进位输出信号不计入)

合理的选用上述方法,构造BCD码X进制计数器。

IP核高速计数器

1.FPGA数字逻辑设计三法
原理图设计法,不推荐
HDL 描述建模的设计方式, 灵活 常用
IP核搭建方法, 合适用就用

IP核调用,节约建模时间;由于功能已被验证,又省去了测试的过程;原型可复用;在合适与熟悉的基础上能用为什么不用呢

2.LPM Counter
LPM: Library of Parameterized Module 参数化模型IP核库

LPM计数器IP核的接口与参数介绍


untitled16.png
untitled17.png

3.图形化设置调用IP核简介
(1)打开MegaWizard 选中LPM_COUNTER
output file name 设置为:/home/shus/svprj/counter_ip/prj/ip/counter.v
其中ip目录是新建的 这样生成的IP的相关文件全在此目录下
对输出生成的模型文件名命名后最好带.v 如这里的counter.v

(2)本处以LPM_COUNTER IP生成一个4bit, up only,Modulus 10计数器,
含进位输入与进位输出,并设置异步清零

注意到图形界面的结构框图上 同步输入信号在左 异步信号输入信号在下
注意到Quartus里IP的使能信号和异步清零信号(aclr)一般是高电平有效的

(3)自动生成的文件
Verilog HDL IP的顶层文件(<function name>.v),
对于Verilog HDL实现,该原型文件必选生成,参数设置也记录在其中;

Quartus ii符号文件(<function name>.bsf),
可以在原理图设计中使用,保持默认(不生成);

例化模板文件(<function name>_inst.v),
设计中需要例化时可以直接复制此模板,一般选择生成;

综合和面积和时序估计网表(<function name>_syn.v),保持默认(不生成);

Verilog HDL黑盒文件(<function name>_bb.v),
可以给第三方综合工具使用,如果不做后仿,可保持默认;

这里勾选 counter.v 与 counter_inst.v

如果是第一次调用IP核 Quartus会弹出对话框提示是否将此IP核添加到当前工程中
且以后也默认自动添加MegaWizard生成的IP核文件到工程中 ;选择是。

(4)写一个顶层文件counter_ip.sv, 从counter_inst.v中找到例化模板复制到顶层文件中 简单修改即可例化使用。

untitled18.png

手工设计计数器

1.带自增自减控制的模10计数器
设计一个模10计数器;当X=1时,加法计数;当X=0时减法计数。
参考RTL描述

module counter_fsmd #(parameter N = 4, M = 10)(
  input  logic rst_n,
  input  logic clk,
  input  logic up_down,
  output logic [N-1:0] q
);

always_ff @(posedge clk or negedge rst_n) begin
  if(!rst_n)
     q <= 0;
  else if(up_down)
     if(q == (M-1)) q <= 0;
     else           q <= q + 1;
  else if(~up_down)
      if(q == 0) q <= M - 1;
      else       q <= q - 1;
   else
       q <= q;
end

endmodule

上述行为风格VerilogHDL描述该功能电路 对应的结构示意图
这是我脑补的,不一定同于综合软件给出的结果

untitled19.png

2.手工设计一个模10计数器;当M=1时,加法计数;当M=0时减法计数
(当计数满量时,输出Z=1,其余状态Z=0)

同步时序电路的一般性设计流程
1.由给定的功能/文字描述 做STG
2.进行状态编码分配,并试图进行状态化简
3.得到状态迁移表
4.得到状态激励表;对于D触发器实现,状态激励表就是状态迁移表,因为Q(n+1)=D
5.得到激励方程,输出方程
6.检查自启动,若不能自恢复,改变某一级FF的激励函数再检查.
7.画电路图/时序(波形)图说明设计功能

(1)STG
根据问题描述画状态转移图

untitled20.png

(2)状态编码
4个触发器共16种状态,此处知识用其中10种,其他6种是invalid态/多余态


untitled21.png

(3)得到状态迁移表
对D触发器,状态转移表同于状态激励表
由这个激励表(真值表)化简可以得到激励方程与输出方程

激励方程指的是各触发器输入端的控制方程,
如果使用D触发器,那么就是驱动D信号的激励产生逻辑,
如果使用T触发器,那么就是产生驱动T信号的逻辑,
输出方程指的是产生Z信号的逻辑表达式

使用D触发器时,可由状态转移表,将现态编码作为输入,每个FF的次态作为输出,看做真值表,并分别作卡诺图

(4)检查自启动
如果电路的全部非工作状态都能经过若干个状态转换后,自动进入工作循环,即不存在孤立的状态(环),称这样的时序电路能自启动。只要系统对于进入有效循环的时间没有严格的限制,它仍然是合理的。

(5)得到最终的激励方程,输出方程,完整的状态转移图
这里以TFF为例,激励与输出如下


untitled23.png

完整的State Transition Graph

untitled24.png

3.关于结构与流程框图
在初学HDL数字设计,进行结构建模风格HDL描述前,可画个结构图,心里有数,思路清晰,方便按图索骥,结构化描述模型;
在写了HDL代码后,如果功能不同于预期或有错,可以心里想象,或画个结构图,看看自己写的代码能否对应真实可行电路;
对于状态机,在做RTL描述前,可以手工绘制状态转移图,在综合后检查综合报告里的状态转移图是不是符合自己预期。
手工设计直指本质,有助于加深对数字逻辑电路结构的理解,有其意义。

书写风格补注

组合与时序分开的写法 这种风格是比较方便调试的
1.二进制Modulo-M加法计数器中的块,下面是组合与Reg不分的描述

  always_ff @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      cnt <= '0;
    else if (cnt == M-1 )
      cnt <= '0;
    else
      cnt <= cnt + 1'b1;
  end

2.组合和Reg分开的描述风格

这里约定:
1.若always块中为cnt 与cnt_d 对
则寄存器下一时刻间隔输出cnt_d,寄存器当前时刻(间隔)输出cnt ;
2.若always块中为cnt_r 与cnt_d 对
则寄存器下一拍输出cnt_d,寄存器当前输出cnt_r ;
3.若always块中为cnt_r 与cnt 对
则寄存器输入端接cnt,寄存器输出端接cnt_r;
4.若always块中为cnt 与cnt_n 对
则寄存器次态cnt_n,寄存器现态cnt;

  always_ff @(posedge clk or negedge rst_n) begin
    if(!rst_n)
      cnt_r <= '0;
    else
      cnt_r <= cnt_d;
  end

  always_comb begin
     if(cnt_r == M-1)
        cnt_d = '0;
     else
        cnt_d = cnt_r + 1'b1;
  end

  assign cnt = cnt_r;
// max_tick = (cnt_r == M-1) ? 1'b1 : 1'b0;

//这里的always_comb块也可直接替代为用assign数据流建模 
//assign cnt_d = (cnt_r == M-1) ? 0 : cnt +1'b1;

对于这里简单计数功能的实现,可以用第一种风格;
对于比较方便用结构化模型描述的功能,如上述的格雷码计数器,最好用第二种。

回想一下状态机的2,3段写法中,FSM的描述分解成:
状态转移逻辑(组合/译码电路) 状态保存寄存器 状态输出逻辑
就是时序组合分开写的,方便理解与调试与综合优化。

测试

单纯的计数器是个挺简单的电路,简单的查看波形就能验证。
1.简单的testbench 测试模60 BCD码计数器

`timescale 1ns/1ps
localparam PERIOD = 50; //clk=20MHz

module counter_bcd_tb #(parameter N=8)();
// source define
  logic clk;
  logic rst_n;
  logic cin;

// probe define
  logic [N-1:0] cout;
  logic [N-1:0] bcd;

// instantiate dut
  counter_bcd  counter_bcd_inst0 (
    .clk  (clk  ),
    .rst_n(rst_n),
    .cin  (cin  ),          // cnt_en
    .bcd  (bcd  ),
    .cout (cout )
);

// generate clock
  initial clk = 1;
  always #(PERIOD/2) clk = ~clk;
  
// generate reset
  initial begin
    rst_n = 1;
    #PERIOD     rst_n = 0;
    #(PERIOD*5) rst_n = 1;
  end

// initialize
  initial begin
    cin = 0;
  end

// load stimulus, testcase
  initial begin
    #(PERIOD*10 +1);
    cin = 1;
    #(PERIOD*400);
    $stop;  // suspend simulation
  end

endmodule

上面注释里的分类是一个testbench中一般构成的几大要素。

2.计数器测试结果波形图
(1)模60 BCD码计数器
8421BCD码编码,01011001对应表示的BCD码为D(59)

untitled25.png

(2)IP核模10计数器

untitled26.png

备注:
(二)针对具体设计/应用要求,介绍计数器功能设计技巧与思路
(三)高速计数器的几种类型,设计性能提升与比较
节拍计数器与纯粹的计时计数器设计区别与优化


参考文献

《数字逻辑基础》 陈光梦
《CMOS VLSI Design A Circuits and Systems Perspective》Neil H. E. Weste, David Money Harris. 4th Edition
《Clock Domain Crossing (CDC) Design & Verification Techniques Using SystemVerilog》 Clifford E. Cummings
《FPGA Prototyping by Verilog Examples》Pong P. Chu
《通信IC设计》李庆华
《基于FPGA的数字信号处理》 高亚军
《Altera系列FPGA芯片IP核详解》刘东华

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,192评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,858评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,517评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,148评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,162评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,905评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,537评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,439评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,956评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,083评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,218评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,899评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,565评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,093评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,201评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,539评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,215评论 2 358

推荐阅读更多精彩内容