FPGAの部屋

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

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。ご利用ください。 http://marsee101.web.fc2.com/index.html

カテゴリ: MIG

Spartan-3AのMIGのユーザー・インターフェースは、FIFOが入っていないような感じで、タイミングを満たすように作るのが面倒だ。対して、Virtex-5のMIGのユーザー・インターフェースは、FIFOを使用していてインターフェースするのが簡単になっている。
自作DDR2 SDRAMコントローラのユーザー・インターフェースは、Virtex-5のMIGのように、FIFOを使用していて、ほとんど同じプロトコルになっている。Spartan-3AのMIGも同様のプロトコルだったら、CMOSカメラ・ディスプレイ回路で自作IPと置き換えて確かめてみようと思ったが、IOパッドを固定するところで、エラーが出てしまった。更に、プロトコルも違ってるので、ラッパー回路を作る必要があるので、諦めることにした。
現在動作している自作DDR2 SDRAMのIPがあるので良しとした。一応、MIGの使い方はひと通りやってみることができた。Virtex-5のMIGは使おうと思っている。

これで、MIGの勉強はとりあえず終了とする。

XUPV5-LX110T Development SystemでMIGを試す3(ISimでシミュレーション)”の続き。
前回、DDR2 SDRAMのテストベンチにdefineして、ISimでのシミュレーションがうまくいった。今回は、Virtex-5のユーザー回路とのインターフェースについて探ってみたい。

XUPV5-LX110Tの使用しているDDR2 SDRAMだが、SO-DIMMを使用している。Micron社製でMT4HTF3264HY-256MB(PDF)だ。DDR2 SDRAMチップはMT47H32M16(PDF)が使われているようだ。このDDR2 SDRAMチップは16ビット幅なので、Rowアドレス13ビット、Columnアドレス10ビット、Bankアドレス2ビットの計25ビットのアドレスを持っている。
Memory Interface Solutions UserGuideの380ページのTable 9-8: DDR2 SDRAM Controller User Interface Signalsのapp_af_adr[30:0]に説明があるが、Virtex-5のMIGのユーザー回路から与えるアドレスの割り当ては、Bank + Row + Column addressとなっている。至極まっとうな割り当てだと思うが、マルチバンク対応のコントローラをCPUで使用する場合には、データの局所性という観点からRow + Bank + Column の方が良いかもしれない。add_af_addrは31ビット幅あるが、今回のアドレス幅は25ビットである。

Memory Interface Solutions UserGuideの372ページのFigure 9-7: DDR2 Memory Controller Block Diagram を下に引用する。
83f4f897.png


DDR2 SDRAMコントローラの入出力信号はSystem Clocks and Reset, User Application, Memory Deviceの信号に分けられる。そのうちのUser Applicationの信号について見ていこう。

Virtex-5用MIGで生成されたDDR2 SDRAMコントローラのユーザー・インターフェース信号について下に記す。()内はそれぞれDDR2 SDRAMコントローラに対しての入力、出力を表す。

app_af_cmd[2:0]:(入力) 3ビットのコマンド。000がWriteコマンド、001がReadコマンド。それ以外は不正値。
app_af_addr[30:0]:(入力) 31ビットのアドレス。今回は25ビット幅、26ビット目はChip Select。アドレスの割当はBank + Row + Column address。
app_af_wren:(入力) User Address FIFOへのWrite enable。これが1の時は、app_af_cmdとapp_af_addrが有効。
aff_wdf_data[2*DQ_WIDTH-1:0]:(入力) User Input Data。DDR2 SDRAMのデータ幅の2倍のデータ幅がある。クロックの立ち上がりのデータが下位、クロックの立ち下がりのデータが上位。128ビット幅。
app_wdf_mask_data[2*DM_WIDTH–1:0]:(入力) User Data Mask。DDR2 SDRAMのマスク幅の2倍の幅がある。 クロックの立ち上がりのマスクが下位、クロックの立ち下がりのマスクが上位。16ビット幅。
app_wdf_wren:(入力) User Write FIFOのWrite enable。これが1の時は、aff_wdf_dataとapp_wdf_mask_dataが有効。
app_af_afull:(出力) Address FIFOのAlmost Full。残り12以下の時に1になる。
app_wdf_afull:(出力) User Write FIFOのAlmost Full。残り12以下の時に1になる。
rd_data_valid:(出力) rd_data_fifo_outのデータが有効であることを示す。
rd_data_fifo_out[2*DQ_WIDTH–1:0]:(出力) メモリからReadしたデータ。128ビット幅。
phy_init_done:(出力) DDR2 SDRAMコントローラの初期化とキャリブレーションが終了した。
clk0_tb:(出力) ユーザー回路へのclk0出力


