##はじめに
Verilog書かずにPythonのみでVerilogのデザイン・テストをやってみました。やってみた系です。
テストは以前書いたcocotb、デザインにはVeriloggenを使用しました。
環境はCentOS6.6になります。
##環境構築
Veriloggenを使用するには、作者さんのブログの通り、Pyverilog
, Jinja2
のインストールが必要になります。
処理系がPython3.3で書かれているため、cocotbとの相性がOS環境も含めて今ひとつよくありません。
よって、ウチの環境ではvirtualenv
を使わずに直接インストールしました。
git clone https://github.com/shtaxxx/Pyverilog
git clone https://github.com/shtaxxx/veriloggen
sudo pip install jinja2
cd Pyverilog
sudo python3 setup.py install
cd ../veriloggen
sudo python3 setup.py install
cd ../
cocotbは、以前と同じです。
今回も前回と同様、example
ディレクトリに新たにワークディレクトリを作成し、そこにrtlおよびtestsディレクトリを作成し、それぞれDUT、テストを保存しました。
違いは、rtlディレクトリにVerilogファイルではなくPythonファイルにしたことです。
├── model
│ └── tests.py
├── rtl
│ └── dff.py
└── tests
├── Makefile
└── run.sh
##DUT
DUTは前回の8bit順序回路になります。リセットが正論理かつ同期になったのが前回との違いです。
import sys, os
from veriloggen import *
def mkdff():
m = Module('dff')
width = m.Parameter('WIDTH', 8)
clk = m.Input('CLK')
rst = m.Input('RST')
d = m.Input('D', width)
q = m.OutputReg('Q', width)
m.Always(Posedge(clk))(
If(rst)(
q(0)
).Else(
q(d)
))
return m
if __name__ == '__main__':
dff = mkdff()
verilog = dff.to_verilog()
print(verilog)
##テスト
リセット極性を前回から変えてみました。
import cocotb
from cocotb.triggers import Timer, RisingEdge
from cocotb.result import TestFailure
from cocotb.clock import Clock
import random
class DffTB(object):
def __init__(self, dut, dubug=True):
self.dut = dut
@cocotb.coroutine
def reset(self, duration=10000):
self.dut.log.info("Resetting DUT")
self.dut.RST <= 1
self.dut.D <= 0
yield Timer(duration)
yield RisingEdge(self.dut.CLK)
self.dut.RST <= 0
self.dut.log.info("Out of reset")
@cocotb.coroutine
def gen_and_check(self):
D = random.randint(0, 255)
self.dut.D = D;
yield RisingEdge(self.dut.CLK)
yield Timer(1)
if int(self.dut.Q) != D :
raise TestFailure(
"[NG] Compre error. D==%s Q==%s" % (D, int(self.dut.Q)))
else :
self.dut.log.info("[OK]")
@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 = DffTB(dut)
cocotb.fork(clock_gen(dut.CLK))
yield RisingEdge(dut.CLK)
yield tb.reset()
for i in range(30):
yield tb.gen_and_check()
##実行スクリプト
つなぎ合わせるのが面倒だったのでシェルスクリプトにしました。
#!/bin/bash
RTLPATH=../rtl
if [ -e ${RTLPATH}/dff.v ]; then
rm ${RTLPATH}/dff.v
fi
python3 ${RTLPATH}/dff.py > ${RTLPATH}/dff.v
make
##結果
Veriloggenでは以下のようなVerilogコードが生成されました。
module dff #
(
parameter WIDTH = 8
)
(
input [0:0] CLK,
input [0:0] RST,
input [(WIDTH - 1):0] D,
output reg [(WIDTH - 1):0] Q
);
always @(posedge CLK)
begin
if(RST) begin
Q <= 0;
end
else begin
Q <= D;
end
end
endmodule
cocotbによるテスト結果も無事にオッケーです。
TESTCASE= TOPLEVEL=dff \
vvp -M /tmp/cocotb/build/libs/x86_64 -m gpivpi sim_build/sim.vvp
-.--ns INFO cocotb.gpi GpiCommon.cpp:47 in gpi_print_registered_impl VPI registered
0.00ns INFO cocotb.gpi gpi_embed.c:229 in embed_sim_init Running on Icarus Verilog version 0.9.6
0.00ns INFO cocotb.gpi gpi_embed.c:230 in embed_sim_init Python interpreter initialised and cocotb loaded!
0.00ns INFO cocotb.gpi __init__.py:103 in _initialise_testbench Running tests with Cocotb v1.0 from /tmp/cocotb
0.00ns INFO cocotb.gpi __init__.py:119 in _initialise_testbench Seeding Python random module with 1437305945
0.00ns INFO cocotb.regression regression.py:153 in initialise Found test tests.basic_test
0.00ns INFO cocotb.regression regression.py:254 in execute Running test 1/1: basic_test
0.00ns INFO ..tb.coroutine.basic_test.0x2353ed0 decorators.py:186 in send Starting test: "basic_test"
Description: basic_test
5.00ns INFO cocotb.dff tests.py:14 in reset Resetting DUT
15.00ns INFO cocotb.dff tests.py:20 in reset Out of reset
25.00ns INFO cocotb.dff tests.py:32 in gen_and_check [OK]
35.00ns INFO cocotb.dff tests.py:32 in gen_and_check [OK]
(中略)
295.00ns INFO cocotb.dff tests.py:32 in gen_and_check [OK]
305.00ns INFO cocotb.dff tests.py:32 in gen_and_check [OK]
315.00ns INFO cocotb.dff tests.py:32 in gen_and_check [OK]
315.00ns INFO cocotb.regression regression.py:201 in handle_result Test Passed: basic_test
315.00ns INFO cocotb.regression regression.py:162 in tear_down Passed 1 tests (0 skipped)
315.00ns INFO cocotb.regression regression.py:168 in tear_down Shutting down...
##おわりに
今度はAvalonなどのバスを絡めてやってみましょうかねえ…。