久し振りにVerilogで回路を書き始めている。ユニットずつ実装をしているのだが、まずはAXI経由でメモリにアクセスする回路を書かなければ。 その際、バッファが溢れないようにAXIインタフェースをちゃんと制御できるか、ちゃんと設計結果を検証することは、なかなかに大変だ。 その際、いろんなパタンを、簡単な言語で記述できるとうれしい。そのための言語としてはやはりSystemVerilogが有名だ。SystemVerilogを使えば、Verilog-HDLよりもより簡単にテストパタンを記述できる。
しかし、今回はもっと別のアプローチを取ってみよう。そのために採用したのは、cocotbを用いたPythonでのテストパタン記述だ。 Pythonをインタフェースとしたことで、VPIを経由したインタフェースでVerilogとの協調検証を行うことができる。
cocotbについては、去年もちょっと試していたが、本格的な導入は未経験だった。
1. cocotb + icarus Verilogでテストパタンを実行する
上記のような環境を構築する。実際には、テスト対象に対して、Pythonとテストシナリオを記述していくだけだ。テストシナリオを書くと、テストパタンは自動的に構築される。
import cocotb from cocotb.triggers import Timer, RisingEdge from cocotb.result import TestFailure from cocotb.clock import Clock import random class tb_mag_ifu(object): def __init__(self, dut, dubug=True): self.dut = dut ... @cocotb.coroutine def clock_gen(signal): while True: signal <= 0 yield Timer(5000) signal <= 1 yield Timer(5000) @cocotb.test() def basic_test(dut): """basic_test""" tb = tb_mag_ifu(dut) cocotb.fork(clock_gen(dut.CPU_CLK)) tb.axi_reset() tb.reset_br_signal() tb.set_pc_init(0xbfc00000) yield RisingEdge(dut.CPU_CLK) yield tb.reset() for i in range(10): yield tb.gen_and_check()
上記のPythonのテストシナリオにより、tb.gen_and_check()を10回呼んでいる。この中に実際のAXIのテストパタンが書かれており、AXIの動作をチェックしているという訳だ。
1.1. AXIテストの本体(書きかけ)
実際のgen_and_check()は、現在は書きかけなのだが、大体こんな感じだ。
def gen_and_check(self): yield RisingEdge(self.dut.CPU_CLK) yield RisingEdge(self.dut.CPU_CLK) if self.dut.IF_MARVALID == 1: self.dut.log.info("Detect MARVALID") else: self.dut.log.info("Wait MARVALID") wait_time = random.randint(0, 10) for i in range(0, wait_time): yield RisingEdge(self.dut.CPU_CLK) if self.dut.IF_MARVALID == 0: raise TestFailure("[NG] IF_MARVILD goes down") self.dut.IF_MARREADY <= 1
IF_MARVALIDが立ち上がる(テスト対象がアドレスチャネルを有効化する)と、それからランダムなタイミングでIF_MARREADYをアサートする。ここでRandomを使えたり、for文で簡単にテスト動作を記述できるのがcocotbの強みだ。 そこから、さらに別のIDとか、VALIDのタイミングなどがチェックできるし、Pythonのライブラリを使ってFIFOを擬似的に作ったりすることができる。 ただし、そこまではまだ構築できていない。
2. 実行結果
makeによりテストパタンを実行すると、以下のような結果が出力された。
TESTCASE= TOPLEVEL=mag_ifu TOPLEVEL_LANG=verilog \ vvp -M /home/vagrant/magnetor-1/hardware/cocotb/build/libs/x86_64 -m gpivpi sim_build/sim.vvp -I /home/vagrant/magnetor-1/hardware/mag_core/mag_ifu/cocotb/../../../common/include/ -.--ns INFO cocotb.gpi GpiCommon.cpp:91 in gpi_print_registered_impl VPI registered 0.00ns INFO cocotb.gpi gpi_embed.c:248 in embed_sim_init Running on Icarus Verilog version 0.9.7 0.00ns INFO cocotb.gpi gpi_embed.c:249 in embed_sim_init Python interpreter initialised and cocotb loaded! 0.00ns INFO cocotb __init__.py:115 in _initialise_testbench Running tests with Cocotb v1.0 from /home/vagrant/magnetor-1/hardware/cocotb 0.00ns INFO cocotb __init__.py:131 in _initialise_testbench Seeding Python random module with 1455812561 0.00ns INFO cocotb.regression regression.py:161 in initialise Found test tb_mag_ifu.basic_test 0.00ns INFO cocotb.regression regression.py:262 in execute Running test 1/1: basic_test 0.00ns INFO ..routine.basic_test.0x2b690cd41910 decorators.py:189 in send Starting test: "basic_test" Description: basic_test /home/vagrant/magnetor-1/hardware/cocotb/cocotb/handle.py:165: UserWarning: Use of log attribute is deprecated warnings.warn("Use of %s attribute is deprecated" % name) 0.00ns INFO cocotb.mag_ifu tb_mag_ifu.py:13 in axi_reset Resetting AXI VCD info: dumpfile dump.vcd opened for output. 5.00ns INFO cocotb.mag_ifu tb_mag_ifu.py:31 in reset Resetting DUT 15.00ns INFO cocotb.mag_ifu tb_mag_ifu.py:40 in reset Out of reset 35.00ns INFO cocotb.mag_ifu tb_mag_ifu.py:47 in gen_and_check Detect MARVALID 105.00ns WARNING ..tine.gen_and_check.0x2b690cd86490 decorators.py:117 in send [NG] IF_MARVILD should go down 105.00ns ERROR cocotb.regression regression.py:246 in handle_result Test Failed: basic_test (result was TestFailure) 105.00ns ERROR cocotb.regression regression.py:167 in tear_down Failed 1 out of 1 tests (0 skipped) 105.00ns INFO cocotb.regression regression.py:176 in tear_down Shutting down...
failになってしまった!MARVALIDとMARREADYが立ち上がったあと、一度間隔をあけるためにMARVALIDを落とすような仕様にしているのだが、それがうまく動作していないようだ? まあ、それ以外にも、前回と違うIDを出力してくるはずだとか、チェックのやりようはたくさんあるので、その辺を追加していこう。
ちなみに、
今回はIcarus Verilogを利用したのだが、GTKWaveがおそろしく使いにくいので、もっと使いやすい環境に移行したい。
おまけ. Vivado Simulatorの環境を構築することは可能なのか?
調査してみたが、どうやらシミュレータにVPIの環境が備わっている必要があるようだ。現在、Vivado SimulatorはDPIしか装備しておらず、うまくいかない。。。 この辺は、もしかしたらDPIを記述すれば、自力で対応させることができるかもしれない?