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

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

3天内不再提示

数字硬件建模SystemVerilog-枚举数据类型

OpenFPGA 来源:OpenFPGA 作者:OpenFPGA 2022-07-01 17:44 次阅读

数字硬件建模SystemVerilog(十三)-枚举数据类型

上一节介绍了已经被淘汰的$unit声明空间,今天我们来看看一种重要的数据类型-枚举数据类型。

枚举数据类型提供了一种声明变量的方法,该变量可以包含有效值的特定列表。每个值都与一个标签(确定的用户自定义名宇)相关联。枚举变量用enum关键字声明,后面是用大括号({})括起来的逗号分隔的标签列表。

在下面的示例中,变量rgb的值可以是RED GREEN BLUE

cf8d2df8-f395-11ec-ba43-dac502259ad0.png

枚举列表中的标签是常量,类似于localparam常量。标签可以是任何名称。本系列使用大写字母作为常量的惯例。

枚举数据类型声明语法

枚举数据类型有一个底层数据类型,称为基类型,可以是任何SystemVerilog内置数据类型或用户自定义类型。枚举列表中的每个标签都有一个与该标签关联的逻辑值。

SystemVerilog提供了两种用于声明枚举数据类型的样式:隐式样式和显式样式。

隐式样式枚举声明

隐式样式枚举声明使用基类型和标签值的默认值。默认的基本类型是int。标签的默认值是列表中的第一个标签的值为0,并且每个后续标签的值递增一。

在以下隐式样式枚举声明中:

enum{WAITE,LOAD,READY}states_e;

states_e是int数据类型的变量,是32位有符号数据类型。这意味着枚举列表最多可以有2147483648(2^(32-1))个标签。

列表中的第一个标签WAITE的值为0,LOAD为l,READY为2。(标签WAITE故意在末尾拼写为“E”,以避免与SystemVerilog中保留的关键字wait产生混淆或冲突。)

这些默认设置很少适用于硬件建模。基类型int是2-state类型,这意味着在仿真期间导致X的任何设计问题都不能反映在枚举变量中。基类型int的宽度为32位,通常比所表示的硬件所需的向量大得多。标签值(如0、1和2)不能代表很多其他类型的硬件设计中使用的编码,例如独热码值、格雷码或约翰逊计数。

显式样式枚举声明

显式样式枚举声明指定基类型和标签值。以下声明表示使用一种独热编码的3位宽状态变量:

cf996802-f395-11ec-ba43-dac502259ad0.png

显式样式枚举声明强制使用了几个语法规则,可以帮助防止编码错误:

基类型的向量宽度和标签值的显式宽度必须相同。允许使用大小不一的文字值(例如WAITE = 1)

每个标签的值必须是唯一的;两个标签不能具有相同的值。

标签的数量不能超过基本类型的向量宽度所能代表的数量。

无需指定枚举列表中每个标签的值。

如果未指定值,则该值将从上一个标签增加1。在下一个例子中,标签A显式地给出了一个值l,B自动给出了递增为值2,C给出了递增的值3。D被明确定义为具有13的值,E和F分别被赋予14和15的递增值。

cfa51206-f395-11ec-ba43-dac502259ad0.png

如果两个标签的值相同,则会导致错误。以下示例将产生一个错误,因为c和D的值相同,都为3:

cfae8ef8-f395-11ec-ba43-dac502259ad0.png

最佳实践指南4-3
在RTL模型中使用显式样式枚举数据类型声明,在RTL模型中,基类型和标签值是指定的,而不是推断的。

指定基本类型和标签值有几个优点:它记录了设计工程师的意图;它可以更准确地仿真门级行为,并允许更准确的RTL到门级逻辑等价性检查。

自定义和匿名枚举数据类型

可以使用typedef将枚举数据类型声明为用户自定义类型,这为使用相同的枚举值集声明多个变量或网络提供了一种便捷的方法。

cfbb1d4e-f395-11ec-ba43-dac502259ad0.png

使用typedef声明的枚举数据类型称为自定义枚举数据类型。如果未使用typedef,则枚举数据类型称为匿名枚举数据类型。

