0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Verilog设计中如何匹配变量的位宽

C29F_xilinx_inc 来源:赛灵思 作者:赛灵思 2022-02-16 16:21 次阅读

1、位宽太小

FPGA设计中,我们经常需要用寄存器来寄存某些“数量类”的变量,比如FIFO的深度啦、或者计数器的最大值啦;又或者输入输出信号也需要将位宽用parameter参数化以便更好的调用等。

举个简单的小例子:系统频率100M(周期10ns),假设需要要求设计一个计时器计时100ns,那么需要计数次数为:100ns/10ns - 1 = 9,9这个数需要用多大位宽的寄存器表示呢?很简单,以2为底取对数就行,答案是最少4位宽。为了方便地复用这个模块,我们把计时时间参数化并放到模块外,如下:

module counter #(
parameter TIME = 'd10 //计时时间,单位10ns
)(
input clk_100M ,
input rst
);
reg [3:0] cnt; //计数器

//计时器
always@(posedge clk_100M)begin
if(rst)
cnt else if(cnt == TIME - 1)
cnt else
cnt end

endmodule

假设我们下次设计需要一个计时器的话,直接调用上面的counter模块并把TIME这个参数改成自己需要的参数就可以,这样做理论上是可以的,只是会有一个致命的隐患。不妨再假设:我现在调用了counter模块,并将TIME设置为20,以实现计时200ns的功能。当TIME = 20这个参数传递到被例化模块后,可以发现由于cnt寄存器的位宽仅为4位,其能表示的最大值为4'b1111(即十进制下的数字15),每次其到达15后就溢出为0重新开始了,也就是说这个200ns的计时器实际上根本就计数不到200ns。

这个隐患发生的原因就是在设计寄存器cnt时的位宽只有4位,无法满足“大量时间的计时任务”。

2、自己写一个Function

现在来想一下如何解决上述的位宽不匹配的问题。将寄存器的位宽设计为一个较大的数值(如固定为32bit)不失为一个不错的方法,但是如果将这条规则适用到每一个寄存器,则势必造成大量的资源浪费(你资源多你随便玩)。而且该方法指标不治本,我们需要做的是,这个寄存器应该有多大就设计多大的位宽(有多大的脚就穿多大的鞋,鞋子太大一定能穿,但你脚不一定舒服)。

前面说过寄存器的位宽的计算方法:以2为底取对数。所以我们只需要设计一个Function(可综合),来实现此项功能即可。刚好在Xilinx的许多源码都出现了这个简单的Function,我们直接拿过来用就是的:

// function 实现
function integer clogb2 (input integer bit_depth);
begin
for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
bit_depth = bit_depth >> 1;
end
endfunction

// 使用案例
localparam integer C_TRANSACTIONS_NUM = clogb2(C_M_AXI_BURST_LEN-1);
reg [C_TRANSACTIONS_NUM : 0] write_index;
reg [C_TRANSACTIONS_NUM : 0] read_index;

上面的代码就是定义了一个求位宽的function,用其求得某类寄存器的位宽,然后再对寄存器赋值时就直接使用求得的位宽来赋值,这样复用起来就比较方便了。

我们将这个代码放到上面的计数器模块中后,不管需要计数多大时间,都能计算出相匹配的寄存器位宽了。

3、无法在输入输出端口使用

自己写Function实现对2取对数的功能也有一定的局限性:无法对输入输出端口信号使用该Function。Function是定义在模块内部,所以若输入输出端口也需要根据输入的parameter参数来以2为底取对数的话此种方法就无能为力了。比如:设计一个同步FIFO,输出信号fifo_cnt(计数器)是对写入FIFO的数据进行计数的寄存器,其最大值即为FIFO的深度DATA_DEPTH ,所以fifo_cnt的位宽就需要在定义模块输入输出端口时确定,显然这无法使用自己构造的 cblogb2 Function。那该当如何?
//计数器法实现同步FIFO

module sync_fifo_cnt
#(
parameter DATA_WIDTH = 'd8 , //FIFO位宽
parameter DATA_DEPTH = 'd16 //FIFO深度
)
(
input clk , //系统时钟
input rst_n , //低电平有效的复位信号
input [DATA_WIDTH-1:0] data_in , //写入的数据
input rd_en , //读使能信号,高电平有效
input wr_en , //写使能信号,高电平有效

output reg [DATA_WIDTH-1:0] data_out, //输出的数据
output empty , //空标志,高电平表示当前FIFO已被写满
output full , //满标志,高电平表示当前FIFO已被读空
output reg [$clog2(DATA_DEPTH) : 0] fifo_cnt //$clog2是以2为底取对数
);

//省略部分代码

endmodule

4、$clog2系统函数

其实办法也有,在上面的代码中也展示出来了,就是使用 $clog2 这个Verilog的系统函数。$clog2是Verilog--2005标准新增的一个系统函数,功能就是对输入整数实现以2为底取对数,其结果向上取整(如5.5取6)。有一点需要说明的是,目前Vivado2017以上的版本都是支持这个系统函数的(Quartus II不清楚 )。但是百度搜索这条结果的时候有两条结论是错误的:

