Kintex-7のPCI Expressリンク幅と速度がどうなっているのかを調べました。
XILINXのユーザガイド「7 Series FPGAs Integrated Block for PCI Express v3.0」によれば、物理層インターフェイスの出力信号にそれらを示す信号が出ているようで
- pl_sel_lnk_rateが現在のリンク速度を示す。'0'なら2.5G、'1'なら5G
- pl_sel_lnk_width[1:0]が現在のリンク幅を示す。"00"ならx1、"01"ならx2、"10"ならx4、"11"ならx8
- pl_initial_link_width[2:0]は、初期のリンク幅を示す。つまり、最大のリンク幅になっている
あと、通信の相手がGen2に対応しているかを示すpl_link_gen2_capや、リンクがアップコンフィギュレーションに対応しているかを示すpl_link_upcfg_capなどの信号があります。
Cosmo-Kで、これらの信号を見てみると、pl_sel_lnk_rateは'1'、pl_sel_lnk_width[1:0]は"10"なので、Gen2のx4でリンクアップしていることがわかります。
では、この幅をいろいろ変えてみましょう。
まず、(需要があるのかどうかはわかりませんが)リンク速度のスピードダウンを行ってみます。pl_directed_link_speedを'0'にして、pl_directed_link_changeを"10"あるいは"11"にすると、スピードが下がります。

pl_sel_lnk_rateが'0'に変わるのが見えました。
そうしたら、次に速度を戻します。pl_directed_link_speedを'1'にして、pl_directed_link_changeを"10"あるいは"11"にします。

このとおり、リンク速度が戻りました。簡単ですね。

リンク幅を減らすことも簡単です。リンク幅を減らすには、pl_sel_lnk_width[1:0] に"01"や"00"を指定して、pl_directed_link_changeを"01"あるいは"11"にします。
お気づきのとおり、pl_directed_link_change(0)はリンク幅の変更、pl_directed_link_change(1)はスピードの変更を指示する信号です。

幅・速度変更の最後には、pl_directed_change_doneが'1'になって完了を示してくれるので、そうしたらpl_directed_link_changeを"00"を戻します。pl_directed_link_changeが != "00"でない状態で放置すると、何度も何度もリンク変更を繰り返してしまいます。
リンク幅を減らすのは4μ秒程度の短い時間で完了します。しかし、リンク幅を増やすのは、うまくいかない場合があるようです。
また、当然ですがx4のリンク幅で作られたボードをx8にしようとしてもx8にはなりません。
わかったことは、
- Cosmo-Kは、デフォルトでは、設計したとおり、Gen2のx4でリンクアップした
- x1にもx2にも変更できるが、x8にはならない
- リンク速度と幅を変更するには、pl_directed_link_speedとpl_directed_link_widthに新しい値を設定して、pl_directed_link_changeに"11"を与える。pl_directed_change_doneが来たら"00"に戻すこと。
ということです。
Kintex-7搭載のPCI Expressボード「Cosmo-K」で、PCI Expressがあっさりと無事に認識されました。
やりかたは意外と簡単で、ISEのCoreGenでPCI Expressのコアを作って、その中にあるExample Designをビルドすればよいだけです。


では、もう少し詳しく説明します。
まずISEを用意してCoreGenで新規にコアを作成します。Vivadoだとややこしくなるので、私はまずはISEで試します。
Standard Bus Interfacesの中にある7 Series Integrated Block for PCI Expressを選びます。

最初の画面では、レーンの幅や速度などを選びます。

最初のDevice / Port Typeというところは、PCI Express Endpoint Device(普通のターゲットボード)にするか、Legacy(I/O空間が使えたり)にするか、RootComplexにするかなどを選びます。(Rootになれるって、すごいですね。)
Gen2に対応させるには5.0GT/sを選びます。Interface Widthというのはユーザポートのデータバスの幅です。Cosmo-KはGen2 x4なので、64bit 250MHzか、128bit 125MHzになります。

次はBAR空間の設定です。32bitメモリ空間ならば2GBytesまで、64bitメモリ空間ならば8ExaBytes要求できるようです。
これはCPUの物理アドレス空間のどの範囲をPCI Expressに割り当てるかということなのですが、好きなだけ確保してください。実際にそのサイズのメモリを用意しなくても良いわけです。

その次は、ベンダIDなどを指定します。1BC8というのは特殊電子回路のベンダIDです。

