FC2カウンター FPGAの部屋 2008年03月

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

FPGAの部屋

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

ISE10.1iのChipscope Proチュートリアル1 (Verilog版DDR SDRAMコントローラのテスト回路)

Verilog版DDR SDRAMコントローラはシミュレーションによるテストは実行したが、実際にSpartan3E Starter Kitの実機テストは行っていなかったので、テスト回路を作ってみた。。これは、Verilog版DDR SDRAMコントローラにバースト・書き込みをしてから、バースト・読み出しをして書き込んだデータと比較し続けるというテスト回路だ。GO、NGの判定はLEDだけなので、Chipscope Pro(以下 Chipscopeとする)を組み込んで、どんなデータでエラーが起きたのか調べることにした。Chipscopeは60日間お試しで使えるので、インストールして使うことにした。このついでに、fpga-labさんのChipscopeのチュートリアルが消えてしまったようなので、自分でチュートリアルを書くことにした。
ISEとChipscpeのバージョンは10.1を使用する。

最初にISEのSourcesペイン内で右クリックする。メニューが出てくるので、New Source... を選択する。
Chipscope_tutorial_1_080330.png

New Source Wizard - Select Source Type ダイアログが出てくるので、Chipscope Definition and Connection File を選択して、File name を入力して Next > ボタンをクリック。
Chipscope_tutorial_2_080330.png

New Source Wizard - Associate Source ダイアログが開くので、Chipscopeをどのソースファイルにかけるかを選らぶ。トップのファイル、ここではDDRtestを選択する。
Chipscope_tutorial_3_080330.png

New Source Wizard - Summary が開く。内容を確認して Finish ボタンをクリック。
Chipscope_tutorial_4_080330.png

これで、SourcesペインにChipscopeのファイルが入った。
Chipscope_tutorial_5_080330.png

次に、この DDRtest_cs_test.cdc をダブルクリックして設定を始めよう。
Chipscope Pro Core Inserter ウインドウが開く。
Chipscope_tutorial_6_080330.png

Next> ボタンをクリックする。

とりあえず今日はここまでにする。

Chipscope Proには Core Inserter と Core generator があって、Core Inserter は論理合成した後のネットリストにプローブして波形を見る方法。
Core Generator は Chipscope コアを生成して、それをソースファイルとつないでプローブする方法という認識だ。
Core Inserter は何といってもお手軽にプローブできるが、Core Generator はソースを改造する必要がある。
Core Inserter の欠点は中間ノードがなくなってしまうか、または名前がわからなくなること。Core Generator の欠点はソースファイルとつなぐので面倒で、ソースファイルの書き換えが必要なこと。
Core Inserter の利点はお手軽なこと。今回のチュートリアルはこれを使用している。Core Generator の利点は、中間ノードがなくならずに見えることだ。
といっても、Core Generator は使ったことがないので推測である。注意されたい。

ISE10.1iのChipscope Proチュートリアル2 (Verilog版DDR SDRAMコントローラのテスト回路)に続く。
  1. 2008年03月31日 21:31 |
  2. Chipscope
  3. | トラックバック:0
  4. | コメント:0

車のタイヤをノーマルに戻した(もう春ですね)

今日は車のタイヤをスタッドレスからノーマルタイヤに戻した。といっても、自分でやったわけではなく。イエローハットでやってもらったのだった。スタッドレスはアルミホイールを購入して入れてもらったのだが、そのアルミホイールのデザインを気に入ったので、新車時についてきたタイヤもホイールを鉄ホイールからアルミホイールに換えてもらったのだ。
これでノーマルタイヤになったので、安定して運転ができる。スタッドレスだとやわらかいので、慎重に運転していたし、発進時にも気を使っていた。白線のところを走るときにうるさしいし。。。
これで、車も春気分になった。
世の中は桜が咲いて良い季節なのだが、花粉症の私のとっては、厳しい季節だ。家にこもっていても鼻がつんつんする。思考がうまくできない。
とりあえず今日は危なそうなので、家にいることにしようと思う。

DDRはとりあえずあきらめて、ISE10.1のFloorplan Editorをいじっていたが、ロジックを位置固定するやり方が良くわからない、もしかして、まだできないのだろうか?
  1. 2008年03月29日 14:52 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Verilog HDLでの数値リテラル(定数)の書き方

昨日は、PCI-Expressのセミナに行ってきてとてもためになった。講師のかたありがとうございました。

さて、”Verilog版DDR SDRAMコントローラのバグフィックス”の”wp, rpと演算する数のビット幅を制限, ビット幅の制限がないと特に-の演算をする時に符号拡張が32ビットで行われるためにfullが出力されない”というバグについて、今後の戒めとするために詳しく書いておこうと思う。
DDR SDRAMコントローラのアクセスするアドレスを入力しておくaddr_fifo.vではルックアップテーブルを使用した分散RAMを使用して、自分でFIFOを構成している。コアジェネレータを使用せずに自分でFIFOを書いている主な理由は、次のアドレスも出力したいからだった。つまり出力アドレスと次に出力するアドレス(入っていれば?)を出力して、BANKやROWアドレスが違っているときにプリチャージ、ACTコマンドを入れるようにしようという目論見でそうなった。コアジェネレータで作ると当然ながらデータ出力は当然1つなのでニーズに合わない。
分散RAMを使用してFIFOにするために、ライトポインタ(wp)とリードポインタ(rp)を定義してある。どちらのポインタともに4ビットとして定義している。FIFOのFULLを判定する式はrp-1 == wp となるのでそのまま下のように書いた。

assign fifo_full = (rp-1==wp) ? 1'b1: 1'b0;