枚举数据类型标签序列

有两种快捷方式可以指定枚举数据类型列表中具有相似名称的多个标签。

cfcf0a70-f395-11ec-ba43-dac502259ad0.png

COUNT_[4] 快捷方式将生成四个标签,分别为COUNT_0、COUNT_1、COUNT_2和COUNT_3。与COUNT_0关联的值将默认为0,随后每个标签的值将增加一。

第二个快捷方式:指定一系列标签。

cfdba762-f395-11ec-ba43-dac502259ad0.png

COUNT_[8:11]简写符号将生成四个标签,分别为COUNT_8、COUNT_9、COUNT_10和COUNT_11。与COUNT_8关联的值被明确定义为8,后续标签的值将增加1。

如果范围中的第一个值小于第二个值,如在COUNT_[8:11]中,则序列将从第一个数字递增到最后一个数字。如果范围内的第一个值大于第二个值,如COUNT_[11: 8]中所示,序列将从第一个数字递减到最后一个数字。

枚举数据类型标签作用域

枚举数据类型列表中的标签在声明和使用标签的范围内必须是唯一的。可以包含枚举数据类型声明的RTL建模范围是模块、接口、包、begin-end块、任务、函数和$unit声明空间。

以下代码片段将导致错误,因为枚举标签 GO在同一模块范围内使用两次:

cff19b12-f395-11ec-ba43-dac502259ad0.png

可以通过将至少一个枚举数据类型声明放在具有自己的名称范围的begin-end块中来纠正上例中的错误。

d002c888-f395-11ec-ba43-dac502259ad0.png

如上图所示为begin-end块命名不是必需的,但有助于记录代码的可读性和维护性。

从包中导入枚举数据类型

自定义枚举数据类型可以在一个包中定义,它允许多个设计块和验证代码使用相同的定义。

笔记
枚举数据类型定义的显式导入不会导入该定义中使用的标签。

使用包的通配符导入是解决此限制的最简单方法 。通配符导入使包中的所有内容都可用。

从包导入自定义枚举数据类型定义时,只导入自定义名称。枚举列表中的值标签不会自动导入,并在导入枚举数据类型名称的名称空间中显示。下面的代码片段将不起作用。

d013c6c4-f395-11ec-ba43-dac502259ad0.png

为了同时导入枚举数据类型标签,必须显式导入每个标签,或者必须通配符导入包-通配符导入将使枚举数据类型名称和枚举标签在import语句的范围内可见。下面的部分示例显示了通配符导入的使用。

d030e830-f395-11ec-ba43-dac502259ad0.png

从多个包进行通配符导入时必须小心。如果在多个包中定义了标识符(名称),并且两个包都使用通配符导入,则会发生编译或细化错误。对于这种情况,要使用的标识符必须显式导入或直接导入。SV包定义中讨论了如何使用多个软件包。

枚举数据类型分配规则

大多数SystemVerilog变量类型都是弱类型的,这意味着任何数据类型的值都可以分配给变量,该值将使用SystemVerilog标准中指定的转换规则转换为变量类型。

枚举类型不在 SV的这个一般原则内。枚举数据类型变量是半强类型的,这意味着只能为该变量指定特定的数据类型。

只能为枚举数据类型变量赋值:

枚举数据类型列表中的标签。

同一类型的另一个枚举数据类型变量。也就是说,这两个变量都是使用相同的自定义或匿名枚举数据类型定义声明的。

转换为自定义枚举数据类型的值,

使用以下定义和枚举变量举例说明这些规则:

d03e8a80-f395-11ec-ba43-dac502259ad0.png

如下所述,state 和 next_state分配枚举变量既是合法的也是非法的:

d0487a72-f395-11ec-ba43-dac502259ad0.png

笔记
枚举数据类型的强类型规则仅适用于对枚举变量的赋值。存储在枚举变量中的值只是一个值,在表达式(如比较和数学运算)中不受限制地使用。

