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

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

3天内不再提示

RTL表达式和运算符

OpenFPGA 来源:OpenFPGA 作者:OpenFPGA 2022-11-03 09:14 次阅读

数字硬件建模SystemVerilog-循环语句

经过几周的更新,SV核心部分用户自定义类型和包内容已更新完毕,接下来就是RTL表达式和运算符。

马上HDLBits-SystemVerilog版本也开始准备了,基本这一部分完成后就开始更新~

069cd34e-5b14-11ed-a3b6-dac502259ad0.png

循环语句允许多次执行编程语句或begin-end语句组。SystemVerilog中的循环语句有:for、repeat、while、do..while、foreach和forever。其中,所有综合编译器只支持for和repeat循环。其他类型的循环可能由一些综合编译器支持,但这些限制限制了这些循环的用途。本系列重点介绍所有综合编译器都支持的for和repeat循环。

for循环语句

for循环的一般语法是:

06b7e620-5b14-11ed-a3b6-dac502259ad0.png

循环开始时,initial_assignment只执行一次。

end_expression在循环第一次通过之前进行计算。如果表达式为true,则执行语句或语句组。如果表达式为false,则循环退出。

在每次循环结束时执行step_assignment。再次计算end_expression。如果为真,则循环重复,否则退出循环。

下面的代码片段演示了使用for循环的一个简单示例,该示例使用b_bus中的反向位位置对a_bus的每个位进行异或。对于4位总线,a_bus[0]与b_bus[3]进行异或,a_bus[1]与b_bus[2]进行异或,以此类推。

06cd07e4-5b14-11ed-a3b6-dac502259ad0.png

综合编译器“展开”循环体来实现循环,这意味着循环中的语句或begin…end语句组被复制到循环迭代的次数。在上面的代码片段中,赋值语句被复制了四次,因为循环从0迭代到3。综合时展开循环后看到的代码是:

06d9bbf6-5b14-11ed-a3b6-dac502259ad0.png

循环将执行的迭代次数必须是固定的次数,以便综合器进行循环展开。迭代次数固定的循环称为静态循环。

循环的优势在迭代次数越多时越明显,如果a和b在上面的for循环片段中是64位总线,则需要64行代码来手动异或两条64位总线,对于for循环,无论总线的向量大小如何,只需要两行代码。

示例6-7展示了上述代码片段的完整参数化模型,图6-7显示了综合该模型的结果。

示例6-7:使用for循环对向量位进行操作

//`begin_keywords"1800-2012"//useSystemVerilog-2012keywords
modulebus_xor
#(parameterN=4)//bussize
(inputlogic[N-1:0]a,b,//scalableinputsize
outputlogic[N-1:0]y//scalableoutputsize
);
timeunit1ns;timeprecision1ns;

