01signal.com

Tcl コマンドを使用して logic elementsを選択する

このページは、 timingに関する一連のページに属しています。前のページでは、 timing 計算の背後にある理論を説明し、 clock period constraintについて説明し、 timing closureの原理を示し、 Tcl 環境の調査を開始しました。このページでは、 timing constraints を特定できるようにするコマンドについて説明します。

概要

timing constraints の目的は、 design 内のすべての paths の timing 要件が確実に満たされるようにすることです。 paths ごとに要件が異なる場合があるため、各 timing constraint は pathsの関連するグループに向ける必要があり、他には何も含めないでください。

paths を定義する唯一の方法は、これらの pathsに関連する logic elements を参照することです。したがって、 logic elementsの正しいグループを選択する正確な式を記述できることが重要です。つまり、 get_clocks、 get_ports 、 get_cellsなどのコマンドを正しく使用して、必要な結果が得られるようにする必要があります。

このページでは、 logic elementsのグループを記述するための基本的な手法について説明します。ここにあるほとんどすべては、 SDC 構文に固有のものです。また、 Tcl command-line インターフェイスが利用可能であると仮定します。これは、 Vivado と Quartus、および最近のほとんどの FPGA ツールに当てはまります。

一部の FPGA ベンダーは、 Synopsysのソフトウェアが自社のツールに統合されていることを公然と宣言しているため、当然これらのツールは同じ Tcl コマンドを使用します。一方、 Vivadoは Synopsysから派生したものとは見なされません。それでも、特に Tcl インターフェイスに関して、この 2 つの間にいくつかの顕著な類似点があります。 Quartus は独自に開発されたようで、その Tcl インターフェイスは少し異なります。

一見すると、このページは Tcl scriptingの詳細に行き過ぎているように見えるかもしれません。真実は反対です: 正確さは非常に重要であり、これはコマンドがどのように解釈されるかを正確に理解することによってのみ達成できます。実際、このページでは基本的な原則のみを説明しています。ドキュメントを読むことに代わるものはありません。

FPGA ツールからガイダンスを得る

多くの場合、 timing constraintsを書き始めるのは難しいものです。 FPGA ツールはこれに役立ちます。

"help" コマンドは、 Tcl コマンドに関するドキュメントを表示するために Tcl console で使用できます。多くの場合、これは公式ドキュメント ( pdf 形式など) とまったく同じ情報です。

ほとんどの FPGA ツールには、 timing constraints を自動的に作成するための GUI インターフェイスがあります。作業方法は、必要な timing constraints のタイプを選択するために一般的に使用されます。次のステップは、関連する logic elements をリストから選択することです。その結果、1 つまたは複数の timing constraints が SDC ファイルに追加されます。

この種の wizard を使用すると、 Tcl 構文に関するヒントを得るのに役立ちます。場合によっては、自動的に作成される constraints をそのまま使用することもできます。ただし、ほとんどの場合、 wizardの出力を使用したいという誘惑に抵抗し、代わりに timing constraint の目的を最もよく達成する方法を慎重に検討する価値があります。また、プロジェクトがどのように発展すると予想されるかを検討し、 timing constraints が長期にわたって正しいままであることを確認することも重要です。 GUI wizard との簡単なセッションでは、これを達成することはまずありません。

一部の FPGA ツールには、 designで logic elements を検索するための GUI インターフェイスもあります。このインターフェースを使用すると、要求された検索に対応する Tcl コマンドが表示されることがよくあります。これは、特定の logic elementsを見つけるための Tcl 式を取得するための便利な方法です。繰り返しになりますが、これらの式は、さらなる作業の出発点として扱う必要があります。

ほとんどの FPGA ツールの 3 番目の機能は Tcl command-line console で、コマンドを入力 (または Copy-Pasteを使用) し、結果を画面に表示できます。これにより、コマンドとその search patternsをテストし、どの objects が見つかったかを確認できます。これは、 search pattern が正しいことを確認するのに役立ちます。

結論として、 FPGA ツールは Tcl コマンドの作成を支援できます。しかし、すでに述べたように、ツールによって作成された Tcl コマンドは、時間の経過とともに正しく動作することが保証されている正確な search patterns を記述するための基礎に過ぎないはずです。

timing constraintsを作成するための怠惰な方法がわかったら、今度はこれを適切に行う方法を学習します。

netlist: 簡単なリマインダー

Tcl 環境について詳しく説明する前に、 netlistsについて簡単に説明しておきます。

netlists の最も一般的なファイル形式は EDIFですが、多くの FPGA ツールには独自の形式もあります。通常、 synthesizer は netlistを作成しますが、後の段階でツールが 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 ツールがプロジェクトの implementation を介して実行されると、実際には Tcl scripts が実行されます。これは、 Vivado と Quartus 、および他のいくつかの FPGA ツールに当てはまります。別の方法で動作するソフトウェアを使用しても、次の仮定を行うことは依然として正しいです。 すべてが 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 コマンドは、これらの objectsにアクセスできます。

これらは、 SDC 構文で動作するすべての FPGA ツールでサポートされている 5 つの Tcl コマンドです。これらのコマンドは、異なるタイプの objects (つまり、異なる classes) を見つけるために使用されます。 timing constraintsの前の例で既にそれらを使用しました。実際、これらのコマンドなしで意味のある timing constraints を書くことはまったく不可能です。

argumentsがない場合、これらのコマンドは関連するタイプのすべての objects を検索します。後で、検索を絞り込む方法について説明します。

これらの 5 つのコマンドを除いて、各 FPGA ツールには独自の追加コマンドと追加の objectsがあります。たとえば、 Vivado には、 all_ffs、 all_registers、 all_inputs、 all_outputs、 all_rams など、この種のコマンドがいくつか追加されています。 Quartus はこれらの一部をサポートしており、 get_registers、 get_keepers、 get_nodes、 get_fanins 、 get_fanouts などもあります。

