IPコア
IPコアについて
当IPコアを使うと、EZ-USB FX3とユーザデザインの間を簡単に接続することができ、またWindows上からインテリジェントな入出力のコマンドを与えることができるようになります。
USBのパケットは、1〜1024バイトのデータのかたまりにすぎません。そのため、FPGAがデータを受信したときに、それが何のモジュール宛てのデータなのかを判断することができません※1。その上、最後まで受信してみないと、全部で何バイトのデータが送られてくるかを知ることができません。
※1 そういう識別はエンドポイント番号でするべきだという指摘があるかもしれませんが、それはそれで面倒です。
そこで、USBのパケットの先頭に「ヘッダ」をつけてカプセル化し、複数のUSBパケットを束ねることを考えます。
ユーザデータに「長さ(0〜4294967295バイト)」と「開始アドレス(32bit)」と「フラグ」という情報を付け加えて、FPGA内のどのモジュール(たとえば、内部レジスタ宛てなのか、メモリ宛てなのか、という識別に用いることができる)に対して送るべきデータなのかを識別することができるようにしました。
こうすることで、FPGA内のユーザ回路に「FX3内のバッファが空か否か」という単純なフラグではなく、「バルク転送が開始した」という高度なイベントを知らせることができます。また、FPGA内のユーザ回路の都合でFX3にWAITをかけたい場合でも、SLRDやSLWRのタイミングを気にすることなく、ユーザ回路の都合に合わせたタイミングでウェイトを発生させることができます。
このような機能を提供するのが特電の用意するFX3用IPコアです。
IPコアの入出力ポート
コアの入出力ポートの定義を示します。
entity fx3sfsync16 is Generic ( FX3_DATABUS_SIZE : integer := 32; USR_DATABUS_SIZE : integer := 32 ); Port ( -- ezusb fx3 port fx3_pclk_op : out std_logic; fx3_data_bp : inout std_logic_vector(FX3_DATABUS_SIZE-1 downto 0); fx3_flaga_ip : in std_logic; fx3_flagb_ip : in std_logic; fx3_sloe_op : out std_logic; fx3_slrd_op : out std_logic; fx3_slcs_op : out std_logic; fx3_slwr_op : out std_logic; fx3_addr_op : out std_logic_vector(1 downto 0); fx3_pktend_op : out std_logic; fx3_reset_bp : inout std_logic; -- user interface port (mandantory) clk100m_i : in std_logic; reset_i : in std_logic; -- active high bulkout_ready_i : in std_logic; -- not implement yet bulkout_wait_i : in std_logic; -- User circuit is ready but nomore -- data cannot be received. bulkout_start_o : out std_logic; -- Start timing of bulkout (SOF) bulkout_busy_o : out std_logic; -- now running. bulkout_end_o : out std_logic; -- End timing. (EOF) bulkout_dvalid_o : out std_logic; -- Received data is valid bulkout_data_o : out std_logic_vector(USR_DATABUS_SIZE-1 downto 0); bulkin_ready_i : in std_logic; -- not implement yet bulkin_start_o : out std_logic; -- Bulkin start (SOF) bulkin_busy_o : out std_logic; -- now running. bulkin_end_o : out std_logic; -- Bulkin end (EOF) bulkin_data_i : in std_logic_vector(USR_DATABUS_SIZE-1 downto 0); bulkin_dreq_o : out std_logic; -- Bulkin data request bulkin_dvalid_i : in std_logic; -- Send data is valid bulkin_abort_i : in std_logic; -- Abort and send PKTEND datalen_o : out std_logic_vector(31 downto 0); addr_o : out std_logic_vector(31 downto 0); flag_o : out std_logic_vector(15 downto 0); debug_o : out std_logic_vector(31 downto 0) -- for debug ); end fx3sfsync16; |
わかりやすく図にすると、次の図のようになります。
図の左側、「fx3_」で始まるポートはFX3にそのまま繋いでください。
「bulkout_*」で始まるポートはBulkOutのときに使い、bulkin_*で始まるポートはBulkOutのときに使います。
各ポートの使用方法の詳細
各ポートの機能と使用方法について説明します。
分類 | 信号名 | 方向 | 機能 |
---|---|---|---|
FX3 |
fx3_pclk_op |
出力 | FPGAの外に直結すること |
fx3_data_bp |
双方向 |
FPGAの外に直結すること |
|
fx3_flaga_ip |
入力 |
FPGAの外に直結すること |
|
fx3_flagb_ip |
入力 |
FPGAの外に直結すること |
|
fx3_sloe_op |
出力 |
FPGAの外に直結すること |
|
fx3_slrd_op |
出力 |
FPGAの外に直結すること |
|
fx3_slcs_op |
出力 |
FPGAの外に直結すること |
|
fx3_slwr_op |
出力 |
FPGAの外に直結すること |
|
fx3_addr_op |
出力 |
FPGAの外に直結すること |
|
fx3_pktend_op |
出力 |
FPGAの外に直結すること |
|
fx3_reset_bp |
双方向 |
FPGAの外に直結すること |
|
clk100m_i |
入力 | クロック入力100MHz | |
reset_i |
入力 |
Hでコアをリセット |
|
BulkOut |
bulkout_ready_i |
入力 | ユーザ回路がOUT転送を受け入れる準備ができていることを示す |
bulkout_wait_i |
入力 | ユーザ回路が次のデータを受け入れる準備ができていないことを示す | |
bulkout_start_o |
出力 | OUT転送の開始時に1クロックだけアサートされる | |
bulkout_busy_o |
出力 | OUT転送が実行中であることを示す | |
bulkout_end_o |
出力 | OUT転送の終了時に1クロックだけアサートされる | |
bulkout_dvalid_o |
出力 |
bulkout_data_o[31:0]が有効であることを示す |
|
bulkout_data_o[31:0] |
出力 | OUT転送で受信したデータが出力される | |
BulkIn |
bulkin_ready_i |
入力 | ユーザ回路がIN転送を開始できる準備ができていることを示す |
bulkin_start_o |
出力 | IN転送の開始時に1クロックだけアサートされる | |
bulkin_busy_o |
出力 | IN転送が実行中であることを示す | |
bulkin_end_o |
出力 | IN転送の終了時に1クロックだけアサートされる | |
bulkin_data_i[31:0] |
入力 | IN転送で送信するデータを入力する | |
bulkin_dreq_o |
出力 | コアがデータの送信を要求している | |
bulkin_dvalid_i |
入力 |
bulkin_data_i[31:0]に有効なデータがあることを示す |
|
bulkin_abort_i |
入力 | IN転送を途中で打ち切る | |
Option |
datalen_o[31:0] |
出力 | OUTまたはIN転送のデータサイズ(4バイト単位) |
addr_o[31:0] |
出力 | 転送するターゲットの開始アドレス | |
flag_o[15:0] |
出力 | 転送する際のフラグ | |
debug_o[31:0] |
出力 | デバッグ用出力(オープンにすること) |
FX3用ポートは、FPGAの外にそのまま出して、EZ-USB FX3に直結してください。
ユーザ回路が、OUT転送を受け入れる準備ができたならば、bulkout_ready_iに'1'を与えます。
ホストPCからOUT転送が発行されると、bulkout_startが1クロックの間アサートされてOUT転送が発生したことを知らせます。その後、その一連のOUT転送が継続している間はbulkout_busy_oが'1'なります。OUT転送が終了するときに、bulkout_end_oが1クロックの間'1'になります。
受信したデータは、bulkout_data_o[31:0]から出力されます。bulkout_dvalid_oが'1'になっているとき、受信したデータが有効であることを示します。ユーザ回路は次のデータを受け入れる余裕がないときには、bulkout_wait_iを'1'にしてWAITをかけます。ただし、コアはすぐにデータを停止させることはできません。WAITをかけてから実際にデータの出力が止まるまでには6ロックの遅延があります。したがって、WAITをかける可能性がある場合には、ユーザ回路側でFIFOを持つようにして、あと数個のデータでFIFOがFULLになるというタイミングでWAITをかけるようにしてください。
実機での動作タイミングを次の図に示します。
これは、OUT転送の開始してから16ワードのデータを受信して終了するまでの波形です。
次の図は、ユーザ回路がWAITをかけた場合です。bulkout_wait_iがアサートされてから実際のデータが停止するまでに6クロックかかっていることがわかります。
bulkout_wait_iを'0'に戻すと、コアはデータの出力を再開します。
ユーザ回路が、IN転送を受け入れる準備ができたならば、bulkin_ready_iに'1'を与えます。
ホストPCからIN転送が要求されると、bulkin_startが1クロックの間アサートされてIN転送を要求していることを知らせます。その後、その一連のIN転送が継続している間はbulkin_busy_oが'1'なります。IN転送が終了するときに、bulkin_end_oが1クロックの間'1'になります。
コアがデータを要求している間は、bulkin_dreq_oがアサートされます。そうしたら、ユーザ回路はbulkin_data_i[31:0]にデータを与え、bulkin_dvalid_iをアサートします。
コアがWAITをかけてくる場合(すなわち、USBの転送が追い付かない。あるいはUSBのパケットの隙間)は、コアがbulkin_dreq_oをネゲートしてきますので、そうなったらデータを送らないようにしてください。
ユーザ回路側がWAITをかけたい場合は、bulkin_dvalid_iをアサートしなければよいので簡単です。
実機での動作タイミングを次の図に示します。
bulkin_start_oが1クロックアサートされて、PCからBulkIn要求が発生したことを知らせているのがわかります。ユーザ回路は、bulkin_dreq_oがアサートされているのを見たら、bulkin_dvalidと共にデータを送っています。
FX3が「データをこれ以上送らないでほしい」(つまりFX3内のバッファがFULL)と言っているときには、bulkin_dreq_oが下がるので、ユーザ回路はデータの送信を止めます。
data_len_oは、送受信する残りのデータの数をワード単位(データバスが32bitならば4バイト単位)で示します。
addr_oは、転送開始アドレスを32bitで示します。このアドレスはオプションで、メモリなどをつなぐ場合に活用できます。
flag_oは、16bitの任意の値です。送受信関数を呼び出したときに与えられる引数の値が出力されます。
※IN転送の場合でも、16bitの値をコアに送ることができます。
問題点あるいは未完成の事項と、これからの課題
- 現在はデータバスが32bit専用なので16bit/8bitでも動作するようにしたい
- BulkIn時のAbort機能は作ったが検証していない
- BulkOut時に4の倍数ではない数のデータが来たときに、4の倍数に切り上げられてしまい、余りの部分に無意味なデータが格納されてしまう。これはホストPCからメモリの一部分を書き換えるような場合に問題となるだろう。
- 非同期FIFOを入れて、任意の周波数のクロックドメインとインタフェースできるようにしたい
- AXI4のインタフェースにして、MicroBlazeやZYNQのARMとインタフェースできるようにしたい