PyMTLは、Pythonの記述からVerilog-HDLを出力するためのツールだ。
http://csl.cornell.edu/~cbatten/pdfs/lockhart-pymtl-micro2014.pdf
1. インストールまで
僕はRTLの開発はWindows+Cygwinの環境を主体にしているので、Cygwin上にインストールする方法を調べた。
ちらのうら - Cygwin上でpipとsetuptoolsをインストールする方法
Cygwinのsetup-x86_64.exeからpython-setuptoolsをインストールして、その後にpipをeays_installからインストールする。
$ easy_install-2.7 pip Searching for pip Reading https://pypi.python.org/simple/pip/ Best match: pip 7.1.0 Downloading https://pypi.python.org/packages/source/p/pip/pip-7.1.0.tar.gz#md5=d935ee9146074b1d3f26c5f0acfd120e Processing pip-7.1.0.tar.gz Writing /tmp/easy_install-ZhJY7c/pip-7.1.0/setup.cfg Running pip-7.1.0/setup.py -q bdist_egg --dist-dir /tmp/easy_install-ZhJY7c/pip-7.1.0/egg-dist-tmp-AJgGzC warning: no previously-included files found matching '.coveragerc' warning: no previously-included files found matching '.mailmap' warning: no previously-included files found matching '.travis.yml' warning: no previously-included files found matching 'pip/_vendor/Makefile' warning: no previously-included files found matching 'tox.ini' warning: no previously-included files found matching 'dev-requirements.txt' no previously-included directories found matching '.travis' no previously-included directories found matching 'docs/_build' no previously-included directories found matching 'contrib' no previously-included directories found matching 'tasks' no previously-included directories found matching 'tests' creating /usr/lib/python2.7/site-packages/pip-7.1.0-py2.7.egg Extracting pip-7.1.0-py2.7.egg to /usr/lib/python2.7/site-packages Adding pip 7.1.0 to easy-install.pth file Installing pip script to /usr/bin Installing pip2.7 script to /usr/bin Installing pip2 script to /usr/bin Installed /usr/lib/python2.7/site-packages/pip-7.1.0-py2.7.egg Processing dependencies for pip Finished processing dependencies for pip
あとは、shitaxxさんのブログのインストール方法に則る。
$ pip install virtualenv Collecting virtualenv Downloading virtualenv-13.1.0-py2.py3-none-any.whl (1.7MB) 100% |████████████████████████████████| 1.7MB 88kB/s Installing collected packages: virtualenv Successfully installed virtualenv-13.1.0
次に、Cygwin上にVerilatorをインストールする。
autoconfとか、gccとかもCygwinのデフォルトに入っていないかったので、インストールした。
apt-cyg install autoconf gcc-core flex bison make
あとはgcc-g++が何故かapt-cygで見付からなかったので、setup-x86_64.exeからインストールした。 そしてVerilatorをインストールしたので、いよいよPyMTLの構築を開始する。
まずは、PyMTLの説明に書いてあるとおり、Virtualenvを構築する。
$ cd $ mkdir ./work/venvs $ cd ./work/venvs $ virtualenv --python=python2.7 ~/work/venvs/pymtl_env Running virtualenv with interpreter /usr/bin/python2.7 New python executable in /home/Masayuki/work/venvs/pymtl_env/bin/python2.7 Also creating executable in /home/Masayuki/work/venvs/pymtl_env/bin/python Installing setuptools, pip, wheel...done. $ source ~/work/venvs/pymtl_env/bin/activate (pymtl_env)
そのまま、PyMTLをcloneしてきてから、ビルドする。
$ cd ~/software $ git clone https://github.com/cornell-brg/pymtl.git Cloning into 'pymtl'... remote: Counting objects: 14170, done. remote: Total 14170 (delta 0), reused 0 (delta 0), pack-reused 14170 Receiving objects: 100% (14170/14170), 4.13 MiB | 617.00 KiB/s, done. Resolving deltas: 100% (10710/10710), done. Checking connectivity... done. Checking out files: 100% (617/617), done. $ pip install --editable ./pymtl ... Successfully installed cffi-1.1.2 execnet-1.3.0 greenlet-0.4.7 py-1.4.30 pymtl pytest-2.7.2 pytest-xdist-1.12 (pymtl_env)
2. テストコードを書いてみる
さっそく自分でコード書いてみた。Python慣れないから辛い...
- decoder.py
from pymtl import * class MipsDecoder(Model): def __init__ (s): inst_length = 5 s.in_ = InPort(inst_length) s.out = OutPort(8) code_add = 0 code_sub = 1 code_mul = 2 code_div = 3 @s.combinational def comb(): if s.in_ == code_add: s.out = 0 elif s.in_ == code_sub: s.out = 2 elif s.in_ == code_mul: s.out = 4 elif s.in_ == code_div: s.out = 8
- decoder_test.py
from pymtl import * from decoder import MipsDecoder def test_decoder(): model = MipsDecoder() model = TranslationTool( model ) model.elaborate()
以下の方法でビルドし、Verilog-HDLのコードを吐き出す。
$ py.test decoder_test.py ============================================== test session starts ============================================== platform cygwin -- Python 2.7.10 -- py-1.4.30 -- pytest-2.7.2 rootdir: /cygdrive/c/usr/work/pymtl/test/examples/decoder, inifile: plugins: xdist collected 1 items decoder_test.py . =========================================== 1 passed in 1.13 seconds ============================================ (pymtl_env)
出来た!
$ ls -1 __pycache__ decoder.py decoder.pyc decoder_test.py libMipsDecoder_0x791afe0d4d8c_v.so MipsDecoder_0x791afe0d4d8c.v MipsDecoder_0x791afe0d4d8c_v.cpp MipsDecoder_0x791afe0d4d8c_v.py MipsDecoder_0x791afe0d4d8c_v.pyc obj_dir_MipsDecoder_0x791afe0d4d8c $ less MipsDecoder_0x791afe0d4d8c.v
//----------------------------------------------------------------------------- // MipsDecoder_0x791afe0d4d8c //----------------------------------------------------------------------------- // dump-vcd: False `default_nettype none module MipsDecoder_0x791afe0d4d8c ( input wire [ 0:0] clk, input wire [ 4:0] in_, output reg [ 7:0] out, input wire [ 0:0] reset ); // localparam declarations localparam code_add = 0; localparam code_div = 3; localparam code_mul = 2; localparam code_sub = 1; // PYMTL SOURCE: // // @s.combinational // def comb(): // if s.in_ == code_add: // s.out = 0 // elif s.in_ == code_sub: // s.out = 2 // elif s.in_ == code_mul: // s.out = 4 // elif s.in_ == code_div: // s.out = 8 // logic for comb() always @ (*) begin if ((in_ == code_add)) begin out = 0; end else begin if ((in_ == code_sub)) begin out = 2; end else begin if ((in_ == code_mul)) begin out = 4; end else begin if ((in_ == code_div)) begin out = 8; end else begin end end end end end endmodule // MipsDecoder_0x791afe0d4d8c `default_nettype wire
うーん、なんか思ってたのと違うなあ。。。ってか、Pythonでswitchってどう書けばいいんだろう。
Pythonで記述することによる汎用性の向上は素晴しいことだと思う。RTLにバリエーションを持たせなければならないとか、まだ仕様が決まってなくてとりあえず作らなければならないとき(これ、会社にいると本当に良くある)とかに、パッと作るには有効な手段だと思う。 こういうツールが役に立つのって、バリエーションを物凄い数試して、良い物を見付けたりとか、とにかく大量のケースを試すときに役に立つと思うので、そういう意味では性能評価とかにうまく使えればいいんだけれどなあ。 ついでに、C++のモデルも出力してくれればなお嬉しい(Chiselのコードが酷いだけに...)