|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
SystemVerilog是一种硬件描述和验证语言(HDVL),它基于IEEE1364-2001 Verilog硬件描述语言(HDL),并对其进行了扩展,包括扩充了C语言数据类型、结构、压缩和非压缩数组、 接口、断言等等,这些都使得SystemVerilog在一个更高的抽象层次上提高了设计建模的能力。SystemVerilog由Accellera开发,它主要定位在芯片的实现和验证流程上,并为系统级的设计流程提供了强大的连接能力。' U e. r2 `" {7 Q- @- h
& [% ` o3 {. V3 C7 a f
1. 接口(InteRFace)
P3 A( k' l* E! |1 K! JVerilog模块之间的连接是通过模块端口进行的。为了给组成设计的各个模块定义端口,我们必须对期望的硬件设计有一个详细的认识。不幸的是,在设计的早期,我们很难把握设计的细节。而且,一旦模块的端口定义完成后,我们也很难改变端口的配置。另外,一个设计中的许多模块往往具有相同的端口定义,在Verilog中,我们必须在每个模块中进行相同的定义,这为我们增加了无谓的工作量。. m2 T1 I# I/ k: h- `1 {! e2 J
SystemVerilog提供了一个新的、高层抽象的模块连接,这个连接被称为接口(Interface)。接口在关键字interface和endinterface之间定义,它独立于模块。接口在模块中就像一个单一的端口一样使用。在最简单的形式下,一个接口可以认为是一组线网。例如,可以将PCI总线的所有信号绑定在一起组成一个接口。通过使用接口,我们在进行一个设计的时候可以不需要首先建立各个模块间的互连。随着设计的深入,各个设计细节也会变得越来越清晰,而接口内的信号也会很容易地表示出来。当接口发生变化时,这些变化也会在使用该接口的所有模块中反映出来,而无需更改每一个模块。下面是一个接口的使用实例:
1 `/ \5 v& T- S4 }, ainterface chip_bus;// 定义接口4 o2 E A0 @' {) R( L' ?
wireread_request, read_grant;
/ O! J7 U& O9 rwire [7:0]address, data;
1 }$ u5 u4 ?. W Tendinterface: chip_bus
0 [, j. Q0 u u: V0 Vmodule RAM(chip_bus io, // 使用接口( ~6 s) e+ J5 O( B
inputclk);- g8 k$ y: k3 c) {2 Q5 g
//可以使用io.read_request引用接口中的一个信号# l' B" J* F, D( m( S. D z$ g
endmodule6 R7 ~& m9 L( ~$ R1 ?9 k& G6 h
module CPU(chip_busio, input clk);
7 d7 I2 l6 z$ E8 ^1 J......; v) B/ {0 _, Y( [. ~' G
实际上,SystemVerilog的接口不仅仅可以表示信号的绑定和互连。由于SystemVerilog的接口中可以包含参数、常量、变量、结构、函数、任务、initial块、always块以及连续赋值语句,所以SystemVerilog的接口还可以包含内建的协议检查以及被使用该接口的模块所共用的功能。
0 p, N$ h; i( L l; I# A. V
. i' M- _. N2 B3 @. R2. 全局声明和语句
' }$ Z9 F% L6 c0 `9 F: @在Verilog中,除了一个模块可以作为模块实例引用其他模块外,并不存在一个全局空间。另外,Verilog允许任意数目的顶层模块,因此会产生毫无关联的层次树。
. Q7 H3 `3 ]& K3 f. P* g- FSystemVeriog增加了一个被称为$root的隐含的顶级层次。任何在模块边界之外的声明和语句都存在于$root空间中。所有的模块,无论它处于哪一个设计层次,都可以引用$root中声明的名字。这样,如果某些变量、函数或其它信息被设计中的所有模块共享,那么我们就可以将它们作为全局声明和语句。全局声明和语句的一个使用实例如下:, j9 S( A% w" A- ]$ E
reg error_flag; // 全局变量4 ], _" Y; D% I
function compare(...); // 全局函数
; R/ X$ H& v4 }always@(error_flag) // 全局语句
& R- w6 F6 h) k4 d& ~...
" h8 n& E9 V4 n1 ^! B ~module test;0 h. F& m/ r7 a
chip1 u1(...)
8 ~$ m9 w$ S. D# ]2 Hendmodule
& ~' L0 B( g- Y) C+ _module chip1(...);; @# M1 P( u/ \
FSM u2(...);
8 W) U$ K) K7 M9 W0 J$ Lalways@(data)* q0 c* ]/ A6 ?
error_flag= compare(data, expected);4 f# N+ r9 E) ^0 o
endmodule
4 y/ f$ w3 e w% w5 Dmodule FSM(...);% B" j1 C1 O: Z( D4 l& c
...0 v. P4 I1 z& A E, `
always @(state)9 z) q) A/ y2 ]; X+ Y8 M
error_flag= compare(state, expected);
# C8 ?& s* H* Z6 F6 zendmodule
. X6 d, {: P/ A" j7 W: o, Y5 r9 e# e/ U
3. 时间单位和精度
* o9 f8 q, ^0 k5 b& R在Verilog中,表示时间的值使用一个数来表示,而不带有任何时间单位。例如:
1 F2 E3 ~" a! b5 I) n: r& b ?# Cforever #5clock= ~clock;
, K) R+ S9 F% `$ x从这一句中我们无法判断5代表的是5ns? 5ps? 还是其他。Verilog的时间单位和精度是作为每一个模块的属性,并使用编译器指令`timescale来设置。使用这种方法具有固有的缺陷,因为编译器指令的执行依赖于源代码的编译顺序,编译器总是将它遇到的最后一个`timescale设置的时间单位和精度作为之后的标准。那么,假如有些模块之前没有使用`timescale设置时间单位和精度,这就有可能出现同一个源代码的不同仿真会出现不同结果的情况。
+ D4 w: t( n* l+ F8 v- l; j/ L |
|