太扯淡了
就是把书给打成文档了
这也拿来赚钱
我给你全贴出来
第二章 SystemVerilog声明的位置内容主要包括以下四个方面:
1.
包定义及引用包的内容
2.
$unit 编辑单元声明
3.
未命名块的声明
4.
增强时间单元的定义
新增数据类型集锦:
1.
logic —— 代表1-bit 4-state变量,类似于Verilog中的reg类型,可用来定义任意长度的变量。
2.
enum —— 代表可计数的net或变量(veriable),类似于C语言中的枚举类型,但是附加了用于硬件模型的语法和语义。
3.
typedef —— 用户自定义类型。
4.
struct —— 结构体类型。
2.1 包2.1.1
包定义SystemVerilog比Verilog增添了包定义,关键字为package和endpackage。
可综合的包中可以包括:
1.
parameter和localparam常量定义
2.
const变量定义
3.
typedef用户自定义类型
4.
全自动化task和function定义
5.
从其他包中引入状态
6.
操作符重载定义
其中在包中,parameter参数是不能进行重定义的。Parameter和localparam可综合。
如例2-1所示,为包定义。
parameter VERSION = "1.1"; typedef enum {ADD, SUB, MUL} opcodes_t; function automatic [31:0] multiplier (input [31:0] a, b); // code for a custom 32-bit multiplier goes here return a * b; // abstract multiplier (no error detection)
2.1.2
引用包的内容在“包”中模块和接口处涉及到的定义和声明常用的四种方式:
1.
直接应用“::”scope resolution operator操作符
2.
从特别“包”中导出应用于模块或接口
3.
从特别“包”中导出通配符(Wildcard)应用于模块或接口
4.
从“包”中导出用于$unit声明中
1.
直接应用“::”scope resolution operator操作符
“::”操作符将“包”与“包中项”相连,包名和包中项名由操作符“::”隔开。举例:module中端口定义为instruction_t类型,instruction_t是在definitions包中进行的定义。如下所示例2-2:
(input definitions::instruction_t IW, output logic [31:0] result always_ff @(posedge clock) begin definitions::ADD : result = IW.a + IW.b; definitions::SUB : result = IW.a - IW.b; definitions::MUL : result = definitions:: 2.
从特别“包”中导出应用于模块或接口
通过该种方式,例2-2可改写为例2-3,如下所示:
(input definitions::instruction_t IW, output logic [31:0] result import definitions::multiplier; ADD : result = IW.a + IW.b; SUB : result = IW.a - IW.b; MUL : result = multiplier(IW.a, IW.b); 注意:importing即只能导引出可枚举的类型,而不能导出定义中用到的标号。如下:
import definitions:pcode_t; 是错误的。它不能起作用。这样导出使得opcode_t在module中是可见得,但是,opcode_t则不能应用definitions中的枚举项。
3.
从“包”中导出通配符(Wildcard)应用于模块或接口
包中所有项可以通过通配符(wildcard)变成可视状态。用“*”表示。
举例: import definitions :: *;
但是通配符不会自动导引出包中的所有内容,而只是导引出模块或是接口中所用到的项。注意,模块或接口中本地的定义和声明的优先级要高于通配符,具体引用的包中项优先级也高于通配符。
如下例2-4中所示,应用通配符“*”引出该模块中所用到的包中项,在case语句中应用ADD,SUB,MUL和multiplier时,将会在definitions包中找到。
Example 2-4: Using a package wildcard import (input definitions::instruction_t IW, output logic [31:0] result import definitions::*; // wildcard import ADD : result = IW.a + IW.b; SUB : result = IW.a - IW.b; MUL : result = multiplier(IW.a, IW.b); 2.1.3
综合指导为了便于综合,包中的任务(tasks)和功能(functions)必须是定义为自动形式,并不包括静态变量。
2.2 $unit 编译单元声明这是SystemVerilog比Verilog多加的一个概念。
编译单元中的所有内容在同一时间进行编译。编译单元提供的一个概念,就是说软件可以分别对子块进行编译。其中子块可能是由单一模块或多重模块组成,并且模块可能包块单一的文件或是多重文件,也可以包含接口模块和测试模块。
同时,编译单元的范畴还包块外部声明。
编译单元的范畴包括以下几个方面:
1.
时间单位和精度的声明。
2.
变量(variable)声明
3.
网表(net)声明
4.
常量(constant)声明
5.
用户自定义类型(typedef,enum,class)
6.
任务和功能定义
如下例2-5所示为外部声明,其中包括常量,变量,用户自定义类型以及功能。
Example 2-5: External declarations in the compilation-unit scope (not synthesizable) /******************* External declarations *******************/ parameter VERSION = "1.2a"; // external constant reg resetN = 1; // external variable (active low) typedef struct packed { // external user-defined type function automatic int log2 (input int n); // external function /********************* module definition *********************/ // external declaration is used to define port types output instruction_word_t q, input instruction_word_t d, always @(posedge clock, negedge resetN) if (!resetN) q <= 0; // use external reset
注意: 外部编译单元的声明不是全局的。
所谓全局声明定义的参数,设计建立的所有模块都可以应用,不管所有的文件是否分别编译或是同时编译。SystemVerilog中一个编译单元只用于需要同时编译的文件。
举例来说,有两个模块分别为CPU模块和Controller模块,两个模块同时引用同一个外部声明变量reset,则可能有以下两种情况存在:
1.
如果两个模块在同一时间进行编译,则会产生一个编译单元,则外部声明变量reset则为两个模块共用。
2.
如果每个模块分别进行编译,则会产生两个编译单元空间,分别应用两个不同的reset变量。
2.2.1
编码指导
$unit 只能用于导出包。
1.
不可在编译单元空间进行声明。所有的声明应在包中命名。
2.
必要的话,可以将包导出到$unit单元中。这对于模块或是接口包含多个由用户自定义端口类型的情况是非常有用的,类型定义可以在包中定义。
当文件分别进行编译时,直接在$unit编译单元中进行对象声明会导致设计的错误。
2.2.2
SystemVerilog标识符搜索规则SystemVerilog定义了简单并直接的标识搜索规则,如下:
1.
首先,搜索本地声明,似Verilog标准
2.
其次,搜索包中声明
3.
第三,搜索编译单元范畴的声明
4.
第四,搜索设计层次的声明
2.2.3
源码顺序注意:数据标识符和类型定义一定要在应用前进行声明。
编译单元中的变量和线网类型
未定义类型的标识符默认为线网类型(wire)。
外部声明定义必须在使用之前。
如下例所示,说明了编码顺序对声明使用的影响。
module parity_gen (input wire [63:0] data ); assign parity = ^data; // parity is an implicit local net reg parity; // external declaration is not used by module parity_gen. because the declaration comes after it has been referenced module parity_check (input wire [63:0] data,output logic err); assign err = (^data != parity); // parity is the $unit 2.2.4
将包导入$unit的编码规则1. 直接引用用户自定义变量
(input definitions::instruction_t IW, output logic [31:0] result 2. 从包中引用用户自定义变量
// import specific package items into $unit import definitions::instruction_t; output logic [31:0] result // wildcard import package items into $unit output logic [31:0] result 若将包的内容陈述于文件definitions.pkg文件中,则若在设计文件或是testbench文件中要用到该包,则在程序开头加上`include “definitions.pkg”一句,即可对包进行编译。
2.2.5
综合规则可综合定义包括以下:
1.
typedef用户自定义类型
2.
Automatic功能
3.
Automatic任务
4.
parameter和localparam静态变量
5.
包导出
应用“包”代替$unit是一种较好的编码方式。
2.3
未命名语句块中的声明2.3.1
未命名块中的局部变量如下例所示:
module chip (input clock); integer i; // declaration at module level integer i; // local variable for (i=0; i<=127; i=i+1) begin 2.4
仿真时间单位及精度2.4.1
Verilog编译指令timescaleVerilog中用该语句来定义,`timescale 1ns / 10ps,1ns表示单位时间长度,10ps表示精度。若遇到以下情况,连续三个模块,若如图1所示,其中A文件和C文件对时间单位及精度进行了定义,但是B没有定义,则B的时间单位将延续它前面的文件中的时间定义,即A的,所以,#5表示的是延时5ns。所示,则#5表示的是延时5ms。
2.4.2
包含时间单位的时间值forever #5ns clock = ~clock;
// 时间值与时间单位之间没有空格。
2.4.3
范围级(Scope-level)时间单位和精度在SystemVerilog中,时间单位和精度可以通过关键字timeunit和timeprecision来定义。举例如下:
关键字timeunit和timeprecision必须紧接着module,interface或program声明就立刻定义,在其他声明和陈述之前。
module adder (input wire [63:0] a, b, 2.4.4
编译单位时间单元和精度举例2-9如下:
Example 2-9: Mixed declarations of time units and precision (not synthesizable) timeunit 1ns; // external time unit and precision timeprecision 1ps; // local precision (priority over external) always @(posedge data_request) begin #2.5 send_packet; // uses external units & local precision #3.75ns
check_crc; // specific units take precedence `timescale 1ps/1ps // directive takes precedence over external(直接定义的优先于外部定义) timeunit 1ns; // local units take priority over directive #1.2 case (State) // uses local units & timescale precision WAITE: #20ps...; // specific units take precedence
第三章 SystemVerilog文本值和数据类型SystemVerilog增加的类型在本章中包括以下:
1.
增强型文字值(literal values 直接赋值)
2.
`define text 代替 enhancements
3.
时间值(time values)
4.
新变量类型
5.
有符号和无符号类型(signed and unsigned)
6.
变量初始化
7.
静态和自动变量(static and automatic)
8.
Casting(计算合计)
9.
常数常量(Constants)
3.1
加强的文本值赋值(Enhanced Literal Value assignments)如下例所示,Verilog中对向量直接赋值
data = 0; // fills all bits of data with zero data = 'bz; // fills all bits of data with Z data = 'bx; // fills all bits of data with X 但是,当要将数值所有位赋值为‘1’时就不太方便,即为data=64'hFFFFFFFFFFFFFFFF;,若将SIZE改为128,则须查找data变量位置,将其值进行修改,而不能灵活改变。可以操作符的方式进行修改,如下所示:
data = ~0; // one's complement operation data = -1; // two's complement operation SystemVerilog中,增加了两种直接赋值的方式。
1.
增加了一种简单语法,无需指定进制类型(二进制、十进制、十六进制等)。直接在之前加一个( ‘ )。
l
‘0 将所有位置0;
l
‘1 将所有位置1;
l
‘z 或 ‘Z 表示所有位置Z
l
‘x 或 ‘X 表示所有位置Z
注意:( ‘ )区别于( ` ),是不同的。
举例:data = ‘1; // 将data所有位置1;
2.
赋的值可以使logic 1。
3.2
`define增强SystemVerilog中扩展了`define的功能,代替了宏定义的功能。
3.2.1
字符串中的宏变元替换(Macro argument substitution within strings)Verilog的
`define宏定义中可以用( ” ),则引号中的文字变成了文字型字符串。
这就意味着,Verilog不能建立含有宏变元的字符串。
如下例所示,不能按原本意愿展开。
$display("variable v = %h", v) 该例中,将`print(data);展开,则为,$display(“variable v = %h”, data);。原本的意愿是,将宏定义中所有的‘v’都变成‘data’,但是,包含在双引号里的v并没有发生变化,所以在Verilog语言中不能实现以上的功能。 SystemVerilog中能够实现宏变元的替换。应用重音符( ` )。 $display(`"variable v = %h`", v) $display(“variable data = %h”, data);。 Verilog中,若要在字符串中加入引号(单引号或双引号),则需在引号前加上字符“\”。举例:$display("variable \"data\" = %h", data); 当字符串中含宏变元时,只用\"是不够的,则需要用`\`"。举例如下:
$display(‘"variable ‘\‘"v‘\‘" = %h‘", v) 则宏展开为:
$display("variable \"data\" = %h", data); 3.2.2
通过宏建立标识符名(Constructing identifier names from macros)SystemVerilog中可以通过( `` )将两个或更多的名字连接在一起形成新的名字。注意,重音符间无空格。
举例:
Verilog中
bit d00_bit; wand d00_net = d00_bit; bit d01_bit; wand d01_net = d01_bit; ... // repeat 60 more times, for each bit bit d62_bit; wand d62_net = d62_bit; bit d63_bit; wand d63_net = d63_bit; SystemVerilog中用`define
`define TWO_STATE_NET(name) bit name``_bit; \
//宏定义 wand name_``net = name``_bit;
//执行的操作
3.3
SystemVerilog变量 3.3.1
对象类型(目标类型)和数据类型Verilog数据类型:
1.
reg,integer,time变量中的每个bit都有4中逻辑值:0,1,Z和X。
2.
wire,wor,wand和net变量中的每个bit有120个值等。
SystemVerilog数据类型
数据的声明包括类型和数据类型。
1.
当信号是net型或variable变量型时,需要定义类型。SystemVerilog承接了Verilog中的所有类型,并添加一些变量类型byte和int型。Net型没有添加。
2.
当信号是两态(2-state即0,1)或四态(4-state即0,1,Z,X)时,需要定义数据类型。用关键字bit定义两态,关键字logic定义四态。其中变量类型的数据类型可以是2-state或4-state,,但是net类型只能是4-state。
3.3.2
SystemVerilog四态变量(4-state variable)4-state logic type
logic resetN; // a 1-bit wide 4-state variable logic [63:0] data; // a 64-bit wide variable logic [0:7] array [0:255]; // an array of 8-bit variables 关键字logic实际上不是变量类型,而是数据类型,且信号可以有四个状态值。但是,logic自用则默认为variable变量型。或者可以明确的指出类型应用关键字var logic,如下:
var logic [63:0] addr; // a 64-bit wide variable Verilog中的net型默认为四态的数据类型,用logic来表示,则为:
wire logic [63:0] data; // a 64-bit wide net
从语义上来说,logic和reg类型是可以等同的(除了reg不能代表net类型)。
3.3.3
SystemVerilog两态变量(2-state variable)SystemVerilog增加了几种新的两态类型,适用于比RTL级设计更为抽象的系统级和传输级设计。包括以下:
1.
bit —— 1-bit 2-state整型
2.
byte —— 8-bit 2-state 整型,类似于C char类型
3.
shortint —— 16-bit 2-state整型,类似于C short类型
4.
int —— 32-bit 2-state整型,类似于C int
5.
longint —— 64-bit 2-state 整型,类似于C longlong
抽象建模级(系统级和传输级)不需要4-state,其中Z和X状态是不需要的。
bit可以与reg和logic同样对变量进行定义,但是它只能定义2-state的变量。例如下:
bit resetN; // a 1-bit wide 2-state variable
bit [63:0] data; // a 64-bit 2-state variable
bit [0:7] array [0:255]; // an array of 8-bit 2-state variables
4-state类型仿真起始的默认值为logic X;2-state类型仿真起始默认值为0。
其他抽象类型:
Void型:无返回值;
Shortreal型:32-bit 单精度浮点型,类似于C float。(不可综合)
Real型:双精度,类似于C double。(不可综合)
SystemVerilog在验证中,天价了classes和其他自动类型。(见SystemVerilog for verification)
3.3.4
显式和隐式变量及线网数据类型(Explicit and implicit variable and net data types)SystemVerilog有线网和变量类型,还包括2-state和4-state的数据类型。
logic [7:0] busA; // infers a variable that is a 4-state data type
bit [31:0] busB; // infers a variable that is a 2-state data type
SystemVerilog中可以应用关键字“var”对变量进行定义。举例:
typedef enum bit {FALSE, TRUE} bool_t;
var bool_t c; // variable of user-defined type
3.3.5
综合规则4-state 的logic类型和2-state的bit,byte,shortint,int和longint类型都是可综合的。
3.4
RTL级模块中2-state类型应用3.4.1
2-state类型特征1.
SystemVerilog增加了一些2-state类型:bit,byte,shortint,int和longint。可应用于抽象级系统设计。
2.
4-state和2-state之间的映射关系,可以将4-state值赋给2-state,映射关系如下表:
3.4.2
2-state type与 2-state simulation 的对比3.4.3
在Case语句中使用两态类型3.5
数据类型规则放宽Verilog的规则具有较大的约束性。
而SystemVerilog做了较大的改进,更加简单化。变量可以通过以下几种情况下使用,而不局限于一种:
1.
在initial或always进程块中进行赋值(同于Verilog);
2.
在always_comb,always_ff或always_latch进程块中进行赋值。具体进程块将在第六章进行介绍;
3.
通过简单的连续赋值语句进行赋值;
4.
从简单模块或原始端口中得到值等等。
大部分的信号定义为logic和bit类型。
变量宽松应用举例:例3-1
module compare (output logic lt, eq, gt,
input logic [63:0] a, b );
always @(a, b)
if (a < b) lt = 1'b1; // procedural assignments
else lt = 1'b0;
assign gt = (a > b); // continuous assignments
comparator u1 (eq, a, b); // module instance
endmodule
module comparator (output logic eq,
input [63:0] a, b);
always @(a, b)
eq = (a==b);
endmodule
注意:同一变量不可以被多个资源驱动。
举例:
module add_and_increment (output logic [63:0] sum,
output logic carry,
input logic [63:0] a, b );
always @(a, b)
sum = a + b; // procedural assignment to sum
assign sum = sum + 1; // ERROR! sum is already being assigned a value
look_ahead i1 (carry, a, b); // module instance drives carry
overflow_check i2 (carry, a, b); // ERROR! 2nd driver of carry
endmodule
module look_ahead (output wire carry, input logic [63:0] a, b);
...
endmodule
module overflow_check (output wire carry,
input logic [63:0] a, b);
...
endmodule
TIP:变量型(variables)用于单一驱动(single-drive)逻辑,网络型(nets)用于多驱动(multi-driver)逻辑。
3.6
有符号和无符号修饰符Verilog举例:
reg [63:0] u; // unsigned 64-bit variable
reg signed [63:0] s; // signed 64-bit variable
SystemVerilog举例:
int s_int; // signed 32-bit variable
int unsigned u_int; // unsigned 32-bit variable
注意:SystemVerilog和C语言的有符号型声明有所不同。
unsigned int u1; /* legal C declaration */
int unsigned u2; /* legal C declaration */
Verilog中(Verilog中无unsigned类型)
reg signed [31:0] s; // Verilog declaration
Systemverilog中
int unsigned u; // SystemVerilog declaration
3.7
静态和自动变量( Static and automatic variables)SystemVerilog增加了static和automatic关键字,对静态自动变量进行声明。可定义在tasks,functions,begin…end,fork…join模块中。注意,在模块级上,所有的变量都是静态的。
3.7.1
静态和自动变量的初始化静态变量只能初始化一次;举例:
function int count_ones (input [31:0] data);
logic [31:0] count = 0; // initialized once(默认为静态变量)
logic [31:0] temp = data; // initialized once
for (int i=0; i<=32; i++) begin
if (temp[0]) count++;
temp >>= 1;
end
return(count);
endfunction
自动变量可以在每次调用的时候进行初始化;举例:
function int count_ones (input [31:0] data); automatic logic [31:0] count = 0; automatic logic [31:0] temp = data; for (int i=0; i<=32; i++) begin 3.7.2
自动变量综合规则注意:静态变量初始化是不可综合的,自动变量初始化是可综合的。
3.7.3
静态和自动变量使用规则以下规则有助于决定何时用静态变量何时用自动变量:
1.
在always和initial块中,如果无in-line初始化使用静态变量,如果有in-line初始化使用自动变量。
2.
If a task or function is to be re-entrant, it should be automatic.
3.
If a task or function represents the behavior of a single piece of hardware, and therefore is not re-entrant, then it should be declared as static, and all variables within the task or function should be static.
3.8
变量初始化的确定性(Deterministic variable initialization)3.8.1
初始化确定机制(Initialization determinism)SystemVerilog中定义,所有in-line变量初始化会在仿真时间0之前进行计算。
3.8.2
时序逻辑异步输入初始化(Initializing sequential logic asynchronous inputs)如例3-3所示,resetN异步复位,即计数器counter在resetN变为0时,立即复位,与时钟信号无关。
module counter (input wire clock, resetN, output logic [15:0] count); always @(posedge clock, negedge resetN) if (!resetN) count <= 0; // active low reset bit resetN = 1; // initialize reset to inactive value counter dut (clock, resetN, count); always #10 clock = ~clock; resetN = 0; // assert active-low reset at time 0 #2 resetN = 1; // de-assert reset before posedge of clock $display("\n count=%0d (expect 0)\n", count); 注意:写Testbench时要对未确定状态的变量进行初始化。 |