PCI Expressで、CombinedWriteで書き込んだデータをDMA Readで読みだすと、稀にデータが化けるという現象が発生します。CombinedWriteで書き込んだデータをPIO Readで読みだしたり、DMA Writeで書き込んだりしたデータをDMA Readで読み込んだりした場合は大丈夫です。
要するに非常に不可解で難しそうな問題なのですが、今回は、MITOUJTAGのBLOGANA機能に内蔵された「FPGA内部へのデータ出力機能」を使って、そのデバッグを行ってみたいと思います。この機能をつかうと、MITOUJTAGの画面からマウスでポチポチすることで、JTAGを介してFPGAの内部のロジックへデータを送り込むことができます。実は、この機能は数年前から用意されていました。
MITOUJTAGを使ってFPGAの中にロジアナを埋め込むには、BLOGANAというコアを埋め込みます。現在はXILINXのFPGAのみ対応しています。
BLOGANAのポートは次のようになっています。
entity blogana is
Port ( CLK : in std_logic;
TRIG : in std_logic;
USER_OP : out std_logic_vector(19 downto 0);
SAMPLE_EN : in std_logic;
DIN : in std_logic_vector(71 downto 0); -- 必ず72本
SAMP_FREQ : in integer range 0 to 2147483647; -- サンプリング周波数
WIDTH72 : in std_logic; -- 1:72ビット 0:36ビット
LENGTH1024 : in std_logic; -- 1:1024ワード 0:512ワード
BUSY : out std_logic -- 必ずどこかに出力すること
);
end blogana;
このうち、USER_OPという20ビットの端子が、FPGAの内部に信号を送り込むためのポートです。
任意の信号を送り込むことができますが、主にトリガ条件の指定に使います。
BLOGANAでは、トリガの条件をユーザがHDLを使って記述します。
たとえば、
BLOGANA_TRIG <= dma_wr_req_i
when (BLOGANA_USEROP(19) = '1')
and (dma_addr(15 downto 0) = BLOGANA_USEROP(15 downto 0)) else
rcvd_cfgrd or rcvd_cfgwr or rcvd_mrd or rcvd_mwr
when (BLOGANA_USEROP(18) = '1') else
'0';
のようにします。
すると、
・BLOGANA_USEROP(19)という信号が'1'で、かつ、dma_addrの下位16bitがBLOGANA_USEROPの下位16bitと一致し、dma_wr_req_iが'1'の場合
という条件と、
・BLOGANA_USEROP(18)という信号が'1'で、かつ、rcvd_cfgrdか、rcvd_cfgwrか、rcvd_mrdか、rcvd_mwrのいずれかの信号が'1'になった場合
というトリガ条件が作れます。
このBLOGANA_USEROPから出す信号は、MITOUJTAGのロジアナ画面の以下の部分から操作することができます。

つまり、MITOUJTAGの画面上でチェックボックスをON/OFFしたり、テキストボックスに値を書き込めば、その値がFPGAの中に出力されるというわけです。
さて、ここでCombined Writeのデバッグに入りましょう。
まず、Combied Writeで書き込んだデータが化けて読みだされるのは、毎回0x300か0x380番地あたりと決まっています。そこで、BLOGANA_USEROPの下位16bitに0x300を指定して、キャプチャをスタートさせます。
こうすると、再コンパイルすることなしにロジアナでトリガしたい条件が変えられます。
すると、DMAアドレスが0x300になったときにトリガがかかります。
実験したところ、アドレス0x380で読みだし不一致エラーが発生しました。
トリガ点から少し右を見ていくと、アドレス0x380用のデータを送信している場所が見つかります。

このデータは、80 B3 30 CA BB 6E ・・と読むことができ、書き込んだデータ(下の画面)と同じです。

つまり、Combined Writeで書き込んだデータをDMA Readで読みだしても、PCI Expressのバス上には正しく流れていました。FPGAの中のコアの問題ではなく、RootComplexが受け取れていないか、Windowsのメモリ管理の問題であるということになります。問題があるとしたらドライバの中か、キャッシュの扱い方などなのでしょう。
結局のところ、Combied Writeの謎は解決していませんが、パケットの送る順番とかプロトコルの問題ではなさそうだということはわかりました。
このBLOGANAからのデータ出力機能はかなり便利で、たとえば、DMAの最後のアドレスにトリガをかけてキャプチャをすると、DMA後の割り込みの部分に焦点を合わせることもできます。
DMA長が8192バイトの場合、DMAアドレス = 0x1F80というトリガ条件を設定します。

BLOGANA_USEROPの機能は、トリガのためだけに使うのではなく、もっと積極的にFPGA内部へのデータ出力を行うのにも使えます。
たとえば、リセット信号を出したり、テスト用の回路を起動させるための信号として使うと便利です。
次の図は、PCI ExpresのLTSSM(リンク・トレーニング・ステートマシン)をリカバリステートに入れてみたときの波形です。FPGA内のIPコアに、リカバリステートに入るようなトリガをBLOGANA_USEROP(16)経由で与えています。

MITOUJTAGの画面上で □16 と書かれたチェックボックスをON/OFFすれば、物理層が強制的にリカバリステートに入れられるわけで、エラー状態などのデバッグに役立ちます。
今回紹介した、BLOGANAからの信号出力機能はいかがでしたでしょうか?
BLOGANAはユーザにオープンにされていて、かつ自由度が高いので、
手軽で便利に使えるのではないかと思っています。
今月は、さらにBLOGANA機能を強化していきたいと思います。
最近のコメント