如何使用CocoTB测试Verilog模块间交互?两种实现方式咨询
用CocoTB测试多个Verilog模块交互的两种方法
被测模块代码
TX模块
// stream data to a receiver module TX ( input clk_i, rst_i, output data_o ); // 模块内部实现(略) endmodule
RX模块
// receive data from a transmitter and synchronize to the data stream module RX ( input clk_i, rst_i, data_i, output sync_o ); // 模块内部实现(略) endmodule
针对你的问题,有两种可行的实现方式,分别对应是否需要编写顶层Verilog测试模块:
方法一:使用顶层Verilog测试模块作为DUT
这是贴近传统Verilog测试流程的方式,步骤如下:
- 编写你提供的
TX_RX_tb.v作为顶层模块,完成TX和RX的实例化与信号连接:
module TX_RX_tb( input clk_i, rst_i, output sync_o ); wire data; TX TX_inst(.clk_i(clk_i), .rst_i(rst_i), .data_o(data)); RX RX_inst(.clk_i(clk_i), .rst_i(rst_i), .data_i(data), .sync_o(sync_o)); endmodule
- 编写CocoTB测试脚本,将这个顶层模块直接作为被测设计(DUT),控制输入并验证输出:
import cocotb from cocotb.clock import Clock from cocotb.triggers import RisingEdge @cocotb.test() async def test_tx_rx_sync(dut): # 生成10MHz时钟 clock = Clock(dut.clk_i, 10, units="ns") cocotb.start_soon(clock.start()) # 执行复位 dut.rst_i.value = 1 await RisingEdge(dut.clk_i) dut.rst_i.value = 0 await RisingEdge(dut.clk_i) # 等待同步完成并验证 await RisingEdge(dut.sync_o) assert dut.sync_o.value == 1, "RX未成功同步TX" # 可扩展:添加特定数据发送与接收验证逻辑
这种方式的优势是和传统Verilog测试流程兼容,复杂模块间的连接逻辑用Verilog编写更直观,适合大型设计。
方法二:直接在CocoTB Python脚本中连接多个模块
CocoTB支持直接在Python中实例化多个Verilog模块,通过cocotb.Wire完成信号连接,无需额外编写顶层Verilog文件:
- 确保TX和RX的Verilog文件能被仿真器识别(比如在Makefile中指定源文件路径)
- 编写Python测试脚本,手动实例化模块并连接信号:
import cocotb from cocotb.clock import Clock from cocotb.triggers import RisingEdge from cocotb.binary import BinaryValue @cocotb.test() async def test_tx_rx_direct_connect(): # 实例化TX和RX模块 tx = await cocotb.instantiate("TX", "tx_inst") rx = await cocotb.instantiate("RX", "rx_inst") # 创建连线连接TX的data_o与RX的data_i data_wire = cocotb.Wire(name="data", dtype=BinaryValue) tx.data_o <= data_wire rx.data_i <= data_wire # 给两个模块共享时钟 clock = Clock(tx.clk_i, 10, units="ns") cocotb.start_soon(clock.start()) rx.clk_i <= tx.clk_i # 执行复位 tx.rst_i.value = 1 rx.rst_i.value = 1 await RisingEdge(tx.clk_i) tx.rst_i.value = 0 rx.rst_i.value = 0 await RisingEdge(tx.clk_i) # 验证同步状态 await RisingEdge(rx.sync_o) assert rx.sync_o.value == 1, "RX未成功同步TX"
这种方式的好处是无需额外编写Verilog顶层文件,测试逻辑集中在Python中,适合快速验证小型模块间的交互。
选择建议
- 若模块间连接逻辑复杂(如多组信号、跨时钟域),优先用方法一,Verilog编写连接更清晰。
- 若只是快速验证简单模块的交互,方法二更高效,减少文件数量。
内容的提问来源于stack exchange,提问作者pbandlead
相关产品推荐
相关产品推荐

