Vengineerの戯言

人生は短いけど、長いです。人生を楽しみましょう!

Bluespec SystemVerilog の回路例 : APB

はじめに

Bluespec SystemVerilogで実装されている回路例の紹介、今回はBluespecのAPBです。

github.com

テストベンチ (Testbench)

テストベンチは、Testbench.sv です。

module mkTestbench (Empty);
   APB_Initiator_IFC source <- mkSource;
   APB_Target_IFC  mem_model <- mkAPB_Mem_Model;

   mkConnection (source, mem_model);

   rule rl_dummy_APB_decoder_and_mux;
      mem_model.psel (True);
   endrule
endmodule

APB_Initiator_IFC と APB_Target_IFC を接続しています。

APB_Initiator_IFC と APB_Target_IFC は、APB_Types.bsv の中で定義されています。

ビルド

cd build/APB-Fabric32
make compile
mkdir -p build_dir
mkdir -p Verilog_RTL
INFO: Verilog RTL generation ...
bsc -u -elab -sim  -bdir build_dir  -simdir build_dir  -info-dir build_dir  -D RV32 -D FABRIC32  -keep-fires -aggressive-conditions -no-warn-action-shadowing -no-show-timestamps -check-assert -suppress-warnings G0020 +RTS -K128M -RTS  -show-range-conflict  -p ./src_bsv:../../src:../../src_tb:+  ../../src_tb/Testbench.bsv
checking package dependencies
compiling ../../src/APB_Defs.bsv
compiling ../../src/APB_Types.bsv
compiling ../../src_tb/Cur_Cycle.bsv
compiling ../../src_tb/Testbench_Commons.bsv
compiling ../../src_tb/APB_Mem_Model.bsv
code generation for mkAPB_Mem_Model starts
Elaborated module file created: build_dir/mkAPB_Mem_Model.ba
compiling ./src_bsv/EdgeFIFOFs.bsv
compiling ./src_bsv/ISA_Decls.bsv
compiling ./src_bsv/Semi_FIFOF.bsv
compiling ./src_bsv/AXI4_Types.bsv
compiling ./src_bsv/Fabric_Defs.bsv
compiling ./src_bsv/MMU_Cache_Common.bsv
compiling ../../src/APB_Adapter.bsv
compiling ../../src_tb/Testbench.bsv
code generation for mkSource starts
Elaborated module file created: build_dir/mkSource.ba
code generation for mkTestbench starts
Warning: "../../src_tb/Testbench.bsv", line 35, column 8: (G0010)
  Rule "rl_connect_psel" was treated as more urgent than
  "rl_dummy_APB_decoder_and_mux". Conflicts:
    "rl_connect_psel" cannot fire before "rl_dummy_APB_decoder_and_mux":
      calls to mem_model.psel vs. mem_model.psel
    "rl_dummy_APB_decoder_and_mux" cannot fire before "rl_connect_psel":
      calls to mem_model.psel vs. mem_model.psel
Warning: "../../src_tb/Testbench.bsv", line 41, column 9: (G0021)
  According to the generated schedule, rule `rl_dummy_APB_decoder_and_mux' can
  never fire.
Elaborated module file created: build_dir/mkTestbench.ba
All packages are up to date.
bsc -u -elab -verilog  -vdir Verilog_RTL  -bdir build_dir  -info-dir build_dir  -D RV32 -D FABRIC32  -keep-fires -aggressive-conditions -no-warn-action-shadowing -no-show-timestamps -check-assert -suppress-warnings G0020 +RTS -K128M -RTS  -show-range-conflict  -p ./src_bsv:../../src:../../src_tb:+  ../../src_tb/Testbench.bsv
checking package dependencies
compiling ../../src_tb/APB_Mem_Model.bsv
code generation for mkAPB_Mem_Model starts
Verilog file created: Verilog_RTL/mkAPB_Mem_Model.v
Elaborated module file created: build_dir/mkAPB_Mem_Model.ba
compiling ../../src_tb/Testbench.bsv
code generation for mkSource starts
Verilog file created: Verilog_RTL/mkSource.v
Elaborated module file created: build_dir/mkSource.ba
code generation for mkTestbench starts
Warning: "../../src_tb/Testbench.bsv", line 35, column 8: (G0010)
  Rule "rl_connect_psel" was treated as more urgent than
  "rl_dummy_APB_decoder_and_mux". Conflicts:
    "rl_connect_psel" cannot fire before "rl_dummy_APB_decoder_and_mux":
      calls to mem_model.psel vs. mem_model.psel
    "rl_dummy_APB_decoder_and_mux" cannot fire before "rl_connect_psel":
      calls to mem_model.psel vs. mem_model.psel
Warning: "../../src_tb/Testbench.bsv", line 41, column 9: (G0021)
  According to the generated schedule, rule `rl_dummy_APB_decoder_and_mux' can
  never fire.
