コード中に制約を書くときの注意点 の履歴(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 以外のモジュールが接続されていると、 そちらへのパスも遅延解析から除かれてしまうことになります。