コード中に制約を書くときの注意点 の履歴(No.1)
更新コード中に制約を埋め込む†
次のコードは [[非同期信号を扱うための危うい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 の記述をほぼ踏襲しているのですが、 そのままつかうにはいくつか問題がありそうで、いろいろ調べてみました。
異なるパラメータでインスタンス化する†
問題をはっきりさせるため、下記のあまり意味はないですがシンプルな例で見てみます。
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 制約について†
この記事の趣旨から言えば、クロックに対する制約も .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 ファイル†
上記コードをインプリメントすると、.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 は出力ピンまで遡ってかかる†
.pcf の記述から、double_ff の入力ピンに記述した TIG 制約は、 そこに接続された出力ピンまで遡って付いています。
これはかなり困ったことで、その出力ピンに double_ff 以外のモジュールが接続されていると、 そちらへのパスも遅延解析から除かれてしまうことになります。