Write, Read両方とも、前のトランザクションとRow + Bankアドレスが違っていたら自動的にプリチャージして、Activateコマンドを発行してくれるようだ。

・Write
Memory Interface Solutions UserGuideの384ページのFigure 9-12: DDR2 SDRAM Write Burst for Four Bursts (BL = 4)を下に引用する。
81aacabc.png


Address FIFOは1024深度、User Write FIFOは512深度あるようだ。
Writeはアドレス(app_af_addr) とコマンド(app_af_cmd)を決めて、app_af_wrenを1にしてAddress FIFOに書きこむと同時に、app_wdf_wrenを1にして、D1,D0をデータ(app_wdf_data)、M1,M0をマスク(app_mask_data) に書きこむ。次のクロックでは、app_af_wrenは0に戻して、データのみを書き込む。これで4バーストモードの1つのWriteができるようになる。コマンドはWrirte(000)。

実際にシミュレーションでデータをWirteしている部分を下に示す。
49274b7b.png


データをUser Write FIFOに書き始めてから、実際にDDR2 SDRAMのWriteアクセスが実行されるまでに116.25ns/3.75ns = 31クロックかかっている。4バーストWrite8個分のトランザクションが始まって、DDR2 SDRAMにWriteし終わる間のクロックは約71クロック。なお、最初の4バーストWrite4個分のバーストできたが、後の4バーストWrite4個分のバーストと2つに分けられている。これは、Rowアドレスが異なるからである。

・Read
Memory Interface Solutions UserGuideの386ページのFigure 9-14: DDR2 SDRAM Read Burst (BL = 4) for Four Bursts を下に引用する。
19b3072c.png


Readの場合は、app_af_wrenを1にして、アドレス(app_af_addr) とコマンド(app_af_cmd)を決めてAddress FIFOに必要な分だけ書きこむ。DDR2 SDRAMコントローラがDDR2 SDRAMからReadしたデータは、rd_data_fifo_outにrd_data_validが1の時に出力される。

実際にシミュレーションでReadしている例を下に示す。
9d2a40ac.png


これは、ユーザー回路からReadコマンドが発行されてから、実際にDDR2 SDRAMにReadコマンドが発行されるまでは、255.1ns / 3.75ns ≒ 68クロックである。これは、Writeの実行を待っているために遅くなってしまった。FIFOの深度が大きいと最大のレイテンシが大きくなるので注意が必要だと思う。
ユーザー回路からReadコマンドが発行されてから、最後のReadデータが到着するまでのクロック数は85クロックだった。

あまりFIFOに入れすぎると、後で入れたコマンド処理のレイテンシが増大してしまうかもしれないので、もし、それが懸念される用途に使用する場合は注意が必要だと思う。

”Spartan-3A Starter KitでMIGを使用する7(論理シミュレーション1)”でMIGのuser desginのシミュレーションができた。今回はユーザー回路からどのようにMIGが制御されているかを見ていく。Memory Interface Solutions UserGuide参照。

DDR2 SDRAMの初期化のシミュレーション波形を下に示す。
00fd7305.png


200us 待ってから、Burst Length=4, CAS Latncy=3, ODT Rtt = Disabled, DQS_N Enable = Enabledに設定している。シミュレーション時の初期化時のログを下に示す。

