sv标准研读第三章-设计和验证的building block

书接上回:

sv标准研读第一章-综述

sv标准研读第二章-标准引用

3 设计和验证的building block

3.1概述

本章描述以下内容:

—modules, programs, interfaces, checkers和primitives的目的

—subroutines的概述

—packages的概述

—configurations的概述

—design hierarchy的概述

—compilation和elaboration的定义

—name spaces的声明

—仿真时间、时间单位和时间精度

本章定义了本文档中使用的几个重要SystemVerilog术语和概念。还概述了用于表示硬件设计及其验证环境的modeling block的目的和用法。

3.2 设计元素

设计元素指的是SystemVerilog的module(见第23章)、program(见第24章)、interface(见第25章)、checker(见第17章)、package(见第26章)、原语(见第28章)或config(见第33章)。这些结构分别由关键字module, program, interface,checker, package, primitive, 和 config引入。

设计元素是用于建模和构建设计和验证环境的主要building block。这些building block是本文档后续章节中讨论的声明和过程代码的容器。

本章描述了这些building block的目的。关于这些块的语法和语义的详细信息将在本标准后面的章节中定义。

3.3 Modules

SystemVerilog中的基本building block是module,包含在关键字module和endmodule之间。module主要用于表示design block,但也可以作为验证代码的容器,以及验证块和设计块之间的互连。module可以包含的一些结构包括:

— Ports, with port declarations

— Data declarations, such as nets, variables, structures, and unions

— Constant declarations

— User-defined type definitions

— Class definitions

— Imports of declarations from packages

— Subroutine definitions

— Instantiations of other modules, programs, interfaces, checkers, and primitives

— Instantiations of class objects

— Continuous assignments

— Procedural blocks

— Generate blocks

— Specify blocks

前面列表中的每一个结构都将在本标准的后续章节中详细讨论。

注:上述列表并不包括所有内容。module可以包含额外的结构,这也将在本标准的后续章节中讨论。

下面是一个代表2对1多路复用器的module的简单示例:

module在第23章中有更详细的介绍。参见3.11关于用module创建设计层次结构。

3.4 Programs

program building block包含在关键字program…endprogram之间。该构造用于对testbench环境进行建模。module结构很好地描述了硬件。然而,对于testbench,重点不在于硬件级别的细节,如线路、结构层次和互连,而在于对验证设计的完整环境进行建模。

Program block服务于以下三个基本目的:

-它提供执行testbench的入口点。

-它创建一个范围,封装program范围的数据、任务和功能。

-它提供了一个语法上下文,用于指定reactive区域的调度。

program结构作为设计和testbench之间的明确分隔,更重要的是,它指定了专门的仿真执行语义。与clocking block一起(参见第14章),program构造提供了设计和testbench之间的无竞争交互,并支持周期和事务级抽象。

一个program块可以包含数据声明、类定义、子例程定义、对象实例以及一个或多个initial或final过程。它不能包含always块、原语实例、module实例、interface实例或其他program实例。

Sv的抽象和建模结构简化了testbench的创建和维护。同时,可以例化的特性以及能够单独连接每个program实例的特性让他们能够作为general model使用。

一个简单的program声明如下:

更详细的关于program的介绍在第24章。

3.5 Interfaces

Interface的结构是由关键字interface…endinterface包裹起来的。它封装了design blocks、design和verification block之间的通信,允许从抽象的系统级设计通过连续的细化平滑地迁移到较低级别的寄存器转移和设计的结构视图。通过封装块之间的通信,interface构造还促进了设计的重用。

在其最低层次上,接口是一组已命名的nets或variables。该接口在设计中实例化,并且可以连接到其他实例化module、interface和program的接口端口。接口可以作为一个单独的项目通过端口访问,并在需要时引用组件nets或variables。设计的很大一部分通常由端口列表和端口连接列表组成,它们只是名称的重复。用单个名称替换一组名称的能力可以显著减少描述的大小并提高其可维护性。