Verilog file created: Verilog_RTL/mkTestbench.v
Elaborated module file created: build_dir/mkTestbench.ba
All packages are up to date.
INFO: Verilog RTL generation finished
make bluesim_simulator

にて、実行プログラムを生成

  • exe_HW_sim
  • exe_HW_sim.so

exe_HW_sim は、shell script で次のようになっています。bluesim.tcl に対して、共有ライブラリ exe_HW_sim.so を渡し、トップテストベンチとして mkTestbech を指定しています。

#!/bin/sh

BLUESPECDIR=`echo 'puts $env(BLUESPECDIR)' | bluetcl`

for arg in $@
do
  if (test "$arg" = "-h")
  then
    exec $BLUESPECDIR/tcllib/bluespec/bluesim.tcl $0.so mkTestbench --script_name `basename $0` -h
  fi
done
exec $BLUESPECDIR/tcllib/bluespec/bluesim.tcl $0.so mkTestbench --script_name `basename $0` --creation_time 1689472003 "$@"

exe_sim_HW の実行

exe_sim_HW を実行すると、次のようなメッセージが表示されます。

./exe_sim_HW
1: top.source.rl_wr_32: Single_Req { is_read: False, addr: 'h00000000, size_code: 'h2 } 0x00000000
     2:[D]:top.source.rl_new_tfr (paddr 0x00000000)            (pwrite: True)            (pstrb: 1111)            (pwdata 0x00000000)
     3:[D]:top.source.rl_setup: (addr 0x00000000) (wdata 0x00000000)
40: top.mem_model.rl_new_write_tfr: IDLE
50: top.mem_model.rl_write_response: (addr 00) (data 00000000) WR_RSP
     5:[D]:top.source.rl_write_response
6: top.source.rl_wr_32: Single_Req { is_read: False, addr: 'h00000004, size_code: 'h2 } 0x00000004
     7:[D]:top.source.rl_new_tfr (paddr 0x00000004)            (pwrite: True)            (pstrb: 1111)            (pwdata 0x00000004)
     8:[D]:top.source.rl_setup: (addr 0x00000004) (wdata 0x00000004)
