前情提要:搭建corundum仿真環境(一)https://www.cnblogs.com/shroud404/articles/15364812.html
三、Running test
接上文,梳理了一下具體的仿真流程,現對整個項目的仿真作以介紹:
總的來講,兩種方式:pytest 和 makefile
pytest方式調用python庫cocotb-test的cocotb-test.simulator.run方法,該方法定義了使用何種仿真器的方法;makefile方式是調用python庫cocotb中的makefile.sim,該Makefile會根據運行cocotb的命令行中仿真器的類別來調用不同仿真器的makefile,從而執行相關仿真器的編譯和仿真操作。
殊途同歸,兩種方式最終都是在cocotb-test的框架下去啟動編譯器仿真器(iverilog)對RTL代碼進行編譯和仿真。
擴展知識:python庫介紹,感興趣的可以去了解cocotb的使用,功能強大並且高效,cocotb是一個基於CO routine的CO simulation TestBench環境,使用Python驗證VHDL和SystemVerilog RTL。
cocotb介紹:https://docs.cocotb.org/en/stable/
cocotb git:https://github.com/cocotb/cocotb
cocotb-test:https://github.com/themperek/cocotb-test
1、成功安裝tox——更方便快捷的使用pytest
tox是通用的虛擬環境管理和測試命令行工具。tox能夠讓我們在同一個Host上自定義出多套相互獨立且隔離的python環境(tox是openstack社區最基本的測試工具,比如python程序的兼容性、UT等)。它的目標是提供最先進的自動化打包、測試和發布功能。
- 作為持續集成服務器的前端,大大減少測試工作所需時間;
- 檢查軟件包能否在不同的python版本或解釋器下正常安裝;
- 在不同的環境中運行測試代碼
個人思考總結:tox方便仿真環境的搭建和移植,它能夠維護項目使用多個版本的python,具體按照個人開發環境進行配置,可以修改項目根目錄下tox.ini文件指定python版本,便於維護和移植。更為強大的功能還不理解。。。
成功安裝tox的開發者:可以使用命令
$ cd /path/to/corundum-master
$ tox
運行仿真。
在tox環境下,所有的測試都可以通過在根目錄下運行 tox 來進行。在這種情況下,tox會建立一個python虛擬環境,並在虛擬環境中安裝所有的python依賴項。此外,tox將以pytest -n auto的方式運行pytest,因此它將在多個CPU上並行運行測試。
該命令可以一次性仿真項目內部的所有測試例,會在各個測試例的位置生成仿真文件夾sim_build,該文件夾下包含了編譯完成的文件xx.vpp(iverilog編譯器對代碼編譯后生成的文件,類似於questasim的compile后生成的文件)和仿真日志。
2、tox未成功,直接使用pytest
所有測試都可以通過在 repo 根目錄下運行 pytest 來運行。建議以pytest -n auto的方式運行,在多個CPU上並行運行多個測試。
$ cd /path/to/corundum-master $ pytest -n auto (多核) $ pytest (單核)
此種方法使用的時間會比tox多出不少,但效果是一樣的。都是使用pytest方式,最終效果和1、成功安裝tox——更方便快捷的使用pytest 中一致,也是運行了所有的測試例。
3、運行單個測試組(單模塊測試)
剛玉這個項目的開發者對於每個模塊都提供了測試文件,如果我們對某個模塊功能不理解可以仿真配合學習。
可以通過在子目錄下運行pytest來運行測試組。建議以pytest -n auto的方式運行,在多個CPU上並行運行多個測試。
$ cd /path/to/corundum/fpga/common/tb/rx_hash $ pytest -n 4 Test session starts (platform: linux, Python 3.9.2, pytest 6.2.2, pytest-sugar 0.9.4) rootdir: /path/to/corundum, configfile: tox.ini plugins: parallel-0.1.0, cocotb-test-0.2.0, split-0.1.6.dev1+g97d96c2, sugar-0.9.4, xdist-2.2.1, forked-1.3.0, metadata-1.11.0, html-3.1.1, flake8-1.0.7, cov-2.11.1 gw0 [2] / gw1 [2] / gw2 [2] / gw3 [2] fpga/common/tb/rx_hash/test_rx_hash.py ✓✓ 100% ██████████ Results (27.68s): 2 passed
如果想要查看仿真波形文件,請在對應模塊目錄下使用命令
$ WAVES=1 pytest
運行仿真,仿真結束后會在sim_build文件夾下生成對應測試例的波形文件 xx.fst,使用gtkwave即可觀察波形。
4、makefile方式
最后,可以通過運行make來運行單個測試。這個方法提供了覆蓋參數和啟用FST格式的波形轉儲的能力,可以在gtkwave中查看。
效果會和4中pytest的方式一樣,生成波形文件 xx.fst。終端中的打印日志信息也可以保存下來以供查閱。
$ cd /path/to/corundum/fpga/common/tb/rx_hash $ make WAVES=1 make results.xml make[1]: Entering directory '/path/to/corundum/fpga/common/tb/rx_hash' /usr/bin/iverilog -o sim_build/sim.vvp -D COCOTB_SIM=1 -s rx_hash -P rx_hash.DATA_WIDTH=64 -P rx_hash.KEEP_WIDTH=8 -s iverilog_dump -f sim_build/cmds.f -g2012 ../../rtl/rx_hash.v iverilog_dump.v MODULE=test_rx_hash TESTCASE= TOPLEVEL=rx_hash TOPLEVEL_LANG=verilog \ /usr/bin/vvp -M /home/alex/.local/lib/python3.9/site-packages/cocotb/libs -m libcocotbvpi_icarus sim_build/sim.vvp -fst -.--ns INFO cocotb.gpi ..mbed/gpi_embed.cpp:76 in set_program_name_in_venv Did not detect Python virtual environment. Using system-wide Python interpreter -.--ns INFO cocotb.gpi ../gpi/GpiCommon.cpp:99 in gpi_print_registered_impl VPI registered -.--ns INFO cocotb.gpi ..mbed/gpi_embed.cpp:247 in _embed_sim_init Python interpreter initialized and cocotb loaded! 0.00ns INFO cocotb __init__.py:247 in _initialise_testbench_ Running on Icarus Verilog version 11.0 (stable) 0.00ns INFO cocotb __init__.py:253 in _initialise_testbench_ Running tests with cocotb v1.6.0.dev0 from /home/alex/.local/lib/python3.9/site-packages/cocotb 0.00ns INFO cocotb __init__.py:274 in _initialise_testbench_ Seeding Python random module with 1622183492 0.00ns INFO cocotb.regression regression.py:127 in __init__ Found test test_rx_hash.run_test_001 0.00ns INFO cocotb.regression regression.py:127 in __init__ Found test test_rx_hash.run_test_002 0.00ns INFO cocotb.regression regression.py:127 in __init__ Found test test_rx_hash.run_test_003 0.00ns INFO cocotb.regression regression.py:127 in __init__ Found test test_rx_hash.run_test_004 0.00ns INFO cocotb.regression regression.py:127 in __init__ Found test test_rx_hash.run_test_005 0.00ns INFO cocotb.regression regression.py:127 in __init__ Found test test_rx_hash.run_test_006 0.00ns INFO cocotb.regression regression.py:127 in __init__ Found test test_rx_hash.run_test_007 0.00ns INFO cocotb.regression regression.py:127 in __init__ Found test test_rx_hash.run_test_008 0.00ns INFO cocotb.regression regression.py:477 in _start_test Running test 1/8: run_test_001 0.00ns INFO ...test.run_test_001.0x7f85f23398e0 decorators.py:312 in _advance Starting test: "run_test_001" Description: Automatically generated test pkt_type: Ether (No docstring supplied) payload_lengths: size_list (No docstring supplied) payload_data: incrementing_payload (No docstring supplied) idle_inserter: None 0.00ns INFO cocotb.rx_hash.s_axis axis.py:271 in __init__ AXI stream source 0.00ns INFO cocotb.rx_hash.s_axis axis.py:272 in __init__ cocotbext-axi version 0.1.13 0.00ns INFO cocotb.rx_hash.s_axis axis.py:273 in __init__ Copyright (c) 2020 Alex Forencich 0.00ns INFO cocotb.rx_hash.s_axis axis.py:274 in __init__ https://github.com/alexforencich/cocotbext-axi 0.00ns INFO cocotb.rx_hash.s_axis axis.py:319 in __init__ AXI stream source configuration: 0.00ns INFO cocotb.rx_hash.s_axis axis.py:320 in __init__ Byte size: 8 bits 0.00ns INFO cocotb.rx_hash.s_axis axis.py:321 in __init__ Data width: 64 bits (8 bytes) 0.00ns INFO cocotb.rx_hash.s_axis axis.py:323 in __init__ AXI stream source signals: 0.00ns INFO cocotb.rx_hash.s_axis axis.py:326 in __init__ tdata width: 64 bits 0.00ns INFO cocotb.rx_hash.s_axis axis.py:328 in __init__ tdest: not present 0.00ns INFO cocotb.rx_hash.s_axis axis.py:328 in __init__ tid: not present 0.00ns INFO cocotb.rx_hash.s_axis axis.py:326 in __init__ tkeep width: 8 bits 0.00ns INFO cocotb.rx_hash.s_axis axis.py:326 in __init__ tlast width: 1 bits 0.00ns INFO cocotb.rx_hash.s_axis axis.py:328 in __init__ tready: not present 0.00ns INFO cocotb.rx_hash.s_axis axis.py:328 in __init__ tuser: not present 0.00ns INFO cocotb.rx_hash.s_axis axis.py:326 in __init__ tvalid width: 1 bits 0.00ns INFO cocotb.rx_hash.s_axis axis.py:367 in _handle_reset Reset de-asserted 0.00ns INFO cocotb.rx_hash.m_axis stream.py:154 in _handle_reset Reset de-asserted FST info: dumpfile rx_hash.fst opened for output. 4.00ns INFO cocotb.rx_hash.s_axis axis.py:357 in _handle_reset Reset asserted 4.00ns INFO cocotb.rx_hash.m_axis stream.py:144 in _handle_reset Reset asserted 12.00ns INFO cocotb.rx_hash.s_axis axis.py:367 in _handle_reset Reset de-asserted 12.00ns INFO cocotb.rx_hash.m_axis stream.py:154 in _handle_reset Reset de-asserted 20.00ns INFO cocotb.rx_hash.s_axis axis.py:502 in _run TX frame: AxiStreamFrame(tdata=bytearray(b'\xda\xd1\xd2\xd3\xd4\xd5ZQRSTU\x90\x00\x00'), tkeep=None, tid=None, tdest=None, tuser=None, sim_time_start=20000, sim_time_end=None) 28.00ns INFO cocotb.rx_hash.s_axis axis.py:502 in _run TX frame: AxiStreamFrame(tdata=bytearray(b'\xda\xd1\xd2\xd3\xd4\xd5ZQRSTU\x90\x00\x00\x01'), tkeep=None, tid=None, tdest=None, tuser=None, sim_time_start=28000, sim_time_end=None) 36.00ns INFO cocotb.rx_hash.s_axis axis.py:502 in _run TX frame: AxiStreamFrame(tdata=bytearray(b'\xda\xd1\xd2\xd3\xd4\xd5ZQRSTU\x90\x00\x00\x01\x02'), tkeep=None, tid=None, tdest=None, tuser=None, sim_time_start=36000, sim_time_end=None) 40.00ns INFO cocotb.tb test_rx_hash.py:191 in run_test RX hash: 0x00000000 (expected: 0x00000000) type: HashType.0 (expected: HashType.0) 48.00ns INFO cocotb.rx_hash.s_axis axis.py:502 in _run TX frame: AxiStreamFrame(tdata=bytearray(b'\xda\xd1\xd2\xd3\xd4\xd5ZQRSTU\x90\x00\x00\x01\x02\x03'), tkeep=None, tid=None, tdest=None, tuser=None, sim_time_start=48000, sim_time_end=None) 48.00ns INFO cocotb.tb test_rx_hash.py:191 in run_test RX hash: 0x00000000 (expected: 0x00000000) type: HashType.0 (expected: HashType.0) 56.00ns INFO cocotb.tb test_rx_hash.py:191 in run_test RX hash: 0x00000000 (expected: 0x00000000) type: HashType.0 (expected: HashType.0) ################ skip a very large number of lines ################ 252908.01ns INFO cocotb.rx_hash.s_axis axis.py:502 in _run TX frame: AxiStreamFrame(tdata=bytearray(b'\xda\xd1\xd2\xd3\xd4\xd5ZQRSTU\x08\x00E\x00\x00V\x00\x8c\x00\x00@\x06d\xfc\n\x01\x00\x8c\n\x02\x00\x8c\x00\x8c\x10\x8c\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00mo\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-'), tkeep=None, tid=None, tdest=None, tuser=None, sim_time_start=252908007, sim_time_end=None) 253000.01ns INFO cocotb.tb test_rx_hash.py:191 in run_test RX hash: 0x6308c813 (expected: 0x6308c813) type: HashType.TCP|IPV4 (expected: HashType.TCP|IPV4) 253008.01ns INFO cocotb.regression regression.py:373 in _score_test Test Passed: run_test_008 253008.01ns INFO cocotb.regression regression.py:496 in _log_test_summary Passed 8 tests (0 skipped) 253008.01ns INFO cocotb.regression regression.py:569 in _log_test_summary *********************************************************************************** ** TEST PASS/FAIL SIM TIME(NS) REAL TIME(S) RATIO(NS/S) ** *********************************************************************************** ** test_rx_hash.run_test_001 PASS 11144.00 1.16 9569.44 ** ** test_rx_hash.run_test_002 PASS 44460.00 3.90 11409.70 ** ** test_rx_hash.run_test_003 PASS 12532.00 1.41 8908.08 ** ** test_rx_hash.run_test_004 PASS 49996.00 4.53 11047.04 ** ** test_rx_hash.run_test_005 PASS 13088.00 1.54 8513.81 ** ** test_rx_hash.run_test_006 PASS 52220.00 4.79 10905.96 ** ** test_rx_hash.run_test_007 PASS 13940.00 9.79 1423.57 ** ** test_rx_hash.run_test_008 PASS 55628.00 16.83 3305.63 ** *********************************************************************************** 253008.01ns INFO cocotb.regression regression.py:586 in _log_sim_summary ************************************************************************************* ** ERRORS : 0 ** ************************************************************************************* ** SIM TIME : 253008.01 NS ** ** REAL TIME : 45.14 S ** ** SIM / REAL TIME : 5604.98 NS/S ** ************************************************************************************* 253008.01ns INFO cocotb.regression regression.py:268 in tear_down Shutting down... make[1]: Leaving directory '/home/alex/UCSD/Projects/corundum-clean-build/fpga/common/tb/rx_hash'
5、總結
包含了一個廣泛的基於Python的開源仿真框架,以評估完整設計。該框架使用Python庫MyHDL構建,並包括PCI Express系統基礎架構,PCI Express硬IP內核,NIC驅動程序和以太網接口的仿真模型。該仿真框架通過提供整個系統狀態的可視性,有助於調試完整的NIC設計。
PCIe仿真框架的核心由大約4,500行Python組成,並包括PCIe基礎結構組件的事務層模型,其中包括根聯合體,功能,端點和交換機以及高級功能,包括配置空間,功能,總線枚舉,根聯合體 內存分配,中斷和其他功能。其他模塊由另外4,000行Python組成,提供FPGA PCIe硬IP核的模型,與模擬的PCIe基礎設施交換事務層流量,並驅動可連接至共同仿真的Verilog設計的信號。
模擬Corundum需要幾行代碼來實例化和連接所有組件。清單1顯示了使用模擬框架發送和接收各種大小的數據包的簡化測試台,在Icarus Verilog中共同模擬了Verilog設計。該測試平台實例化了以太網接口端點,PCIe根聯合體和驅動程序的仿真模型,並將它們連接到協同仿真的設計。然后,它初始化PCIe基礎結構,初始化驅動程序模型,並發送,接收和驗證幾個不同長度的測試數據包。
清單1. NIC測試台的縮寫。包括設置PCIe,以太網接口和驅動程序模型,初始化模擬的PCIe總線和驅動程序以及發送和接收測試數據包。為簡潔起見,大多數信號已刪除。
無論使用何種方式,只要能成功調用編譯器iverilog即可,我們接下來便可搭配產生的波形文件去學習整個工程了!