このページは、 timingに関する一連のページに属します。前のページでは、 timing 計算の背後にある理論を説明し、 clock period constraintについて議論し、 timing closureの原理を示し、 Tcl 環境の調査を始めました。このページでは、 timing constraints を特定できるようにする commands について説明します。
概要
timing constraints の目的は、 design 内のすべての paths の timing 要件が確実に満たされるようにすることです。 paths ごとに要件が異なる場合があるため、各 timing constraint は pathsの関連するグループに向ける必要があり、他には何も含めないでください。
paths を定義する唯一の方法は、これらの pathsに関連する logic elements を参照することです。したがって、 logic elementsの正しいグループを選択する正確な式を書く能力を持つことが重要です。言い換えれば、 get_clocks、 get_ports 、 get_cellsなどの commands を正しく使用して、その結果がまさに必要なものになるようにする必要があります。
このページでは、 logic elementsのグループを記述するための基本的な手法について説明します。ここで説明する内容のほとんどは、 SDC 構文に固有のものです。また、 Tcl command-line インターフェイスも使用可能であると想定します。これは、 Vivado と Quartus、および最近のほとんどの FPGA tools にも当てはまります。
FPGA ベンダーの中には、 Synopsysのソフトウェアが自社のツールに統合されていると公言しているところもあるため、当然これらのツールでは同じ Tcl commandsが使用されています。一方、 Vivadoは Synopsysから派生したものではないと考えられています。しかし、特に Tcl のインターフェースに関しては、この 2 つの間にはいくつかの顕著な類似点があります。 Quartus は独自に開発されたようで、そのため Tcl のインターフェースは少し異なります。
一見すると、このページは Tcl scriptingの詳細に行き過ぎているように見えるかもしれません。真実は反対です: 正確さは極めて重要であり、これは commands がどのように解釈されるかを正確に理解することによってのみ達成できます。実際、このページでは基本原則のみを説明します。ドキュメントを読むことに代わるものはありません。
FPGA toolsからのガイダンスの取得
timing constraintsの作成を始めるのは、考慮すべき細かい点が多すぎるため、難しいことがよくあります。 FPGA tools は、この点に役立ちます。
"help" command は、 Tcl commandのドキュメントを表示するために Tcl console で使用できます。これは、公式ドキュメント (例: pdf 形式) とまったく同じ情報であることがよくあります。
ほとんどの FPGA tools には、 timing constraints を自動的に作成するための GUI インターフェイスがあります。作業方法は、必要な timing constraints のタイプを選択するためによく使用されます。次のステップは、リストから関連する logic elements を選択することです。その結果、1 つまたは複数の timing constraints が SDC ファイルに追加されます。
この種の wizard を使用すると、 Tcl 構文に関するヒントを得るのに役立ちます。場合によっては、自動的に作成される constraints をそのまま使用することもできます。ただし、ほとんどの場合、 wizardの出力を使用したいという誘惑に抵抗し、代わりに timing constraint の目的を最もよく達成する方法を慎重に検討する価値があります。また、プロジェクトがどのように発展すると予想されるかを検討し、 timing constraints が長期にわたって正しいままであることを確認することも重要です。 GUI wizard との簡単なセッションでは、これを達成することはまずありません。
一部の FPGA tools には、 designで logic elements を見つけるための GUI interface もあります。このインターフェイスを使用すると、要求された検索に対応する Tcl command が表示されることがよくあります。これは、特定の logic elementsを見つけるための Tcl 式を取得する便利な方法です。繰り返しますが、これらの式は、今後の作業の出発点として扱う必要があります。
ほとんどの FPGA tools の 3 番目の機能は、 commands (または Copy-Pasteを使用) を入力して画面に結果を表示できる Tcl command-line console です。これにより、 commands とその search patternsをテストし、どの objects が見つかるかを確認できます。これは、 search pattern が正しいことを確認するのに役立ちます。
結論として、 FPGA tools は Tcl commandの作成に役立ちます。ただし、すでに述べたように、ツールによって作成された Tcl commands は、時間の経過とともに正しく動作することが保証される正確な search patterns を作成するための基礎にすぎません。
timing constraintsを作成するための怠惰な方法がわかったら、今度はこれを適切に行う方法を学習します。
netlist: 簡単なリマインダー
Tcl 環境について詳しく説明する前に、 netlistsについて簡単に説明しておきます。
netlists の最も一般的なファイル形式は EDIFですが、多くの FPGA tools にも独自の形式があります。通常、 synthesizer は netlistを作成しますが、ツールによって後の段階で変更されることもあります。このファイルは、 logic design の基本コンポーネントとこれらのコンポーネント間の接続について説明しています。配線図に似ていますが、グラフィック イメージではなくテキスト表現です。
netlist のコンポーネントは「cells」と呼ばれます。 cells の大部分は LUTのようなもので、 combinatorial logic または flip-flopのもう 1 つの小さな要素です。また、 Verilog コードの black boxes の instantiations (例えば IP cores)は、 netlistでは cell として表されます。その他の cells は、 PLLs、 block RAMs、および大型の logic elements ("hard IPs") です。 PCIe blocks、 MGT transceivers、 processors など
各 cell にはいくつかのpinsがあります。 これらの pins は、物理的な電子コンポーネントの外部接続ポイントのようなものです。ただし、これを FPGAの外部 I/Oと混同しないでください。 cells と pins の両方が FPGA内に存在します。
netlist の相互接続は netsで構成されています。これらは物理的なワイヤーのようなものです。たとえば、 signal が Verilogで "wire" と定義されている場合、これは netになります。 net は 2 つ以上の pinsを接続し、そうすることで、これらの pins が常に同じ logic level を持つことが保証されます。
objectsとしての logic elements の表現
FPGA tools がプロジェクトの implementation を実行すると、実際には Tcl scripts が実行されます。これは、 Vivado 、 Quartus 、および他のいくつかの FPGA toolsにも当てはまります。異なる動作をするソフトウェアであっても、この仮定は正しいです。 すべてが 1 つの大きな Tcl script であるという錯覚は、 constraints および他の script ファイルの API によって作成されます。
この Tcl script の環境 (架空かどうかに関係なく) では、すべての logic elements は、異なる classesから作成された objects として表されます。これらの objects は、 SDC ファイル (または Xilinxの XDC ファイル) 内の timing constraints からアクセスできます。同様に、 Tcl command-line console と Tcl scripts 内の Tcl commands は、これらの objectsにアクセスできます。
これらは、 SDC 構文で動作するすべての FPGA tools でサポートされている 5 つの Tcl commands です。これらの commands は、異なるタイプ (つまり、異なる classes) の objects を見つけるために使用されます。これらは、以前の timing constraintsの例ですでに使用しました。実際、これらの commandsなしで意味のある timing constraints を記述することはまったく不可能です。
argumentsがない場合、これらの commands は関連するタイプのすべての objects を検索します。後ほど、検索を絞り込む方法について説明します。
- get_cells: この command は、 cells ( netlist内のコンポーネント) を表す objects を検索します。
- get_pins: この command は、 pins ( cellsの接続ポイント) を表す objects を見つけます。
- get_nets: この command は、 nets ( netlistの「ワイヤ」) を表す objects を見つけます。
- get_ports: この command は、 FPGA designの外部 I/O portsを表す objects を見つけます。これらは、 toplevel moduleの ports です。
- get_clocks: この command は clock objectsを見つけます。ここで言及されている objects のうち、 designの logic element に対応しない objects は clock objects のみであることに注意してください。むしろ、前述のように、 clock objects は clocksに関する情報を含めるために使用されます。
これら 5 つの commandsを除き、各 FPGA tool には独自の追加の commands と追加の objectsがあります。たとえば、 Vivado には、 all_ffs、 all_registers、 all_inputs、 all_outputs、 all_rams などの追加の commands があり、この他にも同様のものがいくつかあります。 Quartus はこれらのいくつかをサポートし、さらに get_registers、 get_keepers、 get_nodes、 get_fanins 、 get_fanouts などがあります。
これらの objects の重要性は、 timing constraints で FPGA designの logic elements を参照するために使用されることです。また、 Tcl scripts で情報を取得するために使用することもできます (たとえば、 clockの frequency)。各 FPGA tool には、 Tcl scriptsのこれらの objects にアクセスするための独自の API があります。たとえば、この Tcl command は、 Vivado で clock periodを取得するために使用できます。
> get_property PERIOD [get_clocks clk] 4.000
Quartusでも同じです。
> get_clock_info -period [get_clocks clk] 4.000
これらの違いにもかかわらず、ほとんどの FPGA tools は、 SDC 形式の timing constraints の構文と意味に同意しています。各ツールがサポートする API に関する情報は、通常、 Tcl scripting または Timing Closureに関連するタイトルを持つ user guides にあります。
このページの例は、特に明記されていない限り、 Vivadoに基づいています。
Tclに関するいくつかの注意事項
Tcl は古い言語ですが、 logic designの分野で確立されているため、この言語がすぐになくなることはないと予想されます。幸いなことに、 Tcl についてよく知らなくても、 Tcl で便利なことを行うことができます。
まず最初に、すでに簡単に触れましたが、角括弧 ("[" および "]") です。 Tclでは、これは角括弧内の command を実行し、その結果をその位置に置くことを意味します。 shell scripting または Perlに詳しい方にとっては、これは backticksと同じです。たとえば、この commandでは、 get_port が "clk" という名前の port object に置き換えられます。
create_clock -period 4.000 -name clk [get_ports clk]
同様に、これは次のように記述できます。
set the_clk_port [get_ports clk] create_clock -period 4.000 -name clk $the_clk_port
この 2 番目の例に示すように、 variables は定義され、「set」コマンドで値が割り当てられます。 variableの値にアクセスするには、 dollar sign ($) が使用されます。これも、 shell script および Perlと同様です。
curly braces ("{" および "}") に関しては、別の話です。 他のいくつかの言語と同様に、その意味は文脈に大きく依存します。 Tclでは、 curly braces のあまり期待されていない意味の 1 つは、同封された string はそのままにしておく必要があるということです。言い換えれば、代替品はなく、 whitespaces は他の characterと同じように見なされるべきです。たとえば、同じ timing constraint は次のように記述できます。
create_clock -period {4.000} -name {clk} [get_ports {clk}]
この例では、 curly braces はまったく不要であり、この command は前とまったく同じ意味になります。残念ながら、不要な curly braces はよく見られ、この例のように、多くの場合、何も意味しません。
Tcl consoleを使用するためのヒント
見つかった objects の数が多く、検索コマンドの出力が読みにくくなることがよくあります。これは、単純な Tcl commandsで解決できます。これを正確に行う方法は、使用するツールによって異なります。 Vivadoの場合、この command は designのすべての cells を出力します。各 cell は別の行に出力されるため、 cellsが多数あっても、出力は読みやすいままです。
> join [get_cells -hierarchical] \n
GND
VCC
bar__0_i_1
bar_reg_OBUF_inst
bar_reg__0
[ ... ]
「join」コマンドは、 get_cell が生成する array の各要素の間に newline を配置します。
Quartusでは、次の方法で同じ結果が得られます。
join [query_collection -all [get_cells -hierarchical] ] \n
または、 query_collection をより賢く使用して:
query_collection -all -report_format [get_cells -hierarchical]
特定の要素を見つける
長い自己紹介の後、いよいよ本当に興味深いことについて話す時が来ました。以下の例のために、後で使用される次の Verilog コードを参照してください。
module top(
input clk,
input foo,
output reg bar_reg,
output reg baz
);
reg foo_reg;
reg bar;
reg baz_metaguard;
wire pll_clk_8, pll_clk_6;
clk_wiz_1 pll_i
(.clk_in1(clk),
.clk_out1(pll_clk_8),
.clk_out2(pll_clk_6));
always @(posedge pll_clk_8)
foo_reg <= foo;
always @(posedge pll_clk_6)
begin
bar <= !foo_reg;
bar_reg <= bar;
end
always @(posedge clk)
begin
baz_metaguard <= bar;
baz <= baz_metaguard;
end
このページの上部で述べたように、 timing constraints の精度は、 logic elementsの正しいグループを選択するかどうかにかかっています。したがって、上記の 5 つの get_* commands から検索結果を絞り込むことは可能であり、また必要です。これを行うにはいくつかの方法がありますが、最も一般的な方法は objectの名前に基づいています。最も簡単な pattern は、探している名前とまったく同じ名前を持つ単一の object を見つけることです。たとえば、 Vivadoの Tcl consoleの場合:
> get_ports clk clk
同様に、特定の patternに一致する名前を持つすべての objects を見つけることができます。
> get_pins pll_i/* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2
これらの両方の例の出力は objectsであることに注意してください。 Vivadoの Tcl consoleでは、これらの objects の名前が便宜上印刷されています。
さらに重要なのは、各 FPGA tool はこれらの search patternsに対してわずかに異なる動作をすることに注意してください。ここでの例では Vivado が使用されています。他のツールにも同じ原則が適用されます。
アスタリスク ("*") は wildcard characterであり、任意の数の charactersを置き換えます。疑問符 ("?") は、1 つの characterを置き換えます。これは、ファイル名を持つ wildcards と同じように機能します。
ファイル名と同じように、 wildcards は hierarchy separator と一致しないことに注意してください (たとえば、"/" は Vivado に、"|" は Quartusに)。
hierarchical path とファイルのディレクトリにも類似点があります。 検索は、 file systemの root directory に似ている top-level hierarchyに関連して行われます。たとえば、次のようになります。
> get_pins */clk_* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2 > get_pins pll_i/clk_out? pll_i/clk_out1 pll_i/clk_out2
hierarchy 内の各 logic element の正確な位置を特定する必要があることは、多くの場合、重大な欠点です。 私たちが見つけたい logic elements は、多くの場合、異なる位置にあります。これは "-hierarchical" で解決されます: この flag が存在する場合、 pattern の検索は hierarchyのすべての位置で行われます。
一般に、 wildcards を使用して logic elements を検索することはお勧めしません。唯一の例外は、 search pattern が非常に単純な場合、または他に選択肢がない場合です。 wildcards と「-hierarchical」の使い方を説明した別ページがあり、この方法の限界も示されています。
-filterの使用
wildcardsに基づく search patterns の使用には、いくつかの欠点があります。最も重大な欠点は、 hierarchy を正確に定義する必要があるか、まったく定義しないことです。 1 つの問題は、 sub-hierarchyに属する objects に検索を制限することがしばしば望まれることです。ただし、これは wildcardsでは不可能であり、「-hierarchical」オプションではこの問題は解決されません。
このような理由から、 search patterns を定義するための推奨される方法は、 -filter オプションを使用することです。このオプションは、 boolean expressionに付属しています。このオプションを使用すると、この expression が true である検索結果のみが残ります。
例えば、
> get_pins */clk_* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2 > get_pins */clk_* -filter {name =~ *2*} pll_i/clk_out2
この例では、「name」と呼ばれる property が、 wildcardによって検出された各 objects で検査されました。この property が「*2*」と一致した場合にのみ、 object が検索結果に残りました。つまり、 object の名前に「2」が含まれている場合のみです。
この例は、実用的な観点からは興味深いものではありません。 "-hierarchical" を使用すると、さらに興味深い結果が得られます。 search patternがない場合、すべての objects が見つかります。言い換えると、この command はすべての hierarchiesのすべての pins を見つけます。
get_pins -hierarchical
この時点から、 -filterで検索結果を絞り込むことができます。
> get_pins -hierarchical -filter {name =~ pll_i/*/*out1 } pll_i/inst/clk_out1 > get_pins -hierarchical -filter {name =~ pll_i/*out1 } pll_i/clk_out1 pll_i/inst/clk_out1 > get_pins -hierarchical -filter {name =~ *out1 } pll_i/clk_out1 pll_i/inst/clk_out1
curly braces ("{" および "}") の意味は、それらの内部にある部分が Tcl interpreterによって変更されるべきではないということだけであることに注意してください。
また、 search pattern は -filter オプションに属し、動作が異なることに注意してください。 「name」を objectの property として扱います。したがって、すべての characters は同等に扱われます。 「/」には特別な意味はありません。 「/」が hierarchy separatorであることは問題ではありません。 "/" を含むすべての文字は、 wildcard ("*") と一致します。同様に、「/」を含むすべての文字が search patternで使用できます。もちろん、これは -filterなしでは当てはまりません。
character が "*" と一致するという事実は、 -filter をより強力なツールにしますが、この利点は間違いの可能性もあります。 上記の例に示すように、無害な "*" が誤って "pll_i/clk_" と "pll_i/inst/clk_" の両方と一致する可能性があることを忘れがちです。
この機能の正しい使い方は、 hierarchyのどこかに既知の名前を持つ logic element を見つけることです。
> get_pins -hierarchical -filter {name =~ */clkout2_buf/O } pll_i/inst/clkout2_buf/O
これは、 design の中に「clkout2_buf」という名前の cell が 1 つだけあることが確実な場合は正しいです。この commandを使用すると、この logic element を含む module が projectの hierarchy内で移動されたとしても、この cell の output pin は常に見つかります。実際のシナリオでは、「clkout2_buf」よりも一意の名前を選択することをお勧めします。
同じ方法が get_cells と get_netsでも機能します。次に例を示します。
> get_cells -hierarchical -filter {name =~ */clk*_buf} pll_i/inst/clkf_buf pll_i/inst/clkout1_buf pll_i/inst/clkout2_buf
しかし、 -filter は名前だけでなく、すべての propertiesに作用します。したがって、この command は、名前の中に「bar」が含まれるすべての registers を検索します。
get_cells -hier -filter {primitive_type =~ register.*.* && name =~ *bar*}
logical AND を意味する "&&" 演算子に注意してください ( Verilog および Cと同様)。
この commandでは、「primitive_type」と「name」は単に propertiesの名前です。「=~」演算子は比較を行い、 wildcardsを許可します。
object の properties は、 "report_property" command ( Vivado内) と一緒にリストできることを思い出してください。
したがって、 -filter は柔軟に操作できます。残念ながら、すべての FPGA toolsで使用できるわけではありません。
Vivado には filterという名前の command があり、これは -filterと同じ操作を実行することに注意してください。したがって、次の 2 つの commands は同等です。
set result [get_cells -hierarchical -filter {name =~ *_reg}] set result [filter [get_cells -hierarchical] {name =~ *_reg}]
2 番目の形式は、 objects のリストが variableに格納されている場合に便利です。したがって、上記の 2 つの commands も次のものと同等です。
set all_cells [get_cells -hierarchical]
set result [filter $all_cells {name =~ *_reg}]
-regexの使用
regular expressions に精通している人は、このオプションを使用するとよいでしょう。通常、これを行うのは良い考えではありません。主な理由は、 timing constraints が他の人にとって理解しにくくなるためです。 regular expressions をサポートする FPGA tools は通常、 -filter オプションもサポートするため、ほとんどの場合、 -filterを使用する方が適切です。
通常の search pattern の主な問題は、 hierarchy separator が wildcardと一致しないことです。
-regexp はこれを解決できます。次の 2 つの例に示します。
> get_pins -hierarchical -regexp {.+/clk_out[123]} pll_i/clk_out1 pll_i/clk_out2 pll_i/inst/clk_out1 pll_i/inst/clk_out2 > get_pins {pll_i/[^/]+/clk[^/]+} -hierarchical -regexp pll_i/inst/clk_in1 pll_i/inst/clk_out1 pll_i/inst/clk_out2
最初の command は、「.」が任意の characterと一致することを示しています。これには、「/」( hierarchy separator) も含まれます。
2 番目の command は、「[^/]+」が hierarchy separator以外のものと一致するようにどのように使用されるかを示しています。これにより、検索結果の hierarchy の正確な深さを制御できます。この command は、 search pattern が -regexpの argument ではないこと、ただし -regexp が search patternの構文を変更することも示しています。
regular expression は、 objectの名前全体と一致する必要があることに注意してください。つまり、ツールは regular expressionの先頭に "^" を暗黙的に追加し、最後に "$" を追加します。
ただし、同じ結果を得る別の方法がある場合は、 -regex を使用しないでください。他のほとんどの FPGA designers は search patternを理解できません。
-of_objectの使用
名前に従って objects を見つける代わりに、 -of_object では、他の objectsとの関係に従って objects を見つけることができます。ほとんどの場合、「-of_objects」は大まかに「接続されている」という意味です。
たとえば、 netに接続されているすべての pins を見つけるには、次のようにします。
> get_pins -of_objects [get_nets bar] bar_reg_reg/D baz_metaguard_reg/D bar_reg__0/Q
または、 cellのすべての pins :
> get_pins -of_objects [get_cells bar_reg_reg] bar_reg_reg/Q bar_reg_reg/C bar_reg_reg/CE bar_reg_reg/D bar_reg_reg/R
または、 clockの元になった pin :
> get_pins -of_objects [get_clocks clk_out1_clk_wiz_1] pll_i/inst/mmcme3_adv_inst/CLKOUT0
同じ方法で netsを見つけます。たとえば、どの nets が特定の pinに接続されていますか?
> get_nets -of_objects [get_pins bar_reg_reg/C] pll_clk_6
または、関連する cellに接続されている nets はどれですか?
> get_nets -of_objects [get_cells bar_reg_reg] bar_reg_OBUF pll_clk_6 <const1> bar <const0>
同様に、この方法で cells を検索することもできます。たとえば、どの cells が @pll_clk_6に接続されていますか?
> get_cells -of_objects [get_nets pll_clk_6]
bar_reg__0 bar_reg_reg pll_i
「pll_i」は、 Clock Wizardの IPの instantiation name であることに注意してください。これはおそらく、検索で望んだ結果ではありません。検索結果を flip-flopsだけに絞り込むとよいかもしれません。
> get_cells -of_objects [get_nets pll_clk_6] -filter {primitive_type =~ register.*.*} bar_reg__0 bar_reg_reg
これまでのところ、 -of_objects を使用した上記の例は、 pins、 nets 、および cells がどのように相互に参照できるかを示しています。ただし、このオプションを使用して clock objects を見つけることもできます。
> get_clocks -of_objects [get_nets pll_clk_6] clk_out2_clk_wiz_1 > get_clocks -of_objects [get_cells bar_reg_reg] clk_out2_clk_wiz_1 > get_clocks -of_objects [get_pins bar_reg_reg/C] clk_out2_clk_wiz_1
これら 3 つの commands は、 clock がそれに接続されている logic element に従ってどのように見つかるかを示しています。この logic element が cellである場合、結果が複数になる可能性があることに注意してください。例:
> get_clocks -of_objects [get_cells pll_i] clk clk_out1_clk_wiz_1 clk_out2_clk_wiz_1
"pll_i" は IPであることを思い出してください。したがって、その pins はこの moduleの ports です。
> get_pins -of_objects [get_cells pll_i] pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2
したがって、特定の clockを見つけるには、 get_pins の方が安全です。
> get_clocks -of_objects [get_pins pll_i/clk_out2] clk_out2_clk_wiz_1
しかし、もちろん、外部 I/O port 上の clock object は、次の場合に最適です。
> get_clocks -of_objects [get_ports clk] clk
または、同等の短い commandの場合:
> get_clocks [get_ports clk] clk
get_portsといえば、 -of_objectsでも動作します。 get_portsに固有の可能性については、ドキュメントを参照してください。他の commands に類似した可能性はまったく意味がありません。たとえば、次のようになります。
> get_ports -of_objects [get_nets clk] clk
要約すると、 -of_objects は、特定の logic elementsを選択する優れた方法です。これは特に、次のトピックである objectの名前による検索が難しいためです。
残念ながら、多くの FPGA tools は -of_objectsをサポートしていないため、信頼性の低い方法に頼るしかありません。
名前で検索する際の問題
すでに説明したように、 timing constraints の精度は logic elementsを見つける精度に依存します。これらの検索結果の少なくとも一部は、 objectの名前に依存しています。これがどのように問題を引き起こすか見てみましょう。
たとえば、「get_ports clk」は、特定の I/O pinに存在する clock object と signal の間の接続を確立するために使用されます。この I/O pin は、「clk」という名前の port object によって表されます。
create_clock -period 4.000 -name clk [get_ports clk]
しかし、なぜこの port object が「clk」という名前になったのでしょうか。答えは、 synthesizer が netlistを作成した方法に関連しています。 Verilog コードの top-level port の名前は、 netlistの top-level port の名前としても選択されました。これは当然の選択であるため、適切な synthesizer はすべて同じことを行います。
しかし、 cellsの名前はどうでしょうか。上記の Verilog コードで "foo_reg" という名前の register を見てみましょう。この registerの flip-flopを代表する cell object の名前は? Vivadoの synthesizer は、この objectに「foo_reg_reg」という名前を付けました。したがって、この synthesizer が Verilog コードの名前に "_reg" サフィックスを追加する傾向があることは明らかです。それは信頼できるルールのように聞こえます。しかし、別の synthesizer はおそらく何か違うことをするでしょう。
しかし、「bar」という名前の register はどうでしょうか。関連する cell object の名前は「bar_reg」である必要がありましたが、 synthesizer は別の選択をしました。 「bar_reg__0」。これは、 Verilog コードに「bar_reg」という register があるためです。そのため、名前の衝突を避けるために、 synthesizer はわずかに異なる名前を選択しました。 「_reg」の代わりに「_reg__0」を追加しました。この単純な例は、 objectsの名前に依存することの問題を示しています。
さらに悪いことに、「bar_reg」という名前の register が Verilog コードに追加される前に、 timing constraint が作成されたとします。この場合、 @bar に関連する cell object は、通常どおり「bar_reg」という名前を取得します。したがって、 timing constraint はこの名前を objectに使用します。後の段階で、「bar_reg」という名前の register が designに追加されます。その結果、要求された cell object の名前が「bar_reg」から「bar_reg__0」に変わります。 「bar_reg」という名前に依存する timing constraintは、突然正しくありません。運が良ければ、ツールはこれについて warning を発行します。
objects の名前の使用がうまくいかない理由は他にも考えられます。たとえば、 fan-out が制限を超えた場合、ツールは register を自動的に複製することがあります。この場合、新しい registerの名前が search patternと一致しないため、追加の register が timing constraintに含まれない場合があります。
より深刻な問題は、 logic elements が誤って timing constraints に含まれている場合です。たとえば、これは IP blocksに属する logic elements で発生する可能性があります。これらの logic elementsの名前を制御できないため、これらの名前が誤って timing constraintの pattern と一致する可能性があります。
timing constraints に誤って logic elements を含めることも、怠惰の結果である可能性があります。 timing constraints は、通常、 logic designに新しい機能を追加すると共に作成されます。 search pattern が試行錯誤によって書かれた場合、将来の logic elements の名前は考慮されない可能性があります。したがって、新しい logic が追加されると、その logic elements の一部の名前が意図せずに既存の timing constraintsと一致する可能性があります。
timing constraintsでミスを避ける方法
最初の最も重要なルールは、どの logic elements が timing constraintの search pattern と一致するかをテストするだけでは不十分だということです。これらの logic elements の完全なリストを作成し、このリストを注意深く確認したとしても、後で追加される logic に関して何も保証するものではありません。このレビューは、 objects の名前が synthesizer によって、または implementationの別の段階で変更された場合、 timing constraints が期待どおりに動作し続けることを保証するものでもありません。
したがって、 search patterns を数式のように扱うことが重要です。 これらの search patterns が現在期待どおりに動作するだけでは十分ではありません。また、期待どおりに機能しない場合は、小さな修正を加えて機能させるだけでは十分ではありません。むしろ、なぜ search pattern が正しいのか、そしてなぜ search pattern が正しいままであり続ける可能性が高いのかについて、論理的な説明がなければなりません。
search patterns が、変更される可能性が低いものに依存していることも重要です。たとえば、ツールは Verilog コード内の instantiations の名前を変更しません。これは、 modules、 IPs 、 primitivesの instantiations にも当てはまります。したがって、 Verilog コードに記述された instantiations の名前のみで構成される hierarchical path に依存しても安全です。 IP block内で作成された名前を使用するのはそれほど安全ではありません。これを説明するために、次の commandを見てみましょう。
get_clocks -of_object [get_pins pll_i/inst/clkout1_buf/O]
clockを配布している global clock buffer の output pin を参照して clock object を取得する方法です。問題は、これが長期的に機能すると確信できるかどうかです。
この方法の問題点は、「inst」と「clkout1_buf」が Clocking Wizard IPの内部で作られている instantiations の名前であることです。これらの名前が変更される可能性は低いですが、変更されないという保証はありません。
考えられる解決策の 1 つは、 IPを実装する Verilog コードを見つけて、この Verilog をプロジェクトに直接含めることです。これにより、将来何も変わらないことが保証されます。
別の方法は、 Verilogで IP の instantiation を調べることです。次のことを思い出してください。
clk_wiz_1 pll_i
(.clk_in1(clk),
.clk_out1(pll_clk_8),
.clk_out2(pll_clk_6));
これは black boxの instantiation であるため、 ports にはそれぞれ netlistに pin があります。これが IP の ports を識別する方法であるため、名前を変更することはできません。したがって、「pll_i/clk_out1」という名前の pin が @pll_clk_8と接続することが保証されます。したがって、これは clock objectを安全に入手する方法です。
get_clocks -of_object [get_pins pll_i/clk_out1]
clk_wiz_1 がプロジェクト内の別の Verilog module である場合、これはおそらく機能しないことに注意してください。 この場合、この moduleの instantiation に代わって pins は作成されません ( synthesizer は通常 netsをマージすることによって ports の接続を実装するため)。考えられる解決策は、 hierarchyの下位レベルに表示される名前を使用することです。
そのため、信頼できる名前にはいくつかの種類があります。
- IP が black boxとしてプロジェクトに含まれている場合、この IP の instantiation の名前と pins の名前は安全です。
- 同じことが primitiveの instantiation にも当てはまります。 instantiation と pins の名前は安全です。これは、 global clock buffersを参照する場合に特に役立ちます。別のシナリオは、 FPGAの関連する primitiveのおかげで、 flip-flops の明示的な instantiation です。これにより、ツールによる操作が防止されます。
- FPGAの I/O ports の名前も信頼できます。これらは、 top-level moduleの portsの名前です。
- registersに長くて珍しい名前を使用する。たとえば、すべての metastability guards が "_metastability_do_not_protect" で終わる名前を持っている場合、この種の false path constraint を書くことはかなり安全です:
set_false_path -to [get_cells -hier *_metastability_do_not_protect*]
patternの末尾にある wildcard に注意してください。
この constraint が適用されるべきではないものに適用される可能性は低いです。また、この constraint が registersを無視するほど名前が変更される可能性は低いです。ただし、これは少し安全性の低い戦略です。
大失敗したほうがいい
最悪の状況は、 timing constraint がほぼ正しい場合です。 含まれていない paths がわずかしかない場合。または、誤って timing constraint に含まれている paths がわずかしかない場合。この種のエラーは、見つけるのが最も困難です。
これが、短く簡潔で数学的なスタイルを持つ timing constraints が優れている主な理由です。 logic elementsの小さなグループごとに timing constraint がある場合、この長いルール リストに間違いが入り込みやすくなります。
この考えを実証するために、 clock objectを見つけるために上に示した例に戻りましょう。
get_clocks -of_object [get_pins pll_i/inst/clkout1_buf/O]
上で述べたように、この expression の問題は、 pll_i の instantiation が hierarchy内の別の位置に移動すると、 clock object が見つからないことです。これはどれほど悪いのでしょうか?
この clock object が次のように Tcl variable に格納されているとします。
set my_clock [get_clocks -of_object [get_pins pll_i/inst/clkout1_buf/O]]
そして、 $my_clock は多くの timing constraintsで使用されているため、多くの paths が関与しています。この場合、バグのために $my_clock が突然 clock object を含まなくても、実際には大きな問題ではありません。 多くのことがうまくいかないため、この間違いはすぐに気付く可能性が高いです。
しかし、 $my_clock が 1 つの timing constraintでのみ使用され、この constraint がほとんど影響を与えない小さな問題を解決することを目的としている場合、これは悪い状況です。おそらく、この間違いは見過ごされてしまうでしょう。
結論は: 適切に作成された timing constraint は、完全に機能するか、まったく機能しないかのいずれかです。
このページでは、 logic elementsを正確に選択する方法を示しました。次のページでは、この知識を使用して選択的 timing constraintsを定義します。