System Verilog提供两组通用的数据类型:网络和变量(nets 和 variables)。网络和变量同时具有类型和数据类型特性。类型表示信号为网络或变量,数据类型表示网络或变量的值系统,即2态或4态。为简单起见,使用术语data type来表示信号的类型和数据类型。
软件工具(如仿真器和综合编译器)使用数据类型来确定如何存储数据和处理数据上的更改。数据类型影响操作,并在RTL建模中用于指示所需的硅行为。例如,数据类型用于确定加法器应基于整数还是基于浮点,以及应执行有符号算术还是无符号算术。
网络用于将设计元素连接在一起,例如将一个模块的输出端口连接到另一个模块的输入端口。网络在三个重要方面不同于变量:
驱动器的强度级别以0~7的步长表示。每个级别由一个关键字表示。大多数建模构件的默认强度级别为“强”,即级别6。强度级别对于晶体管级建模很重要,但不用于RTL建模。强度的表示和使用超出了本文关于RTL建模的范围。
通过同时指定类型和数据类型来声明网络。类型可以是表3-3和3-4中列出的任何关键字。数据类型必须是关键字logic,可以显式指定或隐式推断。
每个SystemVerilog网络类型都有特定的语义规则,这些规则会影响多个驱动程序的解析方式。虽然所有网络类型都表示硅行为,但并非所有网络类型都可以用标准ASIC和FPGA技术表示。表3-3列出了ASIC和FPGA综合编译器支持的网络类型。
表3-3:可综合网络类型
类型 | 代表 |
---|---|
wire | 使用CMOS行为解析多个驱动器的互连网络 |
tri | wire的同义词在所有方面都相同,可用于强调预期具有三态值的网络 |
Supply0 | 在电源强度级别具有恒定逻辑0的互连网络。可用于表示接地轨(GND、VSS) |
Supply1 | 在电源强度级别具有恒定逻辑1的互连网络。可用于表示供电轨(VCC、VDD) |
SystemVeriIog有几种网络类型,综合编译器并不普遍支持这些类型,如表3-4(第77页)所示。
表3-4:一般不可综合的网络类型
类型 | 代表 |
---|---|
uwire | 不允许或不解析多个驱动程序的互连网络 |
pull0 | 一种互连网络,具有将下拉电阻器连接到网络的特性 |
Pull1 | 一种互连网络,具有将上拉电阻器连接到该网络的特性 |
wand | 一种互连网络,通过对驱动值进行AND运算来解析多个驱动程序 |
triand | wand的同义词,在所有方面都相同;可用于强调预期具有三态值的网络 |
wor | 一种互连网络,通过对驱动值进行OR来解析多个驱动程序 |
trior | wor的同义词,在所有方面都相同;可用于强调预期具有三态值的网络 |
trireg | 具有电容性的互连网络;如果所有驱动器均为高阻抗,则电容反映最后解析的驱动值 |
笔记
某些RTL综合编译器可能支持一种或多种网络类型。最佳实践编码风格是不使用这些类型,以确保RTL模型与任何综合编译器兼容。如果使用其中一种类型,设计工程师应检查项目中使用的所有工具是否支持该类型。
大多数ASIC和FPGA器件采用CMOS技术实现。CMOS互连的行为用线和三网类型表示。wire类型是最常用的网络类型,也是隐式推断网络时的默认网络类型。
ASIC和FPGA设计中的大多数互连网络将单个驱动器连接到一个或多个接收器。例外是共享总线,其中多个驱动程序连接到一个或多个接收器。例如,RAM设备具有双向数据总线,用于将值写入RAM和从RAM读取值。ASIC和FPGA设备通常具有一定数量的双向I/O焊盘,用于读取和驱动值。
最佳做法准则3-7
当设计意图是具有单个驱动器功能时,使用逻辑数据类型将设计组件连接在一起。仅当设计意图是允许多个驱动器时,才使用wire or tri类型。
将互连声明为逻辑将推断一个变量而不是网络类型。变量只允许单个源(驱动程序)。
尽管大多数互连网络仅具有一个驱动器;可综合的网络类型(如wire)允许多个驱动程序。工程师在使用网络类型时需要小心避免编码错误。网络列表中的简单错误可能会导致同一网络无意中连接到多个驱动程序。在编译和优化过程中不会捕获这种类型的错误。该错误会导致在仿真过程中检测到功能性错误。下面几个规则可以避免一些错误:
通过将输入端口显式声明为var logic类型,可以防止输入端口的意外多个驱动程序。变量不允许多个驱动源。在编译和详细阐述设计模块时,意外的多个驱动程序将被报告为编码错误。
笔记
在编写本文时,大多数综合编译器和一些仿真器尚未添加对uwire类型的支持,尽管它自2005年以来一直是Verilog/SystemVerilog标准的一部分。当需要多驱动器网络时,本书中的示例使用wire或tri类型。
通过指定网络类型和可选数据类型来定义网络。数据类型必须是4态logic数据类型,或从4态logic数据类型派生的用户定义类型,如果未明确指定数据类型,则隐式推断logic数据类型。
所有网络类型的默认大小都是标量(1位)。可以使用与变量相同的语法将网络显式声明为任何大小的向量。但是,只有变量向量声明可以划分为子字段。向量不能划分为子字段。
一些可综合的网络声明示例如下:
默认情况下,所有网络类型都是无符号的。网络可以用与变量相同的方式显式声明为有符号或无符号。
网络位和部分选择。可使用与变量向量相同的语法从向量中选择任何特定位或位组。常量和变量位和部分选择都可以在网络上执行。
未声明的信号将在多个上下文中推断网络类型:
默认情况下,推断的隐式网络类型为网络wire类型。隐式网络的向量大小基于本地上下文。如果网络是从模块端口声明推断出来的,那么隐式网络的向量大小将是端口的大小。如果从与模块、接口或例化实例的连接推断网络,则将推断标量网络。如果从连续赋值的左侧推断标量网络,则也会推断标量网络。示例3-1说明了几个隐式网络声明。
示例3-1:创建隐式网络的未声明标识符示例
上面还涉及到dot-name 和 dot-star的使用,这将在后面介绍。
更改默认的隐式网络类型。可以使用编译器指令:
'default_nettype
更改隐式网络类型。每当推断出隐式网络时,在指令之后编译的所有SystemVerilog代码都将使用指定的网络类型。'default_nettype必须在模块或接口边界之外指定。
示例3-2将隐式网络类型定义为uwire(单驱动源)类型
示例3-2:更改隐式网络的网络类型
`default_nettype tri1 // change default for implicit nets
//`default_nettype uwire // change default for implicit nets
`begin_keywords "1800-2012" // use SystemVerilog-2012 keywords
module mixed_rtl_and_gate_adder
(input a, // implicit uwire net, logic data type
input logic b, // implicit uwire net, logic data type
input reg ci, // implicit uwire net, logic data type
output sum, // implicit uwire net, logic data type
output logic co // implicit variable, logic data type
);
timeunit 1ns/1ns;
xor g1 (n1, a, b); // undeclared n1 is implicit uwire net
xor g2 (sum, n1, ci);
and g3 (n2, a, b); // undeclared n2 is implicit uwire net
assign n3 = n1 & ci; // undeclared n3 is implicit uwire net
always_comb begin
co = n2 | n3;
end
endmodule: mixed_rtl_and_gate_adder
`end_keywords
`default_nettype wire // reset default for implicit nets
关闭隐式网络声明。
隐式网络有优点也有缺点。大型、复杂的网络表可能需要几十个1位网络来连接设计块。显式声明这些多个网络既繁琐又耗时,显式声明大量互连网络也可能需要大量的键入,并存在需要键入的错误风险。隐式网络可以减少编写网表模型所需的时间,并减少键入错误。
但是,隐式网络的一个缺点是,与模块、接口或例化实例的连接中拼写错误的名称不会被检测为连接错误。不正确的名称将推断出一个隐式网络,其结果是必须检测、调试和纠正的功能性错误。另一个缺点是,从实例连接推断出的网络将是一个1位网络,而不管该网络连接到的端口大小如何。连接大小不匹配将导致警告消息,但仿真或综合仍将继续。端口大小不匹配还可能导致必须检测和纠正的功能缺陷。
隐式net与显式声明net的优缺点是Verilog和SystemVerilog工程师经常争论的话题。这实际上是用户偏好的问题。这两种编码风格都很好地工作,并且两种风格都有优点和缺点。
对于喜欢显式声明所有网络的工程师或公司,SystemVerilog提供了一种禁用隐式网络的方法。这就要求显式声明所有网络,禁用隐式网络是通过设置编译器指令来完成的:
此编译器指令必须在模块外部设置,并对编译到同一编译单元的所有后续模块保持有效,或者直到遇到另一个'default_nettype指令。
使用隐式网络或禁用隐式网络通常是个人偏好,有时也是公司内部的编码准则。本书中的示例假设启用了隐式网络,默认隐式网络类型为wire。
笔记
“default_nettype”指令可以影响多个文件。编译器指令在编译单元中是准全局的。当在同一编译单元中编译多个文件时,编译器指令对遇到该指令之前编译的任何文件没有影响,但会影响遇到该指令之后编译的所有文件。
最佳做法准则3-8
如果更改了默认网络类型,请始终将’default_nettype”用作一对指令,第一个指令将默认设置为所需的网络类型,第二个指令将默认设置回wire。
在任何更改默认值的模块之后,将默认网络类型设置回wire,将防止意外的副作用影响到其他预期默认wire的文件。
给网络赋值。网络可以从两种类型的源接收值:作为output or inout port端口的连接,以及作为连续赋值(assign语句)的左侧。不能在程序赋值的左侧使用网络。
在整个仿真过程中对连续赋值进行求值,赋值右侧的任何更改都会导致对右侧表达式进行求值,并更新左侧表达式。左侧可以是变量或网络。网络的连续赋值可以是显式的,也可以是隐式的。显式连续赋值以关键字assign开始。
隐式连续赋值结合了网络声明和对该网络的赋值。组合中未使用assign关键字。
注意不要混淆内嵌变量初始化和隐式连续赋值。
这两个构造的语法可能看起来很相似,但行为却截然不同。在线变量初始化是一次评估和赋值,在前面的示例中,如果a或b的值在以后的仿真中发生变化,则不会更新变量。隐式连续赋值,顾名思义,是在整个仿真过程中不断求值的表达式。在前面的示例中,每次仿真期间a或b的值发生变化时,n1都会更新。
连接大小不匹配。网络用于将设计块连接在一起,例如将一个模块的输出端口连接到一个或多个其他模块的输入端口。通常,端口和互连网络的向量宽度相同,但SystemVerilog允许向量大小不同。例如16位标量网络可以将32位宽的输出端口连接到8位宽的输入端口。这种尺寸不匹配可能是设计错误,但在SystemVerilog中,只会生成警告。
SystemVerilog语言具有解决端口/连接不匹配的规则:
仿真器和综合编译器将生成连接大小不匹配的警告消息。这些警告不容忽视!连接不匹配通常是需要纠正的设计错误。