01signal.com

クロック周期制約とクロックオブジェクト

このページは、タイミングに関する連載ページの一部です。これまでのページでは、タイミング計算の背後にある理論を説明し、クロック周期制約とタイミングクロージャ(timing closure)の原則について述べてきました。そろそろ、タイミング制約(timing constraints)の技術的な詳細に入る頃です。

Tcl コマンドとしての create_clock の意味

これまでのページは、すべて次のタイミング制約を中心に展開してきました。

create_clock -period 4 -name clk [get_ports clk]

この行の構文について、あえてここまで説明を避けてきました。そろそろ、これが実際に何を意味するのかを説明しましょう。

このタイミング制約は SDC(Synopsys Design Constraints)形式で書かれています。これはタイミング制約の最も一般的な形式です。Vivado と Quartus は、他のいくつかの FPGA ツールと同様に、この形式を使用します。

SDC ファイルは、本質的には Tcl で書かれたスクリプト(script)です。したがって、SDC ファイルの内容は情報の集合ではなく、短いコンピュータプログラムです。ただし、SDC ファイルがスクリプトとして持つ機能は、制約を書くための小さなコマンド群に限定されています。Tcl スクリプトで許されるすべてが SDC ファイルでできるわけではありません。

create_clock コマンドはタイミング制約を定義するために使われます。しかし実際には、このコマンドは FPGA ツールに新しいクロックオブジェクトを作成するように指示します。「オブジェクト」という言葉は、ソフトウェア工学の分野で通常意味するものと同じ意味です。新しく作成されたクロックオブジェクトは、Tcl インタープリタのメモリ内に、独自のプロパティを持つオブジェクトとして保存されます。

たとえば、create_clock コマンドの「-name clk」という部分は、「name」というプロパティに値「clk」を与えます。前のページの 1 つで述べたとおり、この名前はタイミングレポートで使われました。この制約(より正確には、このクロックオブジェクト)のために計算されたタイミングパス(path)に沿って、「clk」という名前が現れたのです。

後のページでは、clk_out1_clk_wiz_1 や clk_out2_clk_wiz_1 といった他のクロック名があることも見ました。これらは実際には、ツールによって自動的に作成された他のクロックオブジェクトの名前です。

すべてのクロックをリストするための Tcl コマンドがあります。それは get_clocks です。前のページの 2 つのクロックを使った例で、Vivado の Tcl コンソールで実行すると、次のようになります。

> get_clocks
clk clkfbout_clk_wiz_1 clk_out1_clk_wiz_1 clk_out2_clk_wiz_1

get_clocks および類似のコマンドについては、次のページで詳しく説明します。

これらのオブジェクトのプロパティを表示することもできます。すべてのプロパティを理解する必要はありません。ここで示すのは、クロックがオブジェクトであるという点を強調するためです。私自身、オブジェクトのプロパティを直接操作する必要が生じたことは一度もありません。

> report_property [get_clocks clk]
Property           Type     Read-only  Value
CLASS              string   true       clock
INPUT_JITTER       double   true       0.040
IS_GENERATED       bool     true       0
IS_PROPAGATED      bool     true       1
IS_USER_GENERATED  bool     true       0
IS_VIRTUAL         bool     true       0
NAME               string   true       clk
PERIOD             double   true       4.000
SOURCE_PINS        string*  true       clk
SYSTEM_JITTER      double   true       0.050
WAVEFORM           double*  true       0.000 2.000

> report_property [get_clocks clk_out1_clk_wiz_1]
Property           Type     Read-only  Value
CLASS              string   true       clock
EDGES              int*     true       1 2 3
EDGE_SHIFT         double*  true       0.000 2.000 4.000
INPUT_JITTER       double   true       0.000
IS_GENERATED       bool     true       1
IS_INVERTED        bool     true       0
IS_PROPAGATED      bool     true       1
IS_RENAMED         bool     true       0
IS_USER_GENERATED  bool     true       0
IS_VIRTUAL         bool     true       0
MASTER_CLOCK       clock    true       clk
NAME               string   true       clk_out1_clk_wiz_1
PERIOD             double   true       8.000
SOURCE             pin      true       pll_i/inst/mmcme3_adv_inst/CLKIN1
SOURCE_PINS        string*  true       pll_i/inst/mmcme3_adv_inst/CLKOUT0
SYSTEM_JITTER      double   true       0.050
WAVEFORM           double*  true       0.000 4.000

ここで認識すべき重要なことは、create_clock は単にオブジェクトを作成するだけだということです。このコマンドのパラメータは、そのオブジェクトのプロパティをどのように設定するかを決めるだけです。たとえば、(これまで繰り返し示してきたタイミング制約の中の)「-period 4」という部分は、「PERIOD」というプロパティに値 4 を設定することを意味するにすぎません。

