博文目录

  • 写在前面
  • 正文
    • 普通的二进制计数器
      • 电路设计
      • 行为仿真
    • 普通的格雷码计数器
      • 电路设计
      • 行为仿真
    • LFSR
      • 电路设计
      • 行为仿真
    • 多功能计数器
      • 电路设计
      • 行为仿真
      • 生成语句实现方式
        • 电路设计
        • 行为仿真
      • 注意事项
  • 参考资料
  • 交个朋友

写在前面

相关博文
博客首页
注:学习交流使用!

正文

多功能计数器,英文名为:Versatile Counter;所谓多功能,这里包括二进制计数,格雷码计数以及线性反馈移位寄存器(LFSR)三种,本文通过从普通的计数器开始,也就是单个功能的计数器开始,一步一步过渡到多功能计数器。
作为对以下相关博文的延伸练习:
Verilog设计实例(1)线性反馈移位寄存器(LFSR)
FPGA设计心得(8)Verilog中的编译预处理语句

普通的二进制计数器

这个作为开头,不必多说,计数就完事了。

电路设计

设计文件:

`timescale 1ns/1ps
//
// Engineer: Reborn Lee
// Module Name: binary counter
// Additional Comments:
//
//
module binary_counter#(parameter N_BITS = 4)(input i_clk,input i_rst,output [N_BITS - 1 : 0] o_cnt,output o_cnt_done);reg [N_BITS - 1 : 0] bin_cnt = 0;always@(posedge i_clk) beginif(i_rst) beginbin_cnt <= 0;endelse beginbin_cnt <= bin_cnt + 1;endendassign o_cnt_done = (bin_cnt == 0)? 1:0;assign o_cnt = bin_cnt;endmodule

行为仿真

tb文件:

`timescale 1ns/1ps
module bin_cnt_tb;parameter N_BITS = 4;reg i_clk;reg i_rst;wire [N_BITS - 1 : 0] o_cnt;wire o_cnt_done;initial begini_clk = 0;forever begin# 2 i_clk = ~ i_clk;endendinitial begini_rst = 1;# 8i_rst = 0;endbinary_counter #(.N_BITS(N_BITS))inst_bin_cnt(.i_rst(i_rst),.i_clk(i_clk),.o_cnt(o_cnt),.o_cnt_done(o_cnt_done));
endmodule

仿真图:

普通的格雷码计数器

任意位宽的格雷码计数器,实现的方式通常是设计一个普通的二进制计数器,同时将计数结果转化为格雷码。
二进制与格雷码的转换方式,详情见:格雷码和二进制转换。
为了方便给出原理图:

伪代码描述为:

assign gray_value = binary_value ^ (binary_value>>1);

或者:

assign gray_cnt = { bin_cnt[N_BITS - 1], bin_cnt[N_BITS - 1 : 1]^bin_cnt[N_BITS - 2 : 0]};

电路设计

一种简单的设计方式为:

`timescale 1ns / 1ps
//
// Engineer: Reborn Lee
// Create Date: 2020/06/02 13:46:10
// Module Name: gray_counter
// Additional Comments: common gray counter
//
//module gray_counter #(parameter N_BITS = 4)(input i_clk,input i_rst,output [N_BITS - 1 : 0] o_cnt,output o_cnt_done);reg [N_BITS - 1 : 0] bin_cnt = 0;reg [N_BITS - 1 : 0] gray_cnt;always@(posedge i_clk) beginif(i_rst) beginbin_cnt <= 0;gray_cnt <= 0;endelse beginbin_cnt <= bin_cnt + 1;// translate binary counter into  gray counter  gray_cnt <= bin_cnt ^ bin_cnt >>> 1; //or // gray_cnt <= { bin_cnt[N_BITS - 1], bin_cnt[N_BITS - 1 : 1]^bin_cnt[N_BITS - 2 : 0]};//or // for(int i = 0; i < N_BITS - 1; i = i + 1) begin//   gray_cnt[i] <= bin_cnt[i+1]^bin_cnt[i];// end// gray_cnt[N_BITS - 1] <= bin_cnt[N_BITS - 1];endendassign o_cnt = gray_cnt;// or assign o_cnt_done = (gray_cnt == 0) ? 1 : 0;endmodule

注释部分解释:

             for(int i = 0; i < N_BITS - 1; i = i + 1) begingray_cnt[i] <= bin_cnt[i+1]^bin_cnt[i];endgray_cnt[N_BITS - 1] <= bin_cnt[N_BITS - 1];

以及:

gray_cnt <= { bin_cnt[N_BITS - 1], bin_cnt[N_BITS - 1 : 1]^bin_cnt[N_BITS - 2 : 0]};

均在always块内,因此使用非阻塞赋值。
又和二进制计数在一起always内,且紧邻分布,因此计数相较于二进制慢一拍,但毫无影响(不影响计数总数)。

注: 三种二进制转换为格雷码的实现原理一致,效果等价。

行为仿真

TestBench设计:

`timescale 1ns/1ps
module gray_cnt_tb;parameter N_BITS = 4;reg i_clk;reg i_rst;wire [N_BITS - 1 : 0] o_cnt;wire o_cnt_done;initial begini_clk = 0;forever begin# 2 i_clk = ~ i_clk;endendinitial begini_rst = 1;# 8i_rst = 0;endgray_counter #(.N_BITS(N_BITS))inst_gray_cnt(.i_rst(i_rst),.i_clk(i_clk),.o_cnt(o_cnt),.o_cnt_done(o_cnt_done));
endmodule

