Kintex-7 PCIe Express光ボード「Cosmo-K」>開発日記>2017年1月

2017年1月

Cosmo-KのDDR3メモリの配線を改良した

Kintex-7搭載のPCI Expressボード「Cosmo-K」のDDR3メモリの配線を修正しています。 

2017.01.22

Cosmokddr3

ぐちゃーっとした配線で何が何だかわからないと思います。

そこで、TOP層、内層1、内層2だけを表示させてみます。

 

今までの配線は、こうなっていました。

Old

データ線やDM、DQSなどは1対1でFPGAとDDR3が接続されているのですが、アドレス線やCAS、RASなどの制御線がT型に分岐しているのです。

DDR3の配線は等長配線のT型にするか、数珠つなぎ型にするかという選択肢はあるのですが、この基板ではT型に分岐した下側のDDR3メモリにだけ終端抵抗が付いているという間違った設計になっていました。

そのため、DDR3メモリを800MHzで動かしているうちはよかったのですが、1600MHzで動かそうとすると、2個あるDDR3メモリのうち、下側のほうだけしか動かないという現象に見舞われました。(実際には1000MHzくらいで限界になる)

高速オシロで見ると、確かにSSTL-15の信号レベルが暴れていました。

sun

そういうわけで、この配線を全面的に見直して、数珠つなぎ型の一直線の配線になるようにして、最後の部分で終端をするように変えました。

New


FPGAから出た配線が全体的に上から下へ流れていくのがわかると思います。アドレス・制御線の信号長の差も1cm以内に収まりました。

これで1600MHzアクセスができるといいのですが、どうなるでしょう。

 

JESD204Bのはじめてのデータ受信 

2017.01.12

昨年11月に作ったJESD204B出力のADCボードと、データ取り込み用ボードで、ようやくデータが受信できるようになりました。

使用しているADCは、TI社のADS54J60です。

2つのボードをこのように40Gbの光ファイバでつなぎます。

Jesd204b

2つのボードの間は10Gbpsのリンク(現在は半分の5Gbpsで運用)が4本でつながっています。ADCのSYNCという端子をLにすると、K28.5のCOMが送られてきます。

K28.5は16進数で1BCなので、最初は4つのチャネルにBCBCBCBCというデータが来ます。

SYNCをHにすると、COM以外の何かが送られてきます。

K28.5 キタ━━━(゚∀゚).━━━!!!

Jesd204b_1_2

K28.5以外のものが来るパターンが上の波形には2回見えていて、最初のは

GTX0  1BC 11C 00 F0 E5 FF FE 00・・
GTX1  1BC 11C 05 FF FF 00 04 00・・
GTX2  1BC 11C 10 FF FA 00 04 FF・・
GTX3  1BC 11C F5 00 0A FF F5 FF・・

と読めます。1BCはK28.5で/K/という記号で表します。11CはK28.0で/R/という記号で表します。/R/は「マルチフレーム先頭文字」の意味だそうです。

2回目のK符号は

GTX0  17C 11C 19C 00 00 01 1C 1C・・
GTX1  17C 11C 19C 00 00 00 03 03・・
GTX2  17C 11C 19C 00 00 03 03 03・・
GTX3  17C 11C 19C 00 00 02 00 00・・

と読めます。17CはK28.3で/A/で、「レーンアラインメント文字」だそうです。19Cは/Q/の「リンクコンフィグ先頭文字」だそうです。なので、/A/ /R/ /Q/ ・・・

その続きの波形を見てみると、

Jesd204b_2

1個目が

GTX0  17C 11C E3 FF FE FF FF 00
GTX1  17C 11C FD 00 02 FF FC 00
GTX2  17C 11C 00 FF FF 00 FF 00
GTX3  17C 11C ED FF F8 FF F5 FF

と読めます。/A/ /R/ ・・です。

2個目は

GTX0  17C 11C 00 00 01 FF FB 00
GTX1  17C 11C FD 00 00 00 FA 00
GTX2  17C 11C 10 FF FA 00 00 FF
GTX3  17C 11C F1 FF FE FF F9 00

これもまた/A/ /R/ ・・です。

3個目は

GTX0  17C 00 02 00 15 FF FE FF
GTX1  17C 00 01 00 08 FF FD FF
GTX2  17C 00 0F FF F7 00 06 FF
GTX3  17C FF F5 00 09 00 01 FF

で、/A/です。

このような感じで、SYNCをONにしたときに5回のK符号のフレームが来るのですが、トラ技2016年9月号を読んで、意味がわかりました。

