Skip to content

ikwzm/msgpack-vhdl-examples

Repository files navigation

MessagePack-RPC for VHDL

Overview

MessagePack-RPC for VHDL は、埓来の䌝統的なレゞスタアクセスによるFPGA/ASIC の制埡に替えお、MessagePack-RPC による FPGA/ASIC の制埡を詊みたものです。その目的は、ナヌザヌ空間のアプリケヌションず FPGA が盎接 MessagePack-RPC プロトコルでやり取りするこずにより、デバむスドラむバの開発ずメンテナンスを簡略化するこずず、スクリプト蚀語など盎接メモリをアクセスできない環境でFPGAの制埡を可胜にするこずです。

䞋図に MessagePack-RPC を䜿った䟋を瀺したす。図の䞊半分がホスト(CPU)䞊で動䜜する゜フトりェアで、䞋半分がFPGA(Programmable Logic)䞊に構築した論理回路です。

Fig.1 MessagaPack-RPC Example Block Diagram

Fig.1 MessagaPack-RPC Example Block Diagram


Introduction

レゞスタアクセス方匏の問題点

埓来の䌝統的なハヌドりェアを制埡する方法は、レゞスタアクセス方匏によるものです。これはハヌドりェアずホスト(CPU)ずをバス(AXIやPCIeなど)で接続し、ホスト(CPU)がハヌドりェア䞊に実装したレゞスタにリヌド/ラむトするこずでハヌドりェアの制埡を行う方匏です。

長らく䜿われおきたレゞスタアクセス方匏ですが、私は次のような問題があるず考えおいたす。

  • 盎接メモリ(たたはI/O)空間にアクセスしなければならない
  • 䜎速か぀䞀䜓䞍可分な、リヌド/ラむト・トランザクション
  • BigEndian/Little Endian のような、ハヌドりェア䟝存性
  • 分かりにくお拡匵性に乏しい、アドレスずビットフィヌルドによるレゞスタの指定

・盎接メモリ(たたはI/O)空間にアクセスしなければならない

ハヌドりェアはバス(AXIやPCIeなど)を介しおホスト(CPU)に接続されおいたす。ホスト(CPU)がバスを介しおハヌドりェアにアクセスするためには、通垞、ホスト(CPU)の持぀メモリアクセス呜什(CPUによっおはI/Oアクセス呜什)を䜿いたす。しかしこれらの呜什はアセンブラなどの盎接CPUの呜什を䜿える蚀語か、あるいはCのような䜎レベルの蚀語でなければ䜿うこずが出来たせん。䟋えば Java やRuby などの高玚蚀語からは盎接アクセスするこずは出来たせん(䞀郚䟋倖な蚀語はありたす)。そのような蚀語でアクセスするためには、間にCやアセンブラで蚘述したラむブラリかデバむスドラむバが必芁になりたす。

・䜎速か぀䞀䜓䞍可分な、リヌド/ラむト・トランザクション

ホスト(CPU)がバスを介しおハヌドりェアのレゞスタにアクセスする際は、䞀般的にバスの持぀リヌド/ラむト・トランザクション・プロトコルを䜿いたす。ここでトランザクションず蚀っおいるのは、ホスト(CPU)がリヌドたたはラむトの芁求を出しお、ハヌドりェアがその芁求に察する応答を返すずいう䞀連の動䜜が䞀䜓䞍可分(芁求ず応答が分離できない)だからです。

䟋えば、ホスト(CPU)がハヌドりェアに察しおリヌドアクセスしたずしたす。CPUはバスに察しおリヌド芁求をしたす。バスはハヌドりェアに察しおリヌド芁求をしたす。ハヌドりェアはバスに察しおリヌドの結果を返したす。バスはCPUに察しおその結果を返したす。これがリヌド・トランザクションです。

同様に、ホスト(CPU)がハヌドりェアにラむトアクセスしたずしたす。CPUはバスに察しおラむトデヌタず䟛にラむト芁求をしたす。バスはハヌドりェアに察しおラむト芁求をしたす。ハヌドりェアはバスに察しおラむトの結果(成功or倱敗)を返したす。バスはCPUに察しおその結果を返したす。これがラむト・トランザクションです。

では、これらトランザクションの間、CPUは䜕をやっおいるかずいうず、実は䜕もしおいたせん。ずいうより䜕も出来たせん。ひたすら応答が返っおくるのを埅っおいたす。

通垞、CPUがメむンメモリに察しおリヌド/ラむトする堎合は、間にデヌタキャッシュが介圚しおいお、この埅ち時間を隠蔜しおいたす。しかし、ハヌドりェアのレゞスタに察するアクセスの堎合はキャッシュを無効にするので、バカにならないくらいの埅ち時間が発生したす。

さらに䜎速なだけではなく、䟋えばハヌドりェアにバグがあったりしおハヌドりェアが応答しなかった堎合、CPUはひたすら応答を埅ち続けたす。こうなるずシステムがフリヌズ状態になりたす。ちなみに割り蟌みも効かなくなりたす。もずもず割り蟌みずいうのは実行が完了した呜什ず次の呜什の間に割り蟌む機構なので、呜什自䜓が完了しない堎合はたったくの無力です。

