#はじめに
MessagePack-RPCを使ってFPGAを制御の続きです。
今回は VHDL で記述したフィボナッチ数を求める回路を MessagePack-RPC で制御する例を示します。
ここでは次のような環境を使っています。
- FPGA : Xilinx Zynq Z-7010 AP SoC
- Board : Digilent ZYBO
- OS : Linux 3.18 + Debian 8.2(jessie)
プロジェクトの全ソースコードはこちらにあります。
#ブロック図
#VHDLで回路を記述
フィボナッチを求める回路は今回はVHDLで次のように記述しました。再帰は使わずにループを使っています。
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;
#テスト用スクリプト
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
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に実装してみた(シミュレーション編)