これらの objects の重要性は、 FPGA designで logic elements を参照するために timing constraints で使用されることです。 Tcl scripts で使用して、 clockの周波数などの情報を取得することもできます。各 FPGA ツールには、 Tcl scriptsでこれらの objects にアクセスするための独自の API があります。たとえば、次の Tcl コマンドを Vivado で使用して、 clock periodを取得できます。

> get_property PERIOD [get_clocks clk]
4.000

Quartusでも同じです。

> get_clock_info -period [get_clocks clk]
4.000

これらの違いにもかかわらず、ほとんどの FPGA ツールは、 SDC 形式の timing constraints の構文と意味に同意しています。各ツールがサポートする API に関する情報は、通常、 Tcl scripting または Timing Closureに関連するタイトルを持つ user guides にあります。

このページの例は、特に明記されていない限り、 Vivadoに基づいています。

Tclに関するいくつかの注意事項

Tcl は古い言語ですが、 logic designの分野で確立されているため、この言語がすぐになくなることはないと予想されます。幸いなことに、 Tcl についてよく知らなくても、 Tcl で便利なことを行うことができます。

最初に、すでに簡単に触れた square brackets ("[" と "]") です。 Tclでは、これは square bracketsでコマンドを実行し、結果をその位置に置くことを意味します。 shell scripting や Perlに慣れている人にとっては、これは backticksと同じです。たとえば、次のコマンドでは、 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 番目の例に示すように、変数が定義され、"set" コマンドで値が割り当てられます。変数の値にアクセスするには、 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 はまったく不要であり、このコマンドの意味は以前とまったく同じです。不必要な curly braces は残念ながら一般的であり、多くの場合、この例のように何の意味もありません。

Tcl consoleを使用するためのヒント

見つかった objects の数が多く、検索コマンドの出力を読み取るのが困難になることがよくあります。これは、単純な Tcl コマンドで解決できます。これを行う方法は、使用するツールによって異なります。 Vivadoでは、このコマンドは 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_* コマンドからの検索結果を絞り込むことが可能であり、必要です。これにはいくつかの方法がありますが、最も一般的な方法は 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 の名前が便宜上印刷されています。

さらに重要なことは、これらの search patternsに関して、各 FPGA ツールの動作がわずかに異なることに注意してください。ここの例では 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 が検出されます。つまり、このコマンドは、すべての 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 つしかないことがわかっている場合は正しいです。このコマンドを使用すると、この 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で動作します。したがって、このコマンドは、名前に「bar」が含まれるすべての registers を検索します。

get_cells -hier -filter {primitive_type =~ register.*.* && name =~ *bar*}

logical AND を意味する "&&" 演算子に注意してください ( Verilog および Cと同様)。

このコマンドの「primitive_type」と「name」は、 propertiesの名前です。 "=~" 演算子は比較を行い、 wildcardsを許可します。

object のプロパティは、"report_property" コマンド ( Vivado内) で一覧表示できることを思い出してください。

そのため、 -filter は柔軟に使用できます。残念ながら、すべての FPGA ツールで利用できるわけではありません。

Vivado には、 -filterと同じ操作を行う filterという名前のコマンドがあることに注意してください。したがって、次の 2 つのコマンドは同等です。

set result [get_cells -hierarchical -filter {name =~ *_reg}]
set result [filter [get_cells -hierarchical] {name =~ *_reg}]

2 番目の形式は、 objects のリストが変数に格納されている場合に役立ちます。したがって、上記の 2 つのコマンドは次のコマンドと同等です。

set all_cells [get_cells -hierarchical]
set result [filter $all_cells {name =~ *_reg}]

-regexの使用

regular expressions に精通している人は、このオプションを使用することをお勧めします。通常、これを行うことはお勧めできません。主な理由は、 timing constraints を他の人が理解するのがより困難になるためです。 regular expressions をサポートする FPGA ツールは通常、 -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

最初のコマンドは、「.」を示しています。どの characterとも一致します。これには「/」( hierarchy separator)が含まれます。

2 番目のコマンドは、"[^/]+" を使用して hierarchy separator以外のものと一致させる方法を示しています。したがって、これにより、検索結果の hierarchy への正確な深さを制御できます。このコマンドは、 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 つのコマンドは、接続されている logic element に従って clock がどのように検出されるかを示しています。この 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

または、同等の短いコマンドを使用します。

> get_clocks [get_ports clk]
clk

get_portsといえば -of_objectsでも動作します。 get_portsに固有の可能性に関するドキュメントを参照してください。他のコマンドに似た可能性はまったく無意味です。たとえば、次のようになります。

> get_ports -of_objects [get_nets clk]
clk

要約すると、 -of_objects は、特定の logic elementsを選択する優れた方法です。これは特に、次のトピックである objectの名前による検索が難しいためです。

残念ながら、多くの FPGA ツールは -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内で作成された名前を使用するのは安全ではありません。これを説明するために、次のコマンドを見てみましょう。

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の下位レベルに表示される名前を使用することです。

そのため、信頼できる名前にはいくつかの種類があります。

大失敗したほうがいい

最悪の状況は、 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]

前述のように、この式の問題点は、 pll_i の instantiation が hierarchy内の別の位置に移動すると、 clock object が見つからないことです。それはどれほど悪いことでしょうか?

この clock object が次のように Tcl 変数に格納されているとします。

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を定義します。

このページは英語から自動翻訳されています。 不明な点は元のページを参照してください。
Copyright © 2021-2024. All rights reserved. (6f913017)