LoginSignup
7
7

More than 5 years have passed since last update.

フィボナッチを求める回路をVHDLとMessagePack-RPCでFPGAに実装してみた(ZYNQ編)

Last updated at Posted at 2015-11-09

はじめに

MessagePack-RPCを使ってFPGAを制御の続きです。
今回は VHDL で記述したフィボナッチ数を求める回路を MessagePack-RPC で制御する例を示します。
ここでは次のような環境を使っています。

  • FPGA : Xilinx Zynq Z-7010 AP SoC
  • Board : Digilent ZYBO
  • OS : Linux 3.18 + Debian 8.2(jessie)

プロジェクトの全ソースコードはこちらにあります。

ブロック図

akgeo1.jpg

VHDLで回路を記述

フィボナッチを求める回路は今回はVHDLで次のように記述しました。再帰は使わずにループを使っています。

fib.vhd
library ieee;
use     ieee.std_logic_1164.all;
use     ieee.numeric_std.all;
entity  FIB is
    port (
        CLK    : in  std_logic;
        RST    : in  std_logic;
        GO     : in  std_logic;
        N      : in  std_logic_vector( 7 downto 0);
        BUSY   : out std_logic;
        DONE   : out std_logic;
        O      : out std_logic_vector(63 downto 0)
    );