对枚举数据类型值的操作。对枚举数据类型变量执行操作时,枚举变量的值将转换为枚举数据类型定义的基类型。操作的结果不再是枚举数据类型,结果可以分配给常规的、弱类型的变量,但不能分配回枚举变量。

logic[2:0]temp;//非枚举变量
temp = next_state + 1;//合规的:temp是弱类型的
state = next_state + 1;//非法的:next_state + 1不是枚举表达式
state++;//非法的:++的结果不是枚举表达式
state += next_state;//非法的:+=的结果不是枚举表达式

将表达式强制转换为枚举数据类型。任何值都可以强制转换为自定义枚举数据类型,然后分配给该枚举数据类型的变量,即使该值与枚举定义的某个标签不匹配,

d05fd550-f395-11ec-ba43-dac502259ad0.png

在RTL建模中,有时需要将非枚举表达式强制转换为枚举数据类型。然而,使用cast运算符(后面将详细讨论)时必须小心。将一个值强制放入不在枚举列表中的枚举变量可能会导致错误行为;无论是在仿真还是在综合中。使用强制转换会给设计工程师带来负担,因为要确保枚举变量中只强制输入有效值。这与弱类型的正则变量没有什么不同,设计工程师需要确保指定的值是有效的。

SystemVerilog还有一个cast系统功能,可以自动验证cast操作的结果。不幸的是,对于RTL设计人员来说,cast不受一些主要综合编译器的支持,cast在验证测试台上很有用,但不被认为是可综合的结构体。

枚举类型的专用系统任务和方法

枚举数据类型有几个内置函数,称为方法methods,用于遍历枚举数据类型列表中的值。这些方法会自动处理枚举数据类型的半强类型性质,这样做很容易,比如递增到枚举数据类型列表中的下一个值,以及跳到列表的开头或结尾。使用这些方法,不需要知道标签名称。

笔记
在撰写本文时,一些综合编译器支持枚举数据类型方法,但并非所有综合编译器都普遍支持。

枚举数据类型方法对硬件行为建模的用处有限。它们只能通过赋值语句实现的快捷方式。由于枚举数据类型方法的综合限制,本文仅简要介绍了这些方法,并给出了一个简单的示例。

调用枚举方法的方法是将方法名附加到枚举数据类型变量名的末尾,并以句点(.)作为分隔符。这些方法是:

<枚举变量名>.first-返回指定变量的枚举列表中第一个成员的值。

<枚举变量名>.last-返回枚举列表中最后一个成员的值。

<枚举变量名>.next(N)-返回枚举列表中下—个成员的值。可以用一个整数值作为 next 的参数。在这种情况下, 从枚举变量的当前位置算起, 返回后面第 N 个成员的值。如果到达了枚举列表的末尾, 则会返回到列表的开头。如果枚举变量的当前值不在枚举列表中, 则返回列表中第一个成员的值。

<枚举变量名>.prev(N))-返回枚举列表中前一个成员的值。同 ne*t 的方法一样.可以给 prev 指定一个整数参数 。在这种情况下, 从枚举变量的当前位S算起, 返回前面第 N 个成员的值。如果到达枚举列表的开头, 则会返冋到列表的末尾。如果枚举变量 当前值不在枚举列表中 , 则返回列表中敁后一个成员的值。

<枚举变量名>.num-返回变量枚举列表中的标签个数。

<枚举变量名>.name-返回枚举变里中代表这个值的字符串。如果这个值不在枚举变M列表中, 则返回一个空字符串。

打印枚举数据类型。枚举数据类型值可以打印为标签的实际值,也可以打印为标签的名称。直接打印枚举数据类型变量将打印枚举数据类型变量的当前实际逻辑值。使用name方法可以打印表示当前值而不是实际值的标签。

举一个使用枚举方法的例子,这个例子演示了如何使用其中一些枚举数据类型方法来建模状态机序列器。该模型是一个状态机,可以设置或清除数据同步标志。如果数据匹配输入在至少8个连续时钟周期内为真,则设置数据同步标志;如果数据匹配输入在多个连续时钟周期内为假,则清除数据同步标志,清除数据同步标志所需的连续假数据匹配数取决于有多少连续周期数据匹配为真,