これらの Tcl コマンドを自分で試してみたい場合、FPGA ツールごとに違いがあることに注意してください。

Vivado では、これらのコマンドは Implemented Design を開いた後でのみ使用できます。

Quartus では、まず TimeQuest Timing Analyzer を開き、Create Timing Netlist、Read SDC File、Update Timing Netlist の順にクリックします。次に、Tcl コンソールで例えば次のようなコマンドを試してください。

> join [ query_collection -all [ get_clocks ] ] "\n"
> get_clock_info -waveform [get_clocks clk]

「クロック」という言葉の意味

FPGA ツールが「クロック」という言葉を使うとき、それは通常クロックオブジェクトを意味し、FPGA 内部の物理的な信号を指すわけではありません。これは特にタイミングレポートで当てはまります。

前のページで「理論上のクロック(theoretical clocks)」という言葉を何度か使いました。これらは実際にはクロックオブジェクトです。タイミングレポートでは「クロック」と呼ばれますが、タイミング解析での使われ方を見れば、それらが単なる情報の入れ物であることがわかります。

では、これらのクロックオブジェクトと実際の信号との間には、どのような関係があるのでしょうか。タイミング解析ではクロックオブジェクトの名前が何度も現れました。これらはどのように連携しているのでしょうか。

ツールが設計の静的タイミング解析を実行するとき、すべてのパスが調べられます。パスがフリップフロップから始まる場合、ツールはそのフリップフロップのクロック入力に接続されている信号(つまりネット)を調べます。この信号に関連するクロックオブジェクトはあるでしょうか。たとえば、信号が @clk の場合、関連するクロックオブジェクトは create_clock コマンドで「clk」という名前を与えられたものです。該当するクロックオブジェクトを見つけたら、ツールはそのオブジェクトのプロパティから必要な情報を取得できます。

同じことがパスの終点にあるフリップフロップにも行われます。これで、ツールはパスに対応する 2 つのクロックオブジェクトを手にします。これらのオブジェクトからの情報を使って、ツールはタイミング解析を実行します。

もちろん、同じ手順はフリップフロップだけでなく、あらゆる順序エレメントに適用されます。

これを理解することがなぜ重要なのでしょうか。その理由の 1 つは、タイミングレポートに「クロックのないレジスタがある」というエラーメッセージが出ることがあるからです。通常、これはフリップフロップのクロック入力に何も接続されていないという意味ではありません。むしろ、ツールがこのクロック入力に関連するクロックオブジェクトを見つけられなかったことを意味します。言い換えれば、ツールはこのフリップフロップのクロック入力に関する情報を見つけられなかったのです。したがって、問題は通常ロジック設計側ではなく、タイミング制約が欠けている(または誤って書かれている)ことにあります。

もう一度言っておきます。タイミングレポートで「クロック」と書かれていても、ロジック設計にその名前の信号があるという意味ではなく、その名前でクロックオブジェクトが作成されているということです。それでは、どの信号に対応するのかをどうやって知るのでしょうか。それが次の話題です。

このクロックはどの信号のもの?

タイミングレポートを読みにくくしているものの 1 つが、クロックの名前です。論理設計のクロック信号のほとんどは PLL によって生成され、タイミングレポートに現れる名前がほとんど役に立たないことがよくあります。多くの FPGA ツールでは SDC ファイルにコマンドを追加することでクロックオブジェクトの名前を変更できますが、ほとんどのプロジェクトではこれを行いません。そして、黄金律 #4 は、プロジェクト固有のことをするのを避けることです。

クロックのソースが IP ブロック(たとえばギガビットトランシーバー、PCIe ブロック、オンチッププロセッサコアなど)である場合、名前の問題はさらに厄介になります。その場合、クロック名から、それがどこから来て何に関係しているのかを読み取るのは難しいことがよくあります。

では、この問題はどのように解決するのでしょうか。最も単純な状況、つまりクロック名が自分たちの SDC ファイル内の create_clock コマンドに由来する場合から始めましょう。同じタイミング制約をもう一度示します。

create_clock -period 4 -name clk [get_ports clk]

このコマンドの最後の部分は「[get_ports clk]」です。Tcl 言語では、角括弧はその中身を Tcl コマンドとして実行し、そのコマンドの結果を角括弧の場所に使うことを意味します。

get_ports コマンドは、「clk」という名前の I/O ポートを見つけます。このコマンドの結果は、そのポートを表すオブジェクトです。したがって、上の create_clock コマンドでは、このオブジェクトがコマンドの引数になります。これが、create_clock がクロックオブジェクトと実信号を結び付ける仕組みです。

