Polyphonyって何だろう(2)使用例:フィボナッチ数列

Python で書いた関数を Verilog HDL に変換する高位合成コンパイラである Polyphony を使ってみたいと思います。実際に動かした方が分かりやすいと思うので、早速フィボナッチ数列を出力する回路を合成したいと思います。計算が必要な回路合成には高位合成は本当に便利だと思います。

フィボナッチ数列とは

直前の2つの数値を足したものを新しい数値とする数列です。すなわち、
0,1,2,3,5,8,13,21,...
というような数列となります。足し算していくだけのいたって簡単なものです。

python コードと簡単な説明

polyphony の便利なところは、そのまま python として実行できることです。また、クラスとして記述する事で、入出力ポートを記述可能で、ビット幅も指定可能です。テストベンチもいたって簡単に記述できます。
早速コードを fib_class_n.py として作成します。
polyphony はどうやら日本語utf-8には対応していないようなので、コメントを入れる時には日本語を使わない方がよさそうです。
モジュールとしては何回ループを回すかの n を設定して、start 信号を入れると fibb からフィボナッチ数列が出力され、ループが終わると次の数値を fiba から出力して finish 信号で終了を知らせるという簡単なものです。

import polyphony
from polyphony import module, pure, is_worker_running, rule
from polyphony import testbench
from polyphony.io import Port
from polyphony.typing import bit, int8, int16, int32
from polyphony.timing import wait_value, wait_rising, clksleep, clkfence

# %%
@module
class fib_class_n:
    def __init__(self):
        self.start  = Port(bool, 'in')
        self.n      = Port(int8, 'in')
        self.fiba   = Port(int16, 'out')
        self.fibb   = Port(int16, 'out')
        self.finish = Port(bool, 'out')
        self.append_worker(self.main)

    def main(self):
        while is_worker_running():
            if(self.start.rd() == True):
                a = self.fib(self.n.rd())
                self.fiba.wr(a)
                self.finish.wr(True)
                clksleep(1)
                self.finish.wr(False)

    def fib(self, n):
        if n <= 0:
            return 0
        if n == 1:
            return 1
        r0 = 0
        r1 = 1
        for i in range(n):
            r0, r1 = r1, r0+r1
            self.fibb.wr(r0)
            print(r0, r1)
        return r1


# %%
@testbench
def fib_class_n_test(m):
    m.n.wr(4)
    m.start.wr(True)
    clksleep(1)
    m.start.wr(False)
    wait_value(True, m.finish)
    clksleep(10)
    m.n.wr(8)
    m.start.wr(True)
    clksleep(1)
    m.start.wr(False)
    wait_value(True, m.finish)
    clksleep(5)
    print('finished')


# %%
m = fib_class_n()
fib_class_n_test(m)

実行

そのまま python として実行すると,バグが無ければ次のような出力が表示されるはずです。

1 1
1 2
2 3
3 5
1 1
1 2
2 3
3 5
5 8
8 13
13 21
21 34
finished

次に、前回作った compile.py を使って、polyphony でコンパイルした Verilog ファイルをシミュレーションして gtkwave で表示するまでを行います。非常に簡単で compile.py の

target = 'fib_class_n' #file name = module name

の所に今回のファイル fib_class_n.py の fib_class_n を書いて実行するだけです。
うまく動くと、下記のファイルが作成され gtkwave で好きな信号の波形が見れるようになります。
fib_class_n_m.v:フィボナッチ数列の出力モジュール(Verilog HDL)
fib_class_n_test.v:テストモジュール(Verilog HDL)
polyphony_out.v:テストを実行するために読み込むモジュール
        (`include "./fib_class_n_m.v" と書かれている)
fib_class_n.out:iverilog で作られた vvp の入力となるシミュレーションファイル
fib_class_n_test.vcd:vvp シミュレーション結果(gtkwave の入力となる)

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

簡単な計算でも Verilog HDL で直接記述しようとするとなかなか難しいものだと思います。それがこんなに簡単に記述できるというのは、polyphony 素晴らしいです。

実行環境:Win10 python3.7.1 polyphony0.3.3 iverilog0.9.7