このデザイン例は、SDC ファイルで使用でき、ピンにフィードするすべてのクロックのリストを返す、カスタム・プロシージャーを示しています。このプロシージャーは、デザイン内にある他のクロック名が不明で、派生クロックを作成する必要がある場合に役立ちます。動的 SDC 制約を使用したデザイン再利用の単純化デザイン例では、このページで説明するカスタム・プロシージャーの詳細、および使用方法例を提供しています。
プロシージャー用のコード全体は、このページの最後にあります。その前に、プロシージャーの動作方法についての完全な説明があります。SDC ファイル内で get_clocks_driving_pins カスタム・プロシージャーを使用するには、プロシージャーが定義済みであることを確認してから、その他の SDC コマンド同様に呼びます。プロシージャーが定義済みであることを確認する簡単な方法が 2 つあります。
- プロシージャー・コードを個別の SDC ファイルに保存し、その SDC ファイルをプロジェクトに含めます。
- get_clocks_driving_pins カスタム・プロシージャーを使用する前に、プロシージャーをコピーし、任意の SDC ファイルの最上部に貼り付けます。
個別の SDC ファイル
プロシージャー・コードを個別の SDC ファイルに保存すると、そのコードは他の制約とは別に保存され、他のプロジェクトで同様に再利用できます。個別の SDC ファイルを使用する場合、プロシージャーのある SDC ファイルをプロジェクト内のファイルリストに追加し、このプロシージャーを使用する他のあらゆる SDC ファイルより上に表示されるようにする必要があります。他の SDC ファイルより上にリスト表示することで、Quartus® II ソフトウェアが、使用前にプロシージャーを確実に定義します。
コピーと貼り付け
プロシージャーを使用するのと同じ SDC ファイル内にコピーと貼り付けすることで、プロジェクト内の SDC ファイルの数を減らせます。他のデザイナーが再利用できるようにモジュール用の SDC ファイルを作成する場合、単一の SDC ファイルにすべての制約およびサポートコードを含めて、できる限りシンプルにできます。プロシージャーを最初に使用する前に、プロシージャー・コードを SDC ファイルに含めて、使用前に定義されるようにする必要があります。通常は、この要件を満たすため、ファイルの最上部に置きます。
スクリプト操作
デザイン内でピンをフィードするすべてのクロックのリストを取得する主要なステップは、以下の 3 つです。
- すべてのクロックを取得し、ターゲット・ノードに、ターゲットノードからクロックへのマッピングを作成します。
- クロックがあるノードのリストを取得します。ノードは特定のピンへのファンイン・パス上にあります。
- ノードのリストから、特定のピンに最も近いノードを検索し、そのノードにあるクロックを返します。
ステップ 1.すべてのクロックを取得し、マッピングを作成する
以下の Tcl コードは、デザイン内にあるすべてのクロックを取得し、ノードからそのノードにあるクロックへのマッピングを (Tcl アレイを使用して) 作成します。
catch { array unset nodes_with_clocks } array set nodes_with_clocks [list] # デザイン内の各クロック上で繰り返します foreach_in_collection clock_id [all_clocks] { set clock_name [get_clock_info -name $clock_id] # 各クロックはノードに適用されます。ターゲットノードのコレクションを取得します foreach_in_collection target_id [get_clock_info -targets $clock_id] { # クロック名をターゲットノードとアソシエイトします set target_name [get_node_info -name $target_id] lappend nodes_with_clocks($target_name) $clock_name } }
仮想クロックにはターゲットがないので、マッピングが作成されません。下記のプロシージャー・コード全体では、ターゲットノードのタイプ (レジスター、ピン、セル、またはポート) に関する情報が、後日使用するために保存されます。
ステップ 2.ファンインパス内でクロックのあるノードを取得する
2 番目のステップは、特定のピンへのファンインパス上の、クロックがあるノードのサブセットを検索することです。クロックのある各ノード (ステップ 1 の検索結果) について、ノードを介した特定のピンへのファンインを取得します。ファンインがある場合、ノードはピンへのファンインパス内にあります。ファンインがない場合、ノードはピンへのファンインパス上にありません。
以下の Tcl コードは、ステップ 1 のクロックがあるすべてのノードで繰り返し、get_fanins コマンドを使用して、各ノードが特定のピンのファンインパス上にあるかどうかを判断します。ノードが特定のピンのファンインパス上にある場合、そのノードは pin_drivers リストに保存されます。
set pin_drivers [list] # ステップ 1 で作成されたマッピングにあるすべてのノード上で繰り返します foreach node_with_clocks [array names nodes_with_clocks] { # 現在のノードを介した特定のピンへのファンインを取得します set fanin_col [get_fanins -clock -through $node_with_clock $pin_name] # ファンインノードが少なくとも 1 つある場合、現在のノードは # 特定のピンへのファンインパス上にあるので、それを保存します。 if { 0 < [get_collection_size $fanin_col] } { lappend pin_drivers $node_with_clocks } }
下記のプロシージャー・コード全体では、ノードタイプに関する追加情報を使用して、get_fanins コマンド内の -through 値用のタイプ固有コレクションを指定します。
ステップ 3.特定のピンに最も近いノードを検索する
ここまでで、pin_drivers 変数には、特定のピンへのファンインパス上の、クロックがあるノードすべてのリストがあります。このステップでは、特定のピンに最も近いノードを検索します。pin_drivers リストに 1 つ以上のノードがある場合、コードはリストにある最初の 2 つのノードを選び、1 つのノードがもう一方のノードへのファンインパス上にあるかどうかを確認します。ノードがファンインパス上にある場合、最初のノードをリストから削除可能とするには、2 番目のノードよりもピンから離れている必要があります。
while { 1 < [llength $pin_drivers] } { # pin_drivers リストにある最初の 2 つのノードを選びます set node_a [lindex $pin_drivers 0] set node_b [lindex $pin_drivers 1] # node_b が node_a のファンインパス上にあるか確認します set fanin_col [get_fanins -clock -through $node_b $node_a] # 少なくとも 1 つのファンインノードがある場合、node_b は特定のピンから # node_a よりも離れている必要があります。 # ファンインノードがない場合、node_b は node_a よりも # 特定のピンに近い必要があります。 if { 0 < [get_collection_size] } { # node_a is closer to the pin. # node_b を pin_drivers リストから削除します set pin_drivers [lreplace $pin_drivers 1 1] } else { # node_b is closer to the pin. # node_a を pin_drivers リストから削除します set pin_drivers [lreplace $pin_drivers 0 0] } } # pin_drivers に残された方のノードは、特定のピンを駆動するノードです set node_driving_pin [lindex $pin_drivers 0] # ステップ 1 のマッピングにあるノード上のクロックを検索して返します return $nodes_with_clocks($node_driving_pin
下記のプロシージャー・コード全体では、ノードタイプに関する追加情報を使用して、get_fanins コマンド内の -through 値用のタイプ固有コレクションを指定します。
プロシージャー・コード全体
下記は、get_clocks_driving_pin カスタム・プロシージャーの完全なコードです。これには、上記で詳細を説明していない、追加のエラーチェックおよびサポート機能が含まれています。
proc get_clocks_feeding_pin { pin_name } { # ステップ 1 の前に、エラーチェックを実行して、プロシージャーに渡された pin_name # が確実に 1 つのピンにのみ一致することを確認します。 # 一致するピンがない場合、また 1 つのピンのみに一致していない場合は、エラーを返します。 set pin_col [get_pins -compatibility_mode $pin_name] if { 0 == [get_collection_size $pin_col] } { return -code error "No pins match $pin_name" } elseif { 1 < [get_collection_size $pin_col] } { return -code error "$pin_name matches [get_collection_size $pin_col]\ pins but must match only one" } # プロシージャーで使う変数を初期化します catch { array unset nodes_with_clocks } catch { array unset node_types } array set nodes_with_clocks [list] array set node_types [list] set pin_drivers [list] # Step 1.デザイン内にあるすべてのクロックを取得し、ターゲットノード上に # ターゲットノードからクロックへのマッピングを作成します # デザイン内にある各クロック上で繰り返します foreach_in_collection clock_id [all_clocks] { set clock_name [get_clock_info -name $clock_id] set clock_target_col [get_clock_info -targets $clock_id] # 各クロックはノードに適用されます。ターゲットノードのコレクションを取得します foreach_in_collection target_id [get_clock_info -targets $clock_id] { # クロック名をターゲットノードとアソシエイトします set target_name [get_node_info -name $target_id] lappend nodes_with_clocks($target_name) $clock_name # ターゲットノードのタイプを後日使用のために保存します set target_type [get_node_info -type $target_id] set node_types($target_name) $target_type } } # Step 2.特定のピンへのファンインパス上にある # クロックのあるノードのリストを取得します # ステップ 1 で作成したマッピングにあるすべてのノードで繰り返します foreach node_with_clocks [array names nodes_with_clocks] { # ターゲットノードのタイプを使用して get_fanins コマンド内の # -through 値用にタイプ特有のコレクションを作成します。 switch -exact -- $node_types($node_with_clocks) { "pin" { set through_col [get_pins $node_with_clocks] } "port" { set through_col [get_ports $node_with_clocks] } "cell" { set through_col [get_cells $node_with_clocks] } "reg" { set through_col [get_registers $node_with_clocks] } default { return -code error "$node_types($node_with_clocks) is not handled\ as a fanin type by the script" } } # 現在のノードを介した特定のピンへのファンインを取得します set fanin_col [get_fanins -clock -through $through_col $pin_name] # 少なくとも 1 つのファンインノードがある場合、現在のノードは # 特定のピンへのファンインパス上にあるので、それを保存します。 if { 0 < [get_collection_size $fanin_col] } { lappend pin_drivers $node_with_clocks } } # ステップ 3 の前に、エラーチェックを実行して、デザイン内のクロックがあるノードの # 少なくとも 1 つが特定のピンへのファンインパス上に # あることを確認します。 if { 0 == [llength $pin_drivers] } { return -code error "Can not find any node with clocks that drives $pin_name" } # Step 3. ステップ 2 で作成したノードのリストから、特定のピンに最も近い # ノードを検索し、そのノードにあるクロックを返します。 while { 1 < [llength $pin_drivers] } { # pin_drivers リストにある最初の 2 つのノードを取得します set node_a [lindex $pin_drivers 0] set node_b [lindex $pin_drivers 1] # ターゲットノードのタイプを使用して、get_fanins コマンド内の #-through 値用のタイプ固有コレクションを作成します。 switch -exact -- $node_types($node_b) { "pin" { set through_col [get_pins $node_b] } "port" { set through_col [get_ports $node_b] } "cell" { set through_col [get_cells $node_b] } "reg" { set through_col [get_registers $node_b] } default { return -code error "$node_types($node_b) is not handled\ as a fanin type by the script" } } # node_b が node_a のファンインパス上にあるかどうかを確認します set fanin_col [get_fanins -clock -through $through_col $node_a] # 少なくとも 1 つのファンインノードがある場合、node_b は node_a よりも # 特定のピンから離れている必要があります。 # ファンインノードがない場合、node_b は node_a よりも # 特定のピンに近い必要があります。 if { 0 < [get_collection_size $fanin_col] } { # node_a is closer to the pin. # node_b を pin_drivers リストから削除します set pin_drivers [lreplace $pin_drivers 1 1] } else { # node_b is closer to the pin # node_a を pin_drivers リストから削除します set pin_drivers [lrange $pin_drivers 1 end] } } # pin_drivers に残された 1 つのノードが、特定のピンを駆動するノードです set node_driving_pin [lindex $pin_drivers 0] # ステップ 1 のマッピングにあるノード上のクロックを検索して返します return $nodes_with_clocks($node_driving_pin) }