shtaxxx日記

コンピュータアーキテクチャについて研究している研究者の日記や技術紹介

PyMTLを使ってLEDチカチカ回路を作ってみる

ACM/IEEE MICRO-48で発表されたPyMTLを試してみたので,その使い方をまとめておきます.

PyMTLはPython上でBehavior level, Cycle level, Register transfer levelの3種類の抽象度でハードウェアをモデリングすることができるフレームワークです.

github.com

ここでは,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での変数名として利用しているようです.なるほど,かっこいい!