動的 SDC 制約によるデザイン再利用の簡素化

author-image

投稿者:

多くのデザインで再利用できるデザインブロックまたは HDL コンポーネントを作成する場合、それに伴って SDC 制約を作成する必要があるでしょう。コンポーネントを再利用するデザイナーが編集する必要がないように、制約を作成することは役立ちます。制約は、デザイン階層内のどこでブロックがインスタンス化されても機能するように、汎用性のあるものとし、またデザインブロックの接続方法に関わらず機能するように、動的なものとする必要があります。デザイン変更を反映させるために制約を手動で編集する必要がある場合、デザイナーが制約を更新せずにデザインを変更すると、制約が同期されなくなります。

このデザイン例では、以下の 2 つの課題に対応する動的 SDC 制約を作成するテクニックを扱っています。

  • ローレベルのモジュールに直接接続されたトップレベル I/O の名前を決定する
  • ローレベルのモジュール内のロジックに派生クロックを作成する

図 1 は、この例の非常にシンプルなデザインを示しています。これには、reusable_block という名前の再利用可能なデザインブロックにおける、2 つのインスタンスが含まれており、黄色で示しています。図 2 は、reusable_block デザインのコンテンツを示しています。reusable_block は、ソースシンクロナス出力バス用のダブル・データ・レート・クロックとして 機能します。その出力は、トップレベル出力に接続する必要があります。reusable_block 用の制約は、派生クロックを含む必要があります。出力はソースシンクロナス・クロックとして機能するからです。

図 1.デザイン例用のサンプル回路。

図 2.reusable_block のコンテンツ。

トップレベル I/O 名の決定

reusable_block 用の制約は、トップレベル I/O 名の変更に対応する必要があります。このため、トップレベル I/O 名は、コンパイル中またはタイミング分析中に決定する必要があります。get_fanouts Tcl コマンドは、指定した名前のファンアウトであるポートまたはレジスターを表す ID のコレクションを返します。get_fanout Tcl コマンドは、コンパイル中またはタイミング分析中に存在するタイミング・ネットリストを使用するため、ファンアウト・ノードの名前を問わず、動的に接続性を決定します。以下の Tcl コードは、get_fanouts を使用して、ローレベルレジスターの直接ファンアウトであるトップレベル出力を取得する方法を示しています。

foreach_in_collection fanout_id [get_fanouts $low_level_register_name] { break }
set top_level_io_name [get_node_info -name $fanout_id]

ローレベルレジスターの全階層名を把握する必要はありません。ワイルドカード、および再利用可能なデザインブロック内に存在する階層の既知の部分を使用して、照合できるからです。このページの最後にあるコード例は、ローレベルのレジスター名を照合する方法の例を示しています。

図 1 のデザインでは、ローレベルモジュール出力ピンが、 1 つのトップレベル出力に直接接続されます。以下の Tcl コードは、エラーチェックを追加して、ローレベルレジスターが 1 箇所にのみファンアウトするようにします。ここでのファンアウト場所は出力ポートです。この Tcl コードは、reusable_block を制約する SDC ファイルの一部である必要があります。

# ローレベルレジスターのファンアウトを取得します
set fanout_collection [get_fanouts $low_level_register_name]

# ファンアウトが 1 つだけであることを確認します
set num_fanouts [get_collection_size $fanout_collection]
if { 1 != $num_fanouts } {
    return -code error "$low_level_register_name fans out to $num_fanouts \
        nodes but must fan out to one."
}

# ファンアウト・ノードの名前を取得します
foreach_in_collection fanout_id $fanout_collection { break }
set fanout_name [get_node_info -name $fanout_id]

# ファンアウト・ノードが出力ポートであることを確認します
if { [catch { get_port_info -is_output_port $fanout_id } is_output] } {
    # エラーがありました。これはポートにファンアウトしません
    return -code error "$low_level_register_name fans out to $fanout_name \
        which is not a port"
} elseif { ! $is_output } {
    # エラーはありませんが、ポートが出力ポートではありません
    return -code error "$fanout_name is not an output port"
} else {
    set top_level_io_name $fanout_name
}

# top_level_io_name は、low_level_register_name の唯一のファンアウトであり、かつ
# 出力ポートです

派生クロックの作成

ソースシンクロナス出力クロックは、ダブル・データ・レート出力レジスターにフィードするクロックをベースとした、派生クロックとして定義する必要がありあす。派生クロックは、デザイン内のクロックに関する手動入力情報なしで作成する必要があります。デザインブロックは、任意のデザイン内で、任意のクロックスキームを使用してインスタンス化される場合があるからです。