行为仿真波形:

局部放大:

LFSR

这个请参考上篇博文,单独做了一篇博客:
Verilog设计实例(1)线性反馈移位寄存器(LFSR)

为了方便不跳转另外一个链接,这里给出设计:

电路设计

`timescale 1ns / 1ps
//
// Company:
// Engineer: Reborn Lee
// Create Date: 2020/06/01 12:50:38
// Design Name:
// Module Name: lfsr
// Revision 0.01 - File Created
// Additional Comments:
//
//module lfsr #(parameter NUM_BITS = 3)(input i_Clk,input i_Enable,// data validinput i_Seed_DV,// Optional Seed Valueinput [NUM_BITS-1:0] i_Seed_Data,output [NUM_BITS-1:0] o_LFSR_Data,output o_LFSR_Done);// internal variablesreg [NUM_BITS:1] r_LFSR = 0;reg              r_XNOR;// Purpose: Load up LFSR with Seed if Data Valid (DV) pulse is detected.// Othewise just run LFSR when enabled.always @(posedge i_Clk)beginif (i_Enable == 1'b1)beginif (i_Seed_DV == 1'b1)r_LFSR <= i_Seed_Data;elser_LFSR <= {r_LFSR[NUM_BITS-1:1],r_XNOR}; //left rightendend// Create Feedback Polynomials.  Based on Application Note:// http://www.xilinx.com/support/documentation/application_notes/xapp052.pdfalways @(*)begincase (NUM_BITS)3: beginr_XNOR = r_LFSR[3] ^~ r_LFSR[2];end4: beginr_XNOR = r_LFSR[4] ^~ r_LFSR[3];end5: beginr_XNOR = r_LFSR[5] ^~ r_LFSR[3];end6: beginr_XNOR = r_LFSR[6] ^~ r_LFSR[5];end7: beginr_XNOR = r_LFSR[7] ^~ r_LFSR[6];end8: beginr_XNOR = r_LFSR[8] ^~ r_LFSR[6] ^~ r_LFSR[5] ^~ r_LFSR[4];end9: beginr_XNOR = r_LFSR[9] ^~ r_LFSR[5];end10: beginr_XNOR = r_LFSR[10] ^~ r_LFSR[7];end11: beginr_XNOR = r_LFSR[11] ^~ r_LFSR[9];end12: beginr_XNOR = r_LFSR[12] ^~ r_LFSR[6] ^~ r_LFSR[4] ^~ r_LFSR[1];end13: beginr_XNOR = r_LFSR[13] ^~ r_LFSR[4] ^~ r_LFSR[3] ^~ r_LFSR[1];end14: beginr_XNOR = r_LFSR[14] ^~ r_LFSR[5] ^~ r_LFSR[3] ^~ r_LFSR[1];end15: beginr_XNOR = r_LFSR[15] ^~ r_LFSR[14];end16: beginr_XNOR = r_LFSR[16] ^~ r_LFSR[15] ^~ r_LFSR[13] ^~ r_LFSR[4];end17: beginr_XNOR = r_LFSR[17] ^~ r_LFSR[14];end18: beginr_XNOR = r_LFSR[18] ^~ r_LFSR[11];end19: beginr_XNOR = r_LFSR[19] ^~ r_LFSR[6] ^~ r_LFSR[2] ^~ r_LFSR[1];end20: beginr_XNOR = r_LFSR[20] ^~ r_LFSR[17];end21: beginr_XNOR = r_LFSR[21] ^~ r_LFSR[19];end22: beginr_XNOR = r_LFSR[22] ^~ r_LFSR[21];end23: beginr_XNOR = r_LFSR[23] ^~ r_LFSR[18];end24: beginr_XNOR = r_LFSR[24] ^~ r_LFSR[23] ^~ r_LFSR[22] ^~ r_LFSR[17];end25: beginr_XNOR = r_LFSR[25] ^~ r_LFSR[22];end26: beginr_XNOR = r_LFSR[26] ^~ r_LFSR[6] ^~ r_LFSR[2] ^~ r_LFSR[1];end27: beginr_XNOR = r_LFSR[27] ^~ r_LFSR[5] ^~ r_LFSR[2] ^~ r_LFSR[1];end28: beginr_XNOR = r_LFSR[28] ^~ r_LFSR[25];end29: beginr_XNOR = r_LFSR[29] ^~ r_LFSR[27];end30: beginr_XNOR = r_LFSR[30] ^~ r_LFSR[6] ^~ r_LFSR[4] ^~ r_LFSR[1];end31: beginr_XNOR = r_LFSR[31] ^~ r_LFSR[28];end32: beginr_XNOR = r_LFSR[32] ^~ r_LFSR[22] ^~ r_LFSR[2] ^~ r_LFSR[1];endendcase // case (NUM_BITS)end // always @ (*)assign o_LFSR_Data = r_LFSR[NUM_BITS:1];// Conditional Assignment (?)assign o_LFSR_Done = (r_LFSR[NUM_BITS:1] == i_Seed_Data) ? 1'b1 : 1'b0;endmodule

行为仿真

`timescale 1ns / 1ps
module lfsr_tb ();parameter c_NUM_BITS = 4;reg r_Clk = 1'b0;wire [c_NUM_BITS-1:0] w_LFSR_Data;wire w_LFSR_Done;lfsr #(.NUM_BITS(c_NUM_BITS)) LFSR_inst(.i_Clk(r_Clk),.i_Enable(1'b1),.i_Seed_DV(1'b0),.i_Seed_Data({c_NUM_BITS{1'b0}}), // Replication.o_LFSR_Data(w_LFSR_Data),.o_LFSR_Done(w_LFSR_Done));always @(*)#10 r_Clk <= ~r_Clk; endmodule // LFSR_TB

