PyMTLを使ってLEDチカチカ回路を作ってみる
ACM/IEEE MICRO-48で発表されたPyMTLを試してみたので,その使い方をまとめておきます.
PyMTLはPython上でBehavior level, Cycle level, Register transfer levelの3種類の抽象度でハードウェアをモデリングすることができるフレームワークです.
ここでは,Verilog HDLなどと同じRTLで回路を記述し,Verilog HDLのソースコードを生成してみます.
GitHubにあるPyMTLプロジェクトのREADMEとISCA2015でのチュートリアルのスライドを参考にして進めます.
PyMTLとVerilatorのインストール
あらかじめpython2.7とvirtualenvをインストールしておく.
pip install virtualenv
作業用ディレクトリを作成する.
mkdir pymtl
PATHの設定等を記述したスクリプトを用意する.setup.shという名前で作成する.
VERILATOR=~/pymtl/verilator/ source ./bin/activate export PATH=$VERILATOR/bin/:$PATH export PYMTL_VERILATOR_INCLUDE_DIR=$VERILATOR/include export VERILATOR_ROOT=$VERILATOR
反映させる.
source setup.sh
PyMTLとVerilatorをインストールする.
cd pymtl virtualenv --python=python2.7 . git clone https://github.com/cornell-brg/pymtl.git pip install --editable ./pymtl git clone http://git.veripool.org/git/verilator cd verilator/ autoconf export VERILATOR_ROOT=`pwd` ./configure make cd ..
PyMTLのテスト
cd pymtl mkdir build cd build py.test .. --verbose --tb=line py.test .. --verbose --test-verilog cd ../
LEDチカチカハードウェアをPyMTLで書いてみる
サンプルディレクトリを作成し,定義本体用ファイルとテスト用ファイルを用意する.
mkdir -p my_examples/led cd my_examples/led touch ledRTL.py touch ledRTL_test.py
定義本体のledRTL.pyはこんな感じ.
from pymtl import * class LedRTL( Model ): def __init__( s ): s.led = OutPort( 8 ) s.count = Wire( 32 ) s.led_count = Wire( 8 ) @s.tick_rtl def seq(): if s.count == 1023: s.count.next = 0 s.led_count.next = s.led_count + 1 else: s.count.next = s.count + 1 @s.combinational def comb(): s.led.value = s.led_count
テストのledRTL_test.pyはこんな感じ.
from pymtl import * from ledRTL import LedRTL def test_simple( test_verilog ): model = LedRTL() if test_verilog: model = TranslationTool( model ) model.elaborate()
実行してみる.
py.test ledRTL_test.py --test-verilog
そうすると,こんな感じのVerilog HDLのソースコードが同じディレクトリに生成されている.
//----------------------------------------------------------------------------- // LedRTL_0x791afe0d4d8c //----------------------------------------------------------------------------- // dump-vcd: False `default_nettype none module LedRTL_0x791afe0d4d8c ( input wire [ 0:0] clk, output reg [ 7:0] led, input wire [ 0:0] reset ); // register declarations reg [ 31:0] count; reg [ 7:0] led_count; // PYMTL SOURCE: // // @s.tick_rtl // def seq(): // if s.count == 1023: // s.count.next = 0 // s.led_count.next = s.led_count + 1 // else: // s.count.next = s.count + 1 // logic for seq() always @ (posedge clk) begin if ((count == 1023)) begin count <= 0; led_count <= (led_count+1); end else begin count <= (count+1); end end // PYMTL SOURCE: // // @s.combinational // def comb(): // s.led.value = s.led_count // logic for comb() always @ (*) begin led = led_count; end endmodule // LedRTL_0x791afe0d4d8c
想像した通りの回路がVerilog HDLで記述されている.
PyMTLの実装について
ハードウェアの各変数は,Modelクラスを継承したクラスのオブジェクトとして保持されています. Verilog HDLソースコードを生成する際には,Model継承クラスが持つ変数とその変数名の辞書をobj.__dict__を使って取得し,その中からハードウェア変数のPythonソースコード中の変数名を取得して,Verilog HDLでの変数名として利用しているようです.なるほど,かっこいい!