FC2カウンター FPGAの部屋 Virtex4のお勉強

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

FPGAの部屋

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

OSERDESとISERDESその後

先週、今週はパソコンのリプレース、プロバイダの乗換えなど、いろいろイベントがあってなかなか進まなかったが、DDR2 SDRAMコントローラ関連のOSERDESとISERDESの問題にはまっている。
どうも最後でPlace & Routeで配線できないと言われてエラーになってしまう。
こんな感じ。

ERROR:Route:472 - 
   This design is unrouteable.
   To evaluate the problem please use fpga_editor.
Routing Conflict 1: 
    Net:GLOBAL_LOGIC0 on pin SR on location OLOGIC_X0Y111 
    Net:SYS_RST_IBUF_1 on pin SR on location ILOGIC_X0Y111 
    Conflict detected on wire: PINFEED(-63835,80448)

Routing Conflict 2: 
    Net:GLOBAL_LOGIC0 on pin SR on location OLOGIC_X0Y113 
    Net:SYS_RST_IBUF_1 on pin SR on location ILOGIC_X0Y113 
    Conflict detected on wire: PINFEED(-63835,84320)


どうやらSR(リセット)ピンがOSERDESとISERDESで違っているのがだめなのか?
DQS付近の入出力用ソースはこの辺。

    // Instantiate DQS DDR registers
    generate
    genvar n;
        for (n=DDR2_DQS_DM_WIDTH-1; n>=0; n=n-1) begin: WRDATA_DQS
            OSERDES # (
                .DATA_RATE_OQ("DDR"),
                .DATA_RATE_TQ("DDR"),
                .DATA_WIDTH(4),
                .INIT_OQ(1'b0),
                .INIT_TQ(1'b1),
                .SERDES_MODE("MASTER"),
                .SRVAL_OQ(1'b0),
                .SRVAL_TQ(1'b1),
                .TRISTATE_WIDTH(4)
            ) WRDATA_DDR2_OUT (
                .OQ(dqs_oq[n]),
                .SHIFTOUT1(),
                .SHIFTOUT2(),
                .TQ(dqs_tq[n]),
                .CLK(clk),
                .CLKDIV(clk100MHz),
                .D1(dqs_oserdes_d_1d[n*4]),
                .D2(dqs_oserdes_d_1d[n*4+1]),
                .D3(dqs_oserdes_d_1d[n*4+2]),
                .D4(dqs_oserdes_d_1d[n*4+3]),
                .D5(),
                .D6(),
                .OCE(1'b1),
                .REV(1'b0),
                .SHIFTIN1(1'b0),
                .SHIFTIN2(1'b0),
                // .SR(dqs_reset_3d[n]),
                .SR(1'b0),
                .T1(dqs_oserdes_t_1d[n*4]),
                .T2(dqs_oserdes_t_1d[n*4+1]),
                .T3(dqs_oserdes_t_1d[n*4+2]),
                .T4(dqs_oserdes_t_1d[n*4+3]),
                .TCE(1'b1)
            );
            
             ISERDES #(
                .BITSLIP_ENABLE("TRUE"),
                .DATA_RATE("DDR"),
                .DATA_WIDTH(4),
                .INTERFACE_TYPE("NETWORKING"),
                .IOBDELAY("IFD"),
                .IOBDELAY_TYPE("FIXED"),
                .IOBDELAY_VALUE(32),
                .NUM_CE(1),
                .SERDES_MODE("MASTER")
            ) DQS_DDR2_IN (
                 .O(ddr2_dqsin_out[n]),
                 .Q1(), 
                 .Q2(), 
                 .Q3(), 
                 .Q4(), 
                 .Q5(), 
                 .Q6(), 
                 .SHIFTOUT1(), 
                 .SHIFTOUT2(),
                 .BITSLIP(1'b0),
                 .CE1(1'b1), 
                 .CE2(1'b1),
                 .CLK(1'b0),
                 .CLKDIV(1'b0),
                 .D(ddr2_dqsin[n]),
                 .DLYCE(1'b0),
                 .DLYINC(1'b0),
                 .DLYRST(1'b0),
                 .OCLK(1'b0), 
                 .REV(1'b0),  
                 .SHIFTIN1(1'b0), 
                 .SHIFTIN2(1'b0),
                 .SR(reset)
              );
             
             BUFIO DQS_DDR2_IN_BUFIO (
                .I(ddr2_dqsin_out[n]),
                .O(ddr2_dqsin_bufio[n])
            );
            
            IOBUF DDD2_DQS_BUF (
                .O(ddr2_dqsin[n]),
                .IO(ddr2_dqs[n]),
                .I(dqs_oq[n]),
                .T(dqs_tq[n])
            );
        end
    endgenerate


.SR(1'b0) と .SR(reset) の違いがある。これをどちらも .SR(reset) にしてみた。
そうするとやはり、このコンフリクトはなくなったが、まだ後、18個のコンフリクトを解消する必要がある。

次は、下のコンフリクト。

Routing Conflict 1: 
    Net:ddr2_sdram_cont_inst/clk90 on pin CLK on location OLOGIC_X0Y97 
    Net:clk on pin OCLK on location ILOGIC_X0Y97 
    Conflict detected on wire: BOUNCEIN(-63349,57088)


これはDQのclk90 と clk がコンフリクトしているようだ。DQのISERDESのOCLK と CLKDIV は clkネットがつながっていて、OSERDESのCLKには clk270 がつながっていた。どうやら、これらのピンは同じクロックがつながっている必要がありようだ。
事実、XAPP721 ISERDES と OSERDES を使用した高性能DDR2 SDRAM インターフェイスを見ても、ISERDESのOCLK と CLKDIV、OSERDESのCLKには同じ CLKfast_90 がつながっている。やはり、配線がこれしかないのだろう。
これで、Place & Route は通ったが、タイミング制約が満足していない。クロックを変更してしまったので、タイミングダイアグラムをもう一度考察する必要が出てきてしまったし。。。

今日の教訓、OSERDES, ISERDESの決まりごと
1.OSERDESとISERDESのSRには同じリセット信号をつなぐ。
2.ISERDESのOCLK と CLKDIV、OSERDESのCLKには同じクロックを入力する。


注:コンフリクトの方がclk90 なのに、なぜclk270 の話になるのかというと、グローバルバッファを削減するためにclk270 は ~clk90として定義してあるからです。
assign clk270 = ~clk90;
  1. 2008年07月11日 04:30 |
  2. Virtex4のお勉強
  3. | トラックバック:0
  4. | コメント:0

OSERDESのお勉強

DDR2 SDRAMコントローラを作っていると、DQなどの入出力ピンの入力をISERDESにして、出力をODDRにすると、どうもPlace & Route でルートできないといわれてエラーになってしまう。
Virtex4のIOブロックの詳細回路図がないのかと思って探したのだが、良くわからなかった。そこでISERDESにはOSERDESを使っておけば問題ないだろうということで、OSERDESを使うことにした。でもOSERDESも内部構造がなぞである。Virtex4 FPGAユーザーズガイド(英語版)ににも載っていないし。。。
でもありました。Xilinx社のアプリケーションノート、XAPP721 ISERDES と OSERDES を使用した高性能DDR2 SDRAM インターフェイスにOSREDESの内部回路が載っていた。説明が少なくてなぞの端子があるが、大体このアプリケーションノートを見るとわかった。でも、もっともっとユーザーズマニュアルに詳しく書いて欲しいと思った。
下にXilinx社のアプリケーションノート、XAPP721 ISERDES と OSERDES を使用した高性能DDR2 SDRAM インターフェイスの3ページより転載します。
V4_OSERSES_1_080630.png

OSERDESをDDRモードにすると、最低4ビット入力となって、CLKDIVはCLK入力の1/2にする必要がある。そうなると、CLKDIVは100MHz、CLKは200MHzとなる。今までは、DDR2 SDRAMコントローラは200MHzで動作していたのだが、OSERDESを使う出力だけは100MHzでデータをロードする必要が出てきた。(ISERDESは200MHzで使うことができた)
最初からすべてのDDR2への出力にOSERDESを使うことを前提に100MHzで設計していたら良いのだろうが、200MHzで動く資産があるので、これを使うには、100MHzで動作するOSERDESとの同期を取る必要がある。200MHzで発行するWriteコマンドを100MHzのクロックエッジに同期させる必要が出てきたので、同期信号を作成した。この同期信号に同期してWriteを発行すれば、100MHzに対してのタイミングが確定されるので、OSERDESでDQとDQSを出力することが出来るようになる。
  1. 2008年06月30日 21:11 |
  2. Virtex4のお勉強
  3. | トラックバック:0
  4. | コメント:0

Virtex4のDCM

私はDCMを使用する際に、IPではなくDCMプリミティブを使用している。DDR2 SDRAMコントローラもSpratan3EのDDR SDRAMコントローラをベースに作り直しているので、DCMプリミティブもそのまま使用していた。
今回、インプリメント時にDDR2 SDRAMコントローラ用のDCMのDLL_FREQUENCY_MODEがLOWだとだめだとDRCが言ってきたので、HIGHに変更した。その後、シミュレーションをしていなかったのだが、スイッチや7セグLEDを上につけてシミュレーションを行ったところ、動作しなかった。
なんだなんだと思って、詳細に見てみたところCLK90が出ていなかった。そういえばVirtex2ではDLL_FREQUENCY_MODEがHIGHだとCLK90とCLK270はでなかった。
Virtex4ではDCMが変更になっているので、DCMプリミティブも変更になっているはずだと思って、ユーザーズマニュアルを見てみた。そうすると、DCM_BASE, DCM_PS, DCM_ADVの3つのプリミティブを使うようだった。(Virtex-4 ユーザーガイド UG070(v1.4)2005年9月12日の56ページから転載)
Virtex4_DCM_080224.png

これを使わないとVirtex4用のDCMは使えないようだ。ちなみにDCM_ADVのVerilog HDLソースコードを読んでみたらDLL_FREQUENCY_MODEがHIGHでもCLK90とCLK270は出力されるようだった。
やはり、CoregenでDCMのIPを使ったほうが安全だと思った。ちょっとやってみたが、DCM_ADVが出てきた。
DCM_ADV_080224.png
  1. 2008年02月24日 15:18 |
  2. Virtex4のお勉強
  3. | トラックバック:0
  4. | コメント:0

ISERDESのNETWORKINGモードのbitslip

ついでなので、ISERDESのNETWORKINGモードのbitslipモードをテストしてみる。”ISERDESのお勉強の続きのその後2”から、わざとDDRのデータをずらして、bitslipを使用してビットの位置を合わせてみた。
テストベンチだけ変えたので、テストベンチはこれ。

`default_nettype none
`timescale 1ps/1ps
module serial_parallel_converter_tb;
    reg Din = 1'b0;
    reg clk_in = 1'b0;
    reg rst = 1'b1; // reset
     reg bitslip = 1'b1; // bitslip mode
    reg enable = 1'b0;
    wire [9:0] recv_data;
    wire [9:0] q_out;
    
    wire [9:0] para10bits;
    wire outbit;
    integer i;
    
    parameter PERIOD = 5000; // 5ns, 200MHz
    parameter real DUTY_CYCLE = 0.5;
    parameter OFFSET = 0;

    initial    // Clock process for clk
    begin
        #OFFSET;
        forever
        begin
            clk_in = 1'b0;
            #(PERIOD-(PERIOD*DUTY_CYCLE)) clk_in = 1'b1;
            #(PERIOD*DUTY_CYCLE);
        end
    end
    
    serial_parallel_converter UUT (
        .Din(Din),
        .clk_in(clk_in),
        .rst(rst),
        .bitslip(bitslip),
        .enable(enable),
        .recv_data(recv_data),
        .q_out(q_out)
    );
    
    initial begin // 10bitを出力
        #100000;    // GSRリセットを待つ
        #(PERIOD);
        rst = 1'b0;
        #(PERIOD);
        enable = 1'b1;
        
        @(posedge UUT.clkdiv); // clkdivの立ち上がりまでWait
         #(PERIOD); // 1clk_inの半分の時間を進める
        #(PERIOD/4);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        #100000
        $stop;
    end
    
    task Out10bits;
        input [9:0] para10bits;
        integer i;
        begin
            for (i=0; i<10; i=i+1)
                Out1bit(para10bits[9-i]);
        end
    endtask
    
    task Out1bit;
        input outbit;
        begin
            Din = outbit;
            #(PERIOD/2);
        end
    endtask
    
    initial begin // データがあってから7つ数えてbitslipを0に。
    // 10'b01_0100_1010の1つ前の立ち上がりでbitslipを0にする必要がある
        @(posedge UUT.clkdiv);
        while (recv_data != 10'b01_0100_1010) 
            @(posedge UUT.clkdiv);
    
        for (i=0; i<10; i=i+1) begin
            @(posedge UUT.clkdiv);
            if (i==7) begin
                #1000;
                bitslip = 1'b0;
            end
        end
    end
    
endmodule
`default_nettype wire


これをシミュレーションするとこうなる。
ISERDES_bitslip_071130.png

rstが上がる前から、bitslipはずーと1で、最初に14ah(10_0100_1010)になってからclkdivの立ち上がりごとにiをカウントしていって7になったときに、bitslipを0にして、ビットの入れ替えをやめる。こうすれば14ah(10_0100_1010)をキープできる。
ネットワークのデータは最初のパターンがわかっていれば、こうしてビットの位置の同期を取ればよいのだろうと思う。
  1. 2007年11月30日 21:33 |
  2. Virtex4のお勉強
  3. | トラックバック:0
  4. | コメント:0

ISERDESのお勉強の続きのその後2

ISERDESのお勉強の続きで1:10のDDRのISERDESをインプリメントしてみたが、今度はシミュレーションをしてみた。ISERDESの1:8のSDRのタイミングチャートがユーザーズマニュアルにあったが、このタイミングチャートだとすると、今やっている1:10のDDRのタイミングと合わない気がするが、とりあえずBitslipを使ってみたので、記録しておく。
どうやら、DDRはCEが1になったclkdivの立ち上がりと同時のclk_inや次のclk_inの立下りからではなく、次のclk_inの立ち上がりからシリアルーパラレル変換するようだ。タイミングを調整して、このタイミングにあわせる。
この前のISERDESのVerilogファイルはこのように変更した。

`default_nettype none
`timescale 1ps/1ps
module serial_parallel_converter (
    Din,
    clk_in,                       
    rst,
    bitslip,
    enable,
    recv_data,
    q_out
);
    input  Din;
    input  clk_in;
    input  rst;
    input bitslip;
    input enable;
    output [9:0] recv_data;
    output [9:0] q_out;
    wire    Din;
    wire    clk_in;
    wire    rst;
    wire    bitslip;
    wire    enable;
    wire    [9:0] recv_data;
    wire    [9:0] q_out;
    wire   iserdes_clkout;
    wire   iobclk;
    wire   clkdiv;
    wire   shiftdata1;
    wire   shiftdata2;
    wire [9:0] data_internal;
    reg    [9:0] data;
    
    // Instantiate ISERDES for forwarded clock
     ISERDES fwd_clk (
         .O(iserdes_clkout),
         .Q1(), 
         .Q2(), 
         .Q3(), 
         .Q4(), 
         .Q5(), 
         .Q6(), 
         .SHIFTOUT1(), 
         .SHIFTOUT2(),
         .BITSLIP(1'b0),
         .CE1(1'b1), 
         .CE2(1'b1),
         .CLK(iobclk),
         .CLKDIV(clkdiv),
         .D(clk_in),
         .DLYCE(1'b0),
         .DLYINC(1'b0),
         .DLYRST(1'b0),
         .OCLK(1'b0), 
         .REV(1'b0),  
         .SHIFTIN1(1'b0), 
         .SHIFTIN2(1'b0),
         .SR(rst)
      );
    defparam fwd_clk.BITSLIP_ENABLE  =  "TRUE"; 
    defparam fwd_clk.DATA_RATE =  "DDR";
    defparam fwd_clk.DATA_WIDTH =  4;   
    defparam fwd_clk.INTERFACE_TYPE =  "NETWORKING"; 
    defparam fwd_clk.IOBDELAY =  "NONE"; 
    defparam fwd_clk.IOBDELAY_TYPE =  "DEFAULT"; 
    defparam fwd_clk.IOBDELAY_VALUE = 0; 
    defparam fwd_clk.NUM_CE = 1; 
    defparam fwd_clk.SERDES_MODE =  "MASTER"; 
    
    // Instantiate Master ISERDES for data channel
    // 1:10 Deserialization Factor
    ISERDES data_chan_master (
        .O(), 
        .Q1(data_internal[0]),
        .Q2(data_internal[1]),
        .Q3(data_internal[2]), 
        .Q4(data_internal[3]),
        .Q5(data_internal[4]),
        .Q6(data_internal[5]),
        .SHIFTOUT1(shiftdata1),
        .SHIFTOUT2(shiftdata2),
        .BITSLIP(bitslip),
        .CE1(enable), 
        .CE2(1'b1),
        .CLK(iobclk),
        .CLKDIV(clkdiv),
        .D(Din), 
        .DLYCE(1'b0),
        .DLYINC(1'b0),
        .DLYRST(1'b0),
        .OCLK(1'b0), 
        .REV(1'b0),
        .SHIFTIN1(1'b0), 
        .SHIFTIN2(1'b0),
        .SR(rst)
    );
    defparam data_chan_master.BITSLIP_ENABLE =  "TRUE"; 
    defparam data_chan_master.DATA_RATE =  "DDR";
    defparam data_chan_master.DATA_WIDTH =  10;   
    defparam data_chan_master.INTERFACE_TYPE =  "NETWORKING";         
    defparam data_chan_master.IOBDELAY =  "NONE";                 
    defparam data_chan_master.IOBDELAY_TYPE =  "DEFAULT";         
    defparam data_chan_master.IOBDELAY_VALUE =  0;                
    defparam data_chan_master.NUM_CE =  1;                        
    defparam data_chan_master.SERDES_MODE =  "MASTER"; 
    //
    // Instantiate Slave ISERDES for data channel
    // 1:10 Deserialization Factor

    ISERDES data_chan_slave (
        .O(), 
        .Q1(), 
        .Q2(), 
        .Q3(data_internal[6]),
        .Q4(data_internal[7]),
        .Q5(data_internal[8]),
        .Q6(data_internal[9]),
        .SHIFTOUT1(), 
        .SHIFTOUT2(),
        .BITSLIP(bitslip),
        .CE1(enable), 
        .CE2(1'b1),
        .CLK(iobclk),
        .CLKDIV(clkdiv),
        .D(1'b0), 
        .DLYCE(1'b0),
        .DLYINC(1'b0),
        .DLYRST(1'b0),
        .OCLK(1'b0), 
        .REV(1'b0),
        .SHIFTIN1(shiftdata1), 
        .SHIFTIN2(shiftdata2),
        .SR(rst)
    );
    defparam data_chan_slave.BITSLIP_ENABLE =  "TRUE"; 
    defparam data_chan_slave.DATA_RATE =  "DDR";
    defparam data_chan_slave.DATA_WIDTH =  10;   
    defparam data_chan_slave.INIT_Q1  =  1'b0;   
    defparam data_chan_slave.INIT_Q2  =  1'b0;   
    defparam data_chan_slave.INIT_Q3  =  1'b0;        
    defparam data_chan_slave.INIT_Q4  =  1'b0;   
    defparam data_chan_slave.INTERFACE_TYPE  =  "NETWORKING";         
    defparam data_chan_slave.IOBDELAY  =  "NONE";                 
    defparam data_chan_slave.IOBDELAY_TYPE  =  "DEFAULT";         
    defparam data_chan_slave.IOBDELAY_VALUE  =  0;                
    defparam data_chan_slave.NUM_CE  =  1;                        
    defparam data_chan_slave.SERDES_MODE  =  "SLAVE";             
    defparam data_chan_slave.SRVAL_Q1  =  1'b0;                   
    defparam data_chan_slave.SRVAL_Q2  =  1'b0;                   
    defparam data_chan_slave.SRVAL_Q3  =  1'b0;                   
    defparam data_chan_slave.SRVAL_Q4  =  1'b0;
    //
    BUFIO bufio1 (
        .O(iobclk),
         .I(iserdes_clkout)
                 );
    // To get a 1:10 deserialization factor in DDR mode, 
    // set the clock divide factor to "5"
    BUFR bufr1 (
        .O(clkdiv),
        .CE(1'b1),
        .CLR(1'b0),
        .I(iobclk)
    );
    defparam bufr1.BUFR_DIVIDE  =  "5";
    
    always @(posedge rst, posedge clkdiv) begin

        if (rst)
            data <= 0;
        else
            data <= data_internal;
    end
    assign q_out = data;
    assign recv_data = data_internal;
endmodule
    


次にテストベンチ。

`default_nettype none
`timescale 1ps/1ps
module serial_parallel_converter_tb;
    reg Din = 1'b0;
    reg clk_in = 1'b0;
    reg rst = 1'b1; // reset
//     reg bitslip = 1'b1; // bitslip mode
    reg enable = 1'b0;
    wire [9:0] recv_data;
    wire [9:0] q_out;
    
    wire [9:0] para10bits;
    wire outbit;
    integer j;
    
    parameter PERIOD = 5000; // 5ns, 200MHz
    parameter real DUTY_CYCLE = 0.5;
    parameter OFFSET = 0;

    initial    // Clock process for clk
    begin
        #OFFSET;
        forever
        begin
            clk_in = 1'b0;
            #(PERIOD-(PERIOD*DUTY_CYCLE)) clk_in = 1'b1;
            #(PERIOD*DUTY_CYCLE);
        end
    end
    
    serial_parallel_converter UUT (
        .Din(Din),
        .clk_in(clk_in),
        .rst(rst),
        .bitslip(1'b0),
        .enable(enable),
        .recv_data(recv_data),
        .q_out(q_out)
    );
    
    initial begin // 10bitを出力
        #100000;    // GSRリセットを待つ
        #(PERIOD);
        rst = 1'b0;
        #(PERIOD);
        enable = 1'b1;
        
        @(posedge UUT.clkdiv); // clkdivの立ち上がりまでWait
        #(PERIOD/2); // 1clk_inの半分の時間を進める
        #(PERIOD/4);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b01_0100_1010);
        Out10bits(10'b10_0101_1011);
        #100000
        $stop;
    end
    
    task Out10bits;
        input [9:0] para10bits;
        integer i;
        begin
            for (i=0; i<10; i=i+1)
                Out1bit(para10bits[9-i]);
        end
    endtask
    
    task Out1bit;
        input outbit;
        begin
            Din = outbit;
            #(PERIOD/2);
        end
    endtask
    
//     always @* begin // q_outが10'b01_0100_1010の1つ前の10'b10_1001_0100になったらbitslipを0にする
//         if (recv_data == 10'b10_1001_0100)
//             bitslip = 1'b0;
//     end
    
    
endmodule
`default_nettype wire


最終的にbitslipは使用しなかったが、クロックと送ってきたビット列が合わずにワード同期が取れない場合は、bitslipを最初1にして、ビット列を移動することができる。そのときに、送ったデータと同一になったらbitslipを0にしてビット列の移動を止めれよいが、ISERDESのQ出力は1段多くラッチされているので、1つ手前でbitslip信号を0にしないと行き過ぎてしまう。
シミュレーションすると下のようになる。
ISERDES_1_10_071129.png

rstが0になって、enable(CE1)がclkdivの前でアサートされたクロックエッジの次のclk_inの立ち上がりエッジからデータ(Din)をサンプルするようだ。
サンプルされたデータはclkdivでラッチされて、次のclkdivの立ち上がりで出力([9:0]data_internal)されるようだ。
これでNETWORKINGモードでは、うまく行ったようだ。ずーと同じタイミングでデータ転送されればこれでOKだと思う。もしビット列が間違っていても、あらかじめ参照パターンがわかっていれば、bitslipを使って必要なだけビット列を入れ換えれば良い。
だが、DDRの受信の場合は、必ずしもそのタイミングに合うというわけではないので、bitslipでビット列を入れ替えるのは難しい。さらにclkdivは、clk_in(DQS)が途中で止まってしまうので、DQSから分周して作るのは難しいと思う。そこで、グローバルクロックから入れたらどうだろうと思っている。
さらに、DDR2-SDRAMコントローラのアプリケーションノートはMEMORYモードで使用しているので、検証してみたい。
  1. 2007年11月29日 20:54 |
  2. Virtex4のお勉強
  3. | トラックバック:0
  4. | コメント:0

ISERDESのお勉強の続きのその後

”ISERDESのお勉強の続き1”で書いたVerilogコードはシミュレーションで動作しないことがわかったので、11月27日に修正した。
ISERDESの属性のNTERFACE_TYPE = "MEMORY";にしておくと、OCLKにクロックを入れないと動作しないようだ。よって、INTERFACE_TYPE = "NETWORKING"; に修正した。このままだとMAPでエラーが出るので、BITSLIP_ENABLE = "TRUE"; に修正した。もう”ISERDESのお勉強の続き1”は修正してある。
シミュレーションで気がついたが、ビット列の並びが合わない。これはCE1,CE2ともイネーブルだし、同期を取っていないので、当たり前といえばあたり前田とおもう。(古いギャグですみません。クラッカーですね)
これが"NETWORKING"ということなんだろうと思う。ちょうど都合がいいので、bitslipを使用して同期を取ろうと思ってやってみている。大体同期が取れそうだ。
DDR2-SDRAMのリードデータを受けるときにも、このような感じでも良いと思うのだが、”XAPP721 - ISERDES と OSERDES を使用した高性能 DDR2 SDRAM インターフェイスのデータ キャプチャ (日本語版) (PDF)”を見ると NTERFACE_TYPE = "MEMORY"; で使ってOCLKにクロックを入れて使っているようだ。やはり、もう少しISERDESの研究が必要のようだ。
それにしても、ISERDESとOSERDESの情報が少ない。ブロック図、タイミングチャートがユーザーズマニュアルにもない。どこかに情報があるのだろうか? 情報があるのを知っている方は、よろしければ教えてください。

2007/11/29 追記:ISERDESの1:8のSDRのタイミングチャートがユーザーズマニュアルにあったが、このタイミングチャートだとすると、今やっている1:10のDDRのタイミングと合わない気がする。1:8のSDRで正しいかどうかを検証したほうが良いかもしれない。とりあえず、今日くらいに現状をブログに書こうと思う。
  1. 2007年11月28日 08:27 |
  2. Virtex4のお勉強
  3. | トラックバック:0
  4. | コメント:0

ISERDESのお勉強の続き2

ISERDESのお勉強の続き1の続き。

制約したタイミングが表示されるところから。
(注:ISEに Timinig Analyzer や Floorplan Editor が統合されているはVirtex4やVirtex5、Spartan3Aのデバイスのみです。その他は、 Timinig Analyzer 単体起動、 Floorplan Editor は起動しないようです)
Soucesウインドウの"TS_clkdiv = PERIOD TIMEGRP "clkdiv" TS_clk_in *5 HIGH 40%"を展開して、data_0からdata_9までの10種類のパスを開こう。そのうちのdata_1をクリックして、右に表示すると、clkdivについてのトータルの遅延は3.193 nsだった。
ISERDES_Verilog_5_071117.png

さらに、data_internal<1>をクリックして、Floorplan Editorを立ち上げてみよう。
チップ全体が表示されるので、アイコンの上の列の左から5番目、Zoom to Selected をクリックして、配線をズームする。
ISERDES_Verilog_6_071117.png

そうすると上のように表示される。
さらに、ピンクの四角で囲ったToggle Visibility of Routiing アイコンをクリックし、その右のアイコンも下の図と同様にクリックしよう。
ISERDES_Verilog_7_071117.png

今度はすべての配線が水色の線で見えているはずだ。下の図と同様に見えると思う。
カーソルを配線にポイントすると、配線遅延がポップアップされる。clkdivの配線遅延は0.567 nsだ。
ISERDES_Verilog_8_071117.png

Toggle Simplified and Actial Views をクリックして、Actial Viewにしてみよう、いままでのViewはSimplified Viewだろうと思う。下の図はもうすでにActial Viewになっている。Actial Viewにするとだいぶ様子が変わってしまう。
さらにズームすると、ちょうどFPGA Editorで見ているように表示されている。Simplified Viewの配線の見た目の長さは当てにならないのかもしれない?
ISERDES_Verilog_9_071117.png

今度はclk_inのタイミングが解析されていないのが気になるので、clk_inポートからISERDESクロック入力ポートまでの遅延とDinポートからISERDESのD入力ポートの遅延の差を比べてみようと思う。
まずはISEのTiming Constarnts Analysis Report 1のタブをクリックして、Timinig Analyzerに戻そう。
AnalyzeメニューからAgainst Use Specified Pathsを選んで、その下のby Defining Endpoins... をクリック。
ISERDES_Verilog_10_071117.png

Analyze against Use Specified Paths by Defining Endp...ダイアログが開くので、Padsを展開してclk_inをSourcesの>ボタンをクリックして、Resourceに追加する。
ISERDES_Verilog_11_071117.png

Netsを展開して、iobclkをクリックして、Destinationsの>ボタンをクリックして、Resoucesに追加する。
ISERDES_Verilog_12_071117.png

そうしたら、OKボタンをクリックする。これでclk_in入力からiobclkネットまでの遅延が算出できる。下の図のように、1.994ns だった。
ISERDES_Verilog_13_071117.png

同様に、Din入力から、Din_IBUFネットまでの遅延を測る。Tisdck Dがなんだか、いまいちわからないがdata_chan_masterの入力遅延だろうか? それを入れても1.358ns だ。
ISERDES_Verilog_14_071117.png

結局、Dinよりもclk_inの方が遅延が大きいので、DDR2-SDRAMのDQとDQSに割り当てたときには、その辺の遅延関係も考慮しなければならないだろう。これだとDQSでデータを取っても大丈夫かもしれないがリードの時のイネーブルを作るのが難しそうだ。今度はグローバルクロックをISERDESのクロックに入れたときどうなるかを調べて見ようと思う。
また、DQSをグローバルクロックの位相と同じになるように遅延させて、その遅延させたDQSでサンプルできるように、DQを遅延調整しても良いかな?
  1. 2007年11月19日 20:44 |
  2. Virtex4のお勉強
  3. | トラックバック:0
  4. | コメント:0
»