6. SystemVerilog Interprocess Communication
SystemVerilog的IPC机制(Event、Semaphore、Mailbox)
1. 进程间通信(IPC)概述
在SystemVerilog测试平台提供了灵活的同步和通信能力:
- Event:用于简单流程控制;
- Semaphore:解决资源竞争问题;
- Mailbox:实现高效的数据传递。
不同组件(如驱动、生成器、监控器等)需要通过 事件(Event)、信号量(Semaphore)和邮箱(Mailbox) 进行通信和同步。以下是三种核心IPC机制的详细说明:
2. 核心IPC机制对比表
机制 | 功能 | 适用场景 | 同步方式 |
---|---|---|---|
Event(事件) | 同步两个或多个进程,通过触发和等待事件实现流程控制。 | 进程间同步(如启动完成通知) | 阻塞等待事件触发 |
Semaphore(信号量) | 控制对共享资源的互斥访问(如临界区资源)。 | 资源竞争管理(如锁机制) | 通过get() 和put() 控制 |
Mailbox(邮箱) | 在组件间安全传递数据对象(如事务级通信)。 | 数据传递(如驱动与生成器之间的事务传输) | 队列式存取(FIFO) |
3. 详细说明
3.1 Event(事件)
-
定义:事件是进程间同步的信号,用于触发或等待特定条件。
-
关键步骤:
- 创建事件:
event eventA;
- 触发事件:
->eventA;
- 等待事件:
@eventA
或wait(eventA.triggered);
- 传递事件:可作为参数传递给任务或函数。
- 创建事件:
-
示例代码:
module tb_top; event eventA; initial begin fork waitForTrigger(eventA); // 等待事件触发 #5 ->eventA; // 触发事件 join end task waitForTrigger(event eventA); $display("[%0t] Waiting for EventA...", $time); wait(eventA.triggered); $display("[%0t] EventA triggered!", $time); endtask endmodule
输出:
[0] Waiting for EventA... [5] EventA triggered!
3.2 Semaphore(信号量)
-
定义:管理对共享资源的互斥访问,通过钥匙(Key)机制控制资源访问权限。
-
核心操作:
- 创建信号量:
semaphore key = new(1);
(初始钥匙数量为1)。 - 获取钥匙:
key.get(1);
(阻塞等待钥匙可用)。 - 释放钥匙:
key.put(1);
(释放钥匙供其他进程使用)。
- 创建信号量:
-
示例代码:
module tb_top; semaphore key = new(1); // 创建一个钥匙 initial begin fork personA(); // 任务A获取资源 personB(); // 任务B尝试获取资源 join_none end task personA(); key.get(1); // 获取钥匙 #20 key.put(1); // 释放钥匙 endtask task personB(); #5 key.get(1); // 延迟后获取钥匙 #10 key.put(1); endtask endmodule
输出:
[0] PersonA获取钥匙 [5] PersonB尝试获取钥匙(需等待) [20] PersonA释放钥匙 → PersonB开始执行
3.3 Mailbox(邮箱)
-
定义:在组件间传递数据对象的FIFO队列,支持生产者-消费者模式。
-
核心操作:
- 创建邮箱:
mailbox mbx = new();
- 发送数据:
mbx.put(data);
(生产者放入数据)。 - 接收数据:
mbx.get(data);
(消费者取出数据)。
- 创建邮箱:
-
示例代码:
class Transaction; rand bit [7:0] data; function void display(); $display("Data = 0x%0h", data); endfunction endclass class Generator; mailbox mbx; function new(mailbox mbx); this.mbx = mbx; endfunction task genData(); Transaction trns = new(); trns.randomize(); trns.display(); mbx.put(trns); // 发送到邮箱 endtask endclass class Driver; mailbox mbx; function new(mailbox mbx); this.mbx = mbx; endfunction task drvData(); Transaction drvTrns; mbx.get(drvTrns); // 从邮箱获取数据 drvTrns.display(); endtask endclass module tb_top; mailbox mbx = new(); Generator Gen = new(mbx); Driver Drv = new(mbx); initial begin fork Gen.genData(); Drv.drvData(); join end endmodule
输出:
[0] Data = 0x9d(生成器发送) [0] Data = 0x9d(驱动器接收)
4. 关键点总结
机制 | 特点 | 典型用例 |
---|---|---|
Event | 非阻塞触发,阻塞等待;轻量级同步。 | 启动/完成通知、状态机同步。 |
Semaphore | 互斥访问资源,支持多钥匙(如允许多线程同时访问)。 | 临界区保护、资源竞争控制。 |
Mailbox | 基于FIFO的数据传递,支持对象类型安全。 | 事务级通信、组件间数据交换(如驱动与生成器)。 |
5. 注意事项
- 事件:触发事件后,所有等待该事件的进程会被唤醒。
- 信号量:
get()
和put()
操作需成对使用,否则可能导致死锁。 - 邮箱:默认为FIFO队列,可通过
#
参数指定大小(如mailbox mbx = new(10);
限制队列长度)。