Veriloggenって何だろう(8)Thread 高位合成

Verilog HDL を生成するための記述を python で行うことで FPGA 回路の生成を楽にする為のライブラリー Veriloggen を使ってみたいと思います。今回は高位合成のThreadの使用例を書きます。

高位合成 Thread によるフィボナッチ数列生成

pythonで書いた関数を Verilog に変換するという高位合成を行う機能という事になります。今まで扱ってきた Veriloggen の python でどんな Verilog を作りこんでいくかの記述の中に、python の計算関数を埋め込むイメージになると思います。
試しに、フィボナッチ数列を出力するモジュールを作ってみました。

from veriloggen import Module
import veriloggen.simulation as sm
from veriloggen import Delay, Wait, Systask
import veriloggen.thread as vthread
import veriloggen_util as vu

# %%
def mkFib():
    m = Module('FIB')
    clk = m.Input('CLK')
    rst = m.Input('RST')
    n = m.Input('N',8)
    st = m.Input('ST')
    fiba = m.OutputReg('FIBA', 16, initval=0)
    fibb = m.OutputReg('FIBB', 16, initval=0)
    finish = m.OutputReg('FINISH', 1, initval=0)

    def fib():
        while True:
            if st != 0:
                finish.value = 0
                fiba.value = fibcalc(n)
                finish.value = 1

    def fibcalc(nt):
        if nt == 0:
            return 0
        if nt == 1:
            return 1
        r0 = 0
        r1 = 1
        for i in range(nt):
            r0, r1 = r1, r0+r1
            fibb.value = r0
            print(r0, r1)
        return r1

    th = vthread.Thread(m, 'th', clk, rst, fib)
    fsm = th.start()

    return m


# %%
def mkTest():
    m = Module('test')

    #target instance
    fib = mkFib()

    #copy parameters and ports
    params = m.copy_params(fib)
    ports = m.copy_sim_ports(fib)

    clk = ports['CLK']
    rst = ports['RST']
    n = ports['N']
    st = ports['ST']
    fiba = ports['FIBA']
    fibb = ports['FIBB']
    finish = ports['FINISH']

    uut = m.Instance(fib, 'uut',
                     params=m.connect_params(fib),
                     ports=m.connect_ports(fib))

    sm.setup_waveform(m, uut, m.get_vars())
    sm.setup_clock(m, clk, hperiod=5)
    init = sm.setup_reset(m, rst, m.make_reset(), period=50)

    init.add(
            st(0),
            n(4),
            st(1),
            [sm.next_clock(clk) for i in range(3)],
            st(0),
            Wait(finish),
            [sm.next_clock(clk) for i in range(10)],
            n(8),
            st(1),
            [sm.next_clock(clk) for i in range(3)],
            st(0),
            Wait(finish),
            [sm.next_clock(clk) for i in range(5)],
            Systask('finish')
            )

    return m


# %%
#delete old file
vu.delete_file('a.out')
vu.delete_file('tmp.v')
vu.delete_file('uut.vcd')

test = mkTest()
verilog = test.to_verilog('tmp.v')
print(verilog)

vu.addtimescale('tmp.v')
vu.run_iverilog('tmp.v')
vu.run_vvp()
vu.view_waveform_gtkwave()

N に繰り返しの回数をセットし、STARTに信号を入れるとフィボナッチ数列を FIBB から出力し、所定回数の繰り返しが終了すると、次の数を FIBA から出力して FINISH 信号が立ち上がるという物です。
python の計算部分が fibcalc になりますが、残念ながら fibcalc のループ内から FIBB を出力しているので、このまま python のコードとはいきませんが、計算アルゴリズムpython 文法で書いているのは確かです。
この中の Verilog_util に関しては、
Veriloggenって何だろう(7)Parameter Delay Mux Sra - メグタンの何でもブログ
を参照してください。

実行結果

上記ファイルを実行すると フィボナッチ数列を出すモジュールとテストベンチが書かれた Verilog HDL ファイルである tmp.v が出力され、iverilog によって出力された シミュレーション用ファイル a.out ができます。a.out を VVP に読み込ませてシミュレーションした結果が uut.vcd で、これが gtkwave の入力となります。
結果は下記になりますが、1行ごとに状態遷移して遅れが生じるようで、あまり速くありませんが、pythonで記述した計算を Verilog にできるのは便利だと思います。

f:id:feynman911:20181222165518j:plain
フィボナッチシミュレーション結果 veriloggen

実行環境:Win10 python3.7.1 veriloggen1.5.4 iv1.5.4