always_combbegin
for(inti=0;i
06efcaa4-5b14-11ed-a3b6-dac502259ad0.png 图6-7:示例6-7的综合结果:循环对向量位进行操作

在图6-7中可以看到,for循环的四次迭代是如何展开的,以及如何成为异或操作的四个实例。

静态循环与依赖数据的循环 (Static loops versus data-dependent loops)

静态循环,也称为数据独立循环,在这种循环中,可以确定迭代次数,而不必知道任何变量网络的值。for (int i=0;i <= 3;i++)是一个静态循环。可以确定循环将迭代4次(i=0  到i = 3),这种不依赖于其他信号,就能确定循环迭代次数的循环就是静态循环。

依赖数据的循环(data-dependent loop)是一种非静态循环,需要评估网络或变量的值,以确定循环将执行多少次。for (int i=0; i<=count; i++)依赖于count具体的数值,因为在不知道count值的情况下,无法确定循环将迭代多少次。

零延迟和定时循环(Zero-delay and timed loops)

零延迟循环不包含任何形式的时序。零延迟循环代表组合逻辑。在仿真中,零延迟循环会立即执行。在由综合器生成的门级电路实现中,零延迟循环在单个时钟周期内执行。前例6-7中所示的for循环是零延迟静态循环。

定时循环是需要消耗时间来执行循环的每个过程。定时循环并不代表组合逻辑的行为,因为循环的执行可能需要超过一个时钟周期才能完成。

最佳实践指南6-3
for循环是静态的、零延迟的循环,迭代次数固定。

为了展开循环,综合编译器需要能够静态地确定循环迭代次数。虽然有些for循环代码写的是静态循环,并且仿真也是正确的,但是可能是不可综合的。这方面的一个例子是:

07007728-5b14-11ed-a3b6-dac502259ad0.png

代码片段的目的是遍历数据向量,以找到为1的最低编号位。循环从数据的最低有效位0开始,并向上迭代,直到数据中的一位为l。通过修改end_count(循环结束条件)的值,找到第一个为l的位后,循环立即终止。虽然在循环开始之前结束计数被初始化为32,但它的值可以随着循环的执行而改变。

综合编译器在这个代码片段中遇到的问题是,不可能静态地确定循环将迭代多少次,因为循环的结束条件可能会根据输入的数据值(data值)发生变化而变化。为了展开循环,综合需要循环执行固定的次数。

无需依赖数据即可退出循环的可综合方式。示例6-8显示了前面代码段的可综合编码样式。示例6-8使用一个执行固定次数的静态循环,避免不是在循环结束时提前终止循环,而不是根据数据的值(data值)来确定循环的结束。

当找到最低的为1的位时,循环对剩余的迭代不做任何操作,图6-8显示了综合该示例的结果。在本例中,数据的总线大小是参数化的,并设置为4位宽,以便减小综合后的原理图的大小。

例6-8;使用for循环查找向量中为1的最低位

//`begin_keywords"1800-2012"//useSystemVerilog-2012keywords
modulefind_lowest_bit
#(parameterN=4)//bussize
(inputlogic[N-1:0]data,
outputlogic[$clog2(N):0]low_bit
);
timeunit1ns;timeprecision1ns;

logicdone;//localflag

always_combbegin
//findlowestbitthatissetinavector
low_bit='0;
done='0;
for(inti=0;i<=N-1; i++) begin 
      if (!done) begin 
        if (data[i]) begin 
          low_bit = i;
          done = '1;
        end 
      end 
    end 
  end 
  
endmodule: find_lowest_bit
//`end_keywords
图6-8:示例6-8的综合结果 07163b44-5b14-11ed-a3b6-dac502259ad0.png

最佳实践指南6-4
以固定的迭代大小对所有循环进行编码,这种编码风格确保循环可以展开,并且将得到所有综合编译器的支持。

循环迭代器变量寿命和可见性(For-loop iterator variable lifetime and visibility)

用于控制for循环的变量称为循环迭代器变量。通常,循环迭代器变量被声明为initial assignment(初始赋值)的一部分,如下所示:

072271a2-5b14-11ed-a3b6-dac502259ad0.png

当作为初始赋值的一部分声明时,循环迭代器变量是for循环的局部变量,不能在循环外引用。循环迭代器变量是自动生成的,这意味着该变量在循环开始的时间创建,并在循环退出时消失。

循环迭代器变量也可以在for循环之外声明,例如在模块级别或在命名的begin-end组中声明。外部声明的循环迭代器变量在循环退出后仍然存在,可以在声明变量的同一范围内的其他地方使用。当循环退出时,外部变量的值将是在结束条件评估为false之前,赋值步骤所指定的最后一个值。

Repeat循环

Repeat循环执行循环一定次数。Repeat循环的一般语法是:

07306668-5b14-11ed-a3b6-dac502259ad0.png

以下示例使用Repeat循环将data信号提高到3的幂(数据立方)。

07467084-5b14-11ed-a3b6-dac502259ad0.png

SystemVerilog有一个指数幂运算符,但一些综合编译器不支持该运算符。上面的代码片段显示了如何使用Repeat循环算法执行指数运算(将一个值与自身重复相乘)。

与for循环一样,如果循环的边界是静态的,则Repeat循环是可综合的,这意味着循环迭代的次数要求是固定的,并且不依赖于运行过程中可能发生变化的值。

示例6-9显示了上述指数运算片段的完整示例。在本例中,数据输入的宽度和指数或幂运算被参数化,以使示例更通用。这些参数在编译时是固定的常量。因此,使用参数作为迭代次数的Repeat循环是可综合的静态循环。这个模型的输出q是时序逻辑,因此q要使用非阻塞赋值,循环中的迭代是组合逻辑,其最终结果记录在阻塞赋值的临时变量中,因此,它的新值可用于循环的下一次迭代。

示例6-9:使用Repeat循环实现幂运算

//`begin_keywords"1800-2012"//useSystemVerilog-2012keywords
moduleexponential
#(parameterE=3,//powerexponent
parameterN=4,//inputbussize
parameterM=N*2//outputbussize
)
(inputlogicclk,
inputlogic[N-1:0]d,
outputlogic[M-1:0]q
);
timeunit1ns;timeprecision1ns;

