FC2カウンター FPGAの部屋 1次元配列データのパートセレクト
FC2ブログ

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

FPGAの部屋

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

1次元配列データのパートセレクト

OSERDESを使ってDDR2 SDRAMコントローラを作成しているが、その際に、どうしてもVerilogの構文がわからないところが出てきた。
OSERDESはDDRモードで4:1のシリアライザとして使用している。CLKDIV (100MHz, CLKは200MHz) 1クロックごとにOSERDESのD1, D2, D3, D4 のデータの4ビットとT1, T2, T3, T4 のトライステート状態ビット4ビット分を一度に入れる。DQSはSUZAKU-Vでは2ビットあるので、2ビット(2つ)分のデータ4ビットとトライステート状態4ビット分を確保したいと思った。1つ分ではないのは、ネットを短くして動作周波数を確保するためだ。
これを宣言するためには、2次元配列で宣言するのが一番自然なので、最初に2次元配列で宣言した。
だが、どうしても出力ポートを2次元配列にして上のモジュールに渡そうとしてもエラーになってしまう。どうしてよいか困ったため、mixiのVeritak友の会で聞いてみたところ、たっくさんからお返事があった。やはり、ポートの宣言に2次元配列は書けないということなので、1次元配列でやることにした。それでためしに自分で作ってみたのが下。

    output reg [4*DDR2_DQS_DM_WIDTH-1 : 0] dqs_oserdes_d_1d;
    output reg [4*DDR2_DQS_DM_WIDTH-1 : 0] dqs_oserdes_t_1d;

    always @(posedge clk) begin : DQS_OSERDES_1D // dqs_oserdes_d_1dとdqs_oserdes_t_1dがOSERDESに入力される
        integer k;
        
        for(k=0; k<=DDR2_DQS_DM_WIDTH-1; k=k+1) begin // 8bitに1個インスタンシエーション
             if (reset) begin
                 dqs_oserdes_d_1d[k*4+3 : k*4] <= 4'bXXXX;
                 dqs_oserdes_t_1d[k*4+3 : k*4] <= 4'b1111;
             end else begin
                 dqs_oserdes_d_1d[k*4+3 : k*4] <= dqs_oserdes_d;
                 dqs_oserdes_t_1d[k*4+3 : k*4] <= dqs_oserdes_t;
             end        
        end
    end


でもこれではエラーになってしまって、XSTの論理合成が通らない。(とりあえず、インプリメントできるかやっているので)
Veritak友の会で、べりろじしゃんという方に教えていただいて、2重ループで書いてみたらOKだった。

    always @(posedge clk) begin : DQS_OSERDES_1D // dqs_oserdes_d_1dとdqs_oserdes_t_1dがOSERDESに入力される
    integer k, m;

        for(k=0; k<=DDR2_DQS_DM_WIDTH-1; k=k+1) begin // 8bitに1個インスタンシエーション
            for(m=0; m<4; m=m+1) begin
                if (reset) begin
                    dqs_oserdes_d_1d[k*4+m] <= 1'bX;
                    dqs_oserdes_t_1d[k*4+m] <= 1'b1;
                end else begin
                    dqs_oserdes_d_1d[k*4+m] <= dqs_oserdes_d[m];
                    dqs_oserdes_t_1d[k*4+m] <= dqs_oserdes_t[m];
                end
            end
        end
    end



また、違う書き方を、たっくさんに教えていただいた。それによるとVerilog2001では下のように書けるそうだ。

    always @(posedge clk) begin : DQS_OSERDES_1D // dqs_oserdes_d_1dとdqs_oserdes_t_1dがOSERDESに入力される
        integer k, m;
        
        for(k=0; k<=DDR2_DQS_DM_WIDTH-1; k=k+1) begin // 8bitに1個インスタンシエーション
            if (reset) begin
                dqs_oserdes_d_1d[k*4 +: 4] <= 4'bXXXX;
                dqs_oserdes_t_1d[k*4 +: 4] <= 4'b1111;
            end else begin
                dqs_oserdes_d_1d[k*4 +: 4] <= dqs_oserdes_d;
                dqs_oserdes_t_1d[k*4 +: 4] <= dqs_oserdes_t;
            end
        end 
    end


下にたっくさんの書き込みを引用させていただきます。

reg [8:0] a;

のとき、

a[1 +:4] は、a[4:1] に等価です。1から出発して1,2,3,4 のパートセレクト
a[5 -:4: は、a[5:2] に等価です。5から出発して5,4,3,2のパートセレクト


ちなみに
reg [0:8] a;
のとき、
a[1 +: 4] は、a[1:4]に等価、a[5 -: 4] はa[2:5] に等価だそうだ。
たっくさん、貴重な知識を教えていただいてありがとうございました。

次に、べろりじしゃんさんにもgenerate を使用した書き方の例を教えていただいた。その例を参考に自分で書き直してみたのが下。

    generate
    genvar k, m;
        for(k=0; k<=DDR2_DQS_DM_WIDTH-1; k=k+1) begin : OSERDES_NO // 8bitに1個インスタンシエーション
            for(m=0; m<4; m=m+1) begin : OSERDES_PIN_NO
                always @(posedge clk) begin
                    if (reset) begin
                        dqs_oserdes_d_1d[k*4+m] <= 1'bX;
                        dqs_oserdes_t_1d[k*4+m] <= 1'b1;
                    end else begin
                        dqs_oserdes_d_1d[k*4+m] <= dqs_oserdes_d[m];
                        dqs_oserdes_t_1d[k*4+m] <= dqs_oserdes_t[m];
                    end
                end
            end
        end
    endgenerate


べろりじしゃんさん、貴重なVerilogコードを開示していただいてありがとうございます。

べろりじしゃんさんは、CQ出版でVerilog関連の本を何冊も書いている方のようだ。
  1. 2008年07月11日 21:18 |
  2. 入門Verilog
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/833-827739f3
この記事にトラックバックする(FC2ブログユーザー)