图4-1显示了该状态机的状态流。状态机可以递增或递减的计数器。计数器统计已发生的连续数据匹配数,最多为16。请注意,对于大多数状态,计数器要么递增1,要么递减2。next和prev枚举数据类型方法可以非常简洁地仿真这种递增或递减行为,但某些综合编译器可能不支持这种方法。

图4-1:置信计数器(confidence counter))状态机的状态图 d06dbcba-f395-11ec-ba43-dac502259ad0.png 示例4-5:对置信计数器状态机使用枚举数据类型方法

//
//Book,"RTLModelingwithSystemVerilogforASICandFPGADesign"
//byStuartSutherland
//
//Statemachinemodelforaconfidencecountermodeledusing
//enumeratedtypemethods.
//
//Copyright2016,StuartSutherland.Allrightsreserved.
//
//Version1.0
//

`begin_keywords"1800-2012"//useSystemVerilog-2012keywords
moduleconfidence_counter
(inputlogicdata_matches,compare_en,rstN,clk,
outputlogicdata_synched
);
timeunit1ns/1ns;

typedefenumlogic[3:0]{COUNT[0:15]}states_enum_t;

states_enum_tCurState,NextState;

//sequentialblock
always_ff@(posedgeclk,negedgerstN)
if(!rstN)CurState<= COUNT0;
    else       CurState <= NextState;

  // next state combination logic block
  always_comb begin
    if (!compare_en)
      NextState = CurState;  // not comparing (no state change)
    else if (data_matches)   // compare_en && data_matches
      case (CurState)
        COUNT15 : ; // can't increment past 15
        default: NextState = CurState.next;  // increment by 1
      endcase
    else                     // compare_en && !data_matches
      case (CurState)
        COUNT0 : ; // can't decrement below 0
        COUNT1 : NextState = CurState.prev(1);  // decrement by 1
        default: NextState = CurState.prev(2);  // decrement by 2
      endcase
  end

  // register output block
  always_ff @(posedge clk, negedge rstN)
    if (!rstN)
      data_synched <= 0;
    else
      begin
        if (CurState == COUNT8)
          data_synched <= 1;
        else if (CurState == COUNT0)
          data_synched <= 0;
      end
endmodule: confidence_counter
`end_keywords

没有枚举数据类型的传统Verilog编码风格

Verilog语言在成为SystemVerilog之前没有枚举数据类型。要为数据值创建标签,必须定义一个parameter或localparam常量来表示每个值,并为该常量指定一个值。或者,可以使用'define宏定义一组宏名称,每个名称都有特定的值。

使用parameter创建标签的一些示例如下:

d0814ba4-f395-11ec-ba43-dac502259ad0.png

请注意,在使用parameters时,state和nex_state变量是reg类型的通用变量,而不是枚举变量。这些通用变量是弱类型的,这意味着任何值都可以分配给变量。使用弱类型的赋值规则,以下赋值语句是合法赋值,但属于功能性错误:

d0920b2e-f395-11ec-ba43-dac502259ad0.png

这种编码错误可能是枚举数据类型变量的语法错误。使用传统的Verilog风格的参数和通用变量类型并不能防止像这样的意外编码错误。

SystemVerilog(十二)-$unit声明空间

d0b18ecc-f395-11ec-ba43-dac502259ad0.jpg

SystemVerilog(十一)-SystemVerilog 包

原文标题:SystemVerilog(十三)-枚举数据类型

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

审核编辑:彭静

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

    关注

    8

    文章

    6786

    浏览量

    88705
  • 硬件
    +关注

    关注

    11

    文章

    3189

    浏览量

    66040
  • 软件包
    +关注

    关注

    0

    文章

    99

    浏览量

    11560

原文标题:SystemVerilog(十三)-枚举数据类型

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