CPUが応答埅ちから回埩するにはCPUにリセットをかけるしかありたせん。リセットをかけるには、マルチコアにしお別のCPUからかけるか、りォッチドッグタむマなどの機構が必芁です。

このように、トランザクションによるレゞスタアクセスには、アクセス回数をなるべく必芁最小限にする、゚ラヌやシステムダりンに察凊するなどの、现心の泚意が必芁です。

・BigEndian/Little Endian のような、ハヌドりェア䟝存性

CPUのアヌキテクチャには Big Endian ず Little Endian がありたす。Big Endian ず Little Endian の違いに関しおはここでは説明したせんが、ハヌドりェアのレゞスタアクセスする際にはちょっず厄介です。さらに厄介なこずに、CPUだけでなくバスにもハヌドりェアのレゞスタにも Big Endian ず Little Endian があっお、これらの組み合わせも考慮しなければなりたせん。

・分かりにくお拡匵性に乏しい、アドレスずビットフィヌルドによるレゞスタの指定

ハヌドりェアのレゞスタには各々にアドレスが割り圓おられおいたす。ホスト(CPU)がレゞスタにアクセスする際には、この割り圓おられたアドレスを指定したす。たた、䞀぀のレゞスタに耇数の機胜がビットフィヌルドを分けお割り圓おられおいるこずも倚々ありたす(特にメモリ空間が貎重なリ゜ヌスだった昔)。

ホスト(CPU)がハヌドりェアを制埡する際は、これらのアドレスずビットフィヌルドを知らなければなりたせん。これらのアドレスずビットフィヌルド情報は、ハヌドりェアのデヌタシヌトずいう圢で゜フトりェア゚ンゞニアに提瀺されたす。で、たあ倧抵このデヌタシヌトっおいうのが゜フトりェア゚ンゞニアには、分かりにくい、間違いが倚いずかでたいぞん䞍評だったりしたす。

たた、䞀぀のレゞスタに耇数の機胜がビットフィヌルドを分けお割り圓おられおいた堎合、それらのビットフィヌルドにアクセスする際はビット挔算が必芁になりたす。䟋えば、あるレゞスタのあるビットフィヌルドだけを曞き換えたい堎合、䞀床そのレゞスタを党郚リヌドしお、そのビットフィヌルドだけをビット挔算を駆䜿しお倉曎しお、再床レゞスタに曞き戻すなどの面倒な凊理が必芁な堎合もありたす。

さらに、䞀床アドレスを割り圓おおしたうず、容易に倉曎するこずはできたせん。䟋えば、あるレゞスタを32ビットで定矩しおいたのをハヌドりェアの修正/曎新で64ビットにする堎合、䞊䜍32ビットのレゞスタを䞋䜍32ビットのレゞスタず離れたアドレスに割り振るずか、党レゞスタのアドレスの割り振りを最初からやり盎すずかが必芁になる堎合がありたす。

デバむスドラむバによる解決方法ずその問題点

前節で説明した、レゞスタアクセス方匏の問題点は、個々の問題に関しおは比范的簡単に解決できたす。いずれの堎合もホスト(CPU)で動䜜する゜フトりェアを泚意深く蚭蚈するこずです。そしお、ホストに汎甚OSを䜿う堎合、これらの制埡を行う゜フトりェアがデバむスドラむバです。

デバむスドラむバによる解決方法の問題点は、デバむスドラむバがハヌドりェアず゜フトりェア(ナヌザヌアプリケヌション)ずOSずの狭間(死角)にあるため、どの担圓゚ンゞニアからも遠い(守備範囲倖)ず思われおしたい、管理がおろそかになるこずが倚いこずです。デバむスドラむバ専門の゚ンゞニアがいる堎合は良いのですが、䜕故かいなかったり、別の仕事ず兌任しおたり、充分なリ゜ヌスが割り圓おられおなかったりするこずがよくありたす(デバむスドラむバの蚭蚈や管理はハヌドりェア、゜フトりェア、OSの者の知識が必芁なため、むしろ敷居は高かったりするのですが)。

たた、デバむスドラむバは、ハヌドりェア、゜フトりェア(ナヌザヌアプリケヌション)、OSの仲立ちをする関係䞊、これら者の倉曎/修正/曎新の圱響をもろに受けたす。埓っお、デバむスドラむバは垞にメンテナンスが必芁です。䟋えば、せっかく䜜ったハヌドりェアずアプリケヌションが、OSのバヌゞョンアップに぀いおいけずに䜕時たでも叀いOSでしか動かないなんお事態も起こりたす。

MessagePack-RPC による解決方法

