FC2カウンター FPGAの部屋 2007年02月12日
FC2ブログ

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

FPGAの部屋

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

Verilog2001版DDR SDRAMコントローラのバグ

mixiの方からModelSimとは違うシミュレータでVerilog2001版DDR SDRAMコントローラがシミュレーションできないという報告をもらった。

最初のバグは、ontroller.v 724行目のendcaseの後に ; を入れてしまったことだ。こう書いてもModelSimではエラーを出さないようだ。VHDLだと ; を書くので思わず入れてしまったようだ。

もう1つは write_data_module.v でグローバル変数 j を定義してその j を2つのalways @* 内で使用してしまったのでレース状態が発生してしまったらしい。ModelSimはそれでも動作するがシミュレータによっては無限ループになるらしい。必ずしもシミュレータが悪いのではなく、記述が悪かった。
元のVerilogコードは、(途中を抜いているが。。。)

    integer  j;

    // inferr the 3-State buffer
    always @ * begin
        for (j=DDR_DATA_WIDTH-1; j>=0; j=j-1) begin
            if (out_tri[j] == 1'b1)
                ddr_dq[j] <= 1'bZ;
            else
                ddr_dq[j] <= ddr_out[j];
        end
    end

    // inferr the 3-State buffer
    always @ * begin
        for (j=DDR_DQS_DM_WIDTH-1; j>=0; j=j-1) begin
            if (dqs_tri_enable_2dx[j]==1'b1)
                ddr_dqs[j] <= 1'bZ;
            else
                ddr_dqs[j] <= dqs_out[j];
        end
    end


これだとalways @*なのでイベントリストには j も入ってしまって、2つのalways @*文の間で無限ループになってしまうということだ。
シミュレータの作りとしては、

1) グローバル変数 j の値とイベントフィールドをタイムホイールに生成する。
2) 1つ目の always @* をDELTA時間で評価する。j が変化したので値とイベントフィールドを更新。
3) j の変更イベントフィールドがアップデートされているので、2つ目の always @* を同じDELTA時間で評価する。j が変化したので値とイベントフィールドを更新。
4) j の変更イベントフィールドがアップデートされているので、1つ目の always @* を同じDELTA時間で評価する。j が変化したので値とイベントフィールドを更新。

ということで、3)と4)を繰り返すことが考えられる。
間違っているかもしれないが、このようなことなのだろうと理解した。
j をグローバル変数ではなく、ローカル変数にする方法も教えていただいたのでローカル変数に変更して、この問題を逃れた。それが下のVerilogコードだ。(ちなみに本当はgenerate文で書いたほうが良いそうだ。)

    // inferr the 3-State buffer
    always @ * begin :Ddr_Dq_Gen_Loop
        integer k;
        
        for (k=DDR_DATA_WIDTH-1; k>=0; k=k-1) begin
            if (out_tri[k] == 1'b1)
                ddr_dq[k] <= 1'bZ;
            else
                ddr_dq[k] <= ddr_out[k];
        end
    end

    // inferr the 3-State buffer
    always @ * begin :Ddr_Dqs_Gen_Loop
        integer k;
        
        for (k=DDR_DQS_DM_WIDTH-1; k>=0; k=k-1) begin
            if (dqs_tri_enable_2dx[k]==1'b1)
                ddr_dqs[k] <= 1'bZ;
            else
                ddr_dqs[k] <= dqs_out[k];
        end
    end


always @ * begin :Ddr_Dq_Gen_Loop というようにbegin end に :Ddr_Dq_Gen_Loop というようなユニークな名前をつけると、その中でスコープを保証する記述になるそうです。(なお、Quartusではローカル変数を使ったVerilog記述は使用できない可能性があるそうです)

もう1つgenerateのgenvarもユニークな変数を割り当てなければだめなようです。

いろいろ問題点を指摘していただいて、ありがとうございます。

今度はインプリメントを説明してみようと思う。
もうわかっている方もいらっしゃると思うが、シミュレーションとインプリメントでパラメータを変更できるようになっている。実際のパラメータでシミュレーションすると何時間かかるかわからない。。。
  1. 2007年02月12日 18:34 |
  2. シミュレーション
  3. | トラックバック:0
  4. | コメント:10