ポートの名前もオブジェクトの名前も「clk」であることに注意してください。これらが同じである必要はありませんが、同じにすることをお勧めします。オブジェクトの名前はタイミングレポートに表示されます。したがって、通常はポートの名前が最良の選択です。

また、信号を識別するためにネットオブジェクトやピンオブジェクトを使うことも可能です。これは、IP ブロックのために自動生成されるタイミング制約でよく使われます。しかし、自分の制約でこれをやりたくなった場合、何か間違ったことをしている可能性が高いです。

つまり、SDC ファイルで create_clock コマンドを使ったのであれば、クロックオブジェクトがどの信号に対応するのかを知るのは簡単です。しかし、ツールが自動的に作成したクロックオブジェクトはどうでしょうか。

その場合は、タイミングレポートを見るのが最も良い方法です。たとえば、前のページの例で、@pll_clk_8 に関連するクロックオブジェクトはどれでしょうか。簡単な方法は、タイミングレポート内でテキスト検索をすることです。「pll_clk_8」を検索すると、次の部分が見つかります。

Location          Delay type                Incr(ns)  Path(ns)    Netlist Resource(s)
--------------------------------------------------------------  -------------------
                  (clock clk_out1_clk_wiz_1 rise edge)
                                              16.000    16.000
AG12                                           0.000    16.000  clk (IN)
                  net (fo=0)                   0.000    16.000  pll_i/inst/clkin1_ibuf/I
AG12              INBUF (Prop_INBUF_HRIO_PAD_O)
                                               0.738    16.738  pll_i/inst/clkin1_ibuf/INBUF_INST/O
                  net (fo=1, routed)           0.105    16.843  pll_i/inst/clkin1_ibuf/OUT
AG12              IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O)
                                               0.049    16.892  pll_i/inst/clkin1_ibuf/IBUFCTRL_INST/O
                  net (fo=1, routed)           0.975    17.867  pll_i/inst/clk_in1_clk_wiz_1
MMCME3_ADV_X1Y0   MMCME3_ADV (Prop_MMCME3_ADV_CLKIN1_CLKOUT0)
                                              -4.438    13.429  pll_i/inst/mmcme3_adv_inst/CLKOUT0
                  net (fo=1, routed)           0.501    13.930  pll_i/inst/clk_out1_clk_wiz_1
BUFGCE_X1Y1       BUFGCE (Prop_BUFCE_BUFGCE_I_O)
                                               0.101    14.031  pll_i/inst/clkout1_buf/O
X2Y0 (CLOCK_ROOT) net (fo=1, routed)           1.369    15.400  pll_clk_8
SLICE_X49Y58      FDRE                                          foo_reg_reg/C

これは clk_out1_clk_wiz_1 のソースクロックパスであり、ここに答えがあります。

もう 1 つの方法は、Tcl コマンドで情報を取得することです。その正確な方法は FPGA ツールごとに異なります。Vivado では、Implemented Design を開いた後に、次のようなコマンドを使用できます。

> get_clocks -of_objects [ get_nets pll_clk_8 ]
clk_out1_clk_wiz_1

この方法では、ネットの名前を知っている必要があります。時にはこの例のように単純なこともありますが、時にはこのネットの名前を見つける作業が必要です。FPGA ツールには通常 GUI でこれを行う方法があります。また、この目的に Tcl コマンドを使うこともできます。

実際、Tcl の例をいくつか見ていただいたことで、Tcl をきちんと扱う方法を知ることの重要性を納得していただけたのではないでしょうか。次のページはまさにその話題についてです。

get_ports を使うことの重要性

上の例では、create_clock コマンドは、クロックオブジェクトと物理的な入力ピンを結び付けるために get_ports に依存しています。上で述べたとおり、この結び付けは、どの論理エレメントがこのクロック(またはそこから生成されるクロック)に接続されているかを知るために必要です。

しかし、get_ports を使うことだけが唯一の可能性ではありません。たとえば、グローバルクロックバッファの出力ピンを参照することもできます。たとえば、次のようなものです。

create_clock -name clk -period 4 [get_pins my_BUFG_inst/O]

違いは、ツールがグローバルクロックバッファの出力ピンをクロックの発生元と見なすことです。つまり、クロックパスの計算はこの位置から始まります。この発生元での最初のクロックエッジは 0 ns に発生するため、この出力ピンが時刻の基準になります。

これは正当なタイミング制約ですが、2 つの重要な欠点があります。

したがって、可能な限り get_ports を使うべきです。そうしないと、そのクロックのタイミングは、それ自身以外の何に対しても未知と見なされるべきです。


このページでは、多くの Tcl コマンドを紹介しましたが、十分には説明しませんでした。次のページでそのギャップを埋めます。

このページは英語から機械翻訳されたものです。不明な点があれば、原文を参照してください。
Copyright © 2021-2026. All rights reserved. (dcc38493)