XDCとSDC制約チートシート
VivadoのXDCとQuartusのSDCで毎週書くタイミング制約とピン制約を、Latticeの対応表記、実践パターン、よくある間違いの表とともにまとめます。
このシートは、制約(constraint)の目的は知っていて、正確な構文が必要なエンジニアのためのものです。VivadoはXDCを読みます。XDCはSDCにset_propertyを加えたものです。Quartus PrimeはタイミングにSDCを、ピンには別のQSFファイルを読みます。Lattice RadiantはSDCに似たタイミング記述を.pdcファイルから読み、Diamondは.lpfを使います。オプションの一覧は末尾にリンクしたベンダーのマニュアルを参照してください。
クロック
| 作業 | XDC(Vivado) | SDC(Quartus Prime) |
|---|---|---|
| ピン上のプライマリクロック | create_clock -period 10.000 -name clk_in [get_ports clk_in] |
create_clock -period 10.0 -name clk_in [get_ports clk_in] |
| デューティ比25%のクロック | -waveform {0 2.5}を追加 |
同じ |
| PLLまたはMMCMからのクロック | 自動的に導出される | derive_pll_clocks(Standard)または自動(Pro) |
| 手動の生成クロック | create_generated_clock -name clk_div2 -source [get_pins u_div/clk] -divide_by 2 [get_pins u_div/q_reg/Q] |
同じ構文 |
| リカバリクロックや外部ソース上のクロック | create_clock -period 8.000 [get_pins u_gt/RXOUTCLK] |
同じ |
| ツールが見つけたクロックの報告 | report_clocks |
report_clocks |
| ジッタと不確かさ | set_clock_uncertainty -setup 0.100 [get_clocks clk_in] |
derive_clock_uncertainty(必ず一度実行する) |
# Vivado: a 100 MHz board clock and a clock-enable style divided clock
create_clock -period 10.000 -name sys_clk [get_ports sys_clk_p]
create_generated_clock -name clk_div4 -source [get_pins u_div/clk_i] \
-divide_by 4 [get_pins u_div/div_reg[1]/Q]
生成クロックを定義するのは、ロジック(トグルするフリップフロップ)で作ったクロックだけにしてください。PLL、MMCM、クロックバッファから出るクロックはツールが導出します。そもそも分周クロックよりクロックイネーブルを優先してください。
I/O遅延
外部遅延はクロックを基準に指定します。ツールはその上で、ピンから最初のレジスタまで(入力)、または最後のレジスタからピンまで(出力)のパスを検査します。
| 作業 | XDCとSDC(同じ構文) |
|---|---|
| 入力、システム同期 | set_input_delay -clock sys_clk -max 2.5 [get_ports data_in[*]]と-min 0.5 |
| 入力、DDR、両エッジ | 立ち下がりエッジ側に-clock_fall -add_delayを追加 |
| 出力 | set_output_delay -clock sys_clk -max 1.0 [get_ports data_out[*]]と-min -0.5 |
| ソース同期入力 | 転送されたクロックピンにcreate_clock、その後set_input_delay -clock fwd_clk |
| ソース同期出力 | 転送クロックのポートにcreate_generated_clock、その後set_output_delay -clock fwd_clk_out |
# Source-synchronous ADC interface, data centred on the forwarded clock
create_clock -period 8.000 -name adc_clk [get_ports adc_clk]
set_input_delay -clock adc_clk -max 1.200 [get_ports adc_d[*]]
set_input_delay -clock adc_clk -min 0.300 [get_ports adc_d[*]]
set_input_delay -clock adc_clk -max 1.200 -clock_fall -add_delay [get_ports adc_d[*]]
set_input_delay -clock adc_clk -min 0.300 -clock_fall -add_delay [get_ports adc_d[*]]
-maxの値はクロックエッジの後にデータが到着しうる最も遅い時刻(セットアップ側)、-minはデータが変化しうる最も早い時刻(ホールド側)です。出力では-maxが外部のセットアップ要件、-minが外部のホールド要件にマイナスを付けたものです。計算は/reference/timing-formulae/を参照してください。
例外
| 作業 | コマンド | 使う場面 |
|---|---|---|
| 無関係なクロック領域 | set_clock_groups -asynchronous -group [get_clocks clk_a] -group [get_clocks clk_b] |
両領域の間が適切な同期化回路で渡されている |
| 1本のパスのタイミングを無視 | set_false_path -from [get_cells u_a/cfg_reg*] -to [get_cells u_b/sync_reg[0]] |
安定してからずっと後にサンプルされる静的な設定ビット |
| リセット解除 | set_false_path -from [get_ports rst_n] |
リセット同期化回路に入る非同期入力 |
| 遅いパス、Nサイクル | set_multicycle_path -setup 2 -from [get_cells a_reg*] -to [get_cells b_reg*]とset_multicycle_path -hold 1 ... |
クロックイネーブルのためデータがNサイクルに1回しか使われない |
| 乗り換えの遅延を制限 | set_max_delay -datapath_only 5.000 -from [get_cells src_reg*] -to [get_cells dst_reg*](Vivado) |
ビット間スキューが問題になるバスの乗り換え |
| バススキュー | set_bus_skew -from [get_cells gray_reg*] -to [get_cells sync_reg*] 2.000(Vivado 2018.1以降) |
非同期FIFOのグレイポインタの乗り換え |
# Vivado: a two-cycle path driven by a clock enable
set_multicycle_path -setup 2 -from [get_cells u_dsp/acc_reg*] -to [get_cells u_dsp/out_reg*]
set_multicycle_path -hold 1 -from [get_cells u_dsp/acc_reg*] -to [get_cells u_dsp/out_reg*]
Quartus Primeは-datapath_onlyなしのset_max_delayを受け付けます。クロックスキューは依然として計算に入るので、set_false_path -holdと組み合わせるか、同じ効果を得るためにset_net_delayを使ってください。Quartusではホールド側のマルチサイクル値の数え方がVivadoと異なり、ここでの-hold 1は「終端マイナス1」を意味します。これは通常、-setup 2の後に望む値と一致します。
ピンとI/O規格
| 作業 | Vivado XDC | Quartus QSF |
|---|---|---|
| ピン位置 | set_property PACKAGE_PIN W5 [get_ports clk] |
set_location_assignment PIN_AF14 -to clk |
| I/O規格 | set_property IOSTANDARD LVCMOS33 [get_ports clk] |
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to clk |
| 両方を一度に | set_property -dict { PACKAGE_PIN W5 IOSTANDARD LVCMOS33 } [get_ports clk] |
2行で書く |
| 差動ペア | _pポートにIOSTANDARD LVDS_25、_nピンは追従する |
両ピンを割り当て、規格はLVDS |
| プルアップ | set_property PULLUP true [get_ports btn] |
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to btn |
| 駆動能力とスルーレート | set_property DRIVE 8 ...とset_property SLEW FAST ... |
-name CURRENT_STRENGTH_NEW 8MAと-name SLEW_RATE 1 |
| 未使用ピン | set_property BITSTREAM.CONFIG.UNUSEDPIN PULLDOWN [current_design] |
set_global_assignment -name RESERVE_ALL_UNUSED_PINS_WEAK_PULLUP "AS INPUT TRI-STATED WITH WEAK PULL-UP" |
| コンフィギュレーション電圧 | set_property CFGBVS VCCO [current_design]とCONFIG_VOLTAGE 3.3 |
不要 |
# Vivado: a bus of eight LEDs, one line per pin
set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]
set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]
Latticeの対応表記
| 作業 | Radiant PDC | Diamond LPF |
|---|---|---|
| クロック | create_clock -period 12.0 -name clk [get_ports clk] |
FREQUENCY PORT "clk" 83.33 MHz ; |
| ピン | ldc_set_location -site {A9} [get_ports clk] |
LOCATE COMP "clk" SITE "A9" ; |
| I/Oタイプ | ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports clk] |
IOBUF PORT "clk" IO_TYPE=LVCMOS33 ; |
| フォルスパス | set_false_path -from [get_clocks a] -to [get_clocks b] |
BLOCK PATH FROM CLKNET "a" TO CLKNET "b" ; |
| マルチサイクル | set_multicycle_path 2 -from ... |
MULTICYCLE FROM CELL "a*" TO CELL "b*" 2 X ; |
オープンソースフローでは、iCE40に.pcfファイル(set_io led A5)、nextpnrを使うECP5に.lpfを使い、クロック目標はコマンドラインか、プリパックスクリプト内のset_frequencyで与えます。
間違いと対処
| 症状 | 考えられる原因 | 対処 |
|---|---|---|
| タイミングパスがまったく報告されず、すべて合格する | create_clockがなく、何も制約されていない |
まずクロックを追加し、check_timing(Vivado)を実行するか「unconstrained paths」レポートを見る |
| 無関係と考えている2つのクロック間で数千のパスが失敗する | set_clock_groupsがない |
すべての乗り換えに同期化回路があることを確認してから、グループを宣言する |
| セットアップが通った後にI/Oでホールド違反が出る | -maxの遅延しか与えていない |
出力の負の値も含め、必ず-minも与える |
| 2サイクルに1回しか意味を持たないパスでセットアップ違反 | マルチサイクルがない | -setup Nと-hold N-1を一緒に追加し、クロックではなくセルで範囲を指定する |
| タイミングは通るがボードの動作が不安定 | I/O遅延をデータシートからではなく推測で与えた | データシートの値とボードの配線長からバジェットを組み直す |
| 制約が黙って無視される | 合成でリネームされた後のオブジェクト名が違う | get_cells -hierarchical -filterを使い、report_propertyで確認し、ネットリストができてから制約を保つ |
| 生成クロックが未制約と報告される | -sourceが間違ったピンを指している |
-sourceは分周レジスタのクロック入力ピンに、ターゲットはその出力に向ける |
Vivadoがset_max_delayは効果がないと警告する |
パスがすでにフォルスパスかクロックグループでカバーされている | 広い方の例外を外す。最も具体的な例外が優先されるのは同じ種類の中だけ |
| バンク電圧の衝突でピン割り当てが失敗する | 1つのバンクに複数のI/O規格が混在 | 規格をバンクごとにまとめ、回路図でVCCOを確認する |
| QuartusがSDC例外に対して「no paths」と報告する | Proは完全な階層名を使い、Standardはワイルドカードの扱いが異なる | Proではget_registersにフルパスを与える |
出典
- UG903: Vivado Design Suite User Guide, Using Constraints
- UG949: UltraFast Design Methodology Guide for FPGAs and SoCs
- UG912: Vivado Design Suite Properties Reference
- Quartus Prime Pro Edition User Guide: Timing Analyzer (document 683243)
- Lattice Radiant Software documentation
- nextpnr constraints documentation