end     FIB;
architecture RTL of FIB is
    signal    curr_count  :  unsigned(N'length-1 downto 0);
    signal    last_count  :  unsigned(N'length-1 downto 0);
    signal    curr_value  :  unsigned(O'length-1 downto 0);
    signal    prev_value  :  unsigned(O'length-1 downto 0);
    signal    run         :  boolean;
begin
    process (CLK, RST) begin
        if (RST = '1') then
            run        <= FALSE;
            curr_count <= (others => '0');
            last_count <= (others => '0');
            curr_value <= (others => '0');
            prev_value <= (others => '0');
        elsif (CLK'event and CLK = '1') then
            if (run = FALSE) then
                if (GO = '1') then
                    run <= TRUE;
                    last_count <= unsigned(N);
                    curr_count <= to_unsigned(1, curr_count'length);
                    prev_value <= to_unsigned(0, curr_value'length);
                    if (unsigned(N) > 0) then
                        curr_value <= to_unsigned(1, curr_value'length);
                    else
                        curr_value <= to_unsigned(0, curr_value'length);
                    end if;
                end if;
            else
                if (curr_count < last_count) then
                    curr_count <= curr_count + 1;
                    prev_value <= curr_value;
                    curr_value <= curr_value + prev_value;
                else
                    run <= FALSE;
                end if;
            end if;
        end if;
    end process;
    BUSY <= '1' when (run = TRUE) else '0';
    DONE <= '1' when (run = TRUE and curr_count >= last_count) else '0';
    O    <= std_logic_vector(curr_value);
end RTL;

テスト用スクリプト

fibonacci_server.rb
require 'msgpack'
require 'serialport'

class FibonacciServer

  def initialize
    @port     = SerialPort.new("/dev/zptty0", 38400)
    @port.read_timeout = 1000
    @port.flow_control = SerialPort::HARD
    @unpacker = MessagePack::Unpacker.new(@port)
    @msgid    = 0
  end

  def call(method, args)
    @msgid = (@msgid+1) % 256
    req = [0, @msgid, method, args].to_msgpack
    @port.write(req)
    @unpacker.each do |obj|
      type, resid, error, result = obj
      if (error == nil) then
        return result
      else
        puts error
        return nil
      end
      break
    end 
  end

  def fib(arg)
    return call('fib', [arg])
  end
end
test.rb
require_relative 'fibonacci_server'

fib = FibonacciServer.new

(0..90).to_a.each do |n|
  f = fib.fib(n)
  puts "#{n} => #{f}"
end

実行結果

shell% ruby test.rb
0 => 0
1 => 1
2 => 1
3 => 2
4 => 3
5 => 5
6 => 8
7 => 13
8 => 21
9 => 34
10 => 55
11 => 89
12 => 144
13 => 233
14 => 377
15 => 610
16 => 987
17 => 1597
18 => 2584
19 => 4181
20 => 6765
21 => 10946
22 => 17711
23 => 28657
24 => 46368
25 => 75025
26 => 121393
27 => 196418
28 => 317811
29 => 514229
30 => 832040
31 => 1346269
32 => 2178309
33 => 3524578
34 => 5702887
35 => 9227465
36 => 14930352
37 => 24157817
38 => 39088169
39 => 63245986
40 => 102334155
41 => 165580141
42 => 267914296
43 => 433494437
44 => 701408733
45 => 1134903170
46 => 1836311903
47 => 2971215073
48 => 4807526976
49 => 7778742049
50 => 12586269025
51 => 20365011074
52 => 32951280099
53 => 53316291173
54 => 86267571272
55 => 139583862445
56 => 225851433717
57 => 365435296162
58 => 591286729879
59 => 956722026041
60 => 1548008755920
61 => 2504730781961
62 => 4052739537881
63 => 6557470319842
64 => 10610209857723
65 => 17167680177565
66 => 27777890035288
67 => 44945570212853
68 => 72723460248141
69 => 117669030460994
70 => 190392490709135
71 => 308061521170129
72 => 498454011879264
73 => 806515533049393
74 => 1304969544928657
75 => 2111485077978050
76 => 3416454622906707
77 => 5527939700884757
78 => 8944394323791464
79 => 14472334024676221
80 => 23416728348467685
81 => 37889062373143906
82 => 61305790721611591
83 => 99194853094755497
84 => 160500643816367088
85 => 259695496911122585
86 => 420196140727489673
87 => 679891637638612258
88 => 1100087778366101931
89 => 1779979416004714189
90 => 2880067194370816120

デザインフロー

用意するもの

ZYNQ用に回路をインプリメンテーションするためには次の開発ツールを使います。

  • Xilinx Vivado 2015.3 or 2015.4
  • Xilinx SDK 2015.3 or 2015.4

テストスクリプトを実行するためには次の ruby パッケージが必要です。

  • msgpack-ruby
  • serialport

リポジトリと各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

IP-Packageを作る

具体的な手順はSynthesijerで作ったモジュールをMessagePack-RPCで制御する(IP-Package編)と同様です。詳細はそちらを参照してください。
ここでは簡単に次のスクリプトを実行することでIPを作ります。

shell% cd examples/fibonacci/fpga/xilinx/zybo_test_vhdl/ip
shell% vivado -mode batch -source create_ip.tcl

論理合成~BOOT.binを作るまで

具体的な手順はSynthesijerで作ったモジュールをMessagePack-RPCで制御する(ZYNQ論理合成編)と同様です。詳細はそちらを参照してください。
ここでは以下の手順でBOOT.binを作ります。

まずは論理合成

shell% cd examples/fibonacci/fpga/xilinx/zybo_test_vhdl/project
shell% vivado -mode batch -source create_project.tcl
shell% vivado -mode batch -source implementation.tcl

SDKのためにハードウェア情報をエクスポートする.

shell% vivado -mode batch -source export_hardware.tcl

これで project/project.sdk/design_1_wrapper.hdf が出来ます.

FSBL(First Stage Boot Loader)を生成する.

shell% xsdk -batch -source build_fsbl.tcl

u-bootを生成する.

このプロジェクトでは u-boot の作成は行いません. とりあえず適当に作った u-boot.elf を ./boot に入れておきました.

BOOT.binを生成する.

shell% cd examples/fibonacci/fpga/xilinx/zybo_test_vhdl/boot/
shell% bootgen -image u-boot.bif -w on -o BOOT.bin

ZPTTYドライバをインストール

具体的な手順はSynthesijerで作ったモジュールをMessagePack-RPCで制御する(TTYドライバ編)と同様です。

参照

MessagePack for VHDL (https://github.com/ikwzm/msgpack-vhdl)
MessagePack for VHDL Examples (https://github.com/ikwzm/msgpack-vhdl-examples)
MessagePack-RPCを使ってFPGAを制御
Synthesijerで作ったモジュールをMessagePack-RPCで制御する(アーキテクチャ編)
Synthesijerで作ったモジュールをMessagePack-RPCで制御する(IP-Package編)
Synthesijerで作ったモジュールをMessagePack-RPCで制御する(ZYNQ論理合成編)
Synthesijerで作ったモジュールをMessagePack-RPCで制御する(TTYドライバ編)
Synthesijerで作ったモジュールをMessagePack-RPCで制御する(MessagePack-Ruby編)
フィボナッチを求める回路をVHDLとMessagePack-RPCでFPGAに実装してみた(シミュレーション編)

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7