クロックの定義
SDCフォーマットで決められているわけではないが、クロックは次の3種類に分けて考えるとよい。
クロック |
説明 |
基本クロック |
他とは独立なクロック 例)外部から入力したクロック,内部SerDesの出力クロック |
派生クロック |
他クロックから生成したクロック 例)内部のPLLで生成したクロック,FFで分周したクロック |
仮想クロック |
入出力タイミングの制約に使う、仮想的な外部FFのクロック |
◇
基本クロックは、周期とエッジの位相を次の構文で指定する。
ここで立上りエッジの位相を指定するということは、複数のクロック同士は独立ではなく同期していると見なされるということである。
create_clock -name clockName ←仮想クロックのオブジェクト名 -period periodValue ←周期(ns単位) [-waveform {rise fall}] ←エッジの位相(ns単位)。省略するとrise=0ns,Duty=50% clockPortName ←クロック入力ポート、クロック出力ピン、ネットのオブジェクト名 |
例1)入力ポートclkin1に100MHz,Duty=50%のクロック波形が入力されている。入力ポートclkin2に2ns遅れたクロック波形が入力されている。
create_clock -name clkin1 -period 10 [get_ports {clkin1}] create_clock -name clkin2 -period 10 -waveform {2 7} [get_ports {clkin2}] |
◇◇
FFで分周したクロックは自動抽出されないので、派生クロックとして分周比を指定する。派生クロックの位相は自動抽出されるので指定しなくてよい。
create_generated_clock [-name clockName] ←派生クロックのオブジェクト名。省略するとclockPinNameと同じになる -source clockPortName ←派生元のクロック入力ポート、または分周FFのCLKピンのオブジェクト名 -divide_by value ←分周比(整数) clockPinName ←分周FFのQピン、またはネットのオブジェクト名 |
例1)FFで2分周している
create_generated_clock -name clkdiv -source [get_ports {clkin}] -divide_by 2 [get_nets {clkdiv}] ←RTL記述で分周クロックのネット名をkeep指定しておくと、 ネットリスト中のネット名も同じになるので便利 (* syn_keep=1 *) wire clkdiv; // Quartusの場合 (* dont_touch="true" *) wire clkdiv; // Vivadoの場合 |
◇◇◇
内部PLLで生成したクロックは自動抽出され、派生クロックとして定義される。ただし自動抽出するとクロック名が勝手に付与されてわかりにくいので、ユーザが指定し直した方がよい。
Quartusでは、次のderiveコマンドでPLLの出力クロックを自動抽出できる。
create_clock -name clkin -period 10 [get_ports {clkin}] derive_pll_clocks ←Quartus固有 |
最初に、これを使ってタイミング解析まで実行した後にTimeQuestでSDCファイルを書き出すと、自動抽出されたcreate_generated_clockコマンドが書かれている。これでderiveコマンドを置き換えて、クロック名を直せばよい。
create_generated_clock -name clk0 -source [get_ports {clkin}] -duty_cycle 50 -multiply_by 3 [get_pins {pll_inst|altpll_component|auto_generated|pll1|clk[0]}] |
Vivadoでは何も指定しなくても自動抽出される。またPLLのIP生成時にIP用の制約ファイルができ、その中に入力クロックと入力ジッタが書かれているので、ユーザは指定しなくてよい。
create_clock -name clkin -period 10 [get_ports {clk_in1}] set_input_jitter clkin 0.1 ←Vivado固有 |
しかし、PLLのクロック名が勝手に付与されてわかりにくいので、次のようにクロック名だけ指定し直すとよい。このときピン名は、合成後のネットリストをopenしてTCLコマンド report_clocksで調べられる。
create_generated_clock -name clk0 [get_pins {pll_inst/inst/plle2_adv_inst/CLKOUT0}] ←Vivado固有 |
◇◇◇◇
すべてのクロック同士はデフォルトでは同期していると見なされるので、非同期関係を指定する。
set_clock_groups -asynchronous ←グループ間は非同期 -group {clockNameList} ←グループ内のクロックのオブジェクト名 [-group {clockNameList} ...] ←グループ内のクロックのオブジェクト名 |
例1)clkin1とclkin2が同期で、clkin3はそれらとは非同期
set_clock_groups -asynchronous -group {clkin1 clkin2} -group {clkin3} |
例2)clkin1とclkin2をMUXで選択したclkを使っている
通常はa_regとb_reg共にclkin1またはclkin2で駆動されているパスだけ解析したいが、この他にa_regがclkin1でb_regがclkin2で駆動されているバスもデフォルトでは解析されてしまうので、clkin1とclkin2は非同期であると指定する必要がある。
set_clock_groups -asynchronous -group clkin1 -group clkin2 |
なお、Quartus,Vivadoには-logically_exclusiveというオプションも用意されているが、-asynchronousとタイミング解析上は同じ意味になる。
◇◇◇◇
クロックのジッタはClock Uncertaintyという量で表される。
Vivadoでは、ジッタは自動抽出されるので指定しなくてよい。
Quartusでは、ジッタが自動抽出されるように次のコマンドを書いておくと、タイミングネットリスト更新時に自動抽出される。(書く位置はどこでもよいということ)
derive_clock_uncertainty ←Quartus固有 |