最初の/R/から/A/までが1セット目のフレームでILAS(Initial Lane Alignment Sequence)というそうです。

/R//Q/・・・/A/が2つ目のセットでマルチフレーム。この中にはコンフィギュレーションコードというのが入っています。

3個目、4個目は/R/・・/A/で、マルチフレーム1と同じ内容でデータに意味はないということでした。

大事なのは/R/ /Q/の続きの14オクテットで、ここにコンフィギュレーションレジスタという情報が書かれているそうです。本当かいな。

GTX0 00 00 01 1C 1C 16 01 12 CF DC 00 00 00 CD
GTX1 00 00 00 03 03 09 01 0D 2F 23 00 00 00 31
GTX2 00 00 03 03 03 09 01 0D 2F 23 00 00 00 34
GTX3 00 00 02 03 03 09 01 0D 2F 23 00 00 00 03

解読した値を書いていてい気が付いたのですが、おそらくGTX0のチャネルはRXPとRXNが反転していますね。GTX1~GTX3は同じような感じのデータなので、そちらはたぶん正解なのでしょう。

解読すると、

L=3、F=3、K=9、M=1、N=13、SUBCLASSV=1、N'=15、JESDV=1、S=3、HD=0、CF=0、RES1=0、RES2=0、FCHK=xx

となりました。

+1する補正を考慮すると、

L=4、F=4、K=10、M=2、N=14、SUBCLASSV=1、N'=16、JESDV=1、S=3、HD=0、CF=0、RES1=0、RES2=0、FCHK=xx

読める、読めるぞ・・

解読したところ

  • L:4 リンク数は4
  • M:2 デバイスには2つのコンバータ
  • F:4 1フレームあたり4オクテット
  • S:4 コンバータあたりフレームあたりのサンプル数
  • K:10 1マルチフレームあたり10フレーム
  • N:14bitでサンプリング
  • N':1サンプルあたり16bit
  • JESD204B

となりました。ADCの分解能が14bitというのが納得いきませんが、概ね良い感じだと思います。

 

JESD204B 1G ADCの動作確認

2017.01.11

昨年から開発を続けているJESD204B対応の1Gs/s ADC「HyperFADC」ですが、高速シリアルのデータをデコードしようと頑張っています。使用しているADCのADS54J60にはSYNCという端子があるのですが、これをLにすると、1BC 1BC 1BC 1BC、つまりK28.5のCOMが送られてきます。

Cosmokp_jesd204_adc_2lane_5gbps

SYNCをHにすると、K28.5ではなく、D0.0に変わったかと思ったのですが・・

Cosmokp_jesd204_adc_2lane_5gbps_3

rxnotintableという信号が立ちあがっているので、D0.0が送られてきているわけでもなさそうです。

いまいち使い方がよくわかりません。

 

Kintex-7のPCI Expressのバーストライト

2017.01.08

Kintex-7のPCI Expressでバーストライトをさせて、その速度を見てみました。

使ったのは、Cosmo-K+というボード。

1478579823_cosmok

PCI Express Gen2でx4という構成です。理論的には2GByte/sec出るはずです。

しかし、実際にやってみると514MBくらいしか出ません。

Cmbwr512mb

原因の1つは、デバイスドライバの問題で、ユーザ空間とカーネル空間を行き来するときにバッファの内容がコピーされるのですが、そのコピーの時間が無駄にかかっているためです。

もう一つの理由は、WriteCombinedで書き込んでいるのですが、AXIから読み出すときに、m_axis_tx_ready_intという信号がパタパタと遷移していて、1つのデータの読み出しに2クロックかかっているためです。

Wr64png

Gen1 x1のときには250MB/secしか出ないので、XILINXのCore Gen IPが作るユーザ側インタフェースは64bit 62.5MHz(最低速度)でも十分に間に合いました。

最低速度の半分のレートしか出ないので、AXバスをパタパタさせてもオーバーヘッドはなかったのですが、Gen2 x8だと64bit 250MHzになるので、もはやReadyをパタパタさせてはなりません。

Gen1のx1では、WriteCombinedで200MBくらい出るので、DMAよりも手軽で速く、速度的にも満足だったのですが、Gen2x4ではそうはいかなくなってきました。

毎クロックできびきび動作するよう、ステートマシンの作り直しが必要なのと、バッファのコピーを避けるためドライバがユーザ空間のメモリ領域のアドレスを見つけて、直接DMAする必要なのでしょう。

 

