FC2カウンター FPGAの部屋 ISERDESのお勉強の続き1
FC2ブログ

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

FPGAの部屋

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

ISERDESのお勉強の続き1

Virtex4搭載SUZAKU-VでDDR2-SDRAMコントローラを自作する準備として、Virtex4のISERDES, OSERDESをもう一度勉強することにした。
まずは、Virtex4ユーザーズガイド日本語版UG070(v1.4)を読んで勉強することにした。読んでは見たが良くわからないので、例によってサンプルをインプリメントしてチップ内を眺めてみることにした。ユーザーズマニュアルの356ページのビ ッ ト 幅拡張用の Verilog インステンシエーションテンプレートをやってみることにした。これは1:10のISERDESの例だ。
このままインプリメントすると、出力データが外に出ていないので、インプリメントするとなくなってしまう。そこで、D-FFを通して外に出力されるように変更した。(取り合えずということで、次にやるときには、分散RAMの非同期FIFOをつけると思う)
書き換えた部分だけを下に示す。

module serial_parallel_converter (
    Din,
    clk_in,                       
    rst,
    q_out
);
...
    output [9:0] q_out;
...
    reg    [9:0] data;
...
    always @(posedge rst, posedge clkdiv) begin
        if (rst)
            data <= 0;
        else
            data <= data_internal;
    end
    assign q_out = data;
endmodule


もう1つUCFはclk_inの周期を5ns、つまり200MHzに設定してみた。

NET "clk_in" TNM_NET = "clk_in";
TIMESPEC "TS_clk_in" = PERIOD "clk_in" 5 ns HIGH 50 %;


これでインプリメントしてTiming Analyzerで見てみたが、clkdvを使っているはずのdataまでのパスが5nsで解析されていた。これはおかしい。少なくとも// synthesis BUFR_DIVIDE of bufr1 is "5";は効いていないんじゃないだろうかということで、defparamに変更してみた。
次にソースを全部示す。

`default_nettype none
`timescale 1ps/1ps
module serial_parallel_converter (
    Din,
    clk_in,                       
    rst,
    q_out
);
    input  Din;
    input  clk_in;
    input  rst;
    output [9:0] q_out;
    wire    Din;
    wire    clk_in;
    wire    rst;
    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(1'b0),
        .CE1(1'b1), 
        .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(1'b0),
        .CE1(1'b1), 
        .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;
endmodule


上のソースでISERDESの属性のうち INTERFACE_TYPE = "MEMORY"; にした。基は"NETWORKING"だったのだが、"NETWORKING"だとISEでインプリメントしているときにMAPでエラーが出てしまう。下のようなエラーだ。

ERROR:PhysDesignRules:1696 - ISERDES instance <data_chan_master> has the
   attribute INTERFACE_TYPE set to NETWORKING and BITSLIP_ENABLE set to FALSE
   which are incompatible. BITSLIP_ENABLE must be set to TRUE when
   INTERFACE_TYPE is set to NETWORKING. This must be corrected in order to
   properly implement the design. 


結局、"NETWORKING"だと、BIT_SLOP_ENABLEをTRUEにしなければいけないようだ。よって、 INTERFACE_TYPE = "MEMORY"; に変更した。
これで、ちゃんとインプリメントできたようだ。

(2007/11/27 追記: MEMORYだとOCLKにクロックを入れないとだめなようなので、"NETWORKING"に戻して、BITSLIP_ENABLE = "TRUE"; に変更した。)

ISE9.2SP3でTiming AnalyzerやFloorplan Editorを使ってみようということもあって、詳しくやり方を見ていこうと思う。
まずはインプリメント後に、Processesペインのimplement Designを展開して、Place & Routeを展開。Generate Post-Place & Route Static Timingを展開して、Analyze Post-Place & Route Static Timingをダブルクリックして、Timing Analyzerを立ち上げる。Virtex4はISEに統合されているので、ISE上でTiming Analyzerが開く。
ISERDES_Verilog_1_071117.png

clk_inの解析するパスはないので、すべてのclkdivのパスを解析してみよう。Analyzメニューから Analyzer Timing Constraints... を選択する。
ISERDES_Verilog_2_071117.png

Analyze against Timing Constarintsダイアログが表示される。
ISERDES_Verilog_3_071117.png

Optionsタブをクリック。Timing Constraint Details を No limit にする。ちなみに、大きなデザインでTiming Constraint Details を No limit にすると時間がかかって大変なことになるので注意。
ISERDES_Verilog_4_071117.png

タイミングが表示されるが、長くなったので、次回とする。
ISERDESのお勉強の続き2に続く。

2007/11/27 追記: INTERFACE_TYPE = "MEMORY";にしておくと、OCLKにクロックを入れないと動作しないようだ。
INTERFACE_TYPE = "NETWORKING"; 
BITSLIP_ENABLE = "TRUE";
に変更した。

2007/11/28 追記:ザイリンクスの”アンサー# 25507 - 9.2i ISE - DRC で「ERROR:PhysDesignRules:1696 -BITSLIP_ENABLE must be set to TRUE when INTERFACE_TYPE is set to NETWORKING」というエラー メッセージが表示される”というのがあった。それによると、ISERDES でタイミングが確実に満たされるようにするレジスタを入れるために NETWORKING では、BITSLIP_ENABLEを TRUE にするようにしたようだ。
  1. 2007年11月17日 22:11 |
  2. Virtex4のお勉強
  3. | トラックバック:0
  4. | コメント:3

コメント

こんばんは
記事が今後の展開では興味があるのですが、
私的なことですみませんが、VHDLは最近パスでしょうか。昔VHDL主体だったと思いますが。Verilog 読めないんです。
更に関係なくてすみません。Verilog VS VHDL なんて記事いかがですか。実際のユーザー割合なんて気になります。若干Verilogが多いみたいですが。
  1. 2007/11/18(日) 00:26:21 |
  2. URL |
  3. NSX #-
  4. [ 編集 ]

NSXさん、こんにちは。
以前はVHDLでやっていたんですが、家にはModelSim Starterしかないので、DDR-SDRAMコントローラを作ったときに、モデルを含めると1万行リミットを越えてシミュレーションにえらく時間がかかりました。ModelSimのかわりにVeritakを使おうと思っていますので、Verilogで書き始めました。
私も仕事はVHDLですので、VHDLでも良いのですが、Verilogにしたのはそういった理由です。VerilogもVHDLのように書くの好きです。taskよりもprocedureの法が好きですし。。。
というわけがありますので、すみません。
VHDL対Verilogのユーザー割合は日本ではVerilogの方が多いような気がします。海外はVHDLも多いような気がしますし、日本でも某C社や某T社はVHDLだそうです。VHDL対Verilogのユーザー割合はMIXIのトピにもありますね。Verilogの方が少し多かった気がしますが、両刀使いという人も結構いました。
  1. 2007/11/18(日) 05:58:27 |
  2. URL |
  3. marsee #-
  4. [ 編集 ]

おはようございます。丁寧な回答ありがとうございます。
Verilogを理解できるよう努力したいと思います。
別トビで語られているわけですね。
昔ある上位言語をみたとき出力コードがVHDLだけだったと思いました。自分的には今後VHDLの比率が高くなってくるような気はしています。
  1. 2007/11/18(日) 11:32:58 |
  2. URL |
  3. NSX #-
  4. [ 編集 ]

コメントの投稿


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

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