[文档].艾米电子 - 二进制计数器及其变体,Verilog
对读者的假设
已经掌握:
- 可编程逻辑基础
- Verilog HDL基础
- 使用Verilog设计的Quartus II入门指南
- 使用Verilog设计的ModelSIm入门指南
内容
1 free-running二进制计数器
自由运行二进制计数器就是按照二进制形式不断循环计数。例如,4位的二进制计数器的从0000数到1111,然后翻回来重新数。
代码1 free-runing二进制计数器
module free_run_bin_counter #(parameter N=8) (// global clock and asyn resetinput clk,input rst_n,// counter interfaceoutput max_tick,output [N-1:0] q );// signal declaration reg [N-1:0] r_reg; wire [N-1:0] r_next;// body // register always@(posedge clk, negedge rst_n)if(!rst_n)r_reg <= 0; // {N{1'b0}}elser_reg <= r_next;// next-state logic assign r_next = r_reg + 1'b1; //output logic assign q = r_reg; assign max_tick = (r_reg == 2**N-1) ? 1'b1 : 1'b0;// r_reg == {N{1'b1}}endmodule
次态逻辑是一个自增器,即给寄存器的当前值加1。由于使用了“+”运算符,因此也暗示了当r_reg到达1111的时候之后,会翻回来变成0000。这个电路也包括一个输出状态信号,max_tick。每当计数器到达最大值——1111(等同于2^N-1),就会插入一个max_tick,即max_tick变为高电平。
所谓tick即一个时刻,比方说我们把1分钟可以分为60个tick,那么每一秒都会产生一个tick。此处的max_tick正是这种意义的信号,相应的,具有同类属性的信号我们都会加上_tick这个后缀。tick信号常用于连接不同频率的时序电路。
2 Universal二进制计数器
通用二进制计数器,可递增或递减计数,亦可载入指定的值,也可被异步清零。其查找表如表1所示。注意rst_n和syn_clr信号的区别,前者是异步复位,且仅应该用于系统的初始化;后者为同步复位,只在时钟的上升沿被采样,可被用于一般的同步设计中。
表1 通用二进制计数器的查找表
syn_clr | load | en | up | q次态 | 操作 |
1 | - | - | - | 00…00 | 异步清零 |
0 | 1 | - | - | d | 并行载入 |
0 | 0 | 1 | 1 | q+1 | 递增计数 |
0 | 0 | 1 | 0 | q-1 | 递减计数 |
0 | 0 | 0 | - | q | 暂停 |
代码2 通用二进制计数器
module univ_bin_counter #(parameter N=8) (// global clock and asyn resetinput clk,input rst_n,// counter interfaceinput syn_clr,input load,input en,input up,input [N-1:0] d,output max_tick,output min_tick,output [N-1:0] q );// signal declaration reg [N-1:0] r_reg, r_next;// body // register always@(posedge clk, negedge rst_n)if(!rst_n)r_reg <= 0; // {N{1'b0}}elser_reg <= r_next;// next-state logic always@*if(syn_clr)r_next = 0;else if(load)r_next = d;else if(en & up)r_next = r_reg + 1'b1;else if(en & ~up)r_next = r_reg - 1'b1;elser_next = r_reg; //output logic assign q = r_reg; assign max_tick = (r_reg == 2**N-1) ? 1'b1 : 1'b0; assign min_tick = (r_reg == 0) ? 1'b1 : 1'b0;endmodule
按照查找表设计的次态逻辑,被放在一个always块内,并且使用if-else-if来控制所需优先性的操作。
3 模-m计数器
模-m计数器,从0计数到m-1,然后翻过来重新计数。代码3所示的参数化的模-m计数器有两个参数:M,指定计数的范围为[0, M-1];N,指定M个数需要多少位宽来存储,其值为大于或等于log2(M)的整数。
代码3 模-m计数器(缺省为模-10)
module mod_m_bin_counter #(parameter N=4 // number of bits in counterparameter M=10 // mod-M) (// global clock and asyn resetinput clk,input rst_n,// counter interfaceoutput max_tick,output min_tick,output [N-1:0] q );// signal declaration reg [N-1:0] r_reg; wire [N-1:0] r_next;// body // register always@(posedge clk, negedge rst_n)if(!rst_n)r_reg <= 0;elser_reg <= r_next;// next-state logic assign r_next = (r_reg == (M-1)) ? 0 : r_reg + 1'b1; //output logic assign q = r_reg; assign max_tick = (r_reg == (M-1)) ? 1'b1 : 1'b0; assign min_tick = (r_reg == 0) ? 1'b1 : 1'b0;endmodule
次态逻辑由一个条件语句组成:如果计数器数到M-1,那么新的值就会被清零;否则它将自增。
虽然N的值取决于M的值,但是有时计算N的值有点烦人,以后我们通过加入function来解决这个问题
4 时序电路的testbench
所谓testbench即模仿物理实验平台的程序。下面我们写一个万用计数器的testbench,当然也做作为其他时序电路的testbench的模板。关于testbench的更加复杂的话题以后会讨论。
代码4 通用计数器的testbench
`timescale 1ns/10 ps // the `timescale specifies that // the simulation time unit is 1 ns and // the simulalor timestep is 10 psmodule univ_bin_counter_tb;// declaration localparam T = 20; // clock period reg clk, rst_n; reg syn_clr, load, en, up; reg [2:0] d; wire max_tick, min_tick; wire [2:0] q;// univ_bin_counter instaniation univ_bin_counter #(.N(3)) univ_bin_counter_inst (//.clk(clk),.rst_n(rst_n),//.syn_clr(syn_clr),.load(load),.en(en),.up(up),.d(d),.max_tick(max_tick),.min_tick(min_tick),.q(q) );// clock // 20 ns clock running forever always beginclk = 1'b1;#(T/2);clk = 1'b0;#(T/2); end// reset for the first half cycle initial beginrst_n = 1'b0;#(T/2);rst_n = 1'b1; end// other stimulus initial begin// ==== initial input ====syn_clr = 1'b0;load = 1'b0;en = 1'b0;up = 1'b1; // count upd = 3'b000;@(posedge rst_n); // wait reset to deassert@(negedge clk); // wait for one clock// ===== test load ====load = 1'b1;d = 3'd011;@(negedge clk);load = 1'b0;repeat(2) @(negedge clk); // wait for two clock// ==== test syn_clear ====syn_clr = 1'b1; // assert clear@(negedge clk);syn_clr = 1'b0;// ==== test up counter and pause ====en = 1'b1; // enable counterup = 1'b1; // count uprepeat(10) @(negedge clk);en = 1'b0; // pauserepeat(2) @(negedge clk);en = 1'b1;repeat(2) @(negedge clk);// ==== test down counter ====up = 1'b0;repeat(10) @(negedge clk);// ==== wait statement ====// continue wait until q=20wait(q==2);@(negedge clk);up = 1'b1;// continue until min_tick becomes 10@(negedge clk);wait(min_tick);@(negedge clk);up = 1'b0;// ==== absolute delay ====#(4*T); // wait for 80 nsen = 1'b0; // pause#(4*T); // ==== stop simulation ====// return to interactive simulation mode$stop; endendmodule
上述代码包括创建一个3位的计数器的例化模块表达式,以及生成时钟、复位和寄存器输入的三段表达式。
通过一个always块来生成指定时钟:
always beginclk = 1'b1;#(T/2);clk = 1'b0;#(T/2); end
T代表每个时钟周期包含多少时间单元。可使用下面的表达式定义。
localparam T = 20; // clock period
注意时钟生成always块没事敏感列表,及永远重复执行下去。clk信号被交替地断言为1或0,且每个值持续半个周期。
通过initial块来模拟复位信号:
initial beginrst_n = 1'b0;#(T/2);rst_n = 1'b1; end
在仿真的开始,initial块会被执行一次。上面的语句表示rst_n信号被初始设置为0;然后在半个时钟周期后变为1。这个initial块代表“上电”情况,即上电后复位信号会被立即插入,以清零及初始化系统。注意:缺省情况下,变量值为未定态。使用复位短脉冲是一个很好的初始化系统的机制。
第二个initial块用于生成其他输入信号的模拟。我们首先测试的是载入(load)和同步清零(syn_clr)操作,然后测试的是两个方向的计数。$stop用于强制仿真器停止仿真。
在带有上升沿触发的触发器的同步电路中,输入信号必须在时钟的上升沿附近保持稳定,以满足建立时间和保持时间的时序约束。一个简单的方法可以实现在保持信号稳定的情况下变换信号:在时钟的1到0跳变情况下,改变信号的值。我们通过使用下面的语句来可以等待这个跳变。注意分号不要落下。
@(negedge clk);
negedge用于指定时钟信号的下降沿。注意:每一条这样的语句都带吧一个新的下降沿。在我们的模版中,我们一般使用这样的表达式来指定时间进程。比方说多个时钟周期,可以使用repeat表达式:
repeat(10) @(negedge clk); // repeat 10 times
同时我们还是用了一个类似的语句,来等待上电异步复位完成,即解除异步复位信号。之所以此处为posedge,因为代码中的异步复位信号是低电平有效,我们所等待的是其恢复为高电平的跳变。
@(posedge rst_n); // wait reset to deassert
在第二个initial块的后面,还有一些时序控制语句。我们可以等待指定的条件。比方说,等到“q=2”的时候。注意一条语句结尾,分号不要落下。
wait(q==2);
再比如等待一个信号跳变:
wait(min_tick);
抑或等待一段绝对时间,比如
#(4*T); // wait for 80 ns
如果修改了输入信号的值,我们需要确认输入的改变不是在时钟的上升沿发生的,因此我们应该在其后附加下面的语句。
@(negedge clk);
完成的上述testbench的前仿真波形如图1和图2所示。
图1 通用计数器的前仿真波形
图2 通用计数器的前仿真波形片段
参考
1 Pong P. Chu.FPGA Prototyping By Verilog Examples: Xilinx Spartan-3 Version.Wiley
另见
[与艾米一起学FPGA/SOPC].[逻辑实验文档连载计划]
[文档].艾米电子 - 二进制计数器及其变体,Verilog相关推荐
- [文档].艾米电子 - 在综合中使用函数,Verilog
对读者的假设 已经掌握: 可编程逻辑基础 Verilog HDL基础 使用Verilog设计的Quartus II入门指南 使用Verilog设计的ModelSIm入门指南 内容 1 概述 在Veri ...
- SAP CRM Opportunity订单的文档流Document Flow的一些变体variant
Monday, February 1, 2016 2:42 PM 今天我测试Opportunity时发现:SAP Fiori处理doc history,是建立在这样一个前提下:source和targe ...
- 纸质文档转电子档的2种高效方法,你用过几种?
工作中很多时候我们需要把一些纸质资料文档存为电子档以便于保存,那么问题来了,当需要把纸质文档变为电子档时,你采用的方法是什么? 其实,不管使用什么方法高效和快速都是我们所追求的,下面跟大家分享3种纸质 ...
- 给PDF文档添加电子图章的方法
在这电子商务遍地走的社会,电子图章被越来越多地应用在合同.发票和其它电子文档中.那么如果不会使用PS,该如何实现在文档中添加电子图章呢?今天就给各位老铁一种为PDF文档添加电子图章的方法. 工具: P ...
- ABBYY FineReader OCR图文识别软件如何快速将纸质文档转为电子档教程
先给大家普及下一个小知识:MFP(Multi-Functional Peripheral),即多功能数码复合一体机,集合了打印.复印.扫描.传真等多种功能. 在这个科技高度发达的年代,相信每家公司都有 ...
- 华为方舟编译器来了,快!上!船!- 开发者文档 [源代码包/二进制包 下载]
本次方舟编译器开源的是编译器框架部分源码,包括编译器中间表示(IR)和语言编译实现,同时搭配编译器其他二进制组件,实现Java程序到aarch64汇编指令的编译过程. 开发者可以通过如下方式获得相关代 ...
- 将PDF转换成Word文档后,为什么字体全变了?
Word作为目前最常用的办公软件之一,对于一些上班要经常使用需要修改各种文档的人来说,虽然PDF格式更文档,但编辑却比较复杂,所以一般都是将PDF转成Word,但有时转出来的Word字体却与PDF不一 ...
- WordZ:Word终结者,基于Google API的文档自动化 电子合同发票流水账单线上集成方案
WordZ: Word终结者, 基于Google API开发的文档自动化产品.可用于线上合同,发票,所有有关文档的业务流程.主要功能包含,创建,复制文档,填充变量,导出word,导出pdf等一系列优秀 ...
- 解决 WPS 文档数字、字母间距突然变大的原因 Win10
找到输入法设置->按键->模式切换->全半角切换->勾选shift+space 解决后WPS输入如下:
最新文章
- Spring Boot定时任务应用实践
- VBS 脚本中的字典、动态数组、队列和堆栈
- 百度 Serverless 架构揭秘与应用实践
- 第一阶段:Java基础之OOP
- Bootstrap4+MySQL前后端综合实训-Day08-PM【ajax获取表单标签内容、根据“栏目信息”添加“新闻信息”、新闻管理系统-项目展示】
- 分析easyVM 未完成)
- MVC下用C#实现Excel导出
- webpack 4.0 配置文件 webpack.config.js文件的放置位置
- 在js的函数中用jquery的trim()方法去掉search前后的空格
- 【算法】背包问题C++
- Spring Security学习
- 彻底卸载删除微软Win10易升方法
- 电脑爱好者 2008年第23期(12月上) PDF
- 高绩效团队-VUCA时代的五个管理策略《二》—代际管理
- TuscanySCA5-理解SCA Domian
- 学习过程中遇到的一些电脑上的小BUG,非学习问题,实时更新
- Linux DDos防御
- 分析网络钓鱼的原理及防御措施
- Omnigraffle 许可证
- 「可口可乐 + Zion」7天上线小程序是如何做到的?