always_ff@(posedgeclk)begin:power_loop
logic[M-1:0]q_temp;//tempvariableforinsidetheloop
if(E==0)
q<= 1;  // do to power of 0 is a decimal 1
    else begin 
      q_temp = d;
      repeat (E-1) begin 
        q_temp = q_temp * d;
      end 
      q <= q_temp;
    end 
  end: power_loop
  
endmodule: exponential
//`end_keywords 

图6-9显示了示例6-9的综合结果,当E的值为3时,Repeat循环执行2次,综合结果创建了乘法器的2个实例。输出向量q的每一位都由一个通用触发器进行赋值,图中只显示了第一个输出寄存器触发器,

07515738-5b14-11ed-a3b6-dac502259ad0.png 图6-9:示例6-9的综合结果:Repeat循环实现幂运算

综合时间考虑。静态、零延迟的循环或Repeat循环将综合为组合逻辑。如果该组合逻辑的输出被记录在触发器中,那么由循环推断的组合逻辑的总传播延迟必须小于一个时钟周期。

笔记
每个特定ASICFPGA设备的功能和限制可能会有很大的不同。使用乘法、除法、模和幂运算符的RTL模型应与目标设备的功能相匹配。

注意,在图6-9中,示例6-9中Repeat循环推断的乘法器是级联的。乘法器链的总传播延迟需要小于等于一个时钟周期,以便在输出触发器中记录有效且稳定的结果。一些综合编译器可以进行寄存器重定时,插入或移动寄存器,以在组合逻辑中创建流水。寄存器重定时是综合编译器的一项功能,不在本文的范围内。有关此主题的更多信息,请参阅综合编译器的文档。

如果寄存器重定时不可用,则不满足设计时钟周期的循环将需要重新编码为流水或状态机形式,手动将循环展开为多个时钟周期。

While和do-While循环

最佳实践指南6-5
使用for循环和repeat循环进行RTL建模。不要使用while和Do-while循环。

尽管许多综合编译器都支持这些循环,但它们有一些限制,比如使代码难以维护和重用,这就限制了它们在RTL建模中的实用性。相反,使用for循环或repeat循环,由于循环迭代的次数是静态的,所以增加了它们在RTL建模中的实用性。为了完整起见,本文简单介绍了while和do-while循环,但不推荐使用。

while循环执行编程语句或begin-end语句组,直到end_expression变为false。在循环的顶部计算结束表达式(end_expression)。如果第一次输入循环时结束表达式为false,则根本不执行语句或语句组。如果结束表达式为true,则执行语句或语句组,然后循环返回顶部并再次计算结束表达式(end_expression)。

do-while循环也执行编程语句或begin-end语句组,直到end_expression变为false。通过do-while循环,结束表达式(end_expression)在循环的底部进行计算。因此,第一次必进入循环。如果循环到达底部时结束表达式(end_expression)为false,则循环退出。如果结束表达式(end_expression)为true,循环将返回顶部并再次执行语句或语句组,

下面的代码显示了一个使用while循环的不可综合示例:

077a683a-5b14-11ed-a3b6-dac502259ad0.png