1BC8を10進数にすると7112なので、もう少し早く取れば7110(ないとう)になったので、すごく惜しかったと思います。
ベースクラス以下11 00 00というのは、汎用のData aquisition and signal processing controllersのDPIOモジュールを意味するので、FPGA拡張ボードなどの用途にぴったりです。
その次から先の数ページ分の画面では、特に設定する必要はありませんし、実際には変更してもメリットはないでしょう。拡張コンフィギュレーション空間とか、エラーレポートとか、パワーマネージメントとか使う必要ないでしょうね。

最後から2ページ目のここは、ちょっと気になります。デフォルトではトランザクション層のバッファに使われるBRAMにパイプラインレジスタを入れない設定(none)になっています。以前、数値計算回路でBRAMを250MHzで動作させた際に、タイミングエラーが生じたことがあるので、もしタイミングエラーが生じたときにはバッファを有効にしたほうがいいかもしれません。
最後のページも特に変更する必要はありません。レーン反転はUCFファイルの設定でも何とでもできてしまうので、ダイナミックに変える必要も感じません。
リファレンスクロックは100MHz、125MHz、250MHzが選べますが、マザーボードから送られてくるクロックは100MHzなので変更する必要もないでしょう。

まとめると、最低限設定する必要があるのはレーン速度、幅、ベンダID、デバイスID、BAR空間くらいです。簡単ですね。

Generateすると、ipdore_dirにpcie_7x_v1_9というディレクトリができて、\ipcore_dir\pcie_7x_v1_9\example_designにxilinx_pcie_2_1_ep_7x.vhdというファイルができます。基本的にはこれをトップデザインとしてビルドすればよいのですが、このファイルはGenerateするたびに上書きされるので、そのまま使うのではなく、内容をコピーして自分で作ったVHDLファイルに貼り付けて使います。
UCFファイルもCoreGenのipcore_dirの中に見つかるはずです。
プロジェクトの構成は下の図のようになるはずです。

inst_pcieというのが、xilinx_pcie_2_1_ep_7x.vhdをコピーして作ったモジュールです。中にはpcie_7x_v1_9というコア(PCI Expressの本体)と、app(BARメモリ空間に実装されたメモリマップドI/O)などがあります。
そのほかに設定する必要があるのはsys_clk_p/nのピン配置とsys_rst_nのピン配置です。sys_rst_nは、PCI ExpressのPERSTBです。sys_clk_p/nはPCI ExpressのREFCLKをGTXに入れているピンです。UCFで設定すればよいでしょう。
NET "sys_rst_n" LOC = H13 | IOSTANDARD = "LVCMOS18" | PULLUP;
NET "wake_op" LOC = G14 | IOSTANDARD = "LVCMOS18";
NET "sys_clk_p" LOC = "H6";
NET "sys_clk_n" LOC = "H5";
回路設計上の問題として、PERSTBやREFCLKをそのままFPGAにつなぐのは避けたいところです。何らかのバッファICを入れたほうがいいでしょう。

ただし、CoreGenのサンプルをそのままビルドしても動きません。
なぜならば、PIPE_MMCM_RST_Nという信号があるのですが、この信号は'0'のままでリセットがかかりっぱなしになっているからです。PIPE_MMCM_RST_Nという信号は

と、signal文の初期値を使って'1'に指定されているのですが、XSTはこれを無視します。example designではPIPE_MMCM_RST_Nに値を代入している部分はないので、source less signalとして常に0になってしまうのです。
だから、自分で
PIPE_MMCM_RST_N <= '1';
と書いてやらねばなりません。これに気が付かないと焦ります。
あと、UCFファイルはBRAMの位置をLOCで固定しているところと、GTXE2_CHANNEL_X0Y4などをLOCで固定している箇所はコメントアウトして、
NET "pci_exp_txp(0)" LOC = "H2";
NET "pci_exp_txn(0)" LOC = "H1";
NET "pci_exp_rxp(0)" LOC = "J4";
NET "pci_exp_rxn(0)" LOC = "J3";
のようにピン番号で配置を指定したほうがわかりやすいでしょう。
これでPCI Expressが認識されるようになりました。


待ちに待ったKintex-7 PCI Expressボードの実装が上がってきました。

まずは、40GのQSFP搭載のCosmo-K+

コンパクトなのに、すごいパワーを感じます。
次は、10GSFPを3機搭載したCosmo-K-

セルフでIBERTテストができそうですね。
最後にECLの汎用I/OがついたCosmo-K0。これは特注品です。

Kintex-7が凛々しい。

早速、注意深く電源を入れてみました。

MITOUJTAGをつかって、バウンダリスキャンでピンの状態が見えたので、FPGAは生きていることがわかりました。
JTAGをつかわなければ、テストデザインを作ったりしてFPGAの生死判別に1日くらいかかりますが、MITOUJTAGなら一瞬でできます。