DRAMインターフェースとPHY(DDR3+インターフェースが起動時にチューニングされる理由)
The DRAM interface and the PHY (why a DDR3+ interface must be tuned at boot) (github.com)
要約
この記事は、FPGAとDRAM間の配線で何が起こるのか、そしてDRAMインターフェースが起動時にチューニングされる必要がある理由を解説します。信号、ストローブ、ボードトポロジー、レベリング手順、終端、基準電圧、そしてコントローラとPHY間のクロックとDFIインターフェースを網羅しています。各セクションでは、LiteDRAMにおける対応する実装部分も紹介しています。
全文翻訳
03_dram_interface.md
DRAMインターフェースとPHY {#dram-interface}
この章では、FPGAとDRAM間の配線で何が起こるのか、そしてDRAMインターフェースが起動時にチューニングされる必要がある理由を説明します。信号、ストローブ、ボードトポロジー、レベリング手順、終端、基準電圧、そしてコントローラとPHY間のクロックとDFIインターフェースを網羅します。
各セクションの最後には、LiteDRAMでそのメカニズムを実装している部分が示されています。前の章であるDRAMの概要ではコマンドとタイミングについて説明し、初期化とキャリブレーションではBIOSが実行する正確な手順を示しています。
信号 {#iface-signals}
DRAMインターフェースは2つの部分からなります。「コマンドとアドレス」の部分はコントローラからDRAMへ一方向で、ランク内のすべてのチップで共有されます。「データ」の部分は双方向で、「バイトレーン」に分割され、それぞれに独自のストローブがあります。以下の図に信号を示します。
[画像: FPGAとDRAM間の信号。PHYはクロック、コマンド、制御ピンを送信します。データ(DQ、DM)とストローブ(DQS)は両方向で、バイトレーンごとに1つのストローブがあります。]
| 信号 | 方向 | 役割 |
|---|---|---|
| CK, CK# | DRAMへ | 差動クロック; コマンドはその立ち上がりエッジでサンプリングされる |
| CS#, RAS#, CAS#, WE# | DRAMへ | コマンドエンコーディング; ACT_nはDDR4で追加される |
| A, BA, BG | DRAMへ | 行または列アドレス、バンク、バンクグループ(DDR4) |
| CKE | DRAMへ | クロックイネーブル; 電源オフおよびセルフリフレッシュ時はロー |
| ODT | DRAMへ | DRAMのデータピンの終端をオンにする |
| RESET# | DRAMへ | リセット(DDR3以降) |
| DQ | 両方向 | データ、チップあたり4、8、または16 |
| DQS, DQS# | 両方向 | データストローブ、バイトレーンあたり1つの差動ペア(x4チップではニブルあたり) |
| DM | DRAMへ | データマスク、バイトレーンあたり1つ:書き込み中にバイトをマスクする |
バイトレーンは8つのDQ、それらのDQSペア、およびDMで構成されます。各レーンは独自にルーティングされるため、それぞれがわずかに異なる時間に到着する可能性があり、それぞれが個別にチューニングされます。
LiteDRAMでは、DRAMのパッドはプラットフォームファイルからのレコードであり、これらの信号(dq、dqs_p、a、ba、cs_n)にちなんで名付けられたフィールドがあります。PHYはそこからレーンを数えます。litedram/common.pyの2つのヘルパーがパッドを整形します。PHYPadsReducerは一部のレーンのみを保持し、PHYPadsCombinerは個別のコマンドバスを持つチップを1つのコントローラにマージします。
ダブルデータレートとストローブ {#iface-dqs}
SDRメモリはクロックごとに1ワードを転送し、コントローラが送信するクロックの立ち上がりエッジでサンプリングします。DDRメモリはクロックごとに2つのワードを転送し、各エッジで1つずつ転送します。このレートでは、コントローラからのクロックはデータのサンプリングを信頼できません。ボードとチップの遅延が大きすぎるためです。
したがって、データは独自のクロックであるストローブDQSと共に転送されます。データを送信する側がDQSも送信し、受信側はDQSでDQをサンプリングします。これはソース同期インターフェースです。両者は同じパスを移動するため、遅延は相殺されます。以下の図は、DQSがDQとどのように整列されるかを示しています。
書き込み時、コントローラはDQSをDQに対して中央揃えで送信し、そのエッジは各ビットの中央にあります。読み出し時、DRAMはDQSをエッジ揃えでビット遷移上に送信し、受信側はそれを1/4クロック遅延させてサンプリングします。バーストの前には、DQSはプリアンブルのために駆動され、後にはデータを持たないポストアンブルのために駆動されます。
LiteDRAMでは、DDR PHYはFPGAの手段を用いて、書き込みDQSをDQから1/4クロックシフトします。
- Artix-7 PHYは、ターゲットが構築する(
bench/arty.py)クロックsys4x_dqsから90度シフトされたクロックでDQSシリアライザをクロックします。 - 出力遅延を持つPHY(Kintex-7およびVirtex-7 HPバンク、UltraScale)は、DQSを1/4クロック遅延させます。
- LatticeおよびGowin PHYは、FPGAのDQSブロックのシフトされた書き込みクロックを使用します。
読み出し時、PHYは異なります。
- Xilinx PHYはDQSを使用しません。それらは、読み出しレベリングがレーンごとにチューニングする入力遅延を通じて、独自の高速クロックでDQをサンプリングします。
- LatticeおよびGowin PHYは、FPGAのDQSブロックを使用します。これはDQSを90度遅延させ、それを使用してDQをキャプチャし、バーストを見たときに報告します(バースト検出)。
フライバイ・トポロジーとライトレベリング {#iface-flyby}
DDR3およびDDR4は、クロック、コマンド、アドレスピンを、各チップを順番に通過し終端で終わる1つのバスとしてルーティングします。これはフライバイトポロジーです。これにより、高レートでもこれらの負荷の高い信号をクリーンに保てますが、各チップは前のチップよりもわずかに遅れてクロックを受信します。以下の図にそれを示します。
データレーンはポイント・ツー・ポイントであるため、その遅延はクロックに従いません。チップはDQSが自身のCKエッジ(tDQSS)の近くに到着する必要があります。フライバイ・ルーティングでは、最初と最後のチップ間のスキューはクロック期間を超える可能性があるため、各レーンは独自のDQS遅延を必要とします。
ライトレベリングはその遅延を測定します。コントローラはモードレジスタビット(DDR3およびDDR4のMR1ビットA7)でDRAMをライトレベリングモードに設定し、次にDQSパルスを送信します。DRAMは各DQS立ち上がりエッジでCKをサンプリングし、サンプリングされた値をDQで返します。コントローラはDQが0から1に変わるまでDQSをステップごとに遅延させます。これにより、そのチップでのDQSがCKと整列されます。
LiteDRAMでは、PHYはレジスタを通じてライトレベリングを公開します。wlevel_enはモードを有効にし、wlevel_strobeは1つのDQSパルスを送信し、レーンごとの出力遅延はDQSとDQを移動させます。BIOSはスキャンを実行します(liblitedram内のsdram_write_leveling)。
ライトレベリングには出力遅延が必要です。Kintex-7およびVirtex-7のHPバンクのPHYとUltraScale PHYにはそれがあります。Artix-7にはありません。1つの静的なDQSフェーズでは、フライバイメモリのレーンの一部のみがtDQSSを満たします。オプションのCKフェーズシフトモード(DDR3で1:4)は、CKをすべてのレーンに対して移動させます(CKフェーズシフト)。
書き込みレイテンシとDQ-DQSトレーニング {#iface-write-latency}
ライトレベリングは、DQSを1クロック期間内でCKに整列させますが、レーンは丸1クロック早くまたは遅れる可能性があります。その場合、DRAMはバーストを数ワードずらして書き込みます。書き込みレイテンシキャリブレーションは、既知のパターンを書き込み、それを読み戻し、パターンが正しくなるまで各レーンをクロック単位で移動させます。
DQ-DQSトレーニングは、書き込み時にDQをDQSに対して中央揃えにします。各レーンのDQピンの出力遅延をスイープし、各ステップでパターンを書き込み・読み戻し、通過範囲の中央を保持します。これは、読み出し側の動作に依存し、その後読み出しレベリングによってさらに調整されます。
LiteDRAMでは、書き込みレイテンシは書き込みビットスリップ(wdly_dq_bitslip)によって移動され、DQは出力遅延(wdly_dq)によって移動されます。各PHYは、サポートするキャリブレーションをその設定(write_leveling、write_latency_calibration、write_dq_dqs_training、read_leveling)で宣言します。BIOSはそれらのみを実行します。
読み出しレベリング {#iface-read-leveling}
読み出し時、コントローラはデータがいつ到着するかを知りません。DRAMはRDのCLクロック後に応答しますが、ボードとI/Oはレーンごとに異なる遅延を追加します。各レーンには2つの設定を見つける必要があります。1つ目は、高速クロックサイクルで最初のワードを保持する粗い設定、2つ目はビットのどこでサンプリングするかを決定する細かい設定です。
粗い設定はビットスリップです。デシリアライザの出力は、ワードが整列されるまでビット単位でシフトされます。細かい設定は入力遅延で、FPGAによって異なりますが、数百ピコ秒から約100ピコ秒まで(7シリーズで200 MHz基準の場合、78 ps)です。読み出しレベリングはパターンを書き込み、次に各ビットスリップに対して遅延をスイープし、パターンを読み戻します。以下の図は、そのようなスキャンを示しています。
ウィンドウは、遅延ラインを通して見えるデータアイです。広いウィンドウは堅牢なインターフェースを意味し、狭いウィンドウは信号整合性またはクロッキングの問題を示唆します。DDR3およびDDR4は、MPR(多目的レジスタ)から固定パターンを返すこともできるため、読み出し側は何も書き込まれる前にチューニングできます。
DQSでキャプチャするPHYは、もう1つの問題を抱えています。DQSはバースト間では駆動されないため、受信側は読み出し中のみそれに注意を払う必要があります。FPGAのDQSブロックは、このゲートを開き、バースト検出を報告します。これは読み出しレベリングが読み出しウィンドウが正しいことを確認するために使用します。
LiteDRAMでは、各PHYは遅延タップ数とビットスリップ数をその設定(delays、bitslips)で宣言し、レジスタ(LatticeおよびGowin PHYではrdly_dq_inc、rdly_dq_bitslip、burstdet_seen)を通じて公開します。BIOSはスキャンを実行し、レーンとビットスリップごとに1行印刷します。DDR4では、登録済みDIMMとクラムシェルレイアウトを除き、MPRパターンを読み取ります。
終端とドライブ強度 {#iface-odt}
DRAMレートでは、終端されていないラインの終端で信号が反射します。したがって、DRAMはオンダイ終端(ODT)で自身のデータピンを終端します。これは、ODTピンが高のときにオンになる抵抗です。FPGAは、読み出しデータを受信するときに同様の方法で入力終端を行います。
DDR3およびDDR4には2つの終端値があります。RTT_NOMはチップがアイドル状態の場合や別のランクが書き込まれる場合に使用され、RTT_WRはチップ自体が書き込まれている間(ダイナミックODT)に使用されます。DRAMのドライバ強度であるRONは、読み出しデータをどれだけ強く駆動するかを設定します。これら3つすべてがモードレジスタで設定されます。
| 設定 | DDR3デフォルト | DDR4デフォルト | モードレジスタ |
|---|---|---|---|
| RTT_NOM | 60オーム | 40オーム | MR1 |
| RTT_WR | 60オーム | 120オーム | MR2 |
| RON | 34オーム | 34オーム | MR1 |
LiteDRAMでは、テーブルのデフォルト値はlitedram/init.pyで設定されます。PHYはそれをオーバーライドできます(設定内のrtt_nom、rtt_wr、ron)。DRAM DLLオフ、低クロックレート用のDDR3モード(GW5A PHYが提供するdll_off)では、両方の終端が無効になります。
ODTピンはデフォルトで静的に駆動されます。with_dynamic_odt(DDR3、シングルランク)を使用すると、コントローラは書き込みの周りのみODTを上げます。そのため、読み出し中はDRAM終端はオフになります(ダイナミックODT)。FPGA側の終端は、LiteDRAMではなく、プラットフォームファイルのI/O標準の一部です。
ZQキャリブレーション {#iface-zq}
チップのドライバと終端の抵抗は、プロセス、電圧、温度によって変動します。DDR3以降のチップは、ZQピンにある240オームの抵抗に対してこれらをキャリブレーションします。ZQCL(ロングキャリブレーション)は初期化時に一度実行されます。ZQCS(ショートキャリブレーション)は、動作中に時々ドリフトを補正します。
LiteDRAMでは、初期化シーケンスはZQCLで終了し(モードレジスタと電源投入)、リフレッシャはデフォルトで1秒に1回ZQCSを送信します(リフレッシュ)。LPDDR4にはZQCSがありません。初期化時のみLiteDRAMが送信する2つの多目的コマンド(MPC)、スタートとラッチでキャリブレーションします。
基準電圧 {#iface-vref}
データ受信機は、各入力を、ハイレベルとローレベルの中間にある基準電圧VREFと比較します。DDR3では、ボードが専用ピンでVREFを提供します。DDR4はデータピンを電源(疑似オープンドレイン)に終端するため、データスイングは電源の上部に近く、正しい基準は中間ではありません。DRAMはMR6でプログラムされた内部でデータVREFを生成します。
FPGA側では、読み出しデータの受信機にもVREFが必要です。一部のFPGA I/Oバンクは、VREFピンを使用する代わりに、内部で段階的に設定できます。
LiteDRAMでは、DDR4初期化はtCCD_LのみでMR6を書き込み、VREFフィールドをゼロ(範囲1の最初の値、VDDQの60%)のままにします。DRAMデータVREFはトレーニングされません。
UltraScale+ PHYは、HP I/OバンクのFPGA読み出しVREFを設定できます(with_hpio_vref、レジスタrd_vref、コード0から72)。BIOSはそれをスキャンしません。ソフトウェアが書き込まない限り、レジスタはビルド時の値(hpio_vref_tune)を保持します。LiteX issue 2769は、不足しているBIOSスキャンを追跡しています。
クロックと周波数比 {#iface-clocking}
FPGAファブリックはDRAMクロックで実行できません。800 MT/sのDDR3は400 MHzクロックを持ち、ピンあたり800 Mbpsでデータを移動します。したがって、PHYはFPGA I/Oのシリアライザとデシリアライザを使用します。コントローラはDRAMクロックの分数で実行され、サイクルあたり数クロック分のコマンドとデータを移動します。
この分数が周波数比です。1:4の場合、コントローラはDRAMクロックの1/4で実行されます。Arty A7ベンチターゲットは、コントローラを125 MHz、DRAMクロックを500 MHz、DDR3を1000 MT/sで実行します。DDRメモリの場合、データレートはDRAMクロックの2倍です。1:4では、コントローラクロックの8倍になります。
Artix-7 DDR3ターゲットは、ボードのクロックモジュールのPLL(bench/arty.py)によって生成される4つのクロックを必要とします。Kintex-7およびVirtex-7ターゲットはsys4x_dqsを必要としません。それらの出力遅延は代わりにDQSをシフトします。
| クロック | 周波数 | 使用目的 |
|---|---|---|
sys | コントローラクロック | コントローラ、DFI、シリアライザの並列側 |
sys4x | sysの4倍 | シリアライザのシリアル側:CK、コマンド、DQ |
sys4x_dqs | sysの4倍、90度 | DQSシリアライザのシリアル側(Artix-7) |
clk200 | 200 MHz | 入出力遅延の基準(IDELAYCTRL) |
他のファミリーは独自のクロッキングを使用します。ECP5 PHYは、I/Oゲーティングのために2倍クロック、1:4で4倍クロックを使用し、Gowin GW5A PHYはフェーズ数で1:2または1:4を選択します。DDR PHYsは、各ファミリーのクロックを示しています。
DFI、コントローラとPHY間のインターフェース {#iface-dfi}
コントローラとPHYは、DDR PHY Interface仕様にちなんで名付けられたDFIインターフェースで接続されます。これは、コントローラサイクルの各DRAMクロックに対して、1つのコマンドスロットと、そのクロックのデータを運びます。これらのスロットのそれぞれがDFIフェーズです。以下の図は、1:4比率でのフェーズを示しています。
| DFI信号 | 方向 | 内容 |
|---|---|---|
address, bank | PHYへ | 行または列アドレス、バンク(DDR4ではバンクグループも) |
ras_n, cas_n, we_n, cs_n, act_n | PHYへ | コマンドエンコーディング |
cke, odt, reset_n | PHYへ | 制御ピン |
wrdata, wrdata_mask | PHYへ | 書き込みデータとバイトマスク、フェーズあたり2ビート |
wrdata_en | PHYへ | 書き込みデータ有効、書き込みレイテンシと共に送信される |
rddata_en | PHYへ | このフェーズで読み出しが発行された |
rddata, rddata_valid | コントローラへ | 読み出しデータとその有効フラグ |
2つのレイテンシがコマンドをデータに結び付けます。書き込みレイテンシは、WRとコントローラが書き込みデータを提示するサイクルとの間のコントローラサイクルの数です。読み出しレイテンシは、RDと読み出しデータが有効になって戻ってくるサイクルとの間のサイクル数です。どちらもCL、CWL、およびPHYのパイプラインから導き出されます。
コマンドは常にフェーズ0で開始されるわけではありません。PHYは、読み書きを発行するフェーズをコントローラに通知します(rdphase、wrphase)。これにより、バーストのデータが完全なコントローラサイクルを埋めるようになります。
LiteDRAMでは、DFIインターフェースはlitedram/phy/dfi.pyのInterfaceです。DFI仕様の構造、フェーズ、信号名に従いますが、そのバージョンを主張するものではありません。
各PHYは、フェーズ数、コントローラサイクルでのレイテンシ、DRAMクロックでのCLとCWL、およびキャリブレーション機能を備えたPhySettingsを埋めます。DFIRateConverterは、より多くのフェーズとフェーズあたりの狭いデータ幅で比率を上げるためにPHYをラップします。コアアーキテクチャを参照してください。
各FPGAファミリーが提供するもの {#iface-fpga}
各PHYは、FPGAファミリーのI/Oプリミティブから構築されます。以下の表は、LiteDRAM PHYが使用するものをまとめたものです。DDR PHYsは、各ファミリーについて説明しています。
| ファミリー | シリアライザ | 遅延タップ | ビットスリップ | 読み出しキャプチャ |
|---|---|---|---|---|
| Xilinx 7-Series | OSERDESE2, ISERDESE2 | 32 | 8 | 高速クロック、DQごとの入力遅延 |
| Xilinx UltraScale(+) | OSERDESE3, ISERDESE3 | 512 | 8 | 高速クロック、DQごとの入力遅延 |
| Lattice ECP5 | ODDRX2DQA, IDDRX2DQA | 8 | 4 | DQSBUFM, バースト検出 |
| Lattice Nexus | ODDRX2DQ, IDDRX2DQ | 16 | 4 | DQSBUF, バースト検出 |
| Gowin GW2A | OSER4_MEM, IDES4_MEM | 256 | 4 | DQSブロック, バースト検出 |
| Gowin GW5A | OSER4_MEM, IDES4_MEM (1:2), OSER8_MEM, IDES8_MEM (1:4) | 256 | 4 または 8 | DQSブロック, バースト検出 |
7シリーズの入出力遅延は、200 MHzまたは300 MHz、あるいはより高速なスピードグレードでは400 MHzの基準クロックを必要とします。出力遅延はKintex-7およびVirtex-7のHPバンクにのみ存在します。UltraScaleの遅延は時間単位で設定され、en_vtcが設定されている間、FPGAは電圧と温度に対してそれらを補償します。
次へ:BIOS手順については初期化とキャリブレーション、各ファミリーについてはDDR PHYs、スキャンでウィンドウが表示されない場合のデバッグについてはデバッグを参照してください。