class myClass;
int myInt;
function void myMethod(input int value);
myInt = value;
endfunction
endclass
myClass myObject = new();
myObject.myMethod(10);
类和对象在硬件设计和验证中支持更高级的抽象,如生成复杂的测试平台组件和设备驱动模型。
2.3 System Verilog 中的类和对象
System Verilog 类和对象为硬件设计和验证提供了面向对象的能力,这使得模拟设计的模块化和封装性得到提高。
2.3.1 类的定义和特性
类是 System Verilog 面向对象特性的核心,它定义了一组操作对象和使用数据的函数和变量。
封装:类中的数据和函数可以封装在类的定义内。
继承:类可以继承另一个类的特性,提高代码复用性。
多态:类的实例可以有多种表现形式,具体取决于实例化对象的类型。
代码示例:
class baseClass;
virtual function void myFunc();
$display("Base method");
endfunction
endclass
class derivedClass extends baseClass;
virtual function void myFunc();
$display("Derived method");
endfunction
endclass
在 System Verilog 中,类和对象的使用极大地增强了设计的抽象能力,使设计师能够创建更加模块化和可维护的设计模型。
2.4 System Verilog 类的高级特性
System Verilog 不仅提供了面向对象编程的基础特性,还增加了一些高级特性以满足更复杂的硬件设计和验证需求。
2.4.1 重载与重写
System Verilog 允许函数重载和重写,这为设计和验证提供了极大的灵活性。
函数重载:同名函数可以有不同的参数列表。
函数重写:派生类可以重写基类中定义的虚函数。
代码示例:
class A;
virtual function void display();
$display("Class A display");
endfunction
endclass
class B extends A;
function void display(int param); // 重载
$display("Class B display with param %0d", param);
endfunction
function void display(); // 重写
$display("Class B display");
endfunction
endclass
B myObject = new();
myObject.display(); // 调用的是重写的 display 方法
myObject.display(5); // 调用的是重载的 display 方法,传入了一个参数
2.4.2 模拟控制和随机化
System Verilog 的类提供了模拟控制方法,如随机化和约束,这些在硬件验证中非常重要。
随机化:允许对象的属性在约束的条件下随机生成。
约束:定义属性生成的约束规则。
代码示例:
class Transaction;
rand int data;
constraint c1 { data >= 0; data < 16; }
function void randomizeData();
assert(randomize(data));
endfunction
endclass
Transaction tr = new();
tr.randomizeData();
3. 模块、接口、类的概念及其在硬件设计中的作用
3.1 System Verilog 的模块和接口
3.1.1 模块的基本概念和使用
在 System Verilog 中,模块是设计的基本构建块,用于实现硬件设计的特定部分。模块具有输入、输出和双向端口,允许它们与设计中的其他部分进行交互。模块可以包含数据流、行为描述、结构体、任务和函数等。
module adder(
input logic [3:0] a, b, // 4-bit input ports
output logic [4:0] sum // 5-bit output port
);
// A simple behavioral description of an adder
always_comb begin
sum = a + b;
end
endmodule
在此示例中, adder 模块将两个 4 位输入 a 和 b 相加,产生一个 5 位的输出 sum 。关键字 always_comb 指示编译器这是一个在任意输入变化时都会重新评估的组合逻辑块。
模块可以被实例化多次,以创建硬件中的多个副本。这使得模块的概念非常适用于创建可重用的硬件组件。
3.1.2 接口的定义和应用
接口在 System Verilog 中用于封装模块间通信所需的信号和协议。它们提供了一种方法,将相关的端口和任务封装在一个单一的单元中,从而简化了模块间的交互和连接。
module main;
initial begin
int result;
example_task_with_parameters(5, result); // 调用任务并接收结果
$display("Result of the task: %0d", result);
end
endmodule
事件是一种特殊的数据类型,当某个过程发生时,可以通知事件来'触发'其他过程。在 System Verilog 中,可以使用 @ 符号来等待一个事件发生。
event my_event;
initial begin
// 触发事件 -> my_event;
end
always @(my_event) begin
// 事件发生时执行的操作
end
wait 语句也可以用来同步多个进程,它会阻塞当前进程直到指定条件成立。
5.2.2 信号量和互斥锁的使用
在并行环境中,确保资源的独占访问是至关重要的,这可以通过信号量和互斥锁来实现。
semaphore my_semaphore = new(1); // 创建一个拥有一个许可的信号量
initial begin
// 尝试获取许可
my_semaphore.get(1);
// ... 执行需要独占访问的代码 ...
my_semaphore.put(1); // 释放许可
end
// 使用互斥锁来保护共享资源
mutex my_mutex = new;
initial begin
// 尝试锁定互斥锁
my_mutex.lock();
// ... 执行需要独占访问的代码 ...
my_mutex.unlock(); // 解锁互斥锁
end
本章介绍了 System Verilog 中并发和同步执行语句的基本概念和用法。通过理解并行进程的概念、 fork/join 语句、事件控制和等待语句以及信号量和互斥锁的使用,读者应该能够在设计硬件和测试平台时更好地控制并发执行的复杂行为。这些概念的熟练掌握对于创建高效、可预测和可靠的 System Verilog 仿真至关重要。