语言基本介绍
像 Verilog 和 VHDL 之类的硬件描述语言 (HDL) 主要用于描述硬件行为,以便将其转换为由组合门电路和时序元件组成的数字块。为了验证 HDL 中的硬件描述正确无误,就需要具有更多功能特性的面向对象的编程语言 (OOP) 来支持复杂的测试过程,这种语言通常被称为硬件验证语言 (HVL)。
SystemVerilog 是 Verilog 的扩展,具有诸多此类验证功能,能支持工程师在仿真中使用复杂的测试激励文件结构和随机激励来验证设计。
相比于 Verilog,SystemVerilog 的主要优势体现在它能够执行受约束的随机激励、在测试激励文件构造中使用 OOP 功能特性、功能覆盖范围、断言等等。
过程赋值和连续赋值
在 SystemVerilog 中,有两种赋值方式:过程赋值(Procedural Assignment)和连续赋值(Continuous Assignment)。它们用于在模块中定义信号的行为。
1.过程赋值(Procedural Assignment): 过程赋值用于在 always 块内或函数、任务中对信号进行赋值。过程赋值使用 = 或 <= 运算符。
- 使用 = 运算符进行赋值时,表示阻塞赋值。即,在当前语句执行完成之前,不会进行下一条语句的执行。具有以下特点:
- 块结束后才完成赋值操作。
- 值并不是立刻就改变的。
- 这是一种比较常用的赋值方法。(特别在编写可综合模块时)
- 使用 <= 运算符进行赋值时,表示非阻塞赋值。即,所有的非阻塞赋值语句都会同时执行,并且不会等待其它语句的完成。具有以下特点:
- 赋值语句执行完后,块才结束。
- 值在赋值语句执行完后立刻就改变的。
- 可能会产生意想不到的结果。
注:一般不会将阻塞赋值和非阻塞赋值一起使用。
下面是一个使用过程赋值的示例:
module Example;
reg a, b, result;
always @(posedge clk) begin
a = in_a; // 阻塞赋值
b <= in_b; // 非阻塞赋值
if (a && b)
result = 1'b1; // 阻塞赋值
else
result = 1'b0; // 阻塞赋值
end
endmodule
2.连续赋值(Continuous Assignment): 连续赋值用于在模块的顶层定义信号与信号之间的连接关系。它使用 assign 关键字。
下面是一个使用连续赋值的示例:
module Example(
input wire a,
input wire b,
output wire result
);
assign result = a & b;
endmodule
需要注意的是,连续赋值只能用于顶层端口或模块内的信号赋值,不能在过程块(如 always 块)中使用。
注:线网类型与Verilog的要求相同,只能使用连续赋值语句(assign),而不能出现在过程块中(initial/always);相比于线网驱动的限制,变量(var)类型的驱动要求就很少,例如logic[3:0] a,该变量默认类型是变量,对它可以使用连续赋值、或者过程赋值。
避坑指南:可以在testbench(module)中大量使用logic类型的变量,减少wire的使用。什么时候必须要使用wire?
答:多于一个驱动源,或者设计模块端口是双向(inout)的时候。具体用法就是声明某个信号为wire sigal_a;或者wire logic signal_a;就可以了。注意直接声明为logic signal_a;是不行的,会报类似如下的错误:xmelab: *E,ICDCBA: Illegal combination of driver and output clockvar to variable 'signal_a' detected (output clockvar found in ......).
数组
非组合型数组(非连续)
赋值非常的严格,必须要对齐
reg [15:0] RAM [0:4095];
logic [31:0] data [1024];
logic [31:0] data [0:1023];
/************初始化************/
int d [0:1][0:3] = '{'{7,3,2,1},'{3,2,32,1}};
byte a [0:3][0:3];
a[1][0] = 8'h5;
a[3] = '{'hF,'hA,'hC,'hE};
组合型数组(连续)
wire [3:0] select;
logic [3:0][7:0] data;
// 结构体
typedef struct packed{
logic [7:0] crc;
logic [63:0] data;
} data_word;
data_word [7:0] darray;
/************初始化************/
logic [3:0][7:0] a = 32'h0;
logic [3:0][7:0] b = {16'hz,16'h0};
logic [3:0][7:0] c = {16{2'b01}};
数组相关的系统函数
$dimensions(array_name) // 用来返回数组的维度
$left(array_name, dimension)// 返回指定维度的最左索引值
$logic [1:2] [7:0] word [0:3] [4:1];
$left(word,1) // will return 0
$left(word,2) // will return 4
$left(word,3) // will return 1
$left(word,4) // will return 7
$size(array_name, dimension) // 返回指定维度的尺寸大小
动态数组
int dyn[], d2[];
initial begin
dyn = new[5];
foreach (dyn[j]) dyn[j] = j;
d2 = dyn;
d2[0] =