仿真波形:

多功能计数器

有了上面三种计数器的单独设计,下面该考虑组合起来了,是用什么样的方式组合?
用户可以选择,可以通过定义条件编译的方式,定义了某个宏就执行某种计数器,计数位宽可选择,通过参数化的方式实现。

电路设计

本设计用到了上面的三个模块,例化到本模块使用;

`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/06/02 16:22:52
// Design Name:
// Module Name: versatile_counter
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//// `define LFSR_MACRO
`define GRAY
// `define BIN
module versatile_counter #(parameter N_BITS = 4)(input i_clk,input i_rst,output [N_BITS - 1 : 0] o_out,output o_out_done);`ifdef LFSR_MACROlfsr #(.NUM_BITS(N_BITS)) LFSR_inst(.i_Clk(i_clk),.i_Enable(1'b1),.i_Seed_DV(1'b0),.i_Seed_Data({N_BITS{1'b0}}), // Replication.o_LFSR_Data(o_out),.o_LFSR_Done(o_out_done));`elsif GRAYgray_counter #(.N_BITS(N_BITS))inst_gray_cnt(.i_rst(i_rst),.i_clk(i_clk),.o_cnt(o_out),.o_cnt_done(o_out_done));`elsebinary_counter #(.N_BITS(N_BITS))inst_bin_cnt(.i_rst(i_rst),.i_clk(i_clk),.o_cnt(o_out),.o_cnt_done(o_out_done));`endifendmodule

这里约定定义了宏GRAY,就是跑格雷码的代码,定义了宏BIN,就是跑二进制的代码,定义了LFSR_MACRO,就是跑LFSR的程序。

行为仿真

先假设定义了宏GRAY,仿真程序通用,如下:

`timescale 1ns/1ps
module sim_versatile_counter;parameter N_BITS = 4;reg i_clk;reg i_rst;wire [N_BITS - 1 : 0] o_out;wire o_out_done;initial begini_clk = 0;forever begin# 2 i_clk = ~ i_clk;endendinitial begini_rst = 1;# 8i_rst = 0;endversatile_counter #(.N_BITS(N_BITS))inst_vc(.i_rst(i_rst),.i_clk(i_clk),.o_out(o_out),.o_out_done(o_out_done));
endmodule

仿真波形 :


确实是格雷码计数器 ,放大:

如果定义了宏BIN,

// `define LFSR_MACRO
// `define GRAY
`define BIN

则仿真图如下:

放大观测:



如果定义了宏LFSR_MACRO,则输出LFSR计数:

 `define LFSR_MACRO
// `define GRAY
//`define BIN


生成语句实现方式

这里使用生成语句,generate case来实现多功能计数器,我们需要定义一个参数SEL,当SEL为0的时候,输出为LFSR;当SEL为1时,输出为格雷码计数器;当SEL为2时候,输出为二进制计数器。

电路设计

`timescale 1ns / 1ps
//
// Create Date: 2020/06/02 16:22:52
// Design Name:
// Module Name: versatile_counter
// Revision 0.01 - File Created
// Additional Comments:
// Reborn Lee
//
module versatile_counter #(parameter N_BITS = 4,parameter SEL = 0)(input i_clk,input i_rst,output [N_BITS - 1 : 0] o_out,output o_out_done);generatecase(SEL)0: beginlfsr #(.NUM_BITS(N_BITS)) LFSR_inst(.i_Clk(i_clk),.i_Enable(1'b1),.i_Seed_DV(1'b0),.i_Seed_Data({N_BITS{1'b0}}), // Replication.o_LFSR_Data(o_out),.o_LFSR_Done(o_out_done));end1: begingray_counter #(.N_BITS(N_BITS))inst_gray_cnt(.i_rst(i_rst),.i_clk(i_clk),.o_cnt(o_out),.o_cnt_done(o_out_done));end2: beginbinary_counter #(.N_BITS(N_BITS))inst_bin_cnt(.i_rst(i_rst),.i_clk(i_clk),.o_cnt(o_out),.o_cnt_done(o_out_done));endendcaseendgenerateendmodule

行为仿真

SEL为0,也即LFSR:
仿真文件例化改为:

 versatile_counter #(.N_BITS(N_BITS),.SEL(0))inst_vc(.i_rst(i_rst),.i_clk(i_clk),.o_out(o_out),.o_out_done(o_out_done));


放大:



SEL为1,也即格雷码计数器:
仿真文件例化改为:

 versatile_counter #(.N_BITS(N_BITS),.SEL(1))inst_vc(.i_rst(i_rst),.i_clk(i_clk),.o_out(o_out),.o_out_done(o_out_done));

放大:


SEL为2,也即 二进制计数器:

仿真文件例化改为:

 versatile_counter #(.N_BITS(N_BITS),.SEL(2))inst_vc(.i_rst(i_rst),.i_clk(i_clk),.o_out(o_out),.o_out_done(o_out_done));


放大:

注意事项

关于多功能计数器的注意事项,这里不做多说,
在debug的过程中,可以先进行elaborated design,


如果没有错误,在进行行为仿真;
其次需要注意,在宏定义过程中,别忘了`这个符号。
就这样吧,感觉如此实现也不是太难,我还记得使用OPENCORES里的那个设计实例,编译预处理指令一大堆,看得我头皮发麻,最关键的是我还没编译通过。

工程要不要分享了呢?暂时算了吧,反正代码已经贴出来了,实在需要的可以说一声。
工具 :vivado 2019.1

参考资料

参考资料1
参考资料2
参考资料3

交个朋友

FPGA/IC技术交流2020

