読者です 読者をやめる 読者になる 読者になる

shtaxxx日記

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

Pythonベースの高位合成コンパイラPolyphonyを試してみた

はじめに

高位合成友の会の第3回が12/8に開催されるらしいです。 (僕はPythonでのハードウェアメタプログラミングの話をします。)

hls.connpass.com

プログラムによると、PolyphonyというPythonベースの高位合成コンパイラの発表があるらしいです。Pythonで高位合成コンパイラを作っている自分としては、これは試さずにいられない!ということで、早速試してみました。

ダウンロード

公式Webからダウンロードしましょう。将来的にはオープンソースになるようですが、現在(11月12日)はzip化された実行形式のみが利用可能です。

http://www.sinby.com/PolyPhony/we-need-your-feedback.html

実行権限が必要なので、chmodしましょう。

chmod 755 polyphony

コンパイル対象のPythonソースコードを準備する

今回は、PyCoRAMのtestsにある、フィボナッチ数列を求める回路の記述を利用しました。以下のように、最低限のコードにしましょう。ここでは名前は"test.py"としましょう。

github.com

def fib(v):
    if v <= 0: return 0
    if v == 1: return 1
    r0 = 0
    r1 = 1
    for i in range(v-1):
        prev_r1 = r1
        r1 = r0 + r1
        r0 = prev_r1
    return r1

コンパイル

先ほどダウンロードしたpolyphonyを実行しましょう。"-o"オプションで出力ファイル名のprefixが指定出来るようです。

./polyphony -o fib test.py 

生成されたVerilog HDLコードをチェックする

"fib.v"という名前で、以下のようなコードが出力されているはずです。

ステートマシンをベースとした回路が生成されています。"READY", "ACCEPT", "VALID"で動作を制御するようですね。

module fib
  (
    input signed [31:0] fib_IN0,
    input CLK,
    input RST,
    input fib_READY,
    input fib_ACCEPT,
    output reg signed [31:0] fib_OUT0,
    output reg fib_VALID
  );

  //localparams
  localparam fib_grp_top0_INIT = 0;
  localparam fib_grp_top0_S0 = 1;
  localparam fib_grp_top0_S1 = 2;
  localparam fib_grp_top0_S2 = 3;
  localparam fib_grp_top0_S8 = 4;
  localparam fib_grp_top0_FINISH = 5;
  localparam fib_grp_ifthen1_S1 = 6;
  localparam fib_grp_ifthen3_S2 = 7;
  localparam L1_grp_top0_S0 = 8;
  localparam L1_grp_top0_S1 = 9;
  localparam L1_grp_forbody5_S2 = 10;
  localparam L1_grp_bridge6_S0 = 11;
  localparam L1_grp_bridge6_S3 = 12;
  
  //internal regs
  reg /*unsigned*/ [3:0] fib_state;
  reg signed [31:0] i;
  reg signed [31:0] prev_r1;
  reg signed [31:0] r0;
  reg signed [31:0] r1;
  reg signed [31:0] t10;
  
  
  //internal wires
  wire cond11;
  wire cond8;
  wire cond9;
  
  //functions
  
  //sub module instances
  
  //assigns
  assign cond8 = (fib_IN0 <= 0);
  assign cond9 = (fib_IN0 == 1);
  assign cond11 = (i < t10);
  
  always @(posedge CLK) begin
    if (RST) begin
      fib_OUT0 <= 0;
      fib_VALID <= 0;
      fib_state <= fib_grp_top0_INIT;
    end else begin //if (RST)
      case(fib_state)
      fib_grp_top0_INIT: begin
        if (fib_READY == 1) begin
          fib_VALID <= 0;
          fib_state <= fib_grp_top0_S0;
        end
      end
      fib_grp_top0_S0: begin
        if (cond8) begin
          fib_state <= fib_grp_ifthen1_S1;
        end else begin
          fib_state <= fib_grp_top0_S1;
        end
      end
      fib_grp_top0_S1: begin
        if (cond9) begin
          fib_state <= fib_grp_ifthen3_S2;
        end else begin
          fib_state <= fib_grp_top0_S2;
        end
      end
      fib_grp_top0_S2: begin
        r0 <= 0;
        r1 <= 1;
        i <= 0;
        fib_state <= L1_grp_top0_S0;
      end
      fib_grp_top0_S8: begin
        fib_OUT0 <= r1;
        fib_state <= fib_grp_top0_FINISH;
      end
      fib_grp_top0_FINISH: begin
        fib_VALID <= 1;
        if (fib_ACCEPT == 1) begin
          fib_state <= fib_grp_top0_INIT;
        end
      end
      fib_grp_ifthen1_S1: begin
        fib_OUT0 <= 0;
        fib_state <= fib_grp_top0_S1;
      end
      fib_grp_ifthen3_S2: begin
        fib_OUT0 <= 1;
        fib_state <= fib_grp_top0_S2;
      end
      L1_grp_top0_S0: begin
        t10 <= (fib_IN0 - 1);
        fib_state <= L1_grp_top0_S1;
      end
      L1_grp_top0_S1: begin
        if (cond11) begin
          fib_state <= L1_grp_forbody5_S2;
        end else begin
          fib_state <= fib_grp_top0_S8;
        end
      end
      L1_grp_forbody5_S2: begin
        prev_r1 <= r1;
        r1 <= (r0 + r1);
        fib_state <= L1_grp_bridge6_S0;
      end
      L1_grp_bridge6_S0: begin
        i <= (i + 1);
        fib_state <= L1_grp_bridge6_S3;
      end
      L1_grp_bridge6_S3: begin
        r0 <= prev_r1;
        fib_state <= L1_grp_top0_S0;
      end
      endcase
    end
  end
  
endmodule

まとめ

Pythonで手軽にハードウェア設計ができるのは素敵ですね! 自分以外にもPythonで高位合成に取り組んでいる方がいるのも嬉しいです。

PyCoRAMの高位合成エンジンも単体で切り出して、普通の高位合成コンパイラとして利用できるようにしようかなぁ、と思いました。