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)。

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

审核编辑:汤梓红

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

    关注

    31

    文章

    5336

    浏览量

    120235
  • 计数器
    +关注

    关注

    32

    文章

    2256

    浏览量

    94479
  • 参数
    +关注

    关注

    11

    文章

    1832

    浏览量

    32195
收藏 人收藏

    评论

    相关推荐

    Verilog 与 ASIC 设计的关系 Verilog 代码优化技巧

    Verilog与ASIC设计的关系 Verilog作为一种硬件描述语言(HDL),在ASIC设计扮演着至关重要的角色。ASIC(Application Specific Integrated
    的头像 发表于 12-17 09:52 96次阅读

    图纸模板的文本变量

    “  文本变量和系统自带的内置变量,可以帮助工程师灵活、高效地配置标题栏的信息,而不用担心模板的文字对象被意外修改。   ” 文本变量
    的头像 发表于 11-13 18:21 170次阅读
    图纸模板<b class='flag-5'>中</b>的文本<b class='flag-5'>变量</b>

    Verilog语法运算符的用法

    verilog语法中使用以下两个运算符可以简化我们的选择代码。
    的头像 发表于 10-25 15:17 604次阅读
    <b class='flag-5'>Verilog</b>语法<b class='flag-5'>中</b>运算符的用法

    Verilog表达式的确定规则

    很多时候,Verilog中表达式的都是被隐式确定的,即使你自己设计了,它也是根据规则先确定位
    的头像 发表于 10-22 15:41 452次阅读
    <b class='flag-5'>Verilog</b>表达式的<b class='flag-5'>位</b><b class='flag-5'>宽</b>确定规则

    FPGA Verilog HDL有什么奇技巧?

    今天给大侠带来在FPAG技术交流群里平时讨论的问题答疑合集(九),以后还会多推出本系列,话不多说,上货。 交流问题(一) Q:Verilog 有什么奇技淫巧? A:在 Verilog ,以下这些
    发表于 09-12 19:10

    西门子博途:通过片断访问对变量区域进行寻址的步骤

    可以选择包含所声明变量的特定地址区域。可以访问为 1 、8 、16 或 32 的区域。
    的头像 发表于 04-28 09:24 2076次阅读

    自定义输入输出截模块的灵活配置方案

    可配置任意输入输出位模块
    的头像 发表于 04-25 11:36 400次阅读

    verilog语音实现浮点运算

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

    网表时序仿真案例:浅说$width语法

    verilog,$width是时序检查函数,用于检查脉冲的是否符合要求。
    的头像 发表于 03-01 09:46 2866次阅读
    网表时序仿真案例:浅说$width语法

    veriloginput和output作用

    Verilog,input和output用于定义模块的输入和输出端口。它们是用于通信的关键元素,定义了模块与其它模块之间的数据传输接口。通过input和output端口,模块之间可以互相传递数据
    的头像 发表于 02-23 10:29 3148次阅读

    veriloginitial和always的区别

    Verilog是一种硬件描述语言(HDL),用于设计和模拟数字电路。在Verilog,关键字initial和always都是用于描述电路行为的特殊语句。它们被用来生成仿真模型,并控制模拟器的启动
    的头像 发表于 02-22 16:09 2836次阅读

    verilogfor循环是串行执行还是并行执行

    Verilog,for循环是并行执行的。Verilog是一种硬件描述语言,用于描述和设计数字电路和系统。在硬件系统,各个电路模块是同时运行的,并且可以并行执行多个操作。因此,在
    的头像 发表于 02-22 16:06 2907次阅读

    自动控制系统的操纵变量指什么

    自动控制系统的操纵变量指的是在系统由控制器控制的可调节参数,用于调节或改变被控对象的输出或状态。操纵变量是自动控制中非常重要的概念,它是控制系统实现自动调节和优化的核心要素之一。本
    的头像 发表于 01-15 11:29 5156次阅读

    C语言:指针内存是如何存放变量

    在程序定义一个变量,那么在程序编译的过程,系统会根据你定义变量的类型来分配「相应尺寸」的内存空间。那么如果要使用这个变量,只需要用
    发表于 01-08 10:14 465次阅读

    stm32变量能存进flash

    当涉及到将变量存储在Flash时,我们通常指的是将变量存储在STM32微控制器的闪存器件。在STM32芯片中,闪存用于存储程序代码和只读数据,但对于一些应用情况,我们可以使用闪存来
    的头像 发表于 12-28 15:33 2109次阅读