Verilog设计实例(2)一步一步实现一个多功能通用计数器相关推荐

  1. Verilog设计实例(3)基于Verilog的单端口同步读写RAM设计

    文章目录 写在前面 正文 电路设计 行为仿真 交个朋友 写在前面 为什么要写单端口同步读写RAM呢? 没有那么多为什么?就是因为简单.基础,能清晰说明单端口RAM的原理,顺手给出设计,也能说明你的设计 ...

  2. Verilog设计实例(8)按键防抖设计之软件防抖

    博文目录 写在前面 正文 背景介绍及回顾 单个按键 单按键的其他设计版本 多个按键 写在最后 参考资料 交个朋友 写在前面 个人微信公众号: FPGA LAB 个人博客首页 注:学习交流使用! 正文 ...

  3. Verilog设计实例(7)基于Verilog的数字电子钟设计

    博文目录 写在前面 正文 设计要求 设计思想 设计文件 仿真文件 参考资料 交个朋友 写在前面 前段时间,有几个小伙伴向我请教数字电子钟设计的问题,这个问题我在之前的BCD计数器以及数码管显示问题中已 ...

  4. Verilog设计实例(5)详解全类别加法器(二)

    文章目录 写在前面 正文 超前进位加法器 4位超前进位加法器 任意位宽的超前进位加法器 参考资料 交个朋友 写在前面 相关博文 个人博客首页 正文 超前进位加法器 超前加法器由许多级联在一起的全加法器 ...

  5. Verilog设计实例(6)基于Verilog的各种移位寄存器实现

    文章目录 写在前面 正文 左移位寄存器 右移位寄存器 串行输入并行输出移位寄存器 并行输入串行输出移位寄存器 参考资料 交个朋友 写在前面 个人微信公众号:FPGA LAB 个人博客首页 注:学习交流 ...

  6. Verilog设计实例(4)详解全类别加法器(一)

    博文目录 写在前面 正文 半加器 设计代码 测试文件 行为仿真波形图 全加器 设计文件 设计完整文件 行为仿真 纹波进位加法器 2bit数据等波纹加法设计 参数化的等波纹加法器设计 参考资料 交个朋友 ...

  7. 一步一步学Silverlight 2系列(18):综合实例之RSS阅读器

    概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...

  8. (转)一步一步Asp.Net MVC系列_权限管理设计起始篇

    原文地址:http://www.cnblogs.com/mysweet/archive/2012/07/26/2610793.html 前一段时间,写了一步一步asp.net的一系列博客,最近,也快要 ...

  9. 如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文

    本系列所有文章 如何一步一步用DDD设计一个电商网站(一)-- 先理解核心概念 如何一步一步用DDD设计一个电商网站(二)-- 项目架构 如何一步一步用DDD设计一个电商网站(三)-- 初涉核心域 如 ...

最新文章

  1. 如果现在只能用汇编和 Goto 编程......
  2. RTMPdump(libRTMP) 源代码分析 3: AMF编码
  3. tcp 发送数据长度比预设缓存大_一文秒懂 TCP/IP实际五层结构(下篇)
  4. [Cypress] install, configure, and script Cypress for JavaScript web applications -- part3
  5. 使用XAMPP轻松建站(上)
  6. 第三次握手为什么没有序列号_TCP三次握手机制-深入浅出(实例演示)
  7. 说明使用tc编程的一般步骤 c语言,TC编程手册详解-完整版.doc
  8. hibernate反向工程
  9. Cadence元件库介绍
  10. user interface(用户界面)
  11. SCARA、通用6轴机器人奇异点位置与问题分析
  12. 中国的高校计算机教育存在哪些问题?
  13. 产品经理告诉你什么是PMF?什么是MVP?
  14. matlab加载xls文件报错,服务器出现意外情况,远程过程调用失败
  15. L2TP更改网络运营商后导致连接不了
  16. 大数据Spark实战第七集 机器学习和数据处理
  17. bean login not found within scope
  18. 二弟机器人_2017中国机器人技能大赛今天在南京理工大学举行
  19. 微信小程序——wxs脚本
  20. SEO竞争对手分析及网站SEO优化方案设计分析

热门文章

  1. 气泡形提示控件grumble.js
  2. python 动画场景_Python GUI教程(十五):在PyQt5中使用动画
  3. BufferedInputStream的read方法原理
  4. android文字广告的循环滚动,android怎样写一个循环文字滚动的TextView
  5. html随机播放不同的音乐,如何随机播不同的背景音乐
  6. python的format输出报文_python构造IP报文实例
  7. 第十六届智能车竞赛参赛队员提问与回答 |2021年7月12
  8. 我们遇到什么困难都不要怕,微笑着面对它
  9. 无线电能接收初步测试
  10. 电容触摸按键IC AT42QT1070