System Verilog提供两组通用的数据类型:网络和变量(nets 和 variables)。网络和变量同时具有类型和数据类型特性。类型表示信号为网络或变量,数据类型表示网络或变量的值系统,即2态或4态。为简单起见,使用术语data type来表示信号的类型和数据类型。
软件工具(如仿真器和综合编译器)使用数据类型来确定如何存储数据和处理数据上的更改。数据类型影响操作,并在RTL建模中用于指示所需的硅行为。例如,数据类型用于确定加法器应基于整数还是基于浮点,以及应执行有符号算术还是无符号算术。
变量用作编程的临时存储。此临时存储用于仿真。实际的硅通常不需要相同的临时存储,这取决于使用变量的编程环境。SystemVerilog有几种变量类型,将在第下节中讨论。
网络用于将设计块连接在一起,网络将数据值从源(称为驱动程序)传输到目标或接收端驱动程序。SystemVerilog提供了几种网络类型,后面会对此进行了更详细的讨论。
SystemVerilog变量可以是2态数据类型或4态数据类型。对于2态,变量的每一位可以具有0或1的值,对于4态,变量的每一位可以具有0、1、Z或X的值。SystemVerilog网络只能是4态数据类型。关键字位定义变量为2态数据类型。关键字逻辑定义变量或网络为4态数据类型。
程序块指定的左侧需要变量。以下代码示例中的信号总和和输出必须是变量。
前面代码段中的always_comb过程将执行赋值语句sum=a+b;每次a或b改变值时。必须通过仿真器存储sum的值,直到下一次a或b发生变化。类似地,always_ff过程将在时钟的每个正边缘执行if-else决策语句。out的值必须在时钟周期之间通过仿真器进行存储。
仿真器所需的临时存储并不一定意味着实际硅需要存储。前面代码片段中的always_comb过程将在硅中作为组合逻辑实现。因此,总和的值将持续反映加法器的输出,并且不需要任何类型的硬件存储。另一方面,always_ff程序将作为触发器在硅中实现,触发器是一种硬件存储设备。
通过同时指定类型和数据类型来声明变量。类型可以显式指定或隐式推断,关键字var。
var关键字很少在实际SystemVeriIog代码中使用。相反,var类型是从其他关键字和上下文推断出来的。
SystemVerilog有几个内置变量数据类型的关键字。这些关键字推断var逻辑(4态)或var位(2态)变量类型。几个变量数据类型表示硅的行为,并且是可综合的。表3-1列出了这些可综合的数据类型。
表3-1:可综合变量数据类型
类型 | 代表 |
---|---|
reg | 用户定义向量大小的通用4态变量;等价于var logic |
logic | 通常推断用户定义向量大小的通用var logic 4态变量,模块input/inout端口除外,在模块input/inout端口上推断wire logic |
integer | 32位4态状态变量;等价于var logic [ 31: 0 ] |
bit | 具有用户定义向量大小的通用2态var变量;如果未指定大小,则默认为1位大小 |
int | 32位2态变量;相当于var bit[31 0];综合编译器将int视为4态integer整数类型 |
byte | 8位2态变量;等效于var bit [ 7 : 0 ] |
shortint | 16位2态变量;等效于var bit [ 15: 0 ] |
longint | 64位2态变量;等效于var bit [ 63: 0 ] |
最佳做法准则3-3 |
---|
使用4态逻辑数据类型推断RTL模型中的变量。不要在RTL模型中使用2态类型。本指南的一个例外是使用int类型声明for-loop迭代中变量。 |
使用4态变量允许仿真器在实际硬件中的值不明确时使用X值。
在几乎所有的上下文中,logic数据类型推断出一个与reg相同的4态变量。关键字logic实际上不是变量类型,它是一种数据类型,表示网络或变量可以有4态值。但是,当logic关键字单独使用或与模块输出端口的声明结合使用时,会推断变量。当logic与input or inout端口的声明结合使用时,如果logic不推断变量,则会推断网络类型.
reg数据类型是原始Verilog语言遗留下来的过时数据类型。应使用logic类型而不是reg。最初的Verilog语言使用reg数据类型作为通用变量。
不幸的是,关键字reg的使用是一个误称,它似乎是“register”的缩写,寄存器是用触发器构建的硬件设备。实际上,使用reg变量与推断的硬件之间没有相关性。使用变量的上下文决定所表示的硬件是组合逻辑还是时序触发器逻辑。使用logic代替reg有助于防止这种错误观念,即硬件寄存器将被推断
当仿真过程中出现X值时,通常表明存在设计问题。会导致X值的某些类型的设计错误包括:
bit、byte、shortint、int和longint数据类型仅存储2态值。这些类型不能表示高阻抗(Z值),也不能使用X值表示未初始化或未知的仿真条件。当使用2态数据类型时,不会出现指示潜在设计错误(如上面列表中的错误)的X值。由于2态数据类型只能有一个0或1值,因此在仿真过程中出现错误的设计可能会正常运行,这是不好的!使用2态变量的合适位置是验证试验台中的随机刺激。
SystemVerilog有几种主要用于验证的变量类型,RTL综合编译器通常不支持这些类型。表3-2列出了这些额外的变量类型。这些数据类型没有在本系列中任何要综合的示例中使用。
表3-2:不可综合的变量数据类型
类型 | 代表 |
---|---|
real | 双精度浮点变量 |
shortreal | 单精度浮点变量 |
time | 具有timeunit和timeprecision属性的64位无符号4态变量 |
realtime | 双精度浮点变量;与real一模一样 |
string | 可存储8位ASCII字符字符串的字节类型的动态大小数组 |
event | 存储仿真同步对象句柄的指针变量 |
class handle | 存储类对象句柄的指针变量(声明类型是类的名称,而不是关键字类) |
chandle | 一个指针变量,用于存储从SystemVerilog直接编程接口(DPI,Direct Programming Interface)传递到仿真中的指针 |
virtual interface | 存储接口端口句柄的指针变量(interface关键字是可选的) |
上述的类型不代表在任何综合器中都不可综合,只代表了在大部分综合器中不可综合。
变量是通过同时指定类型和数据类型来声明的,类型是关键字var,可以显式指定或隐式推断。
笔记 |
---|
在实际的SystemVeriIog代码中很少使用var关键字。相反,var类型是从其他关键字和上下文推断出来的 |
一些示例变量声明:
logic v1 //推断var logic(1位4态变量)
bit v2; //推断var bit(1位2态变量)
integer
v3 //推断var
integer
(32位4态变量)
int v4 //推断var int(32位2态变量)
唯一需要var关键字的地方是将input 或者 inout端口声明为4态变量时。如果未显式声明为变量,则这些端口方向将默认为网络类型,输入端口很少需要是变量。
标量变量。标量变量是一个1位变量。reg, logic 和 bit数据类型默认为1位标量,
向量变量(packed arrays)。向量是连续位的数组。IEEE SystemVerilog标准将向量称为包阵列(packed arrays)。该reg, logic and bit数据类型可以表示任意大小的向量:通过在方括号中指定位的范围([]),后跟向量名称来声明向量的大小。范围声明为[最高有效位编号:最低有效位编号]。最高有效位(MSB)和最低有效位(LSB)可以是任意的数字,并且LSB可以小于或大于MSB。LSB为较小数字的向量范围称为小端点。LSB为较大数值的向量范围称为大端
logic [31:0] v9;//32位向量,小端逻辑
logic [1:32] v10;;//32位向量,大端逻辑
RTL建模中最常见的约定是小端逻辑,并使用0作为向量范围的LSB。上述变量v9说明了这一惯例。本系列中的所有例子都使用了小端逻辑约定。
byte、shortint、int、longint和integer数据类型具有预定义的向量大小,如表3-1所述。预定义范围为小端,LSB编号为位0。
在操作中,存储在向量变量中的值可以被视为有符号或无符号。无符号变量仅存储正值。有符号变量可以存储正值和负值。SystemVerilog使用2的补码表示负值。有符号变量的最高有效位是符号位。设置符号位时,向量的剩余位以二补形式表示负值。
默认情况下,reg、logic、bit和time数据类型是无符号变量,byte、shortint、int、integer和longint数据类型是有符号变量。可以通过将变量显式声明为有符号或无符号来更改此默认值。
向量可以全部或部分引用。位选择引用向量的单个位。位选择使用向量名称,后跟方括号中的位号([ ])部分选择指向量的多个连续位。部分选择使用向量名称,后跟方括号中的一系列位号([ ])
部分选择必须满足两个规则:位的范围必须是连续的,并且部分选择的endian必须与向量声明的endian相同。位选择或部分选择的结果总是无符号的,即使完整变量是有符号的。
变量位选择和部分选择。前面代码段中的位选择使用了硬编码位号。这称为固定位选择。位选择的索引号也可以是变量。比如说。
零位选择的起点也可以是可变的。零位选择可以从变量起点递增或递减。选择的总位数为固定范围,可变部分选择的形式为:
第二个问题:标记指示从起始点位号开始递增。标记指示从起始点位号开始递减。
下面的示例使用可变部分选择来迭代32位向量的字节。
可变位和部分选择是可综合的。但是,前面说明变量位和部分选择的代码段不满足某些综合编译器所需的其他RTL编码限制。
带有子字段的向量。通过使用两组或多组方括号来定义向量范围,可以使用子字段声明向量。下面的代码片段显示了简单32位向量和带有子字段的32位向量之间的区别:
图3-1说明了这两种声明的区别。
图3-1:带有子字段的向量
声明:
第一个范围[3 :0]定义向量中有多少子字段。在本例中,有四个子字段,索引为 b [ 0 ],b [ l ],b [ 2 ],和 b[3]。第二个范围[7:0]定义了每个子字段的大小,在本例中为8位。图3-1说明了简单32位向量和细分为4字节的32位向量的布局。
细分向量的子字段可以使用单个索引而不是部分选择来引用。下面的代码片段演示了在向量b的字节之间循环,并且更简单,因为每个字节都是向量的一个子字段。
细分向量的位选择需要多个索引-选择向量b第三字节的位7编码为:b[3][7]
最佳做法准则3-4 |
---|
当设计主要选择整个向量或向量的单个位时,使用简单的向量声明;当设计经常选择向量的部分时,使用带有子字段的向量,并且这些部分位于已知边界上,例如字节或字边界。 |
选择向量的子字段而不是使用简单向量的固定部分或可变部分,可以使代码更易于编写和维护。
变量可以通过多种方式赋值:
变量只能由单个源分配。例如,如果变量从assign 连续赋值语句中,则在程序块或模块输入端口中也为变量赋值是非法的。但是,对同一变量的任何数量的程序赋值都被视为一个源。要使以下代码正常工作,此规则非常重要:
在RTL建模中,单个源变量赋值的语义限制非常重要,该限制有助于确保抽象RTL仿真行为和综合后实现行为相同
always_ff,always_comb and always_latch程序块进一步将对变量的程序赋值限制为仅在一个程序内,这强制了综合编译器的要求。同一过程中变量的多个赋值被视为单个驱动程序。
在为变量指定值之前,变量未初始化。4态变量的未初始化值为X(所有位均设置为x)。2态变量的未初始化值为“0”(所有位均设置为0)。
在下面的示例中,直到clk的第一个正边缘出现,变量q才被初始化。作为一种4态逻辑类型,在第一个时钟之前,q将有一个X值,此时q将被指定为0值或d值。如果clk的正边缘没有出现,该X值可能表示设计问题,可能是由于时钟选通或其他一些情况。
笔记 |
---|
未初始化的2态变量可以隐藏设计问题。未初始化的2态变量的值为0,这可能是一个合法的复位值。这可能会隐藏设计中复位逻辑的问题。 |
SystemVerilog允许在声明变量时初始化变量,称为在线初始化。例如:
在仿真开始时,变量的在线初始化只执行一次.
一些FPGA设备可以编程,使寄存器在已知状态下通电,而无需复位。在线变量初始化可用于仿真这些时序设备(如触发器)的通电状态。
笔记 |
---|
ASIC技术不支持在线变量初始化,某些FPGA技术可能支持在线变量初始化。 |
当针对不支持可编程通电状态的设备时,综合编译器将:(a)不允许在线初始化,(b)忽略它-当忽略在线初始化时,RTL仿真行为和综合门级实现可能不匹配,
最佳做法准则3-5 |
---|
仅在将作为FPGA实现的RTL模型中使用变量初始化,并且仅对触发器的加电时建模。 |
对于ASIC设计,应使用复位功能来初始化变量。不要使用在线初始化。对于FPGA设计,只有在确定RTL模型始终针对支持加电寄存器状态的设备时,才使用在线初始化。在RTL模型中使用在线初始化有效地将模型锁定为仅用于该类型FPGA设备。
最佳做法准则3-6 |
---|
仅在RTL模型中使用内嵌变量初始化。不要使用初始过程初始化变量。 |
支持在线变量初始化的综合编译器和目标FPGA设备也允许使用初始过程对触发器的通电值进行建模。
全部0条评论
快来发表一下你的评论吧 !