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

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

3天内不再提示

重点介绍所有综合编译器都支持的for和repeat循环

OpenFPGA 来源:OpenFPGA 作者:碎碎思 2022-11-03 09:10 次阅读

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

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

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

for循环语句

for循环的一般语法是:

poYBAGNjFVKAdU8mAABCI3_K8Jo656.jpg

循环开始时,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]进行异或,以此类推。

poYBAGNjFWKAJ1JtAABYSVj8G2w492.jpg

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

poYBAGNjFXKAGNSSAAA9JSOKqFY077.jpg

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

循环的优势在迭代次数越多时越明显,如果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

poYBAGNjFY-AWWQLAAC5TVOCVek564.jpg


图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循环代码写的是静态循环,并且仿真也是正确的,但是可能是不可综合的。这方面的一个例子是:

pYYBAGNjFaiAQv1rAACE_Xd8prs836.jpg

代码片段的目的是遍历数据向量,以找到为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的综合结果

pYYBAGNjFb2AEEQSAACAn8ilslM164.jpg

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

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

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

poYBAGNjFcyAT429AAAQut6xcoA619.jpg

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

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

Repeat循环

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

pYYBAGNjFdyAXMY5AAAi2Kj4xxc318.jpg

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

pYYBAGNjFeyASZRHAAA0q-VZGAM332.jpg

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

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





审核编辑:刘清

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

    关注

    28

    文章

    1343

    浏览量

    109918
  • 编译器
    +关注

    关注

    1

    文章

    1616

    浏览量

    49009
  • 门级电路
    +关注

    关注

    0

    文章

    15

    浏览量

    1952

原文标题:数字硬件建模SystemVerilog-循环语句

文章出处:【微信号:Open_FPGA,微信公众号:OpenFPGA】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    循环模型编译器Verilog和System Verilog语言支持指南

    本节介绍循环模型编译器响应不受支持或被忽略的构造的行为。 一般而言,Cycle Model Compiler支持Verilog和System
    发表于 08-12 06:55

    编译器是如何工作的_编译器的工作过程详解

    随着计算机的发展,编译器已经发挥着十分重要的作用。本文主要介绍编译器的种类、编译器的工作原理以及编译器工作的具体操作过程及步骤详解。
    发表于 12-19 12:54 1.6w次阅读

    MPLAB® XC8 C编译器的架构特性

    本视频介绍了MPLAB® XC8 C编译器的架构特性。该编译器编译过程不同于传统的编译器,采用了一种称为"OCG(全知代码生成)"的技术。
    的头像 发表于 05-23 12:47 5901次阅读
    MPLAB® XC8 C<b class='flag-5'>编译器</b>的架构特性

    关于KEIL ARM编译器的使用介绍

    KEIL ARM编译器的使用
    的头像 发表于 07-10 10:50 6275次阅读

    英特尔Fortran编译器的优势特点介绍

    史蒂夫莱昂内尔,Fortran博士,谈论英特尔编译器如何在公众可用性之前很好地支持未来的处理
    的头像 发表于 11-06 06:36 3230次阅读

    主流的C语言编译器详细介绍

    于Windows操作系统之外,主要用于Unix/Linux操作系统。像现在很多版本的Linux默认使用GCC作为C语言编译器。而像FreeBSD、macOS等系统默认使用LLVM Clang编译器
    发表于 09-05 17:27 2次下载
    主流的C语言<b class='flag-5'>编译器</b>详细<b class='flag-5'>介绍</b>

    主流C语言编译器的详细资料介绍

    于Windows操作系统之外,主要用于Unix/Linux操作系统。像现在很多版本的Linux默认使用GCC作为C语言编译器。而像FreeBSD、macOS等系统默认使用LLVM Clang编译器
    发表于 05-22 18:00 1次下载
    主流C语言<b class='flag-5'>编译器</b>的详细资料<b class='flag-5'>介绍</b>

    华为方舟编译器开源官网正式上线,代码没有放在GitHub

    方舟编译器是为支持多种编程语言、多种芯片平台的联合编译、运行而设计的统一编程平台,包含编译器、工具链、运行时等关键部件。
    的头像 发表于 09-13 16:04 4959次阅读

    Verilog可综合循环语句

    Verilog中提供了四种循环语句,可用于控制语句的执行次数,分别为:for,while,repeat,forever。其中,for,while,repeat是可综合的,但
    发表于 10-13 12:23 1.9w次阅读

    华为方舟编译器正式支持C语言,将继续完全开源

    2019年8月底,华为方舟编译器(OpenArkCompiler)正式开源,迈出了跨越性的一步。一年多来,方舟编程体系陆续实现了编译器、引擎、调试的开源,其中编译器
    的头像 发表于 10-14 17:38 2213次阅读

    为什么要学习编译器课程

    所有优秀的计算机科学学院提供了编译器课程,但是相对比较少的学校把它作为本科课程的必修部分。这篇文章回
    的头像 发表于 03-30 10:49 1568次阅读

    CompCert编译器目标代码生成机制研究综述

    CompCert是著名的C语言可信编译器,是经过形式化验证的编译器的杰出代表,近年来被广泛应用于学术界和工业界的许多研发工作中。 Compcert编译器的当前版本支持多种目标机结构。文
    发表于 05-07 10:17 4次下载

    基于GCC实现支持MISRAC的安全编译器

    基于GCC实现支持MISRAC的安全编译器(通信电源技术杂志简介)-基于GCC实现支持MISRAC的安全编译器                    
    发表于 09-24 11:09 9次下载
    基于GCC实现<b class='flag-5'>支持</b>MISRAC的安全<b class='flag-5'>编译器</b>

    交叉编译器安装教程

    交叉编译器中“交叉”的意思就是在一个架构上编译另外一个架构的代码,相当于两种架构“交叉”起来了。Ubuntu 自带的 gcc 编译器是针对 X86 架构的,而我们现在要编译的是 ARM
    的头像 发表于 09-29 09:12 3408次阅读

    领域编译器发展的前世今生

    近年来,随着GPU和DSA架构在不同领域的广泛应用,特别是AI系统相关技术的飞速发展,对于编译器的需求越来越强烈。编译器已经从一个相对小众的研究领域,变为学界和业界高度关注并大量投入的方向
    的头像 发表于 02-03 10:37 1605次阅读