1、Vivado不支持$clog2系统函数

2、$clog2系统函数在Vivado实现的是以e为底取对数,而不是2

接下来写个简单的模块验证下Vivado对$clog2系统函数的支持如何

`timescale 1ns / 1ps

module clog2_test#(
parameter integer num = 325
)
(
input clk,
input rst,
output reg [$clog2(num) - 1:0] result
);

always @(posedge clk)begin
if(rst)
result else
result end

endmodule

我们直接看reg result的位宽综合出来到底是多少。如果以e为底向上取整,则位宽应是6;如果以2为底向上取整,则位宽应是9。Vivado综合的原理图局部如下:

Verilog设计中如何匹配变量的位宽

可以看到最后编译出的结果是9位的,也就说明Vivado是支持这个系统函数的(版本:2019.2)。

其他变量的位宽设计同理。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    30

    文章

    5032

    浏览量

    117745
  • 计数器
    +关注

    关注

    32

    文章

    2123

    浏览量

    92987
  • 参数
    +关注

    关注

    11

    文章

    1398

    浏览量

    31472
收藏 人收藏

    评论

    相关推荐

    verilog语音实现浮点运算

    , mantissa} = a; // 将a的符号、指数部分和尾数部分提取到对应变量 end always @(posedge clk) begin if (reset ==
    发表于 03-25 21:49

    关于AD6688输出的问题

    有数据。我就想请教这多出来的2是怎么来的呢?是内部的DDC将扩展了吗?有人能详细介绍下在手册什么位置嘛?十分感谢!
    发表于 12-01 07:31

    AD5521可以设计满足1~2GHz范围内的阻抗匹配吗?

    不同频率使用不同的电容电感做匹配,如下图。我想知道AD5521可以设计满足1~2GHz范围内的阻抗匹配吗?如果可以电路设计的电容C1,电感L1应该如何取值?如果不行,ADI有满足我
    发表于 11-17 07:51

    i2c偏移地址为32如何快速适配比较方便?

    现在想用stm32 HAL访问一个PCIE_SW芯片,但是该芯片的偏移地址为32,HAL的i2c协议栈的偏移地址为8
    发表于 10-23 06:56

    Verilog编码中位宽不匹配的危害是什么?

    位宽不匹配会导致综合产生的网表与个人预期差异较大,导致功能不正确。VCS仿真能及时发现问题,但VCS仿真存在部分场景没有覆盖的问题,因此仅仅通过VCS仿真不容易发现问题。通过spyglass lint检测可以发现所有位宽不匹配的情况。
    的头像 发表于 09-19 10:14 651次阅读

    verilog每日一练】变量截取语法

    使用变量[起始地址 +: 数据],变量[结束地址 -: 数据] 的语法截取
    发表于 09-01 18:04

    verilog/systemverilog中隐藏的初始化说明

    Verilog和SystemVerilog中经常需要在使用变量或者线网之前,期望变量和线网有对应的初始值
    的头像 发表于 08-25 09:47 619次阅读
    <b class='flag-5'>verilog</b>/systemverilog中隐藏的初始化说明

    verilog每日一练】变量的选取

    定义一个reg型变量a,a的最大值为2000,则a的最小需定义为多少
    发表于 08-16 10:34

    verilog每日一练】二进制数值1的个数奇偶判断

    verilog实现变量flag为1表示变量a的数值中二进制1的个数是奇数,flag为0表示变量a的数值中二进制1的个数是偶数,比如:a为8’b1111_0000,则二进制1的个数为4
    发表于 08-15 10:42

    关于NICE接口传输的数据问题

    上图是NICE 接口的内存通道,图中内存通道的读写数据都是32bit,根据赛题要求,需要在协处理器设计加速核心,挂靠NICE接口 我的预期:我所设计的加速核心需要更大的数据带宽(比如
    发表于 08-12 07:40

    【每日一练】参与FPGA技术社区每日学习,轻松掌握Verilog语法!

    】二进制数值1的个数奇偶判断 第12练:【verilog每日一练】变量的选取 第13练:【veri
    发表于 08-01 10:37

    必考的Perl语言正则匹配和文件读写

    如果匹配成功,匹配的字符串自动保存在 $& 变量中,打印
    的头像 发表于 06-25 17:42 677次阅读
    必考的Perl语言正则<b class='flag-5'>匹配</b>和文件读写

    Verilog中的基本数据类型

    本文将讨论 verilog 中常用的数据类型,包括对数据表示、线网类型、变量类型和数组,分享一下使用方法和注意事项。
    的头像 发表于 05-12 17:43 4457次阅读
    <b class='flag-5'>Verilog</b>中的基本数据类型

    verilog怎么将一个边沿触发信号的上升沿作为控制变量呢?

    verilog怎么将一个边沿触发信号的上升沿作为控制变量呢?
    发表于 05-10 10:38

    MCUXPresso调试模式变量观察非32变量异常怎么解决?

    我使用 MCUXPresso IDE v10.2.1 Build 795。 我们发现,当变量声明为非 32 变量时,比如 uint8_t 或 uint16_t,那么它的内容(值)将不会正确显示在
    发表于 05-04 08:42