收藏 人收藏

    评论

    相关推荐

    浅析System Verilog中的整数数据类型

    Data TypesVerilog提供了reg和wire数据类型,但是对于功能验证来说远远不够,所以SystemVerilog提供了很多更加丰富的数据类型,下面将一一介绍。我们先来考古下,一开始
    发表于 10-11 14:15

    数字硬件建模SystemVerilog-归约运算符

    介绍归约运算符对单个操作数的所有位执行运算,并返回标量(1位)结果。表5-9列出了归约运算符。表5-9:RTL建模的归约运算符归约运算符包括一个NAND和一个NOR运算符,这是按位运算符所没有
    发表于 10-20 15:03

    vhdl数据类型

    ,它包括实数类型、整数类型枚举类型和时间类型。 复合类型(COMPOSITE TYPE):可以
    发表于 03-30 15:59 11次下载

    go语言枚举类型怎么用

    go 语言枚举类型是这么用的?在什么场景下会用到枚举?本文对 go 语言枚举做了详细讲解。 枚举,是一种重要的
    的头像 发表于 09-02 09:43 5129次阅读

    SystemVerilog硬件功能如何进行建模

    本文定义了通常用于描述使用SystemVerilog硬件功能进行建模的详细级别的术语。
    的头像 发表于 03-30 11:42 1632次阅读

    数字硬件建模SystemVerilog-网络

    每个SystemVerilog网络类型都有特定的语义规则,这些规则会影响多个驱动程序的解析方式。虽然所有网络类型都表示硅行为,但并非所有网络类型都可以用标准ASIC和FPGA技术表示。
    的头像 发表于 05-09 09:26 1967次阅读

    数字硬件建模SystemVerilog-结构体

    默认情况下,结构体会被非压缩的。这意味着结构体的成员被视为独立变量或常量,并以一个共同的名称分组在一起。SystemVerilog没有指定软件工具应该如何存储非压缩结构体的成员。不同的软件工具具对于结构体的存储分布也是不同的。
    的头像 发表于 06-30 09:54 967次阅读

    SystemVerilog枚举类型的使用建议

    SystemVerilog枚举类型虽然属于一种“强类型”,但是枚举类型还是提供了一些“不正经”
    的头像 发表于 09-01 14:20 1594次阅读

    浅析SystemVerilog中的枚举类型

    枚举类型定义了一组具有名称的值,在没有指定值时默认是int型数值。
    的头像 发表于 10-13 09:44 1522次阅读

    SpinalHDL中Bundle数据类型的转换

    SpinalHDL中Bundle与SystemVerilog中的packed struct很像,在某些场景下,与普通数据类型之间的连接赋值可以通过asBits,assignFromBits来实现。
    的头像 发表于 10-17 09:51 1257次阅读

    关于有符号数据类型的示例

    我们学习一下Systemverilog中的有符号数据类型的赋值。
    的头像 发表于 10-17 14:40 954次阅读

    SystemVerilog中至关重要的的数据类型

    对于刚接触SV的小伙伴来说,SV有几种不怎么能引起关注,但在实际工作中又经常会用到的数据类型。它们就是枚举(enumeration)、结构体(structures)和自定义类型(typedef
    的头像 发表于 01-21 17:14 757次阅读
    <b class='flag-5'>SystemVerilog</b>中至关重要的的<b class='flag-5'>数据类型</b>

    SystemVerilog-网络

    System Verilog提供两组通用的数据类型:网络和变量(nets 和 variables)。网络和变量同时具有类型数据类型特性。类型表示信号为网络或变量,
    的头像 发表于 02-09 14:42 684次阅读
    <b class='flag-5'>SystemVerilog-</b>网络

    S71500-硬件数据类型介绍

    硬件数据类型硬件数据类型由 CPU 提供。可用硬件数据类型的数目取决于 CPU。
    的头像 发表于 05-16 09:21 5049次阅读
    S71500-<b class='flag-5'>硬件数据类型</b>介绍

    S71500 硬件数据类型的常量

    硬件数据类型硬件数据类型由 CPU 提供。可用硬件数据类型的数目取决于 CPU。 根据硬件配置中设置的模块存储特定硬件数据类型的常量。在用
    的头像 发表于 05-16 09:24 1141次阅读
    S71500 <b class='flag-5'>硬件数据类型</b>的常量