268252100.0 ps INFO: Precharge All
268372100.0 ps INFO: Load Mode 2
268372100.0 ps INFO: Load Mode 2 High Temperature Self Refresh rate = 1X (0C-85C)
268492100.0 ps INFO: Load Mode 3
268612100.0 ps INFO: Load Mode 1
268612100.0 ps INFO: Load Mode 1 DLL Enable = Enabled
268612100.0 ps INFO: Load Mode 1 Output Drive Strength = Full
268612100.0 ps INFO: Load Mode 1 ODT Rtt = Disabled
268612100.0 ps INFO: Load Mode 1 Additive Latency = 0
268612100.0 ps INFO: Load Mode 1 OCD Program = OCD Exit
268612100.0 ps INFO: Load Mode 1 DQS_N Enable = Enabled
268612100.0 ps INFO: Load Mode 1 RDQS Enable = Disabled
268612100.0 ps INFO: Load Mode 1 Output Enable = Enabled
268732100.0 ps INFO: Load Mode 0
268732100.0 ps INFO: Load Mode 0 Burst Length = 4
268732100.0 ps INFO: Load Mode 0 Burst Order = Sequential
268732100.0 ps INFO: Load Mode 0 CAS Latency = 3
268732100.0 ps INFO: Load Mode 0 Test Mode = Normal
268732100.0 ps INFO: Load Mode 0 DLL Reset = Reset DLL
268732100.0 ps INFO: Load Mode 0 Write Recovery = 3
268732100.0 ps INFO: Load Mode 0 Power Down Mode = Fast Exit
268852100.0 ps INFO: Precharge All
268972100.0 ps INFO: Refresh
269092100.0 ps INFO: Refresh
269212100.0 ps INFO: Load Mode 0
269212100.0 ps INFO: Load Mode 0 Burst Length = 4
269212100.0 ps INFO: Load Mode 0 Burst Order = Sequential
269212100.0 ps INFO: Load Mode 0 CAS Latency = 3
269212100.0 ps INFO: Load Mode 0 Test Mode = Normal
269212100.0 ps INFO: Load Mode 0 DLL Reset = Normal
269212100.0 ps INFO: Load Mode 0 Write Recovery = 3
269212100.0 ps INFO: Load Mode 0 Power Down Mode = Fast Exit
269332100.0 ps INFO: Load Mode 1
269332100.0 ps INFO: Load Mode 1 DLL Enable = Enabled
269332100.0 ps INFO: Load Mode 1 Output Drive Strength = Full
269332100.0 ps INFO: Load Mode 1 ODT Rtt = Disabled
269332100.0 ps INFO: Load Mode 1 Additive Latency = 0
269332100.0 ps INFO: Load Mode 1 OCD Program = OCD Default
269332100.0 ps INFO: Load Mode 1 DQS_N Enable = Enabled
269332100.0 ps INFO: Load Mode 1 RDQS Enable = Disabled
269332100.0 ps INFO: Load Mode 1 Output Enable = Enabled
269452100.0 ps INFO: Load Mode 1
269452100.0 ps INFO: Load Mode 1 DLL Enable = Enabled
269452100.0 ps INFO: Load Mode 1 Output Drive Strength = Full
269452100.0 ps INFO: Load Mode 1 ODT Rtt = Disabled
269452100.0 ps INFO: Load Mode 1 Additive Latency = 0
269452100.0 ps INFO: Load Mode 1 OCD Program = OCD Exit
269452100.0 ps INFO: Load Mode 1 DQS_N Enable = Enabled
269452100.0 ps INFO: Load Mode 1 RDQS Enable = Disabled
269452100.0 ps INFO: Load Mode 1 Output Enable = Enabled
269452100.0 ps INFO: Initialization Sequence is complete


次にユーザー回路とのインターフェース信号を見ていく。
Spartan-3A用のMIGのデータ入力(user_input_data) は90度位相のずれたクロック(clk90_int) に同期している必要がある。その他の信号は、0度のクロック(clk_int) の立ち下がりに同期させる必要がある。また、DDR2 SDRAMからReadしたデータ(usr_output_data) や有効信号(usr_data_valid) は0度のクロック(clk_int) の立ち上がりに同期している。
Virtex-5のMIGよりユーザーインターフェースを作るのが面倒だ。コマンド入力用FIFOが付いていない感じだ。MIGのユーザーインターフェースの上にFIFOを使ったラッパーを作ったほうが良いかもしれない。

Spartan-3A用のMIGのユーザー・インターフェース信号について簡単に説明する。