接口的其他功能来自于它封装功能和连接性的能力,使接口在其最高级别上更像一个类模板。接口可以有参数、常量、变量、函数和任务。可以声明接口中元素的类型,也可以将类型作为参数传入。成员变量和函数作为实例成员相对于接口的实例名被引用。因此,通过接口连接的module可以简单地调用该接口的子例程成员来驱动通信。通过将功能封装在接口中并与module隔离,可以通过使用包含相同成员但在不同抽象级别实现的不同接口替换接口来轻松更改通信协议的抽象级别和/或粒度。通过接口连接的模块根本不需要更改。

为了为模块端口提供方向信息并控制特定模块内子例程的使用,提供了modport构造。顾名思义,方向就是从模块中看到的方向。

除了子例程方法之外,接口还可以包含过程语句(例如,initial或always过程语句)和continuous assignment,这对于系统级建模和testbench应用程序是有用的。这允许接口包括,例如,它自己的协议检查器,它自动验证通过接口连接的所有模块是否符合指定的协议。其他应用程序,如功能覆盖记录和报告、协议检查和断言也可以构建到接口中。

一个简单的interface定义和使用如下:

更多关于interface的描述参见第25章。

3.6 checkers

checker结构,由关键字checker…endchecker包裹,表示封装断言和建模代码的验证块。checker的预期用途是作为验证库单元或作为创建形式化验证中使用的抽象辅助模型的building block。第17章详细讨论了checker结构。

3.7primitives

primitives building block用于表示低级逻辑门和开关。SystemVerilog包括许多内置的基本类型。设计人员可以用用户定义的原语(udp)来补充内置的原语。UDP包含在关键字primitive…endprimitive之间。内置和UDP结构允许建模定时精确的数字电路,通常被称为门级模型。第28至31章更充分地讨论了门级建模。

3.8 subroutines

subroutines提供了一种机制来封装可从一个或多个位置调用的可执行代码。subroutines有两种形式:任务(13.3)和函数(13.4)。

task被称为statement。task可以有任意数量的input、output、inout和引用参数,但不返回值。task可以在执行期间阻塞模拟时间。也就是说,任务退出可以发生在比调用任务更晚的模拟时间。

function可以返回值,也可以定义为不返回值的void函数。非空function调用用作表达式内的操作数。void函数作为statement调用。function可以有input、output、inout和引用参数。函数必须在不阻塞模拟时间的情况下执行,但可以派生阻塞模拟时间的进程。

3.9 packages

Modules, interfaces, programs, 和checkers声明了一个local name space。在Modules, interfaces, programs, 和checkers里声明的标识符是该作用域的局部标识符,不会影响其他building block,也不会与其他building block发生冲突。

packages提供了一个声明空间,它可以被其他building block共享。packages声明可以导入到其他building block中,包括其他packages。

一个package是由关键字package…endpackage包裹起来的,例如:

更多关于package语法和语义请参照第26章。

3.10 configurations

SystemVerilog提供了指定设计配置的能力,它指定模块实例到特定SystemVerilog源代码的绑定信息。库是模块、接口、程序、检查器、原语、包和其他配置的集合。单独的库映射文件指定库中包含的单元格的源代码位置。库映射文件的名称通常指定为在SystemVerilog源代码中读取的模拟器或其他软件工具的调用选项。

更多关于configuration的介绍参照第33章。

3.11 hierarchy概述

module、program、interface、checker和primitives的基本building block用于构建设计层次结构。层次结构是由一个building block实例化另一个building block创建的。当一个module包含另一个module、interface、program或checker的实例时,就会创建一个新的层次结构。通过层次结构级别的通信主要是通过连接到实例化module、interface、program或checker的端口。

下面是使用一些简单声明的两个模块声明的简单示例。模块top包含模块mux2to1的实例,创建具有两层层次结构的设计。

module可以实例化其他module、interface、program、checker和primitives,从而创建一个层次结构树。interface还可以实例化其他building block并创建层次结构树。program和checker可以实例化其他checker。primitives不能实例化其他building block;它们是层次结构树中的叶子。

通常,精心设计但未显式实例化的module或program在层次结构树的顶部隐式实例化一次,并成为顶级层次结构块(见23.3和24.3)。SystemVerilog允许多个顶级块。

任何层次结构中的标识符都可以使用层次路径名从任何其他层次结构中引用(参见23.6)。