此示例统计16位data信号中有多少位被设置为l。data值被复制到名为temp的临时变量中。如果设置了temp的位0为l,则num_ones计数器将递增。然后将temp变量右移一次,这将移出位0,并将位0移到位15。只要至少有一位temp被设置为1,temp的计算结果为true,循环就会继。当temp的计算结果为false时,循环退出。temp中的某个值在某些位中有X或Z,但没有将任何位设置为1,这也会导致while循环退出。

本示例不可综合,因为循环执行的次数取决于data,不是静态的,如上一节所述。综合无法明确地确定循环将执行多少次,因此无法展开循环,就无法综合。

For each循环和通过向量的循环

For each循环遍历未压缩数组的所有维度。未压缩数组是网络或变量的集合,其中集合可以通过使用数组名称作为一个整体进行操作,或者数组的单个元素可以使用数组中的索引进行操作。数组的元素可以是任何数据类型和向量大小,但数组的所有元素必须是相同的类型和大小。数组可以有任意数量的维度。数组声明的一些示例如下:

07a155c6-5b14-11ed-a3b6-dac502259ad0.png

可以使用[ starting_address:ending_address]样式,如上面的mem数组,或使用[dimension_sizel风格,与查找表数组一样,前面更详细地讨论了声明和使用未压缩数组。

foreach循环用于迭代数组元素,foreach循环将自动声明其循环控制变量,自动确定数组的开始和结束索引,并自动确定索引的方向(增加或减少循环控制变量)。

下面的示例遍历一个二维数组,该数组表示带有一些数据的查找表。对于数组中的每个元素,都会调用一个函数来对该值进行某种操作(函数未显示)。

07abf95e-5b14-11ed-a3b6-dac502259ad0.png

请注意,i和j变量没有声明——foreach循环会在内部自动声明这些变量。也不需要知道数组的每个维度的边界。foreach循环会自动从每个维度的最低索引值迭代到最高索引值。

在整理这个系列时,一些综合编译器不支持foreach循环。在RTL模型中使用之前,工程师应该确保项目中使用的所有工具都支持哪种循环类型。

笔记
迭代数组所有维度的另一种编码方式是使用for循环。前面的示例可以使用所有综合编译器支持的静态for循环重写。

07c3fedc-5b14-11ed-a3b6-dac502259ad0.png

请注意,在这个嵌套for循环示例中,每个数组维度的大小及其起始和结束索引值必须进行硬编码(即需要明确的数值),以匹配数组声明的大小。SystemVerilog还提供数组查询系统功能,适用于不同大小或参数化大小的数组,可使for循环更通用。前面的例子可以写成:

07dc0d38-5b14-11ed-a3b6-dac502259ad0.png

笔记
在编写本文时,一些综合编译器不支持数组查询系统函数。在RTL模型中使用之前,工程师应该确保项目中使用的所有工具都支持这些功能。

以下是数组查询系统功能的简要说明。有关这些查询功能的更多信息,请参阅IEEE 1800 SystemVerilog语言参考手册。

(数组名,维度)-返回指定维度的最右边索引号。维度以数字1开头,从最左边的未压缩维度开始。在最右边的未压缩维度之后,维度编号与最左边的压缩维度继续,并以最右边的压缩维度结束。

(数组名,维度)-返回指定维度最左边的索引号。尺寸标注的编号与相同。

(数组名,维度)-如果大于或等于,则返回1;如果小于,则返回-1。

(数组名,维度)-返回指定维度的最低索引号,可以是左索引或右索引。

(数组名,维度)-返回指定维度的最高索引号,可以是左索引或右索引。

(数组名,维度)-返回指定维度中的元素总数(与-+1相同)。

(数组名)返回数组中的维度数,包括压缩维度和未压缩维度,

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

    关注

    11

    文章

    3192

    浏览量

    66043
  • 编程
    +关注

    关注

    88

    文章

    3558

    浏览量

    93524
  • RTL
    RTL
    +关注

    关注

    1

    文章

    385

    浏览量

    59650
  • 运算符
    +关注

    关注

    0

    文章

    170

    浏览量

    11046
收藏 人收藏

    评论

    相关推荐

    数字硬件建模SystemVerilog-按位运算符

    经过几周的更新,SV核心部分用户自定义类型和包内容已更新完毕,接下来就是RTL表达式运算符
    的头像 发表于 08-12 14:27 2427次阅读

    关于数字硬件建模SystemVerilog

    经过几周的更新,SV核心部分用户自定义类型和包内容已更新完毕,接下来就是RTL表达式运算符
    的头像 发表于 09-01 08:50 1364次阅读

    C语言程序设计--运算符表达式

    c语言对数据有很强的表达能力,具有十分丰富的运算符,利用这些运算符可以组成各种表达式及语句。运算符就是完成某种特定
    发表于 07-14 21:30 46次下载

    单片机C语言教程-运算符表达式

    单片机C语言教程-运算符表达式   单片机C语言教程-运算符表达式  运算符的种类、优先级和结合性  c语言中运
    发表于 03-27 17:13 2203次阅读

    基于运算符信息的数学表达式检索技术

    传统的文本检索技术主要面向一维文本,难以用于对二维结构数学表达式的检索。针对该问题,通过引入公式描述结构,实现基于运算符信息的数学表达式检索。利用公式描述结构提取算法获取 Latex数学表达式
    发表于 04-29 15:58 2次下载
    基于<b class='flag-5'>运算符</b>信息的数学<b class='flag-5'>表达式</b>检索技术

    RTL表达式运算符

    运算符对操作数执行操作。大多数运算符都有两个操作数。
    的头像 发表于 07-21 09:11 1673次阅读

    RTL表达式运算符

    经过几周的更新,SV核心部分用户自定义类型和包内容已更新完毕,接下来就是RTL表达式运算符
    的头像 发表于 07-27 09:11 1654次阅读

    SystemVerilog-运算符/表达式规则

    RTL建模中广泛使用的运算符是条件运算符,也称为三元运算符,该运算符用于在两个表达式之间进行选择
    的头像 发表于 08-03 09:03 2970次阅读

    关于RTL表达式运算符

    经过几周的更新,SV核心部分用户自定义类型和包内容已更新完毕,接下来就是RTL表达式运算符
    的头像 发表于 09-01 09:13 1802次阅读

    RTL表达式运算符

    经过几周的更新,SV核心部分用户自定义类型和包内容已更新完毕,接下来就是RTL表达式运算符
    的头像 发表于 10-11 10:15 1604次阅读

    RTL表达式运算符

    决策语句(Decision statements)允许程序块的执行流程根据设计中信号的当前值分支到特定语句。SystemVerilog有两个主要的决策语句:if…else语句和case语句,使用关键字case、case…inside,casex和casez。
    的头像 发表于 10-21 09:04 1275次阅读

    运算符/表达式规则

    运算符对操作数执行操作。大多数运算符都有两个操作数。例如,在运算a+b中,+(加法)运算的操作数是a和b。每个操作数都被称为表达式
    的头像 发表于 02-09 15:37 928次阅读
    <b class='flag-5'>运算符</b>/<b class='flag-5'>表达式</b>规则

    逻辑运算符表达式

    在C语言中,我们通常会进行真值与假值的判断,这时我们就需要用到逻辑运算符与逻辑表达式。如果表达式的值不为0,则通通返回为真值。只有当表达式的值为0时,才会返回假值。
    的头像 发表于 02-21 15:16 2019次阅读
    逻辑<b class='flag-5'>运算符</b>与<b class='flag-5'>表达式</b>

    位逻辑运算符表达式

    位逻辑运算符与位逻辑表达式可以实现位的编辑,比如位的清零、设置、取反和取补等操作。使用位逻辑运算符与位逻辑表达式可以在不使用汇编的情况下实现部分汇编的功能
    的头像 发表于 02-21 15:22 1197次阅读
    位逻辑<b class='flag-5'>运算符</b>与<b class='flag-5'>表达式</b>

    C语言基本的算术运算符表达式

    注意:自增和自减运算符只能用于变量,而不能用于常量或表达式 **C语言算术表达式运算符的优先级与结合性 ** 在表达式求值时,
    的头像 发表于 03-09 10:44 1510次阅读