以下の SDC コマンドは、図 1 のデザイン向けのソースシンクロナス出力クロック用に、階層内の位置が不明な場合に、派生クロックを作成するシンプルな方法を示しています。

create_generated_clock -name reusable_generated -source [get_pins \
    *|reusable_block_clock_out|altddio_out_component|auto_generated|ddio_outa[0]|muxsel] \
    $top_level_io_name

これは、デザイン階層内の任意の位置にある reusable_block を、単一回インスタンス化するのに役立つ直接的なアプローチですが、複数のインスタンス化やマルチクロックの状況は処理しません。クロック・スキームが不明な場合、派生クロックの制約は、デザインブロックにフィードする単一のクロック信号で、複数のクロックが定義されている状況を処理できるようにする必要があります。単一クロック信号上の複数クロックは、異なる I/O プロトコル速度をサポートするデザインや、冗長性のためにクロック切り換えをサポートするデザインによく見られます。上記のシンプルな派生クロックの例は、クロックの状況では失敗します。これは、複数のソースクロックを区別する -master_clock オプションが含まれていないためです。

複数のインスタンス化を処理するには、ループを使用して各インスタンス化用に一意の派生クロックを作成します。マルチクロックの状況を処理するには、ピンをフィードするクロックのデザイン例で説明されている、get_clocks_driving_pin と呼ばれるカスタム・プロシージャーを使用します。カスタム・プロシージャーを使用するには、ピンをフィードするクロックのデザイン例ページからコピーする必要があります。これを、プロジェクトに追加した個別の SDC ファイルに保存するか、または再利用可能なブロックを制約する他の全制約を含む SDC ファイルの中にコピーし張り付けます。プロジェクトに追加する SDC ファイルとして保存する場合、get_clocks_driving_pin カスタム・プロシージャーを使用するいかなる SDC ファイルよりも前に表示されるようにします。

以下の Tcl コードは、図 1 のデザイン内でローレベルレジスター駆動のトップレベル出力を制約する、派生クロックの作成方法を示しています。派生クロックは、トップレベル出力をターゲットとして使用し、altddio_output レジスターの muxsel ピンをソースとして使用します。このコードでは、ループを使用してデザイン内の reusable_block インスタンス化を反復し、入れ子のループを使用して、get_clocks_driving_pin カスタム・プロシージャーを使用したマルチクロックの状況を処理します。get_clocks_driving_pin プロシージャーは定義済みであるものとします。

# get_pins は、reusable_block の各インスタンス化に対して 1 つの muxsel ピンを返します
# foreach_in_collection は、各 muxsel ピンで反復します
foreach_in_collection pin_id [get_pins -compatibility_mode \
    *|reusable_block_clock_out|altddio_out_component|auto_generated|ddio_outa[0]|muxsel] {

    # pin_name には、reusable_block のインスタンス化用 muxsel ピンの
    # デザインの全階層があります
    set pin_name [get_node_info -name $pin_id]
    
    # 上記のコードを使用し、エラーチェックなしで
    # トップレベル出力の名前を取得します
    foreach_in_collection port_id [get_fanouts $pin_name] { break }
    set port_name [get_node_info -name $port_id]
    
    # altddio_output レジスターにフィードするクロックが複数ある可能性があります
    # muxsel ピンにフィードする各クロックに1 つの派生クロックが
    # 必要です。muxsel ピンにフィードする各クロックは、マスタークロックです。
    foreach master_clock [get_clocks_feeding_pin $pin_name] {

        post_message "Creating generated clock on $port_name fed by $pin_name"
        # 適切なマスタークロックに派生クロックを作成します。
        # ソースは、reusable_block の現在のインスタンス化における
        # altddio_output セルの muxsel ピンです。
        # 名前は、マスタークロックと muxsel ピンの全階層名の
        # 組み合わせです。
        # ターゲットは、muxsel ピンのファンアウトであるトップレベルポートです。
        create_generated_clock -add -master_clock $master_clock \
            -source [get_pins $pin_name] -name ${master_clock}-${pin_name} \
            [get_ports $port_name]
    }
}

プロジェクトに含まれる SDC ファイル内のこのコードにより、reusable_block のすべてのインスタンス化が、派生クロックで自動的に制約されます。派生クロックは、以下の状況にあっても、常に正確で最新のものです。

  • reusable_block をデザイン階層の他の位置にインスタンス化または移動する場合
  • トップレベル I/O の名前を変更する場合
  • デザイナーがデザイン内で複数のクロック定義を使用する場合