Hello Verilator—高品質&開源的 SystemVerilog(Verilog) 模擬器介紹&教學(二)
在前面一篇文章中分享了作者使用 verilator 來模擬數位 IC 的經驗。Verilator 具有對新語法的支援度、相當好的可靠度,速度甚至在商用工具之上,這篇文章將會用個簡單的案例分享 verilator 的用法。
Hello Verilator
在今天的目標中,我們要寫出一個 hello world Verilog module,其會花費 5 個 cycle 用 ascii 連續輸出 8-bit data
的 "hello"
,並且在這五個 cycle 把 valid
拉高表示輸出有效:
上一篇文章中提及,要用 verilator 驗證 Verilog 需要的步驟如下:
- 撰寫 testbench
testbench.cpp
。 - 準備可合成之待測模組
design_under_test.v
。 - 把待測試模組轉換成 C++(或是 SystemC),並指名要使用的 testbench
verilator design_under_test.v --exe testbench.cpp --cc
。 - Verilator 產生的檔案都在
obj_dir
資料夾(這個是預設名稱)。 - 在該資料夾下面編譯產生 binary
make -C obj_dir -f Vdesign_under_test.mk
。 - 執行模擬
./obj_dir/Vdesign_under_test
。
接下來的文章中,將會執行一次這些流程,並確定我的們的待測模組 degisn_under_test
真的有輸出想要的 waveform。
準備 Verilog
可以用下面的 Verilog 實做以輸出上面要求的波型,因為撰寫 Verilog 本身不是今天要討論的範圍,就不多作解釋如何實做了,以下是今天的 design_under_test.sv
:
1module design_under_test(
2 input clk, input rst,
3 output logic valid,
4 output logic [7:0] data
5);
6 logic [39:0] out_all;
7 always_comb begin
8 data = out_all[7:0];
9 valid = (data != '0);
10 end
11
12 always_ff @(posedge clk or negedge rst) begin
13 if (!rst) begin
14 out_all <= "olleH";
15 end else if (valid) begin
16 out_all <= out_all >> 8;
17 end
18 end
19endmodule
準備 testbench
我們暫時先拿一個空的 testbench.cpp
來跑整個流程。
1int main() {
2 return 0;
3}
main()
裡面什麼都沒有跑,接下來我們就要慢慢把 testbench 填滿。
準備 testbench(續)
首先先檢查 obj_dir/Vdesign_under_test.h
,裡面是一堆亂七八糟的 code 都看不懂,但是可以看到開頭的前幾行是這樣:
1VL_MODULE(Vdesign_under_test) {
2public:
3 VL_IN8(clk,0,0);
4 VL_IN8(rst,0,0);
5 VL_OUT8(valid,0,0);
6 VL_OUT8(data,7,0);
1class Vdesign_under_test {
2public:
3 uint8_t clk;
4 uint8_t rst;
5 uint8_t valid;
6 uint8_t data;
7};
design_under_test
時,也只需要用到這四個界面。例如下面就是模擬對 design_under_test
作 reset 之後跑 20 個 cycle:
1#include "Vdesign_under_test.h"
2#include <memory>
3#include <iostream>
4int main(int, char**)
5{
6 std::unique_ptr<Vdesign_under_test> dut(new Vdesign_under_test);
7 dut->clk = 1; dut->rst = 1; dut->eval();
8 dut->rst = 0; dut->eval();
9 dut->rst = 1; dut->eval();
10 for (int i = 0; i < 40; ++i) {
11 dut->clk = 1 - dut->clk; dut->eval();
12 }
13 return 0;
14}
dut->eval()
自己讓模擬器知道需要前進一個 timestamp。
最後我們只要在迴圈中加上「如果 valid == 1
則把 data
印出來」的程式碼,注意我們只在 dut->clk == 0
的時候判斷,這個是在 clk
原本是 1 變成之後呼叫 eval()
,也就是在 negedge sample valid
跟 data
值的意思。
1for (int i = 0; i < 40; ++i) {
2 dut->clk = 1 - dut->clk; dut->eval();
3 if (dut->clk == 0 and dut->valid == 1)
4 std::cout << char(dut->data) << std::endl;
5}
1H
2e
3l
4l
5o
以下廢話
前面一篇文章提到了,因為作者最近買了文明帝國,所以這篇被拆出成另外一篇了。可是一般來說買了文明帝國不可能在第二天就生出一篇文章,到底是發生什麼事情呢?原因是因為作者技術太差被電腦狂電,一怒之下就把遊戲關了。
系列文連結
-
Hello Verilator—高品質&開源的 SystemVerilog(Verilog) 模擬器介紹&教學(一)
-
Hello Verilator—高品質&開源的 SystemVerilog(Verilog) 模擬器介紹&教學(二)
-
Hello Verilator—高品質&開源的 SystemVerilog(Verilog) 模擬器介紹&教學(三)
- Hello Verilator—高品質&開源的 SystemVerilog(Verilog) 模擬器介紹&教學(一)
- Hello Verilator—高品質&開源的 SystemVerilog(Verilog) 模擬器介紹&教學(二)
- Hello Verilator—高品質&開源的 SystemVerilog(Verilog) 模擬器介紹&教學(三)