でも、少なくともシミュレータでは危ない記述だそうだ。
なぜだめかというと上の記述で-1はビット幅を指定していないので、32ビット幅に拡張されてしまうそうだ。つまり32'hFFFF_FFFFになってしまう。左辺は当然32ビット符号拡張されるが、== の比較のときに右辺も32ビットに拡張されてしまう。
これでも通常の場合はOKだが、rpが0、wpがFの時(ポインタは4ビットに定義してあるので)当然ながらFIFOはFULLなのだが、左辺は32'hFFFF_FFFF、右辺は32'h0000_000Fとなってイコールにならないので、FULL信号がアクティブにならなかった。
これを避けるためにはrp-1の-1をビット幅を制限する必要があるそうだ。ここではポインタは4ビットなので、4ビットに制限する。つまり1は4'b0001か4'h1と書く必要がある。よって下のように書き換えたらFULL信号が正常に出力されるようなった。

assign fifo_full = (rp-4'h1==wp) ? 1'b1: 1'b0;


たっくさん、教えていただいてありがとうございます。
今度から、かならず数値リテラルもビット幅を指定することにしようと思う。
  1. 2008年03月28日 05:48 |
  2. 入門Verilog
  3. | トラックバック:0
  4. | コメント:3

ISE Design Suite 10.1が出ています

昨日、Xilinxのサイトを見てみたらISE Design Suite 10.1が出ていた。
今度は、下の製品が集まったものをISE Design Suite 10.1と呼ぶようだ。

ISE™ Foundation™ ソフトウェア
ISE™ WebPACK™ ソフトウェア (無償ダウンロード)
ISE Simulator 付属 ISE Foundation
Platform Studio と EDK
PlanAhead デザイン解析ツールおよび PlanAhead Lite
ChipScope™ Pro ツール
ChipScope Pro Serial IO ツールキット
System Generator for DSP
AccelDSP™ 合成ツール

早速、ISE™ WebPACK™ ソフトウェアのフルパッケージをダウンロードしてみたら、ファイル名がwebpack_SFD.tar だった。LinuxとWindows版が一緒になっているみたい?
取りあえず、ISE9.1iをアンインストールして、インストールしてみようと思う。

追加:
上のリストを見るとModelSimがないのが気になる。もしかして、無料シミュレータはModelSimのスタータはやめて、ISE Simulatorのみになったのかもしれない。
ますます、言語をVerilogにして、Veritakシミュレータでシミュレーションということになるかもしれない。
朝にインストールを仕掛けていって、今しがた帰ってきた。インストールは終わっていたが、アップデートをかけ始めて、まだ終わっていないので、ISE10.1はまだ起動していない。

追加2:
ISE10.1がインストールできてVeirlog版DDR SDRAMコントローラをインプリメントしてみたが、問題なくインプリできた。FPGA Editorで内部を見てもIOBのDDR FFが使用されていた。とりあえず問題ない。ISE10.1では、PlanAhead LiteがISEに入っているようだ。Spartan3などでは使えないようだが、Virtex4, Virtex5などでは使えるようだ。

2008/03/28 追加:
インプリメントしてみたVeirlog版DDR SDRAMコントローラを実際に基板にダウンロードして確認してみたが、ちゃんと動作した。(あたりまえか。。。でも、いつもうまくいくとは限らない)

  1. 2008年03月26日 04:57 |
  2. Xilinx ISEについて
  3. | トラックバック:0
  4. | コメント:3

3月25日の近況

最近はたっくさんのプロセッサ用に私のDDR SDRAMコントローラIPを使っていただけるとのことで、たっくさんにテストベンチを書いていただいたり、実機での評価をしていただいたりしたが、なかなかバグが多くて、たっくさんにご迷惑をおかけしてしまった。本当に申し訳ない。反省。。。
おかげさまで、だいぶバグも少なくなったと思う。DDR SDRAMのデータをリードするときにIOBの遅延素子で遅延させて、内部クロックで受けるという方式の欠点は重々承知したが、Spartan3Eスタータキットを使用して、アマチュアができる現実的な解はこの辺だと思うので仕方がないと思う。
とりあえず、バーストで読み書きしまくる回路を上にかぶせて、DDR SDRAMコントローラをテストしてみようと思っている。

DDR2 SDRAMコントローラのDDR400は、こちらは上の方式では本当に厳しいだろうと思うが、とりあえずうまく受けられるポイントがあるかどうか。動的にDQを受けるIOBのIDELAYを変化させてうまく受けるポイントがあるかどうか調べたい。こちらは上のDDR SDRAMコントローラと同様に3/4クロックずらす方式に変える必要がある。
それでだめだったら、どのくらいの周波数では大丈夫かを調べたい。その後、DQSで取れるように考えてみたい。

3月22日にやまちゅうさんとすすたわりさんと飲み会をした。やはり、同じ趣味の方と飲み会をすると本当に話しているのが楽しい。やまちゅうさんにも作った物を見せてもらって、本当に感激した。音声をFPGAで出すのというのも前々からやりたかったこと。DDR、 DDR2がひと段落着いたら考えてみようと思う。

3月27日には東京エレクトロンデバイスの"動かす!!初めてのPCI-Expressセミナ"に行くことになっている。楽しみなのだが、新横浜は遠い。しかし、以前行ったHDラボといい、チップ関係というかFPGA関係の会社は新横浜に集まっているのだろうか?

そういえばfpga-labさんのWebサイトを見に行くと、DNSエラーになってしまう。サイトがなくなってしまったのか? いつも参考にさせていただいたサイトなので残念。

ISE9.2SP4のPACEを使って、DCMの位置を固定してみた。DCMの固定はできたのだが、自分の手で書いたUCFの構文が一部はねられてしまって、SSTL2の指定がなくなってしまった。UCFを読み込むときに大量にエラーが出ていた。この辺はもっと構文解析をどうにかならないものだろうか? ちゃんとISEでインプリメントするときには反映されているのだから。。。
かといって、FloorplannerでDCMの位置を固定すると、いったんPACEで制約をつけたUCFをFloorplannerで編集すると制約が2重になってしまうことがある。この辺も何とかならないか。。。

最後に、Webブラウザをアップルのsafariにしてみた。うちの本当に非力なマシンでは、firefoxでmixiの画面の表示をさせると、とても重かったのだがsafariにするととても軽くなった。メインとして使っても良いかな?と思っている。

(注):まだ、未修正箇所があるのでダウンロードできるVerilog版DDR SDRAMコントローラには、明らかなバグが残っています。
Verilog版DDR SDRAMコントローラのファイルをアップデートしました。でも、まだ実機では確かめていません。インプリメントはOKです。
  1. 2008年03月25日 06:03 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

DDR SDRAMコントローラの変更

またまた、Verilog版DDR SDRAMコントローラを変更した。(前の記事の詳報です)なるべくIPで入れたときに階層が異なって書き換えの必要なUCFを使わずにVerilogソースに制約を記述することを目的とした。といってもパッド位置は階層が変わらないので、そのままUCFに記述し、FFをIOBに入れる制約をVerilogソースに記述した。下のように。。。

(* IOB = "TRUE" *) reg [DDR_ADDRESS_WIDTH-1 :0] ddr_addr_node_2d;


後、Verilog版DDR SDRAMコントローラのVerilogソースをインプリメントしてみたら、DQからリードする最初のDDRのFF(といっても、私の回路では32ビット幅の出力うち半分は使っていないので片側のFFは消えてしまうので、DDRとはならないのだが。。。)がIOBに入らないで、SLICEに行ってしまっている。(下の図で右下のFFを使用しないで入力パッドから右に抜けているのがわかるだろうか?)
DDR_SDRAMC_DQ0_ISE92SP4_080320.png

これではまずいので、Spartan3E用のデータ(DQ)入力用FFを推定させる記述(下)を

    always @(posedge reset, posedge clk) begin // DQのIOB内のDDRレジスタを推定させる
        if (reset==1'b1)
            dq_rise <= 0;
        else // 立ち上がり
            dq_rise <= ddr_dq;
    end
    always @(posedge reset, negedge clk) begin
        if (reset==1'b1)
            dq_fall <= 0;
        else // 立下り
            dq_fall <= ddr_dq;
    end


IBUFプリミティブとIDDR2プリミティブを使用した記述に書き換えた。

    // 入力用DDRレジスタ
    generate
    genvar i;
        for (i=DDR_DATA_WIDTH-1; i>=0; i=i-1) begin : IDDR_GEN
            IBUF IBUF_inst(
                .I(ddr_dq[i]),
                .O(dq_ibuf[i])
            );
            IDDR2 #(
                .DDR_ALIGNMENT("NONE"),
                .SRTYPE("ASYNC")
            ) IDDR2_inst(
                .Q0(dq_rise[i]),
                .Q1(dq_fall[i]),
                .C0(clk),
                .C1(clkx),
                .CE(1'b1),
                .D(dq_ibuf[i]),
                .R(reset),
                .S(1'b0)
            );
        end
    endgenerate


これでUCFにIOB=TRUE制約を書かなくてもIOBのDDRレジスタを使うようになったと思った。
これでISE9.2iSP4でインプリメントをしてみると、MAPでINTERNAL_ERRORが出てしまってインプリメントができない。これは出力ポートの半分を使用していないためIDDR2の半分のFFが消されたのでDRCエラーになったのかな? INTERNAL_ERRORは出てはまずいと思うが、とりあえず使っていない出力も拡張ポートに出力するようにしたらINTERNAL_ERRORはでなくなった。とりあえず良かった。IDDR2の出力の1つを使用していないとINTERNAL_ERRORになってしまうので注意。
これでインプリメントしたら、IOBの入力用のDDRレジスタを使用するようになった。(上の図と比べて右下のFFを使用するようになったのがわかるだろうか?)
DDR_SDRAMC_DQ0_IDDR2_ISE92SP4_080321.png

以前のバージョンではIOBの入力用FFを使用したのだが、修正したので使われなくなったのだろうか?それでも修正したのはこのモジュールではないところなのだけれど。。。ISEのバージョンが変わったからかもしれない。。。ということでXSTにIOBの入力用FFを推定させることは危ないというか、ちゃんとそうなっているかFPGA Editorで確認したほうが良いと思う。それがいやならば、最初から決めうちのプリミティブを使ってしまったほうが良いだろう。しかし、こうするとAlteraに乗り換えるときはおろか、Xilinxのほかのチップに乗り換えるときにも書き換えが必要になるときがあるがしょうがない。
なかなか、この辺のチップの中の構造を積極的に使用する必要があるアプリの場合には、1つソースを書いてどのチップででも適応できるというのが難しい。そこで、CoreGenではチップごとに最適なソースを生成する必要があるんだろう。。。
DCMの位置固定は大体ISEがいいところを使ってくれるようなので大丈夫だろうと思う。私のインプリメントでは、DCM_INST_EXTがDCM_X1Y1(これはDCM_X0Y1でもよさそう、つまりつぎのDCMとひっくり返っても)、DCM_INSTがDCM_X0Y1、DCM_INST1がDCM_X1Y0だった。大きく外れているときにはFloorplannerで位置を固定したほうが良いと思う。
とりあえずVerilog版DDR SDRAMコントローラは修正して、実際にSpartan3E Starter Kitで動作を確認した。使用する方は再度ダウンロードしてみてください。
IFD_DELAY_VALUEは2のままです。
  1. 2008年03月22日 06:09 |
  2. DDR SDRAMコントローラ
  3. | トラックバック:0
  4. | コメント:0

DDR, DDR2 SDRAMコントローラの今後の展開について

DDR SDRAMコントローラはたっくさんのおかげで、大体バグが取れたと思う。後はたっくさんのインプリメントで何かバグが出てくるかもしれないが。。。一番気になっているのが、DDR SDRAMコントローラ用のDCMの位置を固定していなかったことだ。それにそのDCMは外部からのフィードバックを受けて位相が変わるので、他のDCMので出力される同じクロックの位相とは異なってしまう。なので、DDR SDRAMコントローラに入力や出力する場合にはフリップフロップを入れたほうが良いと思われる。この位相差は外部配線の影響を受けるので、Timing Analyzerも静的遅延を計算できないはず。。。遅延シミュレーションをする場合にはプリント基板のパターンの遅延を挿入する必要がある。
追加:DDR SDRAMコントローラのclk_out(クロック)で他の回路を動作させればOKでした。忘れていました。DCMの位置が変更になっても全体の動作クロックの位相が変化するだけなので、パッドからの入力クロックを使っていなければ大丈夫かな?
さらに追加(2008/03/21):自分のかいたVerilog HDLソースをよく読みなおしてみると、DDR SDRAMへクロックを出力しているDCMだけフィードバック入力をフィードバック入力パッドからフィードバックしていて、DDR SDRAMコントローラの回路が使用するクロックを生成するDCMはFPGA内部でフィードバックされていた。やはりこれだとDDR SDRAMへクロックを出力しているDCMの位置でデータの遅延回路の遅延値が変わってくると思われるので、DCMを固定しようと思っている。
さらに私のテスト回路でISE9.2SP4でインプリメントしてみたのだが、データを受ける最初のDDR用のFFがIOBに入っていなかった。これではまずいのでIDDR2プリミティブを使用してVerilog HDLソースを書き直してみたが、出力ポートの半分を使用していないためINTERNAL_ERRORでMAPが通らなかった。これは出力ポートの半分を使用していないためIDDR2の半分のFFが消されたのでDRCエラーになったのかな? INTERNAL_ERRORはまずいと思うが、とりあえず使っていない出力も拡張ポートに出力するようにしたらINTERNAL_ERRORはでなくなった。
ついでに、そのほかのIOBに入れる予定のFFもUCFではなくVerilog HDLソースに制約を書くことにした。それは、UCFだとインスタンスを書かなくてはいけないので、IPとして階層が変わるとUCFを書き直す必要があるためだ。本当はDCMもVerilog HDLソースで位置固定する必要があるが、どうもできないような感じだ。これは仕方ないのでUCFで固定する。

DDR2 SDRAMコントローラの方はとまっている。125MHz動作、つまりDDR2-250で動作させてやってみようと思っていたのだが、64タップもあるので、そのたびにインプリメントしてやっているのも時間がかかって大変だ。それに私のDDR2 SDRAMコントローラはリードのときに1/4クロック分データをずらして受ける方式だが、どうもChipscopeの波形を見ているとIDELAYが0のときに1/4クロック以上データがずれているようだ。これでは受けられないので、3/4クロック分データをずらす方式に変更しながら、遅延を自動判定する回路をつけようと思っている。とりあえず前の200MHzでうまくいくかどうかやってみたい。
1/4クロック分データをずらして受ける方式については”Spratan3E Starter KitのDDR SDRAMコントローラまとめ3”を参照。
  1. 2008年03月19日 05:55 |
  2. DDR SDRAMコントローラ
  3. | トラックバック:0
  4. | コメント:0

山形蔵王温泉スキー場に行ってきました

3月15、16日と山形の蔵王温泉スキー場に行ってきました。
宿は白銀荘というところ。家を5時ころ出て、10時ころつきました。約380Kmくらい距離がありました。ほとんど高速道路です。以前は半日かけていったのがうそのようです。
zao_1_080317.jpg

宿について、早速スキー場に行きました。中央ロープウェーから鳥兜山頂へ。
ショートスキーの感触を確かめながら、中央ゲレンデへ。子供たちは傾斜が急だといって文句を言っていましたが、横の緩斜面に案内。これなら大丈夫。
ガスっていたので、迷子にならないように注意しながら滑りました。
そのうちに横倉の方に行きたいということで、横倉に行くためにパラダイスゲレンデ、樹氷原コースを通って、百万人ゲレンデを通って、横倉に。横倉の壁を下から眺めて、蔵王ロープウェイ山麓線の乗り口まで一気に滑りました。小3の娘もついてこられて、というか、娘の後を滑りました。うまくなっていて感激。
蔵王ロープウェイ山麓線に乗っていったら、ガスっていた山頂がきれい晴れてくるのを発見。すかさず、山頂線に乗って頂上へ。
山頂はさっきまでガスっていたのがうそのように晴天でした。下を見ると先ほどガスっていたところは雲海でした。雲の上に出たように見えました。実際そうなのかな?でもそんなに雲は低くないですよね?
zao_2_080317.jpg

ともかく非常にいい眺め。樹氷と雲海を十分に楽しめました。
zao_3_080317.jpg

山頂のお地蔵様も見てきました。かなり埋もれていました。しかし、冬にしか来たことがないので、このお地蔵様の下半身を見たことがありません。
zao_4_080317.jpg

しばらく景色を堪能してから下に下りました。
サンライズゲレンデの橋を渡って中森ゲレンデに行く橋の所に露天風呂があります。しかし、この露天風呂も冬季閉鎖で入ったことがありません。入ってみたいです。
zao_5_080317.jpg

2日目は晴れわたっていました。山頂からは周辺の山が一望です。2日とも雄大な景色が望めました。写真はユートピアゲレンデの上からです。
zao_6_080317.jpg

宿もトイレが共同だったのが気にかかりますが、なかなか良かったです。

ともかく、疲れました。運転はうちの奥さんに代わってもらったのですが、やはり疲れますね。。。でも楽しかったです。また行きたい。もっと近ければいいんですがね。。。

追加:完全に雪は春スキー状態でした。2日目は山頂でも雪が緩んでいました。下のほうは雪が重い重い。カービングをしないと足が疲れますが、カービングをすると板をたわませるのに脚力を使うということで結局足が疲れました。
  1. 2008年03月17日 21:28 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:2

DDR SDRAMコントローラの高度なシミュレーション3

”DDR SDRAMコントローラの高度なシミュレーション2”のVerilogコードの差分をたっくさんの許可が出たのでブログに載せておこうと思う。
最初にメインのinitial文。

    reg  [31:0] read_fifo [0: 2**23-1];//24bit fifo
    reg [23:0]  seed_address,write_temp_address,read_temp_address;
    integer seed_data,write_temp_data,read_temp_data;
    integer burst_words,burst_words_seed;
    integer burst_write_words, burst_write_words_seed;
    integer test_counter;
    integer burst_read_cmd_end_flag;
    initial begin
        $timeformat(-9,1,"nsec",8);
        //準備ができるまで待つ
        initial_wait;
        
        //シングルライト/リード
        check_random_single_write_read(10);
        //インクリメンタルチェック
        check_incremental_single_write_read(10);
        
        //バースト ライト/リード 固定アドレス
        burst_check_fixed_pattern(0,10,32'h5555_5555);//256まではOK
        burst_check_fixed_pattern(0,258,32'hAAAA_AAAA);//256まではOK
    //    $stop;
        //バースト ライト/リード ランダムアドレス
        seed_address=1<<2;
        seed_data=1;
        write_temp_address=seed_address;
        write_temp_data=seed_data;
        read_temp_address=seed_address;
        read_temp_data=seed_data;
        burst_words_seed=1;
        burst_write_words_seed = burst_words_seed;
        burst_words=burst_words_seed;
        test_counter=0;
        `define Check_Max_burst_words 20
        sequential_burst_write_random(write_temp_address,write_temp_data,burst_words);
        burst_write_words = burst_words;
        repeat(100000) begin
                 
            $display("Start burst write random burst_words=%d%t",burst_words,$time);
            // burst_write_random(write_temp_address,write_temp_data,burst_words);
                
            //$display("Start burst read random %t",$time);
            // burst_read_random(read_temp_address,burst_words);
            // burst_read_check_random(read_temp_data ,burst_words);
            
            fork
                begin
                    sequential_burst_read_random(read_temp_address,burst_words);
                    sequential_burst_read_check_random(read_temp_data ,burst_words);
                end
                begin
                    wait(burst_read_cmd_end_flag==1);
                    wait(burst_read_cmd_end_flag==0); // バーストリードのFIFO書き込みの終了を検出
                    
                    burst_write_words_seed=lfsr8(burst_write_words_seed);
                    
                    if(burst_write_words_seed> `Check_Max_burst_words) begin
                        burst_write_words=burst_write_words_seed%`Check_Max_burst_words;
                        if (!burst_write_words) burst_write_words=1;
                    end
                    sequential_burst_write_random(write_temp_address,write_temp_data,burst_write_words); // 次のライト
                end
            join
            
            test_counter=test_counter+1;
            if (test_counter%100==0) $display("Pass %d",test_counter);
            burst_words = burst_write_words;
        end
        
        #1000000    $finish;
    end


sequential_burst_write_random、sequential_burst_read_random、sequential_burst_read_check_random の各taskを新しく作った。バーストアクセスのチェック用だ。
ライト用のburst_write_words, burst_write_words_seedを宣言する。次のシードの計算をライトのみ行い、次のライトとDDR SDRAMから出てきたリードデータをFIFOに入れるプロセスとを並列に実行するためだ。これはループの最後でリード用(元)の変数に代入する。
最初にsequential_burst_write_randomを実行しておいて、fork join で、sequential_burst_read_random、sequential_burst_read_checkと次のsequential_burst_write_randomを並列に実行する。ただし、DDR SDRAMコントローラへリードのコマンドを入力するプロセスが終了してから、sequential_burst_write_randomを実行しないとバグるため、wait(burst_read_cmd_end_flag==1); wait(burst_read_cmd_end_flag==0);で待たせている。
次にsequential_burst_write_random、sequential_burst_read_random、sequential_burst_read_check_random の各taskのVerilogソースを示す。

    task sequential_burst_write_random(inout integer seed_address,seed_data ,input integer counts);
        integer counter;
        integer address;
        begin
            
            //assert(read_fm_host==0);
            //ライトコマンドをcounts分送出
            counter=0;
            address = seed_address;
            seed_address=get_next_random_address(seed_address);
            
            repeat(counts) begin
    
                @(negedge clk_out);
                if (fifo_full_fm_controller) begin
                    write_fm_host=0;
                    wait(!fifo_full_fm_controller);
                    @(negedge clk_out);
                end
                write_fm_host=1;
                input_data_fm_host=seed_data;
                address_fm_host   =address;
                seed_data=$random(seed_data);
                address = address + 2;
                
                counter=counter+1;
            end    
            @(negedge clk_out);
            write_fm_host=0;
            //ライトコマンド送出終わり
        end    
    endtask        

        task sequential_burst_read_check_random(inout integer seed_data,input integer counts);
        integer counter;
        begin
            counter=0;
            
            repeat(counts) begin
                
                if (read_fifo[counter] !==seed_data) begin
                    $display("Error Detected burst_read_check_random %t %h %h ",$time,read_fifo[counter],seed_data);
                    $stop;
                end
                seed_data=$random(seed_data);
                counter=counter+1;
            end    
            
        end    
    endtask        
    
    task sequential_burst_read_random(inout integer seed_address,input integer counts);
        integer send_counter,read_counter;    
        integer address;
        begin
            send_counter=0;
            //assert(read_fm_host==0);
            //リードコマンドをcounts分送出
            //assert(!read_valid_fm_controller);
            fork//コマンドを送っている間にもReadValidは来るので送信と受信は、平行プロセスでなければならない。
                begin
                    burst_read_cmd_end_flag = 1;
                    address = seed_address;
                    seed_address=get_next_random_address(seed_address);
                    
                    repeat(counts) begin
    
                        @(negedge clk_out);//Mar.6.2008 clk_outに変更
                        if (fifo_full_fm_controller) begin
                            read_fm_host=0;
                            wait(!fifo_full_fm_controller);
                            @(negedge clk_out);
                        end
                        read_fm_host=1;
                        address_fm_host=address;
                        address = address+2;
                        send_counter=send_counter+1;
                    end    
                    @(negedge clk_out);
                    read_fm_host=0;
                //リードコマンド送出終わり
                    burst_read_cmd_end_flag = 0;
                end
                
               //リードデータをcounts分読み込む
                begin
                    read_counter=0;
                    wait(send_counter !==0);//Mar.6.2008 Timeout Check のため
                    repeat(counts) begin
    
                        @(negedge clk_out);//Read 読み込みは、100MHzで来るので100MHzで受ける
                        if (!read_valid_fm_controller) begin
                            time_out_check_read_valid(counts);//Mar.6.2008 タイムアウトチェック追加
                            //wait(read_valid_fm_controller);
                            //@(negedge clk_out);//Read 読み込みは、100MHzで来るので100MHzで受ける
                        end
                        read_fifo[read_counter]=output_data_fm_controller;
                        read_counter=read_counter+1;        
                    end
                end    
            join
            
        end
    endtask


ちなみにsequential_burst_read_check_randomはburst_read_check_randomと同一です。
  1. 2008年03月14日 18:15 |
  2. DDR SDRAMコントローラ
  3. | トラックバック:0
  4. | コメント:0

DDR SDRAMコントローラの高度なシミュレーション2

”DDR SDRAMコントローラの高度なシミュレーション”では、DDR SDRAMコントローラのアクセスパターンとしては、バースト・アクセス(キャッシュ・フィル、キャッシュ書き出し)が多いと思うので、テストベンチをバースト・アクセスに対応するように書き換えてみた。しかし、DDR SDRAMコントローラへのリード・コマンドを発行後すぐに、DDR SDRAMコントローラへライト用のコマンドが入らないという状況があった。DDR SDRAMのリードデータを受けるプロセスとDDR SDRAMコントローラへライト用のコマンドを入れるプロセスを並列化できれば、もっとDDR SDRAMコンローラのライトとリードが接近するはずだ。
ということで、”DDR SDRAMコントローラの高度なシミュレーション”で書き直したバーストでランダム・リードするタスクのうち、DDR SDRAMコントローラへリード・コマンドを発行するプロセスが終了したら、DDR SDRAMコントローラへライト用のコマンドを入れるタスクが走るように、それらのタスクを呼び出すルーチンをfork, joinで平行プロセスに書き換えた。そうしたところ、
シミュレーション波形は下の図のようになった。バーストでランダム・リードするタスクのうち、DDR SDRAMから出てきたリードデータをFIFOに入れるプロセスと、バーストでランダム・ライトするタスクが平行に実行されるようになった。
DDR_SDRAM_CONT_adv_sim_2_080313.png

上の図を見ると、以前の図(下)よりもアクセスの密度が増えたのがわかると思う。
DDR_SDRAM_CONT_adv_sim_1_080312.png

たっくさんの許可をもらっていないので、Verilogコードを書いていないのが、ちょっともどかしいが。文章だけで説明するのは難しい。。。
ともかく、これで当初の目的は達成した。DDR SDRAMコントローラのテストベンチでのデバックは終了した。これでバグはほとんどつぶせたと思う。(といいな?という希望です)

#明日から、娘も合格したし、蔵王スキー場に1泊2日でスキーに行ってきます。
  1. 2008年03月14日 05:38 |
  2. DDR SDRAMコントローラ
  3. | トラックバック:0
  4. | コメント:2

DDR SDRAMコントローラの高度なシミュレーション

”Verilog版DDR SDRAMコントローラのバグフィックス”たっくさんの書かれたテストベンチでバグをフィックスすることができた。
たっくさんの書かれたテストベンチは書き込むデータがランダムパターンなので、バーストアクセスはできない。私の書いたVerilog版DDR SDRAMコントローラは1つのバンクのみアクティベートするので、バンクが異なっているとプリチャージしてバンク・アクティブコマンドを再入力するようになっている。
実際のパターンとしては、バースト・アクセス(キャッシュ・フィル、キャッシュ書き出し)が多いと思うので、テストベンチをバースト・アクセスに対応するように書き換えてみた。
具体的にはすべてランダムアドレスを入れる代わりに、burst_write_randomやburst_read_random中ではアドレスを+2するようにした。これでバーストになる。なぜ、アドレスを+2かというと1クロックで2データ出てしまうので、+1にするとアドレスが重なってしまうからだ。
下にシミュレーション結果波形を示す。これでデフォルトのディスク容量までやったがエラーはなかった。
DDR_SDRAM_CONT_adv_sim_1_080312.png

これでは、かなり無駄というか、アクセスが遅い。これはリードデータをチェックしている間はライトを発行しないからだ。これを解決するには、DDR SDRAMにRASやCAS、WEでリードコマンドを発行している間に、DDRVerilog版DDR SDRAMコントローラのコマンドの入力(addr_fifo_wren, wrdata_fifo_wren, input_address, input_data)でライトコマンドを発行する必要がある。今度はこれをやってみようと思う。上の図でピンクの丸で囲った部分を矢印くらいの位置に持って来たい。
  1. 2008年03月12日 09:03 |
  2. DDR SDRAMコントローラ
  3. | トラックバック:0
  4. | コメント:0

発表会で発表

今日は発表会だった。私はFPGA内のPCIバスの66MHz, 64bit幅のIPについて発表した。15分発表、5分質疑応答だった。40人くらいはいたと思うが、あまり、FPGAをやっている人はいないので、質問は座長からのみだった。
やはり、暖簾に腕押しという感じがする。PCI-Xがうまくいったら、FPGA関連の展示会でできれば発表してみたい。

PCIモジュール1
(うちの基板のコンフィギュレーション・レジスタ・マップ、PCIのコンフィギュレーション方法を紹介)
PCIモジュール2
(PCIターゲットアクセスについて。ステート図、シミュレーションのwave付き)
PCIモジュール3
(PCIマスタアクセスについて、ステートマシンは載せていないが、IOB付近のデータパスの図を添付)
PCIボードの起動時間
(FPGAのコンフィギュレーション時間とPCIボードの起動時間について考察)
あるパソコンでのPCIマスタアクセス波形
(XeonプロセッサのパソコンのPCI66MHz,64bitボードからパソコンのメモリへPCIマスタリードしたときのChipscope波形。PCIリードを何回か繰り返した後リードできている。Chipscopeで信号をまとめてバスとして16進で表示する方法)
  1. 2008年03月10日 22:58 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

竹とんぼ飛行写真

昨日、竹とんぼの飛んでいるところをとろうと、下の娘と竹とんぼの飛行写真を撮りに行った。
なかなか、タイミングが合わずに取れなかったが、やっととることができた。
F1の車を取る並みの難しさではないだろうか?
私のデジカメは1秒間に4こま連射できるのだが、それを使った。何十枚とったうちの1枚だった。
はじめは、自分で竹とんぼをまわして、自分でとろうとしたが無理だった。(それは無謀ですよね。。。)
taketonbo_080310.jpg
  1. 2008年03月10日 05:59 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:4

Verilog版DDR SDRAMコントローラのバグフィックス

たっくさんのおかげで、Verilog版DDR SDRAMコントローラのバグが解消した。
テストベンチを作っていただいたので、ほぼバグは取れたと思う。しかし、やはり完璧なテストベンチでシミュレーションするとバグが見つかるのが早いので感激した。以前はシミュレーションは適当にやって、実機に入れてテストした。全部のモジュールができるまでテストができなかったし、最初はいい加減なテストベンチしか通してなかったので、バグがぼろぼろ出た。
今回、たっくさんの書いたテストベンチを見て、こんな風に単体テストをやらなければ、という気持ちがわいてきた。テストベンチを書く手間が増えるが、結局このほうが、デバック時間を驚異的に短縮できるだろう。テストベンチを勉強させていただいて、こんなテストベンチが書けるようになろうと思った。

Verilog版DDR SDRAMコントローラのバグはcntroller.vが4つ。

// 2008/03/03 Ver. 1.1 : equal_active_bankの比較がrow_addrだけでbank_addrを比較していなかったバグを修正
// 2008/03/05 Ver. 1.2 : カラムアドレスを超えてバーストする場合に、バンクをプリチャージしてACTコマンドを入れてからREADやWRITEコマンドを入れるが、その際にCLK0度とCLK180度のクロックの違いでアドレスが次のアドレスになってしまった。バンクアドレスのみCLK180度でラッチしたアドレスを使用した。
// 2008/03/06 Ver. 1.3 : dqs_enableを出力するステートマシンにバグがあった。WRITEして1つ間が開いてもう一度WRITEをするときにidle_detsステートに戻してしまったが、これはWRITEであることを判定してwrite_detsステートに遷移させる必要がある。
// 2008/03/07 Ver. 1.4 : row_addr, bank_addrに入れるaddressのビットフィールドが間違っていた。


addr_fifo.v, rddata_fifo.v, wr_data.vが1つだった。

// 2008/03/07 : Ver. 1.1 : wp, rpと演算する数のビット幅を制限, ビット幅の制限がないと特に-の演算をする時に符号拡張が32ビットで行われるためにfullが出力されない


現在あがっているZIPファイルは修正済みである。

結構、家でも根を詰めてデバックしていたので、いささか疲れてしまった。DDR2の方はそのうちにシミュレーションしてからバグフィックスを行う。
  1. 2008年03月07日 20:12 |
  2. DDR SDRAMコントローラ
  3. | トラックバック:0
  4. | コメント:0

Verilog版DDR SDRAMコントローラ、DDR2 SDRAMコントローラのバグ

たっくさんのおかげで、Verilog版DDR SDRAMコントローラDDR2 SDRAMコントローラのシミュレーションモデルにバグのあるのがわかった。現在のファイルサーバにあがっている圧縮ファイルは修正済みだが、以前にダウンロードされた方は修正をお願いします。
バグのあったVerilogファイルは contorller.v だ。
Verilog版DDR SDRAMコントローラでは110行目、DDR2 SDRAMコントローラでは144行目の equal_active_bank の論理を以下のように修正ください。

assign equal_active_bank = (active_row_addr==row_addr && active_bank_addr==bank_addr) ? 1'b1 : 1'b0;


現在のコントローラは1つのBANKのみサポートしている。コントローラはROWアドレスとBANKアドレスを監視している。つまり、現在のアクセスのROWアドレスとBANKアドレスと、以前のアクセスのROWアドレスとBANKアドレスが違っているとプリチャージしてACTコマンドを入れなおす。そのときにBANKアドレスを比較するのを忘れてしまった。つまり、前のアクセスと現在のアクセスのBANKアドレスが違っているときに、プリチャージしてACTコマンドを入れないで、直接READやWRITEコマンドを発行してしまうのでエラーになってしまった。

2008/03/07:またまたバグがあって、Verilog版のDDR SDRAMコントローラのcontroller.vを修正しました。修正箇所が多いので必要な方は再度ダウンロードしてください。まだバグがあるようですが、ある程度バーストしても大丈夫なようです。引き続きバグを修正します。
DDR2 SDRAMコントローラのシミュレーションモデルの方は、Verilog版のDDR SDRAMコントローラのバグフィックスが終了した時点で修正します。
  1. 2008年03月05日 05:40 |
  2. DDR SDRAMコントローラ
  3. | トラックバック:0
  4. | コメント:0

Doxygenを使ってVHDLソースコードをドキュメント化してみました

”コーヒーでも飲みながら検証の話でも”さんの火曜日, 2月 12, 2008、”DoxygenがVHDLをサポート”の記事でDoxygenがVHDLをサポートしたのを知った。
Doxygenがどんなものか、まったく知らなかったので、Windows版をダウンロードして、どんなものか触ってみたのだが、あまり良くわからずに放置していた。しかし、院生がC++で使っていたのを見たので、ぜひ使いたいと思い、今度は本気で使い方を探ってみた。
いろいろやってみた結果、だいぶ使い方がわかって来た。
”7セグメントLEDを何個ダイナミック点灯できるか?2”で使用した回路をDoxygenでドキュメント化してみた結果をここにおきます

Doxygenの使い方メモ

・Doxygen設定
OPTIMIZE_OUTPUT_VHDL = YES
SOURCE_BROWSER = YES
OUTPUT_LANGUAGE = Japanese
STRIP_CODE_COMMENTS  = NO
後は良くわからない。

・コメントの入れ方
doxygenのexamplesのmux.vhdlの書き方に加えて
1.日本語はUTF-8に変換する必要がある。
2.最初のコメントには、--! が使えないので、-- を使用する。
3.<は使えないようだ。portは --! を使用して、横に書けばOK。
4.component, signalの説明文は1行を使用し、上の行に --! を使ってコメントを書く。<を使って、同じ行の横に書くことはできない。
5.下位モジュールのインスタンシエーションの時のコメントは --! @details 説明。
6.process文にはラベルをつけたほうが良い。5.同様にコメントは --! @details 説明。
7.component文に横に --! で書いてもだめ。--! @param を使用して上に書く。
8.STRIP_CODE_COMMENTS = YES にしておくとdoxygenのコマンドが抜けてしまうので、STRIP_CODE_COMMENTS = NO にしておいたほうがスカスカにならなくて良い。



2008/03/06:追加
INLINE_SOURCES = YES にするとPROCESS文のソースがドキュメントに記載されます

どなたか、下のようなPROCESS文でない組み合わせ回路をドキュメントにする方法を知っていたら教えてください。
nLEDDB <= not decout;

2008/03/11:追加
GENERATE_TREEVIEW = YES; にするとFRAMEができて、選びやすくなる。
ここに表示サンプルを置いておく。

2008/03/14:追加
VHDLのときにはEXTRACT_PRIVATE = YESにする必要があるそうだ。
最初のファイルのコメントの部分(@authorなどが書いてある部分)は空行をあけないほうがよさそうだ。
修正したサンプルを置いておく。
  1. 2008年03月04日 12:57 |
  2. Doxygen
  3. | トラックバック:0
  4. | コメント:2

Verilog HDLシミュレータVeritakがNotepad++に対応

キジバト日記さんの”Verilog HDLシミュレータVeritakがNotepad++に対応”を読んで、(本当はmixiで見たのだけれど。。。) お、これはと思って早速やってみた。
なかなか良い。ブレークポイントやSTEP動作がNotepad++から操作できて便利だ。おまけにHDLソースの信号にカーソルを合わせると、現在の値も表示される。これは便利。。。
Notepad++_Veritak_080303.png

新しいVeritakバージョンのBASIC版もすぐにリリースしてくれた、たっくさんに感謝します。
  1. 2008年03月03日 06:00 |
  2. シミュレーション
  3. | トラックバック:0
  4. | コメント:2

竹とんぼを購入

この前、竹とんぼを作ったが、羽のピッチを逆にしてしまって悔しい思いをしたので、竹とんぼを購入した。竹とんぼ屋さんからひねり竹とんぼを購入した。
taketonbo_1_080301.jpg

上が小学校1年~4年生用、下が小学校5年生以上大人用。
大人用を小学校3年の娘が作ったが、簡単に作れて、本当に良く飛ぶ。やはり、羽が軽いし、羽を炎であぶって曲げるので、ピッチが自由自在だ。これで娘と竹とんぼキャッチボールをしたが、うまくできた。結構楽しい。
taketonbo_2_080301.jpg

左が先週作った逆に飛ばす竹とんぼ、右が今回購入した竹とんぼ。
  1. 2008年03月01日 16:40 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

DDR2 SDRAMコントローラのその後(DDR2-400では動作せず)

DDR2 SDRAMコントローラは動作周波数200MHz (DDR2-400) でインプリメントしてSuzaku-V(SZ410)にダウンロードしてテストしているが、なかなか良い遅延値(IDELAYの値)を見つけられない。
書き込んだ値はチップスコープで見ると一部読めているのだが、データが化けてしまうところがある。それに、私のDDR2 SDRAMコントローラは動作周波数の1/4データをずらして、内部クロックに同期してデータを読むように作ってあるのだが、どうもIDELAYで遅延させる前に1/4以上内部クロックから遅れてしまっているようだ。もっとも動作周波数200MHzというと周期で 5ns 、1/4周期というと1.25nsなので、FPGAのIOBの出力遅延、配線遅延などを考えると、やはり厳しいと思う。動作周波数200MHzで動作させるのであれば、以前にやっていたように3/4遅延させてデータをとるようにしないとだめだと思う。
というわけで、データが表示されるはずの7セグLEDには、データの取得タイミングが前ずれしているため表示されないが、チップスコープで見ると一部のデータは読めているのがわかる。結局、動作周波数200MHzは厳しいのかもしれない。私のDDR2 SDRAMコントローラ回路にとっては。。。
そういえば、前の展示会でアットマークテクノの方に聞いたときにEDKのDDR2 SDRAMコントローラでも200MHzでは動いていないといっていたと思った。もちょっと低い周波数だったと思う。もしかしたら本当に厳しいのかもしれない。
というわけで、動作周波数を200MHzから思い切って、DDR2 SDRAM仕様上の最低クロックの125MHz(周期8ns) に落とそうと思っている。これでうまくいったら徐々にクロックを上げいていけば良いしね。。。
  1. 2008年03月01日 05:42 |
  2. DDR SDRAMコントローラ
  3. | トラックバック:0
  4. | コメント:11