FC2カウンター FPGAの部屋 Virtex-6, Spartan-6

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Spartan-6のGTPトランシーバの勉強

Spartan-6 FPGA SP605評価キットでGTPトランシーバを使ってみたい。最初にはサンプルにあるIBRETをやってみて、次にAuroraをインプリメントしてテストしてみたい。シミュレーションもやってみた。

最初に、”Spartan-6 FPGA GTP トランシーバ ユーザー ガイド v2.0 (日本語版)”でSpartan-6のGTPトランシーバを勉強してみることにした。
概要はというと下に引用させていただく。(日本語版はコピペ禁止なので、この英語版の13ページから引用)

• Current Mode Logic (CML) serial drivers/buffers with configurable termination and
voltage swing
• Programmable TX pre-emphasis, linear continuous-time RX equalization
• Support for multiple industry standards with the following line rates:
• 614 Mb/s to 810 Mb/s
• 1.22 Gb/s to 1.62 Gb/s
• 2.45 Gb/ to 3.125 Gb/s
• Optional built-in PCS features, such as 8B/10B encoding, comma alignment, channel
bonding, and clock correction
• Fixed latency modes for minimized, deterministic datapath latency
• Beacon signaling for PCI Express® designs and Out-of-Band signaling including
COM signal support for SATA designs
• Receiver eye scan:
Horizontal eye scan in the time domain for testing purposes


14ページのFigure 1-1: Simplified Spartan-6 FPGA GTP Transceiver Block Diagramを見ると、TX側にはPattern Generator、8B10B Encoderなどが入っているのがわかる。RX側には、Pattern Checker, Comma Dectect and Align, Elastic Buffer, 8B10B Decoderなどが入っていて、RXの方が複雑な感じがする。

”Figure 1-2: GTP Transceiver within the Spartan-6 LX45T FPGA”によると、Spartan-6 LX45Tには、2つのGTPA1_DUAL
Tileがあって、2つのGTPトランシーバが入っているそうだ。ということは合計4つのGTPトランシーバがあることになる。下に、15ページのFigure 1-2を引用する。
GTP_Tran_1_100629.png

後は、複雑なポート及び属性について書いてあるが、これは読み切れない。ただ、LOOPBACKポートによって近端2種類、遠端2種類のループバックができる。今回は自分のところで折り返しなので、近端の2種類のみしか使えない。(日本語版の67ページ、英語版の63ページ)

色々、TX, RXについて詳しい情報が書いてあるが、あとは、Auroraのマニュアルを読んで、Auroraマニュアルでわからないところを、このマニュアルで調べることにする。読んでいると大変。。。でもクロックをどう回すか?という部分は読む必要があるか?それともAurora IPをつくるとそれも入っているのだろうか?

(2010/06/30:追加)
クロックは、外部入力端子やGCLKなどから入れることができるようだ。2つのGTP1_DUALタイルに同じクロックリソースからも入れられるみたいだし、Virtex-2Proのときよりもクロックの自由度が確実に上がっていると思う。その中でも推奨があるかもしれないから注意が必要だ。
SP605ではPCIeのクロックはカードエッジからのクロック (100MHz?) を ICS874001 でジッタを低減して、250MHzにして、MGTREFCLK0に入れている。
  1. 2010年06月29日 05:19 |
  2. Virtex-6, Spartan-6
  3. | トラックバック:0
  4. | コメント:0

Spartan-6のMCBの動作3(Readポート)

Spartan-6のMCBの動作2(コマンドポートとWriteポート)”で、MCBのコマンドポートとWriteポートの構成と操作方法を見てきたが、今度はReadポートの構成と操作方法を見ていくことにする。

Readポートのexsample_top.vのmemc3_wrapperのポート接続を下に示す。

.p0_rd_clk (c3_clk0),
.p0_rd_en (c3_p0_rd_en),
.p0_rd_data (c3_p0_rd_data),
.p0_rd_full (c3_p0_rd_full),
.p0_rd_empty (c3_p0_rd_empty),
.p0_rd_count (c3_p0_rd_count),
.p0_rd_overflow (c3_p0_rd_overflow),
.p0_rd_error (c3_p0_rd_error),


p0_rd_emptyが0の時に有効なReadデータがp0_rd_dataに出ているので、ユーザー回路がp0_rd_en が1にして、p0_rd_dataを読み込む。p0_rd_dataは現在の構成では128ビット幅。
p0_rd_countは7ビット幅のReadデータカウントで64まで。
p0_rd_overflow はReadデータ用のFIFOにReadデータの十分な格納領域がないなどで、Readデータが無くなってしまったときに1になる。
p0_rd_error は、Read用のポインタがおかしくなったときに1になる。

現在のシミュレーション波形でDDR3 SDRAMのRead部分を下に示す。
MIG_OP_4_100430.png

上の図では図中に3つのReadコマンドが見える。最初のコマンドは、”Spartan-6のMCBの動作2(コマンドポートとWriteポート)”で見たWriteコマンドの番地をReadしている。mcb3_dram_dq にそのデータが見える。
これがMCBで読み込まれて、ユーザー側にどのように出てくるかを、シミュレーション波形で見てみよう。
MIG_OP_5_100430.png

p0_rd_empty が1から0になった時に、Readデータが用意されている。すでにp0_rd_data[127:0] に"00000400000004000000040000000400"が出力されている。po_rd_clk に同期して、ユーザー回路がp0_rd_en が1になり、次のpo_rd_clk に同期して次のp0_rd_data[127:0] が出力される。

最後にReadのレイテンシを測定した。Readコマンドが発行されてから、p0_rd_emptyが0になるまでの時間は下のシミュレーション結果から、約46nsec だった。
MIG_OP_6_100430.png
  1. 2010年04月30日 21:57 |
  2. Virtex-6, Spartan-6
  3. | トラックバック:0
  4. | コメント:0

Spartan-6のMCBの動作2(コマンドポートとWriteポート)

MCBでユーザーデータをWriteする場合について勉強する。

MCBのユーザーデータをWrite/Readするには、コマンドを入れる必要がある。コマンドのexsample_top.vのmemc3_wrapperのポート接続を下に示す。

.p0_cmd_clk (c3_clk0),
.p0_cmd_en (c3_p0_cmd_en),
.p0_cmd_instr (c3_p0_cmd_instr),
.p0_cmd_bl (c3_p0_cmd_bl),
.p0_cmd_byte_addr (c3_p0_cmd_byte_addr),
.p0_cmd_empty (c3_p0_cmd_empty),
.p0_cmd_full (c3_p0_cmd_full),


信号名の最初のP0はPort0を表す(と思う)。
p0_cmd_enはコマンドのイネーブルで1でコマンドが有効となる。
p0_cmd_instrは3ビット幅で000がWrite、001がRead、010がオートプリチャージ付きのWrite、011がオートプリチャージ付きのRead、1XXがRefreshを実行する。
p0_cmd_blは6ビット幅のバースト長で、ユーザーのデータビット幅でのWrite/Readするデータの個数を表す。設定された数字+1のデータを転送する。例えば、000011を設定すると4個の128ビット幅のデータをRead/Writeする。4 X 16Bytes = 64Bytes。
p0_cmd_byte_addrは30ビット幅のDDR3 SDRAMメモリのアドレスで、128ビット幅のデータバスの場合は、下の4ビットが必ず0000となる。
p0_cmd_emptyとp0_cmd_fullは、コマンドのFIFOのemptyとfullだ。
コマンドのFIFOの深度は4だそうだ。4個のコマンドをFIFOに積むことができる。

Writeコマンドを発行する場合は、十分な量のデータをWriteデータのFIFOに積んでからWriteのコマンドを入れろと書いてある。実際にこのトラフィック・ジェネレータのサンプルではWriteデータをすべてFIFOに積んでからWriteコマンドを入れている。
Readコマンドを発行する場合は、Readデータを格納するFIFOに十分な空きがあることを確認してからReadコマンドを発行しろと書いてある。この辺は一般的な注意だろう。要はunderflow, overflowしないようにデータを出し入れすれば良いと思うが、タイミングによってはunderflow, overflowが起こる可能性があるので、上に示したように安全策をとれば安全だと思う。(当たり前!!!)

コマンドのタイミングチャートを示す前に、Writeのデータポートについて説明する。Writeのデータポートのexsample_top.vのmemc3_wrapperのポート接続を下に示す。

.p0_wr_clk (c3_clk0),
.p0_wr_en (c3_p0_wr_en),
.p0_wr_mask (c3_p0_wr_mask),
.p0_wr_data (c3_p0_wr_data),
.p0_wr_full (c3_p0_wr_full),
.p0_wr_empty (c3_p0_wr_empty),
.p0_wr_count (c3_p0_wr_count),
.p0_wr_underrun (c3_p0_wr_underrun),
.p0_wr_error (c3_p0_wr_error),


p0_wr_enが1の時にp0_wr_mask、p0_wr_dataがWriteデータのFIFOに積まれる。WriteデータのFIFOは64深度のFIFOとなっていて、p0_wr_countも7ビット長のデータカウンタになっている。
p0_wr_maskはマスクビットで1の時にWriteデータがマスクされる。データ長が128ビットなので、マスクビット長は16ビットとなる。
p0_wr_dataは言わずと知れた128ビット(このコンフィギュレーションでは)のWriteデータ。
p0_wr_underrunは、WriteデータのFIFOのデータが十分になくてunderflowしたことを示す。
p0_wr_errorはunderrunなどで、FIFOのポインタが不正になってしまった時だろうか?

トラフィック・ジェネレータサンプルでのMCBへのWriteデータのFIFOへの最初のWriteを示す。
MIG_OP_2_100429.png

カーソルの位置で、p0_wr_enが1になり、その時のp0_wr_dataとp0_wr_maskをWriteデータのFIFOに書き込み始めている。それにとなってp0_wr_emptyが0になり、p0_wr_countのカウントが増えている。
このようにデータをWriteデータのFIFOにWriteしてから、Writeコマンドを入れている。次にWriteコマンドのシミュレーション波形を示す。
MIG_OP_3_100429.png

p0_cmd_enが1になった時が、コマンドをコマンドのFIFOに書き込む時となっている。p0_cmd_instrは、000なのでWriteコマンドとなる。p0_cmd_blは 3F なので、64個のデータを書き込む。Writeコマンドを発行する前に、64深度のWriteデータのFIFOはFULLになっていて、すべてのWriteデータの準備ができている。p0_cmd_byte_addrは 00000400 だ。

このユーザー回路からのWriteに対応するDDR3 SDRAMへのWrite波形を下に示す。最初のWriteコマンドのアドレスは0200だった。16ビットアドレスなのでp0_cmd_byte_addr のアドレスは1ビット右にシフトされている。データを見ると最初にWriteデータのFIFOに書いたデータが出力されているのが分かる。(あたり前田の○ラッカー(これが分かる人はほとんどいないだろう。。。古すぎ。。。))
SP605_MIG_ISIm_9_100426.png

最後に、p0_cmd_en が1になってから、Writeコマンドを発行するまでの時間は、約46nsec だった。
MIG_OP_7_100430.png
  1. 2010年04月29日 07:49 |
  2. Virtex-6, Spartan-6
  3. | トラックバック:0
  4. | コメント:0

Spartan-6のMCBの動作1(スタートアップ処理)

UG388(v2.1)(Spartan-6 FPGA Memory Controller User Guide)を元にMCBの動作を勉強していくことにする。

43ページのMCB Operation のStartup Sequence から、見て行く。
まず、UG388(v2.1)(Spartan-6 FPGA Memory Controller User Guide)の44ページの”Figure 4-1: MCB Startup Sequence”を下に引用する。
MIG_OP_1_100428.png

これによると最初にFPGAのコンフィギュレーションをして、PLLがロックしてから、Phase 1の入力終端のキャリブレーションを行うことになっているが、これは、”SP605用のMCBをMIGで生成する”の13で無効にしているのでやらないようだ。
SP605_MIG_13_100421.png

上の図で、Un-calibrated Input Terminationをチェックしている。

次はMode Registersをロードしている。これは、”SP605のMCBの動作を確認する1(ISimでシミュレーション)”で確認した。

その次は、Phase 2 のDQSのセンタリング・キャリブレーションを行うようだ。これは、ユーザーズ・ガイドによると、Readのキャプチャ・ウインドウ用のキャリブレーションで、Read時にDQSはReadデータと一緒にDDR3 SDRAMから出てくるのだが、Readデータの真ん中にDQSのエッジがくるようにキャリブレーションを行う。(ユーザーズ・ガイドの46ページのPhase 2: DQS Centeringを参照のこと)

その後、通常動作モードに移行する。通常動作モードにいるときに、電圧変動や温度のでDQに対するDQSの遅延を保証するためにContinuous DQS Tuning を行うようだ。(ユーザーズ・ガイドの46ページのPhase 3: Continuous DQS Tuningを参照のこと)
Continuous DQS Tuning を行うかどうかは、どうやら、ユーザーズ・ガイド25ページのコントローラーの属性のC_MC_CALIBRATION_MODE で決定されるらしい。シミュレータでC_MC_CALIBRATION_MODEはC_MC_CALIBRATION_MODE[87:0] となっていて、値が入っているが、どこで定義されていて、どのような意味かは特定していない。
  1. 2010年04月28日 04:55 |
  2. Virtex-6, Spartan-6
  3. | トラックバック:0
  4. | コメント:0

SP605のMCBの動作を確認する2(ISimでシミュレーション)

SP605のMCBの動作を確認する1(ISimでシミュレーション)”で初期化部分のパラメータを確認したが、今度はWrite, Read部分のパラメータを確認する。

ZQ CALIBRATION LONGコマンドからBank ACTIVATEコマンドまでは、約3.8usecだった。
SP605_MIG_ISIm_8_100425.png

Bank ACTIVATEコマンドの次の2つ目のWRITEコマンドが実行するまでのDDR3 SDRAMモデルが出力した表示を下に示す。

sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 9622501.0 ps INFO: Activate bank 0 row 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 9637501.0 ps INFO: Write bank 0 col 200, auto precharge 0
sim_tb_top.\MEM_INST3.u_mem_c3 .main: at time 9645001.0 ps INFO: Sync On Die Termination Rtt_NOM = 60 Ohm
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 9647501.0 ps INFO: Write bank 0 col 208, auto precharge 0
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9651251.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 00000200 data = 0400
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9652501.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 00000201 data = 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9653751.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 00000202 data = 0400
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9655001.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 00000203 data = 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9656251.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 00000204 data = 0400
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9657501.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 00000205 data = 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 9657501.0 ps INFO: Write bank 0 col 210, auto precharge 0
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9658751.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 00000206 data = 0400
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9660001.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 00000207 data = 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9661251.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 00000208 data = 0410
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9662501.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 00000209 data = 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9663751.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 0000020a data = 0410
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9665001.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 0000020b data = 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9666251.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 0000020c data = 0410
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 9667501.0 ps INFO: WRITE @ DQS= bank = 0 row = 0000 col = 0000020d data = 0000


上の図でmcb3_dram_odt がWriteの時に1になって、ODTが入っている(9645001.0 ps INFO: Sync On Die Termination Rtt_NOM = 60 Ohm)。
SP605のMCBの動作を確認する1(ISimでシミュレーション)”でWrite Latency = 5に設定したはずだが、シミュレーション波形で見てもWrite Latency = 5だった。(当たり前) 12.62nsec / 2.5nsec ≒ 5(カーソルでクロックが違っているので値が少し違っている)
SP605_MIG_ISIm_9_100426.png

Readの場合を見てみよう。CAS Latency = 6 と設定されていた。下のタイミングチャートを見ると15nsec = 2.5nsec =6 となっている。
SP605_MIG_ISIm_10_100426.png

下に、READコマンド2つ分のDDR3 SDRAMモデルが出力した表示を下に示す。

sim_tb_top.\MEM_INST3.u_mem_c3 .main: at time 13102501.0 ps INFO: Sync On Die Termination Rtt_NOM = 0 Ohm
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 13105001.0 ps INFO: Read bank 0 col 200, auto precharge 0
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 13115001.0 ps INFO: Read bank 0 col 208, auto precharge 0
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13118751.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 00000200 data = 0400
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13120001.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 00000201 data = 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13121251.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 00000202 data = 0400
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13122501.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 00000203 data = 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13123751.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 00000204 data = 0400
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13125001.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 00000205 data = 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 13125001.0 ps INFO: Read bank 0 col 210, auto precharge 0
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13126251.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 00000206 data = 0400
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13127501.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 00000207 data = 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13128751.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 00000208 data = 0410
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13130001.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 00000209 data = 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13131251.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 0000020a data = 0410
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13132501.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 0000020b data = 0000
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13133751.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 0000020c data = 0410
sim_tb_top.\MEM_INST3.u_mem_c3 .data_task: at time 13135001.0 ps INFO: READ @ DQS= bank = 0 row = 0000 col = 0000020d data = 0000


1つ目のReadコマンドが入ってからデータが出る前に、2つ目のReadコマンドが出力されている。その後に1つ目のデータが出力されている。

これでMCBがDDR3 SDRAMをコントロールする動作は大体わかったので、MCBのユーザー側のインターフェースを見て行こうと思う。
  1. 2010年04月26日 05:51 |
  2. Virtex-6, Spartan-6
  3. | トラックバック:0
  4. | コメント:0

SP605のMCBの動作を確認する1(ISimでシミュレーション)

SP605のMCBをISimでシミュレーションする1”の続き。続きなんだけど、MCBのシミュレーション時の動作を見るので、タイトルと記事のカテゴリーを変えた。

さて、このシミュレーションでは2回、DDR3 SDRAMのリセットがかかっているが、2度目のリセット後を見てみよう。Micron社のDDR3 SDRAMモデルは色々なメッセージを出してくれるので便利だ。そのうちの初期化部分のメッセージを下に示す。なお、Micron社のDDR3 SDRAMデータシートを参照のこと。

sim_tb_top.\MEM_INST3.u_mem_c3 .reset at time 5471251.0 ps WARNING: 200 us is required before RST_N goes inactive.
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task at time 5622501.0 ps WARNING: 500 us is required after RST_N goes inactive before CKE goes active.
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5755001.0 ps INFO: Load Mode 2
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5755001.0 ps INFO: Load Mode 2 CAS Write Latency = 5
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5755001.0 ps INFO: Load Mode 2 Auto Self Refresh = Enabled
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5755001.0 ps WARNING: Load Mode 2 Auto Self Refresh is not modeled
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5755001.0 ps INFO: Load Mode 2 Self Refresh Temperature = Normal
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5755001.0 ps INFO: Load Mode 2 Dynamic ODT = Disabled
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5765001.0 ps INFO: Load Mode 3
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5765001.0 ps INFO: Load Mode 3 MultiPurpose Register Select = Pre-defined pattern
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5765001.0 ps INFO: Load Mode 3 MultiPurpose Register Enable = Disabled
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5775001.0 ps INFO: Load Mode 1
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5775001.0 ps INFO: Load Mode 1 DLL Enable = Enabled
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5775001.0 ps INFO: Load Mode 1 Output Drive Strength = 40 Ohm
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5775001.0 ps INFO: Load Mode 1 ODT Rtt = 60 Ohm
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5775001.0 ps INFO: Load Mode 1 Additive Latency = 0
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5775001.0 ps INFO: Load Mode 1 Write Levelization = Disabled
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5775001.0 ps INFO: Load Mode 1 TDQS Enable = Disabled
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5775001.0 ps INFO: Load Mode 1 Qoff = Enabled
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5785001.0 ps INFO: Load Mode 0
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5785001.0 ps INFO: Load Mode 0 Burst Length = 8
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5785001.0 ps INFO: Load Mode 0 Burst Order = Sequential
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5785001.0 ps INFO: Load Mode 0 CAS Latency = 6
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5785001.0 ps INFO: Load Mode 0 DLL Reset = Reset DLL
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5785001.0 ps INFO: Load Mode 0 Write Recovery = 6
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5785001.0 ps INFO: Load Mode 0 Power Down Mode = DLL off
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5817501.0 ps INFO: ZQ long = 1
sim_tb_top.\MEM_INST3.u_mem_c3 .cmd_task: at time 5817501.0 ps INFO: Initialization Sequence is complete


”sim_tb_top.\MEM_INST3.u_mem_c3 .reset at time 5471251.0 ps WARNING: 200 us is required before RST_N goes inactive.”は、RST_NのLOWの時間が規格で必要とされる200usecよりも小さいと言っている。これは、シミュレーションの時のみ、見やすいように縮めているためかもしれない。シミュレーションでの測定値は、117.5nsec。
SP605_MIG_ISIm_6_100425.png

次に”WARNING: 500 us is required after RST_N goes inactive before CKE goes active.”はRST_Nが1になった跡で、CKEが1にするに500nsec必要だが、それを満たしていないと言ってる。シミュレーションでの測定値は、150nsec。
その後、132.5nsec後から、4つのMODE REGISTER SETコマンドと1つのZQ CALIBRATION LONGコマンドを発行している。
SP605_MIG_ISIm_7_100425.png

最初がMode Register 2(MR2), MR3, MR1(DLL Enable), MR0(DLL RESET) の順番でMRが書き込まれる。MRの番号はBank Addressの値で決まる。

SP605のMCBをISimでシミュレーションする1”の下に図に設定された内容を上のメッセージで確認することができる。”Output Drive Strength = 40 Ohm、ODT Rtt = 60 Ohm、Auto Self Refresh = Enabled、Self Refresh Temperature = Normal、Dynamic ODT = Disabled”。
SP605_MIG_10_100421.png

シミュレーションでは、特に遅延を合わせるためのトレーニング・シーケンスをしているような様子は見えない?これで大丈夫なのだろうか?もしかして、シミュレーションのときだけはトレーニング・シーケンスなしになるのだろうか?
  1. 2010年04月25日 07:35 |
  2. Virtex-6, Spartan-6
  3. | トラックバック:0
  4. | コメント:0

Spartan-6のMemory Contoller Block(MCB)の勉強1

Spartan-6 FPGA メモリ コントローラ ユーザー ガイド (英語版)”で、Memory Contoller Block(MCB)の勉強をすることにした。

まずは仕様を下に示す。”Spartan-6 FPGA メモリ コントローラ ユーザー ガイド (英語版)”より引用。

1. DDR, DDR2, DDR3, and LPDDR (Mobile DDR)サポート
2. 800Mbps(400MHz DDR)までサポート
3. パッケージに最大4つのMCBが入っている。それぞれのMCBコアは以下の特徴がある。
 ・4、8、16ビット長の1つのメモリを制御する。
 ・メモリのサイズとしては4Gbitまで。
 ・最大12.8Gbit/secの性能。(800MHz X 16bit = 12,800Mbit/sec = 12.8Gbit/sec)
4. MCBはユーザーロジックからマルチポートのメモリ・コントローラとして使うことができる。
 ・1ポートから6ポートまで設定できる。
 ・データポートを32、64、128ビットのバス幅に設定できる。
 ・2つの両方向ポートと4つの片方向ポートがある。
5. 8個までのバンクを同時に開くことが出来る。(これは凄い、私の作ったコントローラは1つのバンクしか開かない、でもプリチャージは自分で管理するのかな?)
6. ハードマクロでコントローラ、PHYが内蔵されている。
7. それぞれのMCBで使用するピン配置は決定されている。(これも性能を取ったらそうなるだろう?)
8. メモリデバイスのパラメータは設定可能。
 ・ドライバのドライブ強度
 ・On-Die Termination(ODT)
 ・CAS Latency
 ・Self refresh
 ・リフレッシュ間隔
 ・Write recovery time
9. Readの時のDQSとDQの自動遅延キャリブレーション
10. FPGAon-chip input terminationのオプションの自動キャリブレーション
11. COER Generator とEDKでサポート
 ・MIGでサポート
 ・EDKからはマルチポートのメモリ・コントローラ(MPMC)IPとしてサポート


下に、”Spartan-6 FPGA メモリ コントローラ ユーザー ガイド (英語版)”の11ページの Figure 1-1: Spartan-6 FPGA Memory Controller Block (IP Wrapper View) を引用する。
MCB_1_100420.png

上の図を見るとわかるように、6つのコマンドFIFOと6つの両方向または片方向のデータポートがある。アービタやコントローラ、データパス、PHY、キャリブレーションロジックなどがある。

DDRの最大データレートは400Mbits/sec、DDR2とDDR3は800Mbits/sec、LPDDRは400Mbis/sec。

メモリ・コントローラのアトリビュートとポートはVHDLのコンポーネントを見るとよくわかる。unisim_VCOMP.vhdのMCBのコンポーネント宣言を下に引用する。

component MCB
  generic (
     ARB_NUM_TIME_SLOTS : integer := 12;
     ARB_TIME_SLOT_0 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_1 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_10 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_11 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_2 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_3 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_4 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_5 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_6 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_7 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_8 : bit_vector := "111111111111111111";
     ARB_TIME_SLOT_9 : bit_vector := "111111111111111111";
     CAL_BA : bit_vector := X"0";
     CAL_BYPASS : string := "YES";
     CAL_CA : bit_vector := X"000";
     CAL_CALIBRATION_MODE : string := "NOCALIBRATION";
     CAL_CLK_DIV : integer := 1;
     CAL_DELAY : string := "QUARTER";
     CAL_RA : bit_vector := X"0000";
     MEM_ADDR_ORDER : string := "BANK_ROW_COLUMN";
     MEM_BA_SIZE : integer := 3;
     MEM_BURST_LEN : integer := 8;
     MEM_CAS_LATENCY : integer := 4;
     MEM_CA_SIZE : integer := 11;
     MEM_DDR1_2_ODS : string := "FULL";
     MEM_DDR2_3_HIGH_TEMP_SR : string := "NORMAL";
     MEM_DDR2_3_PA_SR : string := "FULL";
     MEM_DDR2_ADD_LATENCY : integer := 0;
     MEM_DDR2_DIFF_DQS_EN : string := "YES";
     MEM_DDR2_RTT : string := "50OHMS";
     MEM_DDR2_WRT_RECOVERY : integer := 4;
     MEM_DDR3_ADD_LATENCY : string := "OFF";
     MEM_DDR3_AUTO_SR : string := "ENABLED";
     MEM_DDR3_CAS_LATENCY : integer := 7;
     MEM_DDR3_CAS_WR_LATENCY : integer := 5;
     MEM_DDR3_DYN_WRT_ODT : string := "OFF";
     MEM_DDR3_ODS : string := "DIV7";
     MEM_DDR3_RTT : string := "DIV2";
     MEM_DDR3_WRT_RECOVERY : integer := 7;
     MEM_MDDR_ODS : string := "FULL";
     MEM_MOBILE_PA_SR : string := "FULL";
     MEM_MOBILE_TC_SR : integer := 0;
     MEM_RAS_VAL : integer := 0;
     MEM_RA_SIZE : integer := 13;
     MEM_RCD_VAL : integer := 1;
     MEM_REFI_VAL : integer := 0;
     MEM_RFC_VAL : integer := 0;
     MEM_RP_VAL : integer := 0;
     MEM_RTP_VAL : integer := 0;
     MEM_TYPE : string := "DDR3";
     MEM_WIDTH : integer := 4;
     MEM_WR_VAL : integer := 0;
     MEM_WTR_VAL : integer := 3;
     PORT_CONFIG : string := "B32_B32_B32_B32"
  );
  port (
     ADDR : out std_logic_vector(14 downto 0);
     BA : out std_logic_vector(2 downto 0);
     CAS : out std_ulogic;
     CKE : out std_ulogic;
     DQIOWEN0 : out std_ulogic;
     DQON : out std_logic_vector(15 downto 0);
     DQOP : out std_logic_vector(15 downto 0);
     DQSIOWEN90N : out std_ulogic;
     DQSIOWEN90P : out std_ulogic;
     IOIDRPADD : out std_ulogic;
     IOIDRPADDR : out std_logic_vector(4 downto 0);
     IOIDRPBROADCAST : out std_ulogic;
     IOIDRPCLK : out std_ulogic;
     IOIDRPCS : out std_ulogic;
     IOIDRPSDO : out std_ulogic;
     IOIDRPTRAIN : out std_ulogic;
     IOIDRPUPDATE : out std_ulogic;
     LDMN : out std_ulogic;
     LDMP : out std_ulogic;
     ODT : out std_ulogic;
     P0CMDEMPTY : out std_ulogic;
     P0CMDFULL : out std_ulogic;
     P0RDCOUNT : out std_logic_vector(6 downto 0);
     P0RDDATA : out std_logic_vector(31 downto 0);
     P0RDEMPTY : out std_ulogic;
     P0RDERROR : out std_ulogic;
     P0RDFULL : out std_ulogic;
     P0RDOVERFLOW : out std_ulogic;
     P0WRCOUNT : out std_logic_vector(6 downto 0);
     P0WREMPTY : out std_ulogic;
     P0WRERROR : out std_ulogic;
     P0WRFULL : out std_ulogic;
     P0WRUNDERRUN : out std_ulogic;
     P1CMDEMPTY : out std_ulogic;
     P1CMDFULL : out std_ulogic;
     P1RDCOUNT : out std_logic_vector(6 downto 0);
     P1RDDATA : out std_logic_vector(31 downto 0);
     P1RDEMPTY : out std_ulogic;
     P1RDERROR : out std_ulogic;
     P1RDFULL : out std_ulogic;
     P1RDOVERFLOW : out std_ulogic;
     P1WRCOUNT : out std_logic_vector(6 downto 0);
     P1WREMPTY : out std_ulogic;
     P1WRERROR : out std_ulogic;
     P1WRFULL : out std_ulogic;
     P1WRUNDERRUN : out std_ulogic;
     P2CMDEMPTY : out std_ulogic;
     P2CMDFULL : out std_ulogic;
     P2COUNT : out std_logic_vector(6 downto 0);
     P2EMPTY : out std_ulogic;
     P2ERROR : out std_ulogic;
     P2FULL : out std_ulogic;
     P2RDDATA : out std_logic_vector(31 downto 0);
     P2RDOVERFLOW : out std_ulogic;
     P2WRUNDERRUN : out std_ulogic;
     P3CMDEMPTY : out std_ulogic;
     P3CMDFULL : out std_ulogic;
     P3COUNT : out std_logic_vector(6 downto 0);
     P3EMPTY : out std_ulogic;
     P3ERROR : out std_ulogic;
     P3FULL : out std_ulogic;
     P3RDDATA : out std_logic_vector(31 downto 0);
     P3RDOVERFLOW : out std_ulogic;
     P3WRUNDERRUN : out std_ulogic;
     P4CMDEMPTY : out std_ulogic;
     P4CMDFULL : out std_ulogic;
     P4COUNT : out std_logic_vector(6 downto 0);
     P4EMPTY : out std_ulogic;
     P4ERROR : out std_ulogic;
     P4FULL : out std_ulogic;
     P4RDDATA : out std_logic_vector(31 downto 0);
     P4RDOVERFLOW : out std_ulogic;
     P4WRUNDERRUN : out std_ulogic;
     P5CMDEMPTY : out std_ulogic;
     P5CMDFULL : out std_ulogic;
     P5COUNT : out std_logic_vector(6 downto 0);
     P5EMPTY : out std_ulogic;
     P5ERROR : out std_ulogic;
     P5FULL : out std_ulogic;
     P5RDDATA : out std_logic_vector(31 downto 0);
     P5RDOVERFLOW : out std_ulogic;
     P5WRUNDERRUN : out std_ulogic;
     RAS : out std_ulogic;
     RST : out std_ulogic;
     SELFREFRESHMODE : out std_ulogic;
     STATUS : out std_logic_vector(31 downto 0);
     UDMN : out std_ulogic;
     UDMP : out std_ulogic;
     UOCALSTART : out std_ulogic;
     UOCMDREADYIN : out std_ulogic;
     UODATA : out std_logic_vector(7 downto 0);
     UODATAVALID : out std_ulogic;
     UODONECAL : out std_ulogic;
     UOREFRSHFLAG : out std_ulogic;
     UOSDO : out std_ulogic;
     WE : out std_ulogic;
     DQI : in std_logic_vector(15 downto 0);
     DQSIOIN : in std_ulogic;
     DQSIOIP : in std_ulogic;
     IOIDRPSDI : in std_ulogic;
     P0ARBEN : in std_ulogic;
     P0CMDBA : in std_logic_vector(2 downto 0);
     P0CMDBL : in std_logic_vector(5 downto 0);
     P0CMDCA : in std_logic_vector(11 downto 0);
     P0CMDCLK : in std_ulogic;
     P0CMDEN : in std_ulogic;
     P0CMDINSTR : in std_logic_vector(2 downto 0);
     P0CMDRA : in std_logic_vector(14 downto 0);
     P0RDCLK : in std_ulogic;
     P0RDEN : in std_ulogic;
     P0RWRMASK : in std_logic_vector(3 downto 0);
     P0WRCLK : in std_ulogic;
     P0WRDATA : in std_logic_vector(31 downto 0);
     P0WREN : in std_ulogic;
     P1ARBEN : in std_ulogic;
     P1CMDBA : in std_logic_vector(2 downto 0);
     P1CMDBL : in std_logic_vector(5 downto 0);
     P1CMDCA : in std_logic_vector(11 downto 0);
     P1CMDCLK : in std_ulogic;
     P1CMDEN : in std_ulogic;
     P1CMDINSTR : in std_logic_vector(2 downto 0);
     P1CMDRA : in std_logic_vector(14 downto 0);
     P1RDCLK : in std_ulogic;
     P1RDEN : in std_ulogic;
     P1RWRMASK : in std_logic_vector(3 downto 0);
     P1WRCLK : in std_ulogic;
     P1WRDATA : in std_logic_vector(31 downto 0);
     P1WREN : in std_ulogic;
     P2ARBEN : in std_ulogic;
     P2CLK : in std_ulogic;
     P2CMDBA : in std_logic_vector(2 downto 0);
     P2CMDBL : in std_logic_vector(5 downto 0);
     P2CMDCA : in std_logic_vector(11 downto 0);
     P2CMDCLK : in std_ulogic;
     P2CMDEN : in std_ulogic;
     P2CMDINSTR : in std_logic_vector(2 downto 0);
     P2CMDRA : in std_logic_vector(14 downto 0);
     P2EN : in std_ulogic;
     P2WRDATA : in std_logic_vector(31 downto 0);
     P2WRMASK : in std_logic_vector(3 downto 0);
     P3ARBEN : in std_ulogic;
     P3CLK : in std_ulogic;
     P3CMDBA : in std_logic_vector(2 downto 0);
     P3CMDBL : in std_logic_vector(5 downto 0);
     P3CMDCA : in std_logic_vector(11 downto 0);
     P3CMDCLK : in std_ulogic;
     P3CMDEN : in std_ulogic;
     P3CMDINSTR : in std_logic_vector(2 downto 0);
     P3CMDRA : in std_logic_vector(14 downto 0);
     P3EN : in std_ulogic;
     P3WRDATA : in std_logic_vector(31 downto 0);
     P3WRMASK : in std_logic_vector(3 downto 0);
     P4ARBEN : in std_ulogic;
     P4CLK : in std_ulogic;
     P4CMDBA : in std_logic_vector(2 downto 0);
     P4CMDBL : in std_logic_vector(5 downto 0);
     P4CMDCA : in std_logic_vector(11 downto 0);
     P4CMDCLK : in std_ulogic;
     P4CMDEN : in std_ulogic;
     P4CMDINSTR : in std_logic_vector(2 downto 0);
     P4CMDRA : in std_logic_vector(14 downto 0);
     P4EN : in std_ulogic;
     P4WRDATA : in std_logic_vector(31 downto 0);
     P4WRMASK : in std_logic_vector(3 downto 0);
     P5ARBEN : in std_ulogic;
     P5CLK : in std_ulogic;
     P5CMDBA : in std_logic_vector(2 downto 0);
     P5CMDBL : in std_logic_vector(5 downto 0);
     P5CMDCA : in std_logic_vector(11 downto 0);
     P5CMDCLK : in std_ulogic;
     P5CMDEN : in std_ulogic;
     P5CMDINSTR : in std_logic_vector(2 downto 0);
     P5CMDRA : in std_logic_vector(14 downto 0);
     P5EN : in std_ulogic;
     P5WRDATA : in std_logic_vector(31 downto 0);
     P5WRMASK : in std_logic_vector(3 downto 0);
     PLLCE : in std_logic_vector(1 downto 0);
     PLLCLK : in std_logic_vector(1 downto 0);
     PLLLOCK : in std_ulogic;
     RECAL : in std_ulogic;
     SELFREFRESHENTER : in std_ulogic;
     SYSRST : in std_ulogic;
     UDQSIOIN : in std_ulogic;
     UDQSIOIP : in std_ulogic;
     UIADD : in std_ulogic;
     UIADDR : in std_logic_vector(4 downto 0);
     UIBROADCAST : in std_ulogic;
     UICLK : in std_ulogic;
     UICMD : in std_ulogic;
     UICMDEN : in std_ulogic;
     UICMDIN : in std_ulogic;
     UICS : in std_ulogic;
     UIDONECAL : in std_ulogic;
     UIDQCOUNT : in std_logic_vector(3 downto 0);
     UIDQLOWERDEC : in std_ulogic;
     UIDQLOWERINC : in std_ulogic;
     UIDQUPPERDEC : in std_ulogic;
     UIDQUPPERINC : in std_ulogic;
     UIDRPUPDATE : in std_ulogic;
     UILDQSDEC : in std_ulogic;
     UILDQSINC : in std_ulogic;
     UIREAD : in std_ulogic;
     UISDI : in std_ulogic;
     UIUDQSDEC : in std_ulogic;
     UIUDQSINC : in std_ulogic
  );
end component;


とてもじゃないが、プリミティブで使う気になれない。。。(詳しい機能は”Spartan-6 FPGA メモリ コントローラ ユーザー ガイド (英語版)”を参照のこと)やはりCORE GeneratorからMIGを起動して使うのが良いと思う。
上のコンポーネント宣言を見ると、独立したデータポート、コマンドポートが6つあるのがわかる。

MCBはコマンドを入れてRead, Write, Prechargeなどを行う。その辺の様子が、”Spartan-6 FPGA メモリ コントローラ ユーザー ガイド (英語版)”47ページのInstructionsから下辺りに書いてある。

大体、MCBの概要はわかったので、SP605に対応するDDR3 SDRAMコントローラをMIGで生成してシミュレーションしてみたい。
  1. 2010年04月20日 05:26 |
  2. Virtex-6, Spartan-6
  3. | トラックバック:0
  4. | コメント:0
»