实例化语法和设计层次结构在第23章中有更详细的介绍。

3.12 compilationelaboration

编译是读取SystemVerilog源代码,解密加密代码,分析源代码的语法和语义错误的过程。实现可以在一次或多次传递中执行编译。实现可以将编译的结果保存为专有的中间格式,或者可以将编译的结果直接传递到elaboration阶段。在编译过程中不能检查所有语法和语义。有些检查只能在elaboration过程中或完成时进行。

SystemVerilog通过使用编译单元支持单文件和多文件编译(见3.12.1)。

elaboration是将组成设计的组件绑定在一起的过程。这些组件可以包括module实例、program实例、interface实例、checker实例、基本实例和设计层次结构的顶层。elaboration发生在解析源代码之后,simulation之前;它包括扩展实例化、计算参数值、解析层次名称、建立网络连接以及为仿真设计做准备。有关elaboration过程的更多细节,请参见23.10.4。

尽管这个标准定义了compilation和elaboration的结果,但是compilation和elaboration步骤并不要求在实现中是不同的阶段。在本标准中,术语compilation、compile和compiler通常指的是compilation和elaboration过程的结合。因此,例如,当标准提到“编译时错误”时,允许实现在模拟开始之前的任何时间报告错误。

本标准通常不规定有关设计元素的编译顺序的要求。两个例外是关于“编译单元”的规则(见3.12.1),其中编译过程中的实际文件边界是重要的,以及关于引用包项的规则(见26.3),其中需要在引用包之前编译包。

3.12.1编译单元

SystemVerilog支持使用编译单元进行单独编译。提供了以下术语和定义:

—编译单元:一个或多个SystemVerilog源文件编译在一起的集合。

—编译单元作用域:编译单元的局部作用域。它包含位于任何其他作用域之外的所有声明。

—$unit:用于显式访问编译单元范围内的标识符的名称。

定义哪些文件构成编译单元的确切机制是特定于工具的。然而,兼容的工具应该提供允许以下两种情况的使用模型:

a)给定编译命令行上的所有文件构成单个编译单元(在这种情况下,这些文件中的声明可以按照整个文件集的正常可见性规则访问)。

b)每个文件都是一个单独的编译单元(在这种情况下,每个编译单元作用域中的声明只能在其相应的文件中访问)。

使用一个或多个“include”指令包含的文件的内容成为包含它们的文件的编译单元的一部分。

如果在文件末尾有一个不完整的声明,那么包括该文件在内的编译单元将在每个后续文件中扩展,直到在文件组末尾没有不完整的声明。

还有其他可能的文件到编译单元的映射,并且定义它们的机制是特定于工具的,并且可能不可移植。

尽管编译单元作用域不是包,但它可以包含任何可以在包中定义的项(参见26.2)和bind构造(参见23.11)。这些项位于编译单元作用域的name space中(参见3.13)。

下列项目在所有编译单元中都是可见的:module、primitive、program、interface和package。在编译单元范围内定义的项不能从编译单元外部按名称访问。可以使用PLI访问编译单元作用域中的项,PLI必须提供遍历所有编译单元的迭代器。

编译单元作用域中的项可以具有对标识符的分层引用。对于向上的名称引用(参见23.8),编译单元作用域被视为顶层设计单元。这意味着,如果这些不是对在编译单元作用域中创建的标识符的引用,或者不是通过将包导入到编译单元作用域中而使其可见,那么它们将被视为从设计顶部开始的完整路径名($root,在23.3.1中描述)。

在单独编译的单元中,编译器指令一旦被工具看到,就会应用到所有后续的源文本中。但是,来自一个单独编译单元的编译器指令不得影响其他编译单元。这可能导致单独编译单元或作为包含整个源代码的单个编译单元之间的行为差异。

当在作用域中引用标识符时,

—首先,搜索嵌套作用域(参见23.9)(包括嵌套模块声明),包括通过包导入声明提供的任何标识符。

—接下来,搜索在引用之前定义的编译单元作用域的部分(包括通过包导入声明提供的任何标识符)。

—最后,如果标识符遵循层次名称解析规则,则搜索实例层次结构(参见23.8和23.9)。