....
44790: top.mem_model.rl_new_read_tfr: IDLE
44800: top.mem_model.rl_read_response: (addr fc) (data fffefdfc) RD_RSP
  4480:[D]:top.source.rl_read_response: Read_Data { ok: False, data: 'hfffefdfc }
4481: top.source.rl_rd_rsp_8: Read_Data { ok: False, data: 'hfffefdfc }

verilator_simulator

Verilator にて実行してみます。

make verilator_simulator
INFO: Verilating Verilog files (in newly created obj_dir)
sed  -f ../../build/Resources/Verilator_resources/sed_script.txt  Verilog_RTL/mkTestbench.v > tmp1.v
cat  ../../build/Resources/Verilator_resources/verilator_config.vlt \
     ../../build/Resources/Verilator_resources/import_DPI_C_decls.v \
     tmp1.v                                     > Verilog_RTL/mkTestbench_edited.v
rm   -f  tmp1.v
verilator \
        -IVerilog_RTL \
        -I../../src_bsc_lib_RTL \
        --stats -O3 -CFLAGS -O3 -LDFLAGS -static --x-assign fast --x-initial fast --noassert --trace  --trace-depth 10  -CFLAGS -DVM_TRACE \
        --cc  mkTestbench_edited.v \
        --exe  sim_main.cpp \
        ../../src_tb/C_Imported_Functions.c
%Error: Verilog_RTL/mkTestbench_edited.v:6:10: syntax error, unexpected '-'
    6 | lint_off -msg WIDTH
      |          ^
%Error: Exiting due to 1 error(s)
make: *** [Makefile:85: verilator_simulator] Error 1

生成された Verilog_RTL/mkTestbench_edited.v の 6行目でエラーになります。Verilog_RTL/mkTestbench_edited.vをみてみます。どうやら、下記の部分がエラーになっています。

`verilator_config
lint_off -msg WIDTH
lint_off -msg CASEINCOMPLETE
lint_off -msg STMTDLY
lint_off -msg INITIALDLY
lint_off -msg UNSIGNED
lint_off -msg CMPCONST
`verilog

この部分は、build/Resources/Verilator_resources/verilator_config.vlt なので、これをコメントアウトしてみました。

rm -rf Verilator_RTL
make compile
make verilator_simulator
INFO: Verilating Verilog files (in newly created obj_dir)
sed  -f ../../build/Resources/Verilator_resources/sed_script.txt  Verilog_RTL/mkTestbench.v > tmp1.v
cat  ../../build/Resources/Verilator_resources/verilator_config.vlt \
     ../../build/Resources/Verilator_resources/import_DPI_C_decls.v \
     tmp1.v                                     > Verilog_RTL/mkTestbench_edited.v
rm   -f  tmp1.v
verilator \
        -IVerilog_RTL \
        -I../../src_bsc_lib_RTL \
        --stats -O3 -CFLAGS -O3 -LDFLAGS -static --x-assign fast --x-initial fast --noassert --trace  --trace-depth 10  -CFLAGS -DVM_TRACE \
        --cc  mkTestbench_edited.v \
        --exe  sim_main.cpp \
        ../../src_tb/C_Imported_Functions.c
%Error: Verilog_RTL/mkSource.v:292:3: Cannot find file containing module: 'FIFO1'
  292 |   FIFO1 #(.width(32'd33), .guarded(1'd1)) f_mem_rdata(.RST(RST_N),
      |   ^~~~~
        Verilog_RTL/mkTestbench_edited.v:194:1: ... note: In file included from mkTestbench_edited.v
        ... Looked in:
             Verilog_RTL/FIFO1
             Verilog_RTL/FIFO1.v
             Verilog_RTL/FIFO1.sv
             ../../src_bsc_lib_RTL/FIFO1
             ../../src_bsc_lib_RTL/FIFO1.v
             ../../src_bsc_lib_RTL/FIFO1.sv
             FIFO1
             FIFO1.v
             FIFO1.sv
             obj_dir/FIFO1
             obj_dir/FIFO1.v
             obj_dir/FIFO1.sv
%Error: Verilog_RTL/mkSource.v:303:3: Cannot find file containing module: 'FIFO1'
  303 |   FIFO1 #(.width(32'd35), .guarded(1'd1)) f_mem_req(.RST(RST_N),
      |   ^~~~~
        Verilog_RTL/mkTestbench_edited.v:194:1: ... note: In file included from mkTestbench_edited.v
%Error: Verilog_RTL/mkSource.v:314:3: Cannot find file containing module: 'FIFO1'
  314 |   FIFO1 #(.width(32'd32), .guarded(1'd1)) f_mem_wdata(.RST(RST_N),
      |   ^~~~~

FIFO1が無いと怒られます。上記のコマンドの引数を見ると、../../src_bsc_lib_RTL なるディレクトリを参照しています。APB には src_bsc_lib_RTL なるディレクトリはありません。調べてみたら、AHB-Lte という repo に src_bsc_lib_RTL ディレクトリがありましたので、コピーしてみました。再度、make を実行しましたら、

                Verilog_RTL/mkTestbench_edited.v:180:1: ... note: In file included from mkTestbench_edited.v
%Error-NEEDTIMINGOPT: Verilog_RTL/mkSource.v:668:5: Use --timing or --no-timing to specify how delays should be handled
                                                  : ... In instance mkTestbench.source
  668 |     #0;
      |     ^

ここで使っている verilator は 5.002 なので、上記のように #0 を使う時は、--timing オプションを使うことになっています。Makefileの中で

        verilator \
                --timing \     <===== これを追加
                -IVerilog_RTL \
                -I$(REPO)/src_bsc_lib_RTL \
                $(VERILATOR_FLAGS) \
                --cc  $(TOPMODULE)_edited.v \
                --exe  sim_main.cpp \
                $(REPO)/src_tb/C_Imported_Functions.c

再度実行したら、下記のようなエラーが発生しました。

%Error-ZERODLY: Verilog_RTL/mkAPB_Mem_Model.v:387:5: Unsupported: #0 delays do not schedule process resumption in the Inactive region
  387 |     #0;
      |     ^

--timing を --no-timingにしたら、上記のエラーは無くなりましたが、make コマンドは失敗します。

%Error: Exiting due to 38 warning(s)
make: *** [Makefile:85: verilator_simulator] Error 1

verilator の後の下記の部分を手動で実行してみました。

        @echo "INFO: Linking verilated files"
        cp  -p  $(VERILATOR_RESOURCES)/sim_main.cpp  obj_dir/sim_main.cpp
        cd obj_dir; \
           make -j -f V$(TOPMODULE)_edited.mk  $(VTOP); \

生成された VmkTestbench_edited ($VTOP) を実行したら、bluesim_simulator ターゲットで生成された exe_sim_HW のログとだいたい同じになりました。 (Pathの top と TOP.mkTestbench の違いと、タイムスタンプの上位ビットが0で埋まっているぐらいの違い)

verilator v5.012

Verilator v5.012 にて、同じように行ったら、

--no-timing / --timing 共に、 `` ./VmkTestbench_edited Segmentation fault

となってしまいました。

# おわりに

Verilator が Warningだけなのに、exit status が 0 じゃないのは仕様なんでしょうか?