LinuxでのCombined Write

2017.01.07

PCI Expressにおけるメモリ書き込みは、Combined Writeを使うと高速に行えます。

Write Combinedを使わないと、PCI Expressは長さ1(4ワード)のトランザクションを発行してしまうので、極めて遅くなります。

Combined Writeというのは、CPUの書き込み機構をうまく利用した方法で、複数のメモリ書き込みを1つに結合して長いパケットにして発行するやり方です。

LinuxでCombined Writeを使う方法はよくわからないのですが、デバイスドライバの中でBARの物理アドレスを仮想アドレスにマップするときに、

ioremap_wc(BARx_BaseAddr,BARx_Length);

という関数を使うと良いようです。

ioremap(BARx_BaseAddr,BARx_Length);

ioremap_nocache(BARx_BaseAddr,BARx_Length);

という関数を使うと通常のWriteとなってしまうようなのですが、正直なところよくわかりません。うまく切り替わってくれないことが多々あります。

sun

では、実際に波形をみてみましょう。MITOUJTAGのロジアナ機能を使って、PCI Expressの書き込みトランザクションを見てみます。

書き込みは、

memcpy_toio(Mapped_BAR1_BaseAddr , WriteBuffer , count);

を使いました。

まずは、普通のWriteの場合です。128バイトのデータ転送を行ってみたところ、32回のトランザクションが発生して、5.45μ秒かかっています。したがって、転送速度は23MB/secとなります。

Single_write

拡大してみると、先頭のワードが40000001なので、1ワードの書き込みトランザクションになっていることがわかります。これでは遅いですね。

Single_write2

sun

次は、Combined Writeにした場合の波形です。先頭のワードが40000010なので64バイトの書き込みトランザクションが2回になっています。128バイトを752nsで書き込んでいるので、速度は170MB/sとなります。

Wc

圧倒的に速くなりました。

sun

切り替えは、ioremapを使うか、ioremap_wcを使うかといった違いだけなのですが、どうやらLinuxの起動時にはWriteCombiedを使うようになっていて、関数を変えるだけでは切り替わらないようです。

rescanを行う際に、

sudo chmod 666 /sys/bus/pci/devices/0000\:04\:00.0/rescan
sudo echo 1 > /sys/bus/pci/devices/0000\:04\:00.0/rescan

のように、バスの中までrescanをすると、この機能が切り替わるようなのですが、切り替わらないときもあります。

何がトリガーとなって、ioremapとioremap_wcが切り替わるのかは、正直、よくわかりません。OSごと再起動すると切り替わることが多いように見えます。

 

PCI ExpressのFPGAを効率的に開発する方法(Linux版)

2017.01.06

PCI ExpressをFPGAで実装すると、新しいデザインが出来たら当然、書き換えることになります。

FPGAを書き換えると内部のレジスタがすべて0にクリアされてしまいます。BARなどの設定値が全部消えてしまうので、アクセスできなくなってしまいます。

普通はFPGAを書き換えるたびにOSを再起動しなければなりません。再起動を待つ時間がもったいないだけでなく、アプリの起動やディレクトリの移動など面倒な手間が増えます。

PCI ExpressのFPGAを書き換えても、OSの再起動なしに続行したいわけです。

Windowsの場合ならばデバイスマネージャから無効/有効を行えばBARの再設定が行われるので再起動する手間を省けますが、Linuxでやる方法を調べました。

ここではScientific Linux CERN 6 (SLC6)というディストリビューションを使用しています。

sun

基本的なやり方は、rescanというドライバを使って、

sudo echo "1" > /sys/bus/pci/rescan

 

のようにします。一瞬、??となる書き方なのですが、rescanというのは、

--w--w---- 1 root root 4096  1月  6 16:09 2017 /sys/bus/pci/rescan

というスペシャルファイルで、このファイルに1を書き込むと再スキャンが行われるという代物のようです。

ただ、私が使っているSLC6というディストリビューションではrescanに書くだけではうまく行かず、sudoを付けていても許可がありませんと出てしまいます。

そこでchmod 666でドライバrescanに読み書き属性を付与してから行っています。また、なぜかrescanだけではうまくいかないので、removeというドライバにも同様に1を書き込んでから行います。

結局のところ、以下のようなスクリプトを書いて実行しています。

#!/bin/sh
sudo chmod 666 /sys/bus/pci/devices/0000\:0\:00.0/remove
sudo echo 1 > /sys/bus/pci/devices/0000\:0\:00.0/remove
sudo chmod 666 /sys/bus/pci/rescan
sudo echo "1" > /sys/bus/pci/rescan

使い方は、./rescan 4 のようにrescanの後にバス番号を指定します。

バス番号というのは、lspciで表示される一覧の一番左の数字です。

Lspci

上のDPIO moduleというのがFPGAで作ったPCI Expressのファンクションです。この数字が4なので、rescan 4とすると、上のスクリプトが起動して、PCI Expressデバイスが削除されてから再スキャンされて、BARが再設定されるというわけです。

これで、OSを再起動することなく、FPGAのみ書き換えて動作を続行することができるようになります。

sun

実際にやってみてわかった注意点がいくつかあります。

  1. BARのサイズを増やすと、再設定が行われない場合がある。
    つまり、最初は16kB程度の領域を確保していて、再スキャン後に64MBに増えているような場合は、うまくいかない。FPGAを書き換えてもリクエストするメモリ空間のサイズは変えない方が良い。
  2. BARサイズを減らすのは大丈夫なようだ。
  3. VIDやDIDが変わるのはOK。

以下に、実際の実行結果を示します。

まずは、起動したLinuxを直後にlspciでデバイスのコンフィギュレーション情報を見たところです。1bc8:1080のデバイスが見えています。Region 0..2の表示にも注目してください。

[user@px ~]$ lspci -d 1bc8:* -vvvx
04:00.0 DPIO module: Device 1bc8:1080
        Subsystem: Device 1bc8:1080
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0, Cache Line Size: 256 bytes
        Interrupt: pin A routed to IRQ 11
        Region 0: Memory at dbfec000 (32-bit, non-prefetchable) [size=16K]
        Region 1: Memory at dbff0000 (32-bit, non-prefetchable) [size=64K]
        Region 2: Memory at dc000000 (32-bit, non-prefetchable) [size=64M]
        Capabilities: <access denied>
00: c8 1b 80 10 07 00 10 00 00 00 00 11 40 00 00 00
10: 00 c0 fe db 00 00 ff db 00 00 00 dc 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 c8 1b 80 10
30: 00 00 00 00 40 00 00 00 00 00 00 00 0b 01 00 00

FPGAを書き換え中にlsmodしてみました。すべてのレジスタがffになって見えないことがわかります。

[user@px ~]$ lspci -d 1bc8:* -vvvx
04:00.0 DPIO module: Device 1bc8:1080 (rev ff) (prog-if ff)
        !!! Unknown header type 7f
00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

下の表示はFPGAの書き換えが完了した直後の状態です。Region 0,1,2がvirtualと出ています。

[user@px ~]$ lspci -d 1bc8:* -vvvx
04:00.0 DPIO module: Device 1bc8:1080
        Subsystem: Device 1bc8:1080
        Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Interrupt: pin A routed to IRQ 255
        Region 0: [virtual] Memory at fb310000 (32-bit, non-prefetchable) [size=16K]
        Region 1: [virtual] Memory at fb300000 (32-bit, non-prefetchable) [size=64K]
        Region 2: [virtual] Memory at fb400000 (32-bit, non-prefetchable) [size=4M]
        Capabilities: <access denied>
00: c8 1b 80 10 00 00 10 00 00 00 00 11 00 00 00 00
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 c8 1b 80 10
30: 00 00 00 00 40 00 00 00 00 00 00 00 ff 01 00 00

ここでrescanすると、

[user@px ~]$ lspci -d 1bc8:* -vvvx
04:00.0 DPIO module: Device 1bc8:1080
        Subsystem: Device 1bc8:1080
        Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Interrupt: pin A routed to IRQ 255
        Region 0: Memory at fb310000 (32-bit, non-prefetchable) [disabled] [size=16K]
        Region 1: Memory at fb300000 (32-bit, non-prefetchable) [disabled] [size=64K]
        Region 2: Memory at fb400000 (32-bit, non-prefetchable) [disabled] [size=4M]
        Capabilities: <access denied>
00: c8 1b 80 10 00 00 10 00 00 00 00 11 00 00 00 00
10: 00 00 31 fb 00 00 30 fb 00 00 40 fb 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 c8 1b 80 10
30: 00 00 00 00 40 00 00 00 00 00 00 00 ff 01 00 00

virtualと表示されていたregionが設定され、使用できるようになります。

この情報が、Linux上で動くPCI Expressのアドインカードを開発する人の助けになれば幸いです。


© 2015 TokushuDenshiKairo Inc. All rights reserved