在Verilog中有一个独特的概念,大多数初学者无法理解,就是现在SystemVerilog硬件描述语言(HDL)中的wire(网络)和reg(变量)之间的区别。这个概念是每个有经验的RTL设计人员都应该熟悉的,但是现在有许多验证工程师没有Verilog经验,试图为他们的测试平台采用SystemVerilog。验证方法学课程倾向于专注于面向对象编程(OOP)的测试平台设计,但不包括这个主题,认为它仅适用于设计人员。不对,如果您必须与DUT进行通信,那么您需要了解 wire's and reg's(网络和变量)之间的区别。
任何负责设计或验证硬件的人都应具备一些基本的编程技巧,并理解变量的概念。如果没有,你最好在这里停下来,并刷一些编程基础知识。您需要从以前学到的其他编程语言中忘掉的关键概念是您将值写入变量,并且该值将保存到该变量的下一次赋值。这个概念被称为程序分配,它是执行一组有序的语句的一部分。 HDL可以在assignments和其他statements之间添加一些时间概念。最后一个分配决定变量的当前值。
Combinatorial Logic | Sequential Logic
|
reg a,b,c; | reg a,b,c;
|
always @(b or c) | always @(posedge c)
|
begin | begin
|
a = b | c; | a = a + b;
|
end | end
最初,Verilog使用关键字reg来声明代表时序硬件寄存器的变量。最后,综合工具开始使用reg来表示时序和组合硬件,如上所示,并且Verilog文档被改为说reg是用来声明变量的。 SystemVerilog将reg重新命名为logic以避免与寄存器混淆 - 它只是一种数据类型(具体来说,reg是1位,4状态的数据类型)。然而,由于有些老旧的材料引用的依然是reg类型,人们会感到困惑。从现在开始就忘掉它并使用logic。
HDL的另一个显着特征是它模拟了大量的并行进程。在数字设计的最底层,每个原始门(AND,OR,DFF)都是一个独立的并发进程。模块是代表在不同抽象层次建模的过程的容器。基元和模块组通过信号网络将值传递给对方。在Verilog中,wire声明表示与每个连接的连接的网络(net),它们驱动一个值或响应网络上驱动的解析值。每个并发进程的输出在所谓的连续赋值中驱动一个网络,因为该进程不断更新其想要在网络上驱动的值。有多种方式可以声明连续赋值,所有这些都代表永久性行为:
wire A, B, C;
assign A = B| C; // continuous assignment construct.
or(A,B,C); // gate-level instance terminal connection
mymodule m1(A,B,C); // module instance port connection
虽然这些都是连续赋值结构的不同形式,但它们都没有像程序赋值那样直接为网络赋值。并行驱动到网上的所有值都被传递到内置的解析函数中。该解析功能的结果基于代表所使用硬件技术的每个驱动程序的优势。例如,一个中断请求信号可能使用有线网络或(工作)网络类型来指示至少有一个设备正在驱动'1',否则它将解析为'0'。一些信号会有较弱的上拉/下拉电阻,这些电阻将被更强大的驱动器的值所覆盖。大多数技术不允许在同一个网络上驱动不同的值,并且当这种情况发生时,网络将解析为未知的'x'。在这种情况下,只有一个驱动器主动分配“0”或“1”,其他驱动器通过驱动高阻或“z”状态被有效关闭。这样做的结果是,必须使用网络对双向端口进行建模,以便在端口的任一侧都有多个驱动程序。
请参阅我最近的DVCon论文,了解双向信号建模的示例以及将Testbench连接到DUT的其他提示。
事实证明,设计中绝大多数的网络将只有一个驱动程序,因此不需要强度信息或分辨率功能。 SystemVerilog添加了一项功能,允许单个连续赋值来驱动一个变量。每当表达式改变其值时,驱动连续赋值的表达式就被分配给变量。只要你有多个驱动或需要强度信息,你必须回到使用net。您不能将过程性和连续性赋值混合到同一个变量中。这种限制的原因在于,无法解决过程性赋值语句的“最后写赢”语义,其中包括想要持续分配变量的驱动程序(即,最后一次写入的时间和连续分配应该接管的时间?)。
总之,您现在应该使用4态的logic(或2态的bit)来表示所有单个驱动信号。任何具多个驱动的信号都应声明为wire。