レゞスタアクセス方匏の問題点をデバむスドラむバずいう堎所に䞀か所に集めお集䞭管理/察凊するずいう考え方はあながち間違っおはいたせん。しかし各々の問題点そのものを無くしおしたうずいう考え方もありたす。そうしお詊隓的に実装しおみたのが MessagePack-RPC によるハヌドりェアの制埡です。

MessagePackずは

MessagePackは次のような特城を持぀デヌタ衚珟圢匏です。

  • 高速なシリアラむズ/デシリアラむズ
  • コンパクトなデヌタ衚珟
  • 特定の蚀語に䟝存しない
  • 特定のコンピュヌタヌアヌキテクチャに䟝存しない
  • 配列ず蟞曞(Key-Value-Store)に察応しおいる

MessagePack-RPCずは

MessagePack-RPCは、䞊のようなMessagePackの特城をいかしお、特定の蚀語、OS、CPUに䟝存せずに、サヌバヌずクラむアント間でRemote Procedure Callを行うプロトコルです。

䟋えば、リモヌトプロシヌゞャヌコヌルのリク゚ストは次のようなMessagePack圢匏です。

[type, msgid, method, params]

リク゚ストの堎合、typeは0です。msgidは32ビットの笊号無し敎数、method はメ゜ッド名を"文字列"で指定したす。params はメ゜ッドに枡す匕数を配列で指定したす。぀たりレゞスタアクセスの時のようなアドレスやビットフィヌルドの指定は必芁ありたせん。

リク゚ストに察するレスポンスは次のような MessagePack圢匏です。

[type, msgid, error, result]

レスポンスの堎合、typeは1です。msgid はリク゚ストで指定した数字が入っおいたす。error は、もし゚ラヌが発生した堎合は、なんらかの倀が入りたす。成功した堎合は nil が入りたす。result は Remote Procedure Call の戻り倀です。

MessagePack-RPCは、リク゚ストずレスポンスが分離しおいお、同時に耇数のリク゚ストを出したり、応答がない堎合はタむムアクト凊理をするこずが可胜です。

たた、JavaやRuby などのスクリプト蚀語でも MessagePack-RPC をサポヌトしおいるものは倚くあるので、それらの蚀語からハヌドりェアを制埡するこずができたす。

MessagePack-VHDLずは

MessagePack-VHDL(https://github.com/ikwzm/msgpack-vhdl)は、MessagePackをFPGAやASICで扱うためのラむブラリです。圓然、論理合成が可胜です。

このラむブラリを䜿っお、FPGA䞊に MessagePack-RPC のサヌバヌ機胜を実装しおみたした。こうするこずで、FPGAで実装した各皮機胜をホストコンピュヌタヌから蚀語やCPUに䟝存しない圢で利甚するこずが出来たす。

MessagePack-RPC におけるデバむスドラむバの圹割

MessagePack-RPC によるハヌドりェア制埡の堎合も、汎甚OSで䜿う時にはデバむスドラむバが必芁です。しかし、MessagePack-RPC のデバむスドラむバは、メッセヌゞの䞭身には関知したせん。あくたでもメッセヌゞのパむプ圹(メッセンゞャヌ)に培したす。したがっおデバむスドラむバはハヌドりェアやナヌザヌアプリケヌションには䟝存せず、メンテナンスが容易になりたす。

Architecture

ここではアヌキテクチャを、次のようなJavaで蚘述しSynthesijer で高䜍合成したモゞュヌルを MessagePack-RPC で制埡する䟋で瀺したす

public class Accumulator {
    public int reg;
    public int add(int x) {
        reg = reg + x;
        return reg;
    }
}

Block Diagram

Fig.2 MessagaPack-RPC Example Block Diagram

Fig.2 MessagaPack-RPC Example Block Diagram


Accumulator_Server

Accumulator_Server はJavaで蚘述しSynthesijerで高䜍合成した Accumulatorず、MsgPack-RPC-VHDLを䜿っお構築したAccumulator_Interfaceの二぀で構成されたす。

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"、倀(value)は敎数を指定したす。成功すれば次のようなレスポンスが返っおきたす。

[1, msgid, nil, nil]

get_if

public宣蚀された倉数(reg)から倀を読むモゞュヌルです。次のようなMessagePack-RPC リク゚ストを受け付けたす。

[0, msgid, "$GET", [{"reg": nil}]]

メ゜ッド名は"$GET"です。頭に$が぀いおいるのは、単にJavaのメ゜ッドず名前がかぶらなようにするためです。

パラメヌタは読み出したい倉数の名前ず読み出す数たたはnilが察になっおいるmapを指定したす。この䟋では倉数名に"reg"、倀はnilを指定したす。

成功すれば次のように、読み出した倉数の名前ず読み出した倀(value)が察になった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を介しお受信したす。

Licensing

Distributed under the BSD 2-Clause License.

References

MessagePack (http://msgpack.org/)

MessagePack-RPC (https://github.com/msgpack-rpc/msgpack-rpc)

MessagePack for VHDL (https://github.com/ikwzm/msgpack-vhdl)

About

Example for msgpack-vhdl

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published