フィボナッチを求める回路をFortRockとMessagePack-RPCでFPGAに実装してみた(シミュレーション編)

#はじめに

[高位合成友の会第三回(2015年12月8日)](http://hls.connpass.com/event/22464/)で発表のあった高位合成ツールの中で、唯一、当日までに試すことの出来なかった FortRock ですが、ちょっと遅れましたがフィボナッチを求める回路を記述してシミュレーションしてみました。
FortRock は LLVMを用いた Fortran ベースの高位合成ツールです。
高位合成友の会での FortRock の発表スライドは[こちら](http://www.slideshare.net/takahiroyamashita9674/2015128-55977857)です。


#用意するもの

 - Xilinx Vivado 2015.3
 - [FortRock](https://github.com/nyakuo/FortRock)
 - clang++-3.6 (FortRock をコンパイルするのに必要)
 - gfortran-4.8 (FortRock で高位合成するのに必要)
 - LLVM 3.4 (FortRock で高位合成するのに必要)
 - dragonegg-4.8 (FortRock で高位合成するのに必要)
 - Ruby 1.9.3 以降
 -  [msgpack-vhdl-examples](https://github.com/ikwzm/msgpack-vhdl-examples)

#ブロック図

![akgeo2.jpg](https://qiita-image-store.s3.amazonaws.com/0/24981/d9802aeb-3dc3-1f7e-daf5-b2a3d070fbdf.jpeg)

#ソースコード

フィボナッチを求めるFortranのソースコードです。

````Fortran:fib.f
      SUBROUTINE FIB(N,O)
      INTEGER N,O,I,CURR,NEXT,PREV
      CURR = 0
      NEXT = 1
      I    = 0
 0001 CONTINUE
      IF(I >= N)THEN
        GOTO 0002
      ENDIF
      PREV = CURR
      CURR = NEXT
      NEXT = NEXT + PREV
      I = I + 1
      GOTO 0001
 0002 CONTINUE
      O = CURR
      RETURN
      END
````

#手順

##事前の準備

FortRock を使うためには、gfortran-4.8、dragonegge-4.8、llvm-3.4 が必要です。
また、FortRock をコンパイルするのに clang++-3.6 が必要です。

````
shell% sudo apt-get install gfortran-4.8
shell% sudo apt-get install dragonegge-4.8
shell% sudo apt-get install llvm-3.4
```

##FortRock をインストール

````
shell% git clone https://github.com/nyakuo/FortRock.git
shell% cd FortRock/src
shell% make
````

これで FortRock/src/ に fortrock.so が出来ていれば、成功です。

##msgpack-vhdl-examplesリポジトリと各submodule をダウンロード

````
shell% git clone git://github.com/ikwzm/msgpack-vhdl-examples.git
shell% cd msgpack-vhdl-examples
shell% git submodule init
shell% git submodule update
````

##fib.f をテスト

今回、初めてFortran を使うので、試しに次のようなプログラムを作って fib.f をテストしました。

````Fortran:fib_test.f
      program fib_test
      implicit none
      integer i, n, o
      n = 7
      i = 0
 1000 call fib(i,o)
      print *,i,o
      if (i < n) then
         i = i + 1
         goto 1000
      endif
      end
````

````
shell% cd examples/fibonacci/src/main/fortrock
shell% gfortran-4.8 -O1 -o ./fib_test ./fib_test.f ./fib.f 
shell% ./fib_test
           0           0
           1           1
           2           1
           3           2
           4           3
           5           5
           6           8
           7          13
````

##fib.fをFortRockで高位合成

````
shell% cd examples/fibonacci/src/main/fortrock
shell% gfortran-4.8 -O1 ./fib.f -fplugin=/usr/lib/gcc/x86_64-linux-gnu/4.8/plugin/dragonegg.so -fplugin-arg-dragonegg-emit-ir -S -o ./0fib00.s
shell% opt-3.4 -load ~/work/FortRock/src/fortrock.so -instnamer -fortrock ./0fib00.s -S
opt-3.4: CommandLine Error: Argument 'info-output-file' defined more than once!
opt-3.4: CommandLine Error: Argument 'track-memory' defined more than once!
opt-3.4: CommandLine Error: Argument 'version' defined more than once!
opt-3.4: CommandLine Error: Argument 'print-all-options' defined more than once!
opt-3.4: CommandLine Error: Argument 'print-options' defined more than once!
opt-3.4: CommandLine Error: Argument 'help-hidden' defined more than once!
opt-3.4: CommandLine Error: Argument 'help' defined more than once!
opt-3.4: CommandLine Error: Argument 'help-list-hidden' defined more than once!
opt-3.4: CommandLine Error: Argument 'help-list' defined more than once!
opt-3.4: CommandLine Error: Argument 'time-passes' defined more than once!
opt-3.4: CommandLine Error: Argument 'print-after-all' defined more than once!
opt-3.4: CommandLine Error: Argument 'print-before-all' defined more than once!
opt-3.4: CommandLine Error: Argument 'print-after' defined more than once!
opt-3.4: CommandLine Error: Argument 'print-before' defined more than once!
opt-3.4: CommandLine Error: Argument 'debug-pass' defined more than once!
; ModuleID = './0fib00.s'
target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64--linux-gnu"

module asm "\09.ident\09\22GCC: (Ubuntu 4.8.4-1ubuntu15) 4.8.4 LLVM: 3.4.2\22"

; Function Attrs: nounwind uwtable
define void @fib_(i32* noalias nocapture readonly %n, i32* noalias nocapture %o) unnamed_addr #0 {
entry:
  %tmp = load i32* %n, align 4
  %tmp1 = icmp sgt i32 %tmp, 0
  br i1 %tmp1, label %"4.lr.ph", label %"5"

"4.lr.ph":                                        ; preds = %entry
  %tmp2 = load i32* %n, align 4
  br label %"4"

"4":                                              ; preds = %"4", %"4.lr.ph"
  %tmp3 = phi i32 [ 1, %"4.lr.ph" ], [ %tmp6, %"4" ]
  %tmp4 = phi i32 [ 0, %"4.lr.ph" ], [ %tmp7, %"4" ]
  %tmp5 = phi i32 [ 0, %"4.lr.ph" ], [ %tmp3, %"4" ]
  %tmp6 = add i32 %tmp3, %tmp5
  %tmp7 = add i32 %tmp4, 1
  %tmp8 = icmp sgt i32 %tmp2, %tmp7
  br i1 %tmp8, label %"4", label %"5"

"5":                                              ; preds = %"4", %entry
  %.lcssa = phi i32 [ 0, %entry ], [ %tmp3, %"4" ]
  store i32 %.lcssa, i32* %o, align 4
  ret void
}

attributes #0 = { nounwind uwtable "no-frame-pointer-elim-non-leaf"="false" }
````

途中で出力するLLVMファイルの名前が 0fib00.s としているのは、何故かモジュール名の前に１文字、後ろに２文字つけないと、Verilog-HDL のモジュール名が正常に生成されないからです。
また、opt-3.4 で CommandLine Error が出ていますが、とりあえず気にしないでください。
output.v が生成されていれば成功です。

なお、output.v を Verilog でシミュレーション/論理合成するには、Add、multiplier、Divider等の演算モジュールが必要です。実際には Add しか使わないのですが、何故か output.v には multiplier と Divider のインスタンスも含まれているのでとりあえずダミーでもいいから用意しておきます。

````Verilog:operator.v
module Add(a,b,clk,ce,s);
   input  signed[31:0] a;
   input  signed[31:0] b;
   input               clk;
   input               ce;
   output signed[31:0] s;
   reg    signed[31:0] s;
   
   always @(posedge clk)
     if (ce)
       s <= a + b;
endmodule

module multiplier(a,b,clk,ce,p);
   input  signed[31:0] a;
   input  signed[31:0] b;
   input               clk;
   input               ce;
   output signed[31:0] p;
   reg    signed[31:0] p;
   
   always @(posedge clk)
     if (ce)
       p <= a * b;
endmodule

module Divider(dividend,divisor,clk,quotient,fractional,rfd);
   input  signed[31:0] dividend;
   input  signed[31:0] divisor;
   input               clk;
   output signed[31:0] quotient;
   output signed[31:0] fractional;
   output signed[31:0] rfd;
endmodule
````

##テストシナリオの作成

すでに作成済みのテストシナリオ(examples/fibonacci/src/test/scenarios/test_1_32.snr)を用意しています。このテストシナリオを使う場合は、以下の手順は飛ばしてください。

AXI4_Stream_Master_PlayerおよびAXI4_Stream_Slave_Player用のテストシナリオを作ります。

````
shell% cd examples/fibonacci/src/test/scenarios
shell% ruby test_1_32.rb
````

test_1_32.rb はテストシナリオ(YAML形式)を生成するためのrubyスクリプトです。

##Vivado プロジェクトの作成

Vivado プロジェクトを作成するためのTclファイル(create_project.tcl)を用意しています。
Vivadoを起動して次のメニューからTclファイルを実行してください。

````
Vivado > Tools > Run Tcl Script... > examples/fibonacci/sim/vivado/fortrock/create_project.tcl
````

##シミュレーションを実行

前節で作った Vivado プロジェクトを開き、次のようにシミュレーションを実行してください。

````
Vivado > Flow > Run Simulation > Run Behavioral Simulation
````

#結果
とりあえずシミュレーションすることは出来ました。
n=0～42までの計算結果もあっています。
参考までにn=2の時のシミュレーション波形を示します。

![fibonacci_fortrock_wave.jpg](https://qiita-image-store.s3.amazonaws.com/0/24981/a39c9189-181f-bebf-5b41-492e1afaaeba.jpeg)

シミュレーション時のログは次の通りです。
![fibonacci_fortrock_log.jpg](https://qiita-image-store.s3.amazonaws.com/0/24981/e468f771-19f0-b2d6-79c4-91782b6389c2.jpeg)


#参考

- [LLVMを用いたFortranベースの高位合成ツールFortRockの開発](http://www.slideshare.net/takahiroyamashita9674/2015128-55977857)
- [https://github.com/nyakuo/FortRock](https://github.com/nyakuo/FortRock)
- [msgpack-vhdl-examples](https://github.com/ikwzm/msgpack-vhdl-examples)
- [フィボナッチを求める回路をSynthesijerとMessagePack-RPCでFPGAに実装してみた(シミュレーション編)](http://qiita.com/ikwzm/items/6b3e8120cc4ebbdd5a27)
- [フィボナッチを求める回路をVHDLとMessagePack-RPCでFPGAに実装してみた(シミュレーション編)](http://qiita.com/ikwzm/items/a0ff6cf559f766162951)
- [フィボナッチを求める回路をPolyphonyとMessagePack-RPCでFPGAに実装してみた(シミュレーション編)](http://qiita.com/ikwzm/items/48acfa3003522cf0c7a3)
- [フィボナッチを求める回路をSynverllとMessagePack-RPCでFPGAに実装してみた(シミュレーション編)](http://qiita.com/ikwzm/items/37e496680e44d4b80347)
- [フィボナッチを求める回路をneonlightとMessagePack-RPCでFPGAに実装してみた(シミュレーション編)](http://qiita.com/ikwzm/items/1b7cae327719c23fe55d)