clk0:位相0度のクロック
clk90:位相90度のクロック
user_command_register:Write Request(100) やRead Request(110)、NOP(000) などのコマンド。Initialize memory(010)。(clk0の立ち下がりに同期)
user_cmd_ack:MIGからコマンドをうけとれるという返事。リフレッシュなどの用事があってコマンドを受け取れない場合はアサートされない。(clk0の立ち下がりに同期)
user_input_address:アドレス入力。使いにくいことにROW+COLUMN+BANKの順番になっているので、まともに使用するためには、COLUMNとBANKのアドレスを入れ替える必要がありそう。(clk0の立ち下がりに同期)
burst_done:バーストの終了時に4バーストモードは2クロック間、8バーストモードは4クロック間アサートする。(clk0の立ち下がりに同期)
user_input_data:clk90に同期してデータを出力する(Writeのみ)。(clk90の立ち上がりに同期)
user_data_valid:user_output_dataが有効。(Readのみ)(clk90の立ち上がりに同期)
user_output_data:Readしたデータ。(Readのみ)(clk90の立ち上がりに同期)


Memory Interface Solutions UserGuideの332ページのFigure 8-10: DDR2 SDRAM Write Burst, Burst Lengths of Four and Two Burstsを下に引用する。
1205b807.png


上の図はSpartan-3A用MIGのWriteの例だ。

1.clk0の立ち下がりに同期して、ユーザー回路はWriteコマンドを発行し始める。
2.最低1クロック後にMIGは、clk0の立ち下がりに同期してuser_cmd_ackをアサートし、Writeコマンドを受け付けたことをユーザー回路に知らせる。ただし、リフレッシュ動作中でuser_cmd_ackのアサートが遅れることもある。
3.user_cmd_ackがアサートされた後のclk90の立ち上がりに同期して、ユーザー回路はuser_input_dataにWriteするデータを入力する。user_input_dataはDDR2 SDRAMのデータ幅の2倍幅となっている。4バーストモードならば、2つのデータを入力する必要がある。
4.ユーザー回路が入力するアドレス(row+column+bank address)は、user_cmd_ackがアサートされた後の3クロック間維持する。その後のバーストアドレスは2クロック維持する。(clk0の立ち下がりに同期)
5.write burstを終了させるときに、ユーザー回路はburst_doneをアサートしてMIGに知らせる。4バーストモードの時は2クロック間アサートする。
6.burst_doneのアサート後にWriteコマンドをデアサートする。(NOPコマンドに変更)
7.プリチャージをした後に、MIGはuser_cmd_ackをデアサートする。user_cmd_ackをデアサートされたら、ユーザー回路は次のコマンドを入力することができる。


実際にシミュレーションでデータをWirteしている部分を下に示す。
713f260f.png


4バーストモードで2組のデータをWriteすると、25クロックほどかかる。


次に、Memory Interface Solutions UserGuideの333ページのFigure 8-11: DDR2 SDRAM Read, Burst Lengths of Four and Two Burstsを下に引用する。
8953379b.png


上の図はSpartan-3A用MIGのReadの例だ。

1.clk0の立ち下がりに同期して、ユーザー回路はReadコマンドを発行し始める。
2.最低1クロック後にMIGは、clk0の立ち下がりに同期してuser_cmd_ackをアサートし、Readコマンドを受け付けたことをユーザー回路に知らせる。ただし、リフレッシュ動作中でuser_cmd_ackのアサートが遅れることもある。
3.ユーザー回路が入力するアドレス(row+column+bank address)は、user_cmd_ackがアサートされた後の3クロック間維持する。その後のバーストアドレスは2クロック維持する。(clk0の立ち下がりに同期)
4.user_output_dataが有効なのは、user_data_validがアサートされた時である。
5.DDR2 SDRAMのReadしたデータがuser_output_dataに出力される。user_output_dataはDDR2 SDRAMのバス幅の2倍の幅がある。DDR2 SDRAMは1クロックで2つのデータを読み書きするが、その2つのデータがuser_output_dataにSDR1クロックで出力される。4バーストモードでは、2つのデータがclk90の立ち上がりに同期して出力される。
6.read burstを終了させるときに、ユーザー回路はburst_doneをアサートしてMIGに知らせる。4バーストモードの時は2クロック間アサートする。
7.burst_doneのアサート後にReadコマンドをデアサートする。(NOPコマンドに変更)
8.プリチャージをした後に、MIGはuser_cmd_ackをデアサートする。user_cmd_ackをデアサートされたら、ユーザー回路は次のコマンドを入力することができる。大体、Readコマンドを発行してからデータが来るまで17クロックかかるようだ。


