#はじめに
MessagePack-RPCを使ってFPGAを制御の続きです。
今回は Synthesijer で作ったモジュールを MessagePack-RPC で制御する方法を紹介します。
プロジェクトの全ソースコードはこちらにあります。
次のような論理合成可能なJavaのコードを例にします。
public class Accumulator {
public int reg;
public int add(int x) {
reg = reg + x;
return reg;
}
}
#アーキテクチャ
##全体のブロック図
Accumulator_Server
Accumulator_Server はJavaで記述しSynthesijerで高位合成した Accumulatorと、MsgPack-RPC-VHDLを使って構築したMsgPack_RPC_Serverの二つで構成されます。
###Accumulator
public class Accumulator {
public int reg;
public int add(int x) {
reg = reg + x;
return reg;
}
}
上のJavaコードをSynthesijerで高位合成したものです。Synthesijer によって、次のようなentityを持つVHDLファイルが生成されます。
entity Accumulator is
port (
clk : in std_logic;
reset : in std_logic;
reg_in : in signed(32-1 downto 0);
reg_we : in std_logic;
reg_out : out signed(32-1 downto 0);
add_x : in signed(32-1 downto 0);
add_return : out signed(32-1 downto 0);
add_busy : out std_logic;
add_req : in std_logic
);
end Accumulator;
###Unpacker
シリアライズされたMessagePack-RPCのリクエストメッセージを AXI4-Streamインターフェースから受け取って内部形式に変換します。
###Requester
メソッド名を解析して該当するメソッドインターフェース(add_if、set_if、get_if)にmsgidとparamを渡します。
###Responder
メソッドインターフェース(add_if、set_if、get_if)からのレスポンス出力要求を調停して、レスポンスメッセージを構築します。
###Packer
レスポンスメッセージをMessagePack形式にシリアライズして AXI4-Streamインターフェースから出力します。
###set_if
public宣言された変数(reg)に値を設定するモジュールです。
次のようなMessagePack-RPC リクエストを受け付けます。
[0, msgid, "$SET", [{"reg": value}]]
メソッド名は"$SET"です。頭に$がついているのは、単にJavaのメソッドと名前がかぶらなようにするためです。
パラメータは変数名と設定する値が対になっているmapを指定します。
この例では変数名に"reg"、値は整数を指定します。
成功すれば次のようなレスポンスが返ってきます。
[1, msgid, nil, nil]
###get_if
public宣言された変数(reg)から値を読むモジュールです。
次のようなMessagePack-RPC リクエストを受け付けます。
[0, msgid, "$GET", [{"reg": nil}]]
メソッド名は"$GET"です。頭に$がついているのは、単にJavaのメソッドと名前がかぶらなようにするためです。
パラメータは読み出したい変数の名前と読み出す数またはnilが対になっているmapを指定します。
この例では変数名に"reg"、値はnilを指定します。
成功すれば次のように、読み出した変数の名前と読み出した値が対になったmapが返ってきます。
[1, msgid, nil, [{"reg": value}]]
###add_if
addメソッドを呼び出すモジュールです。
次のようなMessagePack-RPCリクエストを受け付けます。
[0, msgid, "add", [value]]
valueにはaddメソッドに渡す引数を指定します。
成功すれば次のように、addメソッドの戻り値が返ってきます。
[1, msgid, nil, result]
add_ifはAccumulator に対して引数をadd_xに出力し、リクエスト信号(add_req)を'1'にします。
Accumulatorはリクエスト信号(add_req)に対してビジー信号(add_busy)に'1'を出力して、処理が終わるとビジー信号に'0'を出力して結果をadd_return に出力します。
add_if はaccumulator からの結果(add_return)を内部形式に変換してmsgidと一緒にResponderに渡します。
PTTY_AXI
PTTY_AXI はAXI4-Streamの入出力インターフェースをホストからはシリアルインターフェースとして見せるためのIPです。
-
ホストとのインターフェースはAXI4です。
-
Accumulator_ServerとのインターフェースはAXI4-Streamです。
-
送信と受信に各々128バイトのバッファを持っています。
/dev/zptty
/dev/zpttyはPTTY_AXIを介してAccumulator_Serverの入出力をあたかもシリアルポートに見せるためのデバイスドライバです。
このドライバを使うことにより、Accumulator_ServerとのMessagePack-RPCのやりとりはシリアルポートを介して行うように見えます。
/dev/zpttyは、Linux標準のttyコア部と、PTTY_AXI固有のドライバ部zptty.koで構成されます。
Client
Linuxのユーザー空間で動作するクライアントプログラムです。
このクライアントプログラムがMessagePack-RPCのリクエストメッセージを作成し/dev/zpttyを介してAccumulator_Serverに送信します。
そしてAccumulator_ServerからのMessagePack-RPCのレスポンスメッセージを/dev/zpttyを介して受信します。
#課題
現時点では未だ実装途中のため、次のような課題が残っています。
add_if、set_if、get_if はVHDLでゴリゴリ書かなければなりません。 将来的には、MessagePack IDL Compilerから生成するか、Synthesijerから自動的に生成することを考えています。- msgpack-vhdl ver.0.2.0 以降、Synthesijer が生成した VHDL からインターフェース回路を生成するスクリプト(msgpack-rpc-synthesijer-ifgen)が追加されています。
public変数やメソッドのパラメータ、戻り値の型は整数のみです。- msgpack-vhdl ver.0.2.0 以降、public 変数に配列がサポートされました。
#参照
MessagePack (http://msgpack.org/)
MessagePack-RPC (https://github.com/msgpack-rpc/msgpack-rpc)
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で制御する(IP-Package編)
Synthesijerで作ったモジュールをMessagePack-RPCで制御する(ZYNQ論理合成編)
Synthesijerで作ったモジュールをMessagePack-RPCで制御する(TTYドライバ編)
Synthesijerで作ったモジュールをMessagePack-RPCで制御する(MessagePack-Ruby編)
Synthesijerで作ったモジュールをMessagePack-RPCで制御する(リモートサーバー編)