コード中に制約を書くときの注意点 のバックアップソース(No.1)

更新

[[公開メモ]]

#contents

* コード中に制約を埋め込む [#s40b8ab3]

次のコードは [[非同期信号を扱うための危ういVerilogライブラリ>電気回路/HDL/非同期信号を扱うための危ういVerilogライブラリ#非同期信号を2段FFで受ける]] で紹介している、非同期信号を同期化するためのコードです。

 LANG:verilog
 module double_ff #(
     parameter INIT = 1'b0
 ) (
     (* TIG="TRUE" *) input wire idata,
     input wire oclk,
     output wire odata
 );
     wire temp;
 
     (* IOB="FALSE", RLOC="X0Y0", ASYNC_REG="TRUE" *)
     FDRSE #(
         .INIT(INIT)     // Initial value of register (1'b0 or 1'b1)
     ) temp0 (
         .Q(temp),       // Data output
         .C(oclk),       // Clock input
         .CE(1'b1),      // Clock enable input
         .D(idata),      // Data input
         .R(1'b0),       // Synchronous reset input
         .S(1'b0)        // Synchronous set input
     );
 
     (* IOB="FALSE", RLOC="X0Y0" *)
     FDRSE #(
         .INIT(INIT)     // Initial value of register (1'b0 or 1'b1)
     ) temp1 (
         .Q(odata),      // Data output
         .C(oclk),       // Clock input
         .CE(1'b1),      // Clock enable input
         .D(temp),       // Data input
         .R(1'b0),       // Synchronous reset input
         .S(1'b0)        // Synchronous set input
     );
 endmodule

このモジュールは1つのプロジェクト中で何十回、何百回も使うことになるため、
上記のように TIG や IOB, ASYNC_REG, RLOC といった制約をコード中に埋め込めれば
大きな助けになります。

そうでなければ、何百もの double_ff 
のインスタンスに対応する個別の制約を .ucf 
ファイルに別途記述しなければならないからです。

上記制約は次の意味を持っています。

- idata から temp0 へのパスは遅延解析が必要ないため idata に TIG を付けています
- temp0 や temp1 が IOB に入らないように IOB を付けています
- temp0 は非同期信号を受け取る事が分かっているので ASYNC_REG を付けています
- temp0 と temp1 とが同じスライスに入るように RLOC を付けています

この書き方は ISE コードエディタの Language Templates の記述をほぼ踏襲しているのですが、
そのままつかうにはいくつか問題がありそうで、いろいろ調べてみました。

* 異なるパラメータでインスタンス化する [#if684495]

問題をはっきりさせるため、下記のあまり意味はないですがシンプルな例で見てみます。

 LANG:verilog
 module main1 (
     input clk_125MHz_in,
 
     input idata,
     output odata
 );
 
     DCM_SP #(
         .CLKIN_PERIOD(8.0),         // Specify period of input clock
         .CLK_FEEDBACK("1X")         // Specify clock feedback of NONE, 1X or 2X
     ) DCM_SP_inst (
         .CLK0(clk_125MHz),          // 0 degree DCM CLK output
         .CLK90(clk_125MHz90),       // 90 degree DCM CLK output
         .CLKFB(clk_125MHz),         // DCM clock feedback
         .CLKIN(clk_125MHz_in)       // Clock input (from IBUFG, BUFG or DCM)
     );
 
     double_ff double_ff0  ( .idata(idata),      .oclk(clk_125MHz),   .odata(clk0_idata) );
     double_ff double_ff90 ( .idata(clk0_idata), .oclk(clk_125MHz90), .odata(clk90_idata) );
     assign odata = clk90_idata;
 
 endmodule

対応する ucf ファイル
 NET "clk_125MHz_in" TNM_NET = "clk_125MHz_in";
 TIMESPEC TS_clk_125MHz_in = PERIOD "clk_125MHz_in" 8 ns HIGH 50 %;

これは、idata という非同期入力を clk_125MHz_in に同期化し、
さらにその信号を clk_125MHz_in と 90 度ずれた位相を持つクロックに同期化して、
出力します。

入力クロック clk_125MHz_in タイミング制約が掛かっているので、
clk_125MHz, clk_125MHz90 も 125MHz で動作するよう制約が掛かります。

** PERIOD 制約について [#g1b133fc]

この記事の趣旨から言えば、クロックに対する制約も .ucf ファイルに書くのではなく、

 LANG:verilog
 module main(
     (* PERIOD="125MHz" *) input clk_125MHz_in,
 
     input idata,
     output odata
 );

のように書いてしまえばよいはずなのですが、これだと、インプリメント中のメッセージで

 WARNING:Xst:1577 - Converting constraint on signal clk_125MHz_in: 'PERIOD=125MHz' 
 to XCF style constraint NET clk_125MHz_in PERIOD = 125.000000 MHz HIGH 50 %

となって、一見うまく行っているように見えるものの、

 WARNING:ConstraintSystem:3 - Constraint <TIMESPEC TS_clk_125MHz = PERIOD
   "clk_125MHz" TS_clk_125MHz_in HIGH 50%>: This constraint will be ignored
   because the relative clock constraint named 'TS_clk_125MHz_in' was not found.

 WARNING:ConstraintSystem:3 - Constraint <TIMESPEC TS_clk_125MHz90 = PERIOD
   "clk_125MHz90" TS_clk_125MHz_in PHASE 2 ns HIGH 50%>: This constraint will be
   ignored because the relative clock constraint named 'TS_clk_125MHz_in' was
   not found.

となって、正しく制約が掛かりませんでした。

実際 .pcf にはクロック周期制約の記載がなく、どうなっているのかまだ不明です。

* main1 に対する .pcf ファイル [#vad2cbe9]

上記コードをインプリメントすると、.pcf ファイルは次のようになりました。

 SCHEMATIC START;
 TIMEGRP clk_125MHz90    = BEL "double_ff90/double_ff_temp1" 
                           BEL "double_ff90/double_ff_temp0";
 TIMEGRP clk_125MHz90_0  = BEL "double_ff90/double_ff_temp1" 
                           BEL "double_ff90/double_ff_temp0";
 TIMEGRP clk_125MHz      = BEL "double_ff0/double_ff_temp1" 
                           BEL "double_ff0/double_ff_temp0";
 TIMEGRP clk_125MHz_0    = BEL "double_ff0/double_ff_temp1" 
                           BEL "double_ff0/double_ff_temp0";
 PIN DCM_SP_inst_pins<3> = BEL "DCM_SP_inst" PINNAME CLKIN;
 TIMEGRP clk_125MHz_in = PIN "DCM_SP_inst_pins<3>";
 TS_clk_125MHz_in  = PERIOD TIMEGRP "clk_125MHz_in"                         8 ns HIGH 50%;
 TS_clk_125MHz     = PERIOD TIMEGRP "clk_125MHz"     TS_clk_125MHz_in            HIGH 50%;
 TS_clk_125MHz90   = PERIOD TIMEGRP "clk_125MHz90"   TS_clk_125MHz_in PHASE 2 ns HIGH 50%;
 TS_clk_125MHz_0   = PERIOD TIMEGRP "clk_125MHz_0"   TS_clk_125MHz_in            HIGH 50%;
 TS_clk_125MHz90_0 = PERIOD TIMEGRP "clk_125MHz90_0" TS_clk_125MHz_in PHASE 2 ns HIGH 50%;
 PIN "idata_IBUF_pins<1>"                 = BEL "idata_IBUF"                 PINNAME OUT;
 PIN "double_ff0/double_ff_temp1_pins<2>" = BEL "double_ff0/double_ff_temp1" PINNAME Q;
 PIN "idata_IBUF_pins<1>"                 TIG;
 PIN "double_ff0/double_ff_temp1_pins<2>" TIG;
 SCHEMATIC END;

クロックに対する記述を除くと、

 PIN "idata_IBUF_pins<1>"                 = BEL "idata_IBUF"                 PINNAME OUT;
 PIN "double_ff0/double_ff_temp1_pins<2>" = BEL "double_ff0/double_ff_temp1" PINNAME Q;
 PIN "idata_IBUF_pins<1>"                 TIG;
 PIN "double_ff0/double_ff_temp1_pins<2>" TIG;

の部分が double_ff 関連の制約です。

* TIG は出力ピンまで遡ってかかる [#wd567aae]

.pcf の記述から、double_ff の入力ピンに記述した TIG 制約は、
そこに接続された出力ピンまで遡って付いています。

これはかなり困ったことで、その出力ピンに double_ff 以外のモジュールが接続されていると、
そちらへのパスも遅延解析から除かれてしまうことになります。

&attachref;

Counter: 17195 (from 2010/06/03), today: 1, yesterday: 0