実際にシミュレーションでReadしている例を下に示す。
e08631c6.png


4バーストモードで2組のデータをReadすると、データが到着し終わるまでに26.75クロックかかる。

Spartan-3AのMIGで困ったことは、user_input_addressのアドレス割り当てがrow+column+bank addressなことだ。COLUMNアドレスとBANKアドレスを入れ替えないと使いにくい。

Spartan-3A Starter KitでMIGを使用する6(MIGのインプリメント状況)”でMIGをインプリメントの状況を見た。
今回は論理シミュレーションを行う。

右のProject Managerをクリックして、Behavioral Simulationを表示させる。下の図は表示させた状態。
b83b7de9.png


FileメニューからAdd Sources...を選択すると、Add Sourcesダイアログが開く。Add or Simulation Sourcesラジオボタンをクリックする。
bcdd928b.png


Add or Simulation Sourcesダイアログが開く。Add Files...ボタンをクリックする。
36a6f26f.png


example_design\simに移動して、そこのVerilogファイルをすべて選択して、OKボタンをクリックする。
b9148ea9.png


Add or Simulation Sourcesダイアログに選択したVerilogファイルがリストされる。Next>ボタンをクリックする。
bc7af813.png


Add Sources Summaryダイアログが表示された。Finishボタンをクリックする。
c3503663.png


PlanAheadのProject ManagerのSourcesウインドウにSimulation-Only Sourcesが追加されている。
MIG_65_110516.png

Project Managerの中のBehavioral Simulationをクリックする。
2295d18a.png


Launch Behavioral Simulation ダイアログが開く。Simulation Top Module Nameを入力する。Simulation Top Module Nameの脇の…ボタンをクリックする。
MIG_67_110516.png

するとトップモジュールを検索して、候補が出てくる。sim_tb_topを選択して、OKボタンをクリックする。
MIG_68_110516.png

Launch Behavioral SimulationダイアログのSimulation Top Module Nameにsim_tb_topが表示された。Launchボタンをクリックするとシミュレーションが始まるが、Options...ボタンをクリックして、オプション設定を見てみよう。
MIG_69_110516.png

Simulation Optionsダイアログが開く。Launch OptionsとLanguage Optionsがある。Language Optionsは”PlanAhead13.1を試してみた1(インプリメント、シミュレーション)”でdefine値を指定するのに使用したので、Launch Optionsを見てみよう。Project Navigatorのシミュレーションのプロバティと同様な設定項目がある。このままだと1000ns シミュレーションを行う。今回はデフォルトとするので、OKボタンをクリックする。
740c3111.png


Launch Behavioral Simulationダイアログに戻る。Launchボタンをクリックするとコンパイルが始まり、ISimが起動する。
6e80b273.png


300us間シミュレーションを行うと、270380100.0 psで、ERROR: Activate Failure. Initialization sequence is not complete.で止まってしまった。これは、”XUPV5-LX110T Development SystemでMIGを試す3(ISimでシミュレーション)”で遭遇したのと同じエラーだ。DDR2 SDRAMモデルにdefine値を与える必要がある。
ce46fc96.png


example_design\simフォルダのddr2_model_parameters.vhの最初に下の記述を追加した。