$unit是包含编译单元的作用域的名称。它的目的是允许对编译单元最外层(即编译单元范围内的那些)的声明进行明确的引用。这是通过与访问包项相同的作用域解析操作符完成的(见26.3)。

举例:

除了任务和函数名(见23.8.1)之外,只能引用编译单元中已经定义的名称。使用显式的$unit::前缀只提供名称消歧,而不增加引用以后编译单元项的能力。

举例:

编译单元作用域允许用户轻松地在编译单元之间共享声明(例如,type),而不必声明一个包,从这个包中可以找到需要导入的文件。由于没有名称,编译单元作用域不能与import声明一起使用,并且在作用域中声明的标识符不能通过层次引用访问。但是,在特定的编译单元中,可以使用特殊名称$unit显式访问其编译单元作用域的声明。

3.13 Name spaces

SystemVerilog有八个标识符名称空间:两个是全局的(definitions名称空间和package名称空间),两个是编译单元全局的(compilation unit名称空间和text macro名称空间),四个是本地的。这8个名称空间描述如下:

a) definitions名称空间统一了所有非嵌套的module、primitive、program和interface标识符,这些标识符定义在所有其他声明之外。一旦一个name被用来在一个编译单元内定义一个module、primitive、program和interface,该name就不能再(在任何编译单元中)被用来在所有其他声明之外声明另一个非嵌套的module、primitive、program和interface。

b)package命名空间统一了所有编译单元中定义的所有package标识符。一个名称一旦在一个编译单元内定义了一个package,就不能在任何编译单元内再次使用该名称声明另一个package。

c)编译单元作用域名称空间存在于module、interface、package、checker、program和基本构造之外。它统一了编译单元范围内的function、task、checker、parameter、命名事件、net声明、变量声明和用户定义类型的定义。

d) 文本宏名称空间在编译单元中是全局的。由于引入文本宏名称并使用前导字符',因此它们与任何其他名称空间保持一致。文本宏名称在组成编译单元的一组输入文件中按出现的线性顺序定义。相同名称的后续定义将覆盖先前定义。

e) module名称空间由module、interface、package、program、checker和基本结构引入。它将module、interface、program、checker、function、task、命名块、实例名、参数、命名事件、网络声明、变量声明和用户定义类型的定义统一在封闭结构中。

f)block名称空间由命名或未命名块、specify、函数和任务结构引入。它统一了命名块、函数、任务、参数、命名事件、声明的变量类型和封闭结构中的用户定义类型的定义。

g)端口名称空间由模块、接口、原语和程序结构引入。它提供了一种从结构上定义位于两个不同名称空间中的两个对象之间的连接的方法。连接可以是单向的(input或output)或双向的(inout或ref)。端口名称空间与模块和块名称空间重叠。实际上,端口名称空间指定了不同名称空间中名称之间的连接类型。声明的端口类型包括input、output、inout和ref。在端口名称空间中引入的端口名称可以通过声明与端口名称同名的变量或网络在模块名称空间中重新引入。

h)属性名称空间由附加到语言元素的(*和*)结构包围(参见5.12)。属性名称只能在属性名称空间中定义和使用。不能在此名称空间中定义任何其他类型的名称。在名称空间内,重新声明先前声明过的名称是非法的。

3.14 仿真时间单位和时间精度

仿真的一个重要方面是时间。术语仿真时间指的是由模拟器维护的时间值,以模拟所模拟的系统描述所需的实际时间。术语时间与模拟时间可互换使用。时间值在设计元素中用于表示传播延迟和过程语句执行之间的模拟时间量。时间值有两个组成部分,时间单位和时间精度。

—时间单位表示时间和延迟的测量单位,可以指定从100秒到1飞秒的单位。

—时间精度表示延迟的精确程度。

时间单位和时间精度都使用以下字符串之一表示:s、ms、us、ns、ps和fs,其数量级为1、10或100。如表3-1所示。

注意:s、ms、ns、ps和fs是秒、毫秒、纳秒、皮秒和飞秒的常用SI单位符号,由于编码字符集中缺少希腊字母(mu),“us”恰当地表示微秒的SI单位符号。

设计要素的时间精度至少与时间单位相同;它不能是比时间单位更长的时间单位。

3.14.1时间值的舍入

在设计元素(如模块、程序或接口)中,时间精度指定在仿真中使用延迟值之前如何四舍五入。

时间精度与时间单位有关。如果精度与时间单位相同,则延迟值四舍五入为整数(整数)。如果精度比时间单位小一个数量级,则延迟值四舍五入到小数点后一位。例如,如果指定的时间单位为1ns,精度为100ps,则延迟值四舍五入到小数点后一位(100ps相当于0.1ns)。因此,2.75ns的延迟将四舍五入到2.8ns。

设计元素中的时间值精确到为该设计元素指定的时间精度单位内,即使设计中其他地方指定的时间精度更小。

3.14.2 指定时间单位和时间精度

时间单位和时间精度可以通过以下两种方式指定:

—使用编译器指令`timescale

—使用关键字timeunit和timeprecision

3.14.2.1 `timescale编译器指令

' timescale编译器指令为所有没有使用timeinit/timeprecision结构的设计单元指定默认的时间单位和精度。当在源代码中遇到' timescale指令时,' timescale指令保持有效,直到读取另一个' timescale编译器指令。' timescale指令只影响当前编译单元;它不会跨越多个编译单元(参见3.12.1)。

`timescale的通用语法如下(更多细节参照22.7):

下面的示例指定一个时间单位为1ns,精度为10ps(精度为小数点后两位)。编译器指令同时影响模块A和模块B。第二个时间刻度指令取代了第一个指令,为模块C指定了1 ps的时间单位和1 ps的精度(精度的小数点后零点)。

' timescale指令可能导致文件顺序依赖问题。如果前面三个模块按照A、B、C的顺序编译(如图所示),那么模块B将以纳秒为时间单位进行模拟。如果同样的三个文件按照C, B, A的顺序编译,那么模块B将以皮秒为单位进行模拟。这可能会导致非常不同的模拟结果,具体取决于模块B中指定的时间值。

3.14.2.2 关键字timeunit和timeprecision

时间单位和精度可以分别由timeunit和timeprecision关键字声明,并设置为时间字面值(参见5.8)。还可以使用timeunit关键字的第二个可选参数(使用斜杠分隔符)来声明时间精度。例如:

在设计元素中定义timeunit和timeprecision构造可以消除编译器指令的文件顺序依赖问题。

对于任何模块、程序、包或接口定义或在任何编译单元范围内,最多只能有一个timeunit和一个timeprecision。这将定义一个时间范围。有规定的,其时间单位和时间精度声明应当在当前时间范围内的其他事项之前(即声明要放在当前scope的最前面)。timeunit和timeprecision声明可以在后面重复,但必须与当前时间范围内的前一个声明匹配(即当前scope下,timeunit和timeprecision可以重复,但是重复的内容必须一致)。

3.14.2.3 timeunit、timeprecision、`timescale的优先级

如果在模块、程序、包或接口定义中没有指定timeunit,则时间单位应使用以下优先级规则确定:

a)如果模块或接口定义是嵌套的,则嵌套的module和interface的时间单位继承上层的时间单位 (程序和包不能嵌套)。

b)否则,如果之前已经指定了`timescale(在编译单元内),则时间单位设置为最后一个`timescale的单位【即前面最近的`timescale发挥作用】。

c)否则,如果编译单元作用域指定了时间单位(在所有其他声明之外),则该时间单位应设置为编译单元的时间单位【编译单元指定的时间单位起作用】。

d)否则,使用默认的时间单位。

编译单元作用域的时间单位只能通过timeunit声明来设置,而不能通过' timescale指令来设置。如果未指定,则使用默认时间单位。

当前时间范围未规定时间精度的,那么优先级规则和上面时间单位的优先级规则一样。

默认的时间单位和精度是特定于实现的。

如果某些设计元素有时间单位和精度,而其他元素没有,则为错误。

3.14.3 仿真时间单位

global time precision,也称为simulation time unit,是所有timeprecision语句(包括使用timeprecision声明的、使用timeunit声明的、使用`timescale声明的)的最小值。

Step的时间单位等于global time precision。与表示物理单位的其他时间单位不同,Step不能用于设置或修改精度或时间单位。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值