reg、wire、var和logic傻傻分不清
Verilog reg和Verilog wire之间的区别经常使刚开始使用该语言的许多程序员感到困惑。作为一个初学者,我被告知遵循这些准则,这些准则通常可以正常工作:
-
使用Verilog的reg信号,用于过程块中的左值赋值。
-
使用Verilog的wire信号,用于连续赋值。
然后,当我采用SystemVerilog编写RTL设计时,被告知现在一切都可以成为“logic”。通常,这通常仍然有效,但是我时不时会遇到有关变量,net和赋值的神秘错误消息。
Verilog语言本身就是对硬件的描述,因此具有针对硬件的变量类型和线网类型。这些类型具有特定的仿真和综合语义,表示在硬件系统中的实际连接行为。
因为在实际硬件电路中总是存在四种状态:0、1、X、Z。因此在Verilog中的变量都是四态逻辑的,加上线网类型的多个强度级组合,形成了100多种值。
其中wire类型表示的是单元间的物理连线,wire不存储值,它的值由驱动单元的值决定,如果没有驱动,线网的默认值为Z(tri、trireg类型除外)。常见的线网类型是wire和tri,两者的语法和功能基本一致,但是tri本意用于描述多个驱动源同时驱动一根线的线网类型,而wire用来描述一个驱动源的驱动。
寄存器reg类型是数据存储单元的抽象表示,reg类型和wire类型共同构成RTL级描述的基本数据类型。
需要注意的是,reg变量和硬件电路没有任何关系,并不一定用在时序电路中,在组合逻辑的行为描述中,也可能使用reg类型。例如要在always @(*)块中使用组合逻辑来驱动物理连接,则必须将物理连接声明为reg类型。
正如上文所述,因为在Verilog中,所有的线网和变量都是使用四态值,因此没必要也不能清晰的区分信号类型。为了增强灵活性,SV中定义信号同时具有类型和数据类型两个属性。
类型指示信号是属于线网(net)还是变量(var)。SV使用所有的Verilog线网类型,并且没有进行任何拓展。如下表所示:
需要注意的是,线网类型必须配合使用四态数据类型,一般情况下省略数据类型,默认为四态。
数据类型指示线网或者变量的值系统。对于四态数据类型就是0、1、Z或X,对于两态数据类型就是0或1。
在Verilog中,初学者往往分不清reg和wire的区别。SV作为一门侧重验证的语言,并不十分关心逻辑是reg还是wire,因此引入了一个新的四态数据类型logic。它能替代大部分reg和wire出现的场景,但是不能被多个结构进行驱动。logic的出现降低了设计时出错的可能性。
关键字logic是一个数据类型。当logic单独使用时,则隐含这是一个变量var,四态变量可以使用一对关键字var logic进行显式声明。例如:
var logic [31:0] data; //一个32位宽的变量
wire logic [31:0] addr; //一个32位宽的线网
从语义上来说,SV中的logic数据类型和Verilog中的reg类型是一样的,可以互换使用,更多的是兼容wire类型。
SV中的两态数据变量
bit --1位两态无符号整数 byte --8位两态有符号整数 shortint --8位两态有符号整数 int --16位两态有符号整数 longint --32位两态有符号整数
两态仿真语义
仿真开始时,对于四态变量,例如reg,logic和integer等的所有位缺省逻辑值是X。这因为在硬件系统中这些变量被认为没有初始化,因此直到驱动赋值给变量前,它们的值都是不确定的。所有的两态数据类型默认的初始逻辑为0,因为两态类型不能存储X值,因此它们不能描述未初始化的状态。这也是使用四态数据类型描述可综合RTL模型的原因之一。
需要注意的是,把四态值赋给两态数据类型是合法的。此时四态值中任何位的X或Z值均会对应的转换为逻辑0。
把四态变量赋给两态类型时,最可怕的不是这些值被转换为0还是1,而是要检查是否有未知值的传播。SV中存在”$isunknown”操作符,用来检测表达式中是否存在X或Z,一旦存在就会返回1。如例所示:
例:对四态状态值的检查
if ($isunknown(data) ) $display(“@%0t : 4-state value detected“,$time);