`define x512Mb
`define sg3
`define x16


修正後にISimのRe-Launchボタンをクリックする。コンパイルが始まって終了する。
Consoleウインドウで、

restart; run 300us


とコマンドを入力して、300us 間シミュレーションを行う。
25e8e947.png


今度は、エラー無く300us 間のシミュレーションが完了した。下の図はDDR2 SDRAMの初期化部分を拡大した。
00fd7305.png

Spartan-3A Starter KitでMIGを使用する5(インプリメント)”でMIGをインプリメントしてみた。

MIGのインプリメント状況を見てみようと思った。PlanAheadの配置図を下に示す。
22dd4219.png


cal_ctlというPblockが真ん中の上にある。他のスライスはIOに沿ってまばらに配置されているようだ。DCMもDCMを外したので、実装されていない。
FPGA Editorをクロスプローブ用に立ち上げて、見てみた。この時にうまくクロスプローブ出来なかった。やり方がおかしいのだろうか?
cntrl0_ddr2_dq[0]を見てみよう。
113234ae.png

(MIGのcntrl0_ddr2_dq[0]のIOB)

IOBの出力用FFは使用されている。DDRなので、IOBのDDRレジスタを使用する必要がある。IOのトライステート制御用のFFは片側だけ使用されている。これは4つ単位でデータを出力するので、そうなるのだと思う。入力FFはスルーされている。
下に、私の自作DDR2 SDRAMコントローラのIOBを示す。
a755aa48.png

(自作DDR2 SDRAMコントローラのddr2_dq[0]のIOB)

IOのトライステート制御用のFFを2つ使用している。これは、ODDR2プリミティブをインスタンスしているからだ。(自作DDR2 SDRAMコントローラのVeilog HDLコードの一部)

    ODDR2 #(
        .DDR_ALIGNMENT("NONE"),
        .SRTYPE("ASYNC")
    ) ODDR2_TRI(
        .Q(tri_out),
        .C0(clk270),
        .C1(clk90),
        .CE(tri_ddr_ce_to_io),
        .D0(tri_ddr_d0_to_io),
        .D1(tri_ddr_d1_to_io),
        .R(1'b0),
        .S(reset)
    );
    
    ODDR2 #(
        .DDR_ALIGNMENT("NONE"),
        .SRTYPE("SYNC")
    ) ODDR2_DATA(
        .Q(to_io_pad),
        .C0(clk270),
        .C1(clk90),
        .CE(data_ddr_ce_to_io),
        .D0(data_ddr_d0_to_io),
        .D1(data_ddr_d1_to_io),
        .R(1'b0),
        .S(reset)
    );
    
    IOBUF IOBUF_DQ(
        .O(dq_data_from_io),
        .IO(io_pad),
        .I(to_io_pad),
        .T(tri_out)
    );



もう一度MIGの実装に戻る。
cntrl0_ddr2_dq[0]の出力(IOパッドの入力)は、fifo_0_data_out[0]とfifo_1_data_out[0]スライスに入力されている。2つのスライスを見てみるとSLICE MでデュアルポートのRAMとして設定されていた。どちらかがクロックの立ち上がりのデータをキャプチャして、どちらかは立ち下がりのデータをキャプチャするのだと思う。これは、自作DDR2 SDRAMコントローラと同じ構成のようだ。
a7bf3c15.png

(MIGのcntrl0_ddr2_dq[0]と次段回路の接続状況)

FPGA Editorでこの配線の遅延値を測定してみた。

driver - comp.pin "cntrl0_ddr2_dq[0].I", site.pin "AA1.I"
0.464ns - comp.pin "main_00/top0/data_path0/data_read0/fifo_1_data_out[0].BY", site.pin "SLICE_X0Y3.BY"
0.464ns - comp.pin "main_00/top0/data_path0/data_read0/fifo_0_data_out[0].BY", site.pin "SLICE_X0Y2.BY"


0.464nsの低遅延配線を使用しているようだ。
自作DDR2 SDRAMコントローラでも、低遅延の配線を試行錯誤して見つけて使用している。下に接続状況を示す。なお、配線が多いので、他の配線は消してある
1d1ccd1c.png

(自作DDR2 SDRAMコントローラのddr_dq[0]と次段の接続状況)

ddr2_dq[0]からの出力は、MIGと同様にRAMに指定された2つのSLICE Mに接続されている。立ち下がりのデータキャプチャ用と立ち下がりのデータキャプチャ用だ。
FPGA Editorでこの配線の遅延値を測定した結果を下に示す。

driver - comp.pin "ddr2_dq<0>.I", site.pin "H1.I"
0.411ns - comp.pin "ddr2_sdram_cont_inst/read_write_io_inst/dout<16>.BY", site.pin "SLICE_X2Y63.BY"
0.411ns - comp.pin "ddr2_sdram_cont_inst/read_write_io_inst/dout<0>.BY", site.pin "SLICE_X2Y62.BY"


MIGも自作DDR2 SDRAMコントローラもDDR2 SDRAMのデータの受け方は同じ方法を取っているのがわかった。ただし、Readのタイミングをどのように判断しているかの解析はしていない。

MIGのインプリメントを見るのはこの辺で終了とする。次はシミュレーションしてみたい。

↑このページのトップヘ