Vereinfachen Sie die Wiederverwendung von Designs mit dynamischen SDC-Beschränkungen

author-image

Von

Wenn Sie einen Design-Block oder eine HDL-Komponente erstellen, die in vielen Designs wiederverwendet werden kann, ist es möglicherweise erforderlich, SDC-Beschränkungen zu erstellen, um damit fortzufahren. Es ist sinnvoll, Beschränkungen zu erstellen, die nicht durch die Wiederverwendung der Komponente durch den Designer bearbeitet werden müssen. Beschränkungen sollten generisch sein, damit sie unabhängig davon funktionieren, wo der Block in der Designhierarchie instanziiert wird, und dynamisch, damit sie unabhängig davon funktionieren, wie der Design-Block verbunden ist. Wenn Beschränkungen manuell bearbeitet werden müssen, um Designänderungen widerzuspiegeln, werden sie nicht mehr synchronisiert, wenn der Designer Designänderungen vornimmt, ohne die Beschränkungen zu aktualisieren.

Dieses Designbeispiel behandelt Techniken zum Erstellen dynamischer SDC-Beschränkungen, die die folgenden zwei Probleme lösen:

  • Ermittlung des Namens eines I/O der obersten Ebene, der direkt mit einem Low-Level-Modul verbunden ist
  • Erstellen von generierten Taktfrequenzen auf Logik in Modulen niedriger Ebene

Das Diagramm in Abbildung 1 zeigt ein sehr einfaches Design für dieses Beispiel. Es umfasst zwei Instanzen eines wiederverwendbaren Design-Blocks mit dem Namen reusable_block, der in Gelb angezeigt wird. Abbildung 2 zeigt den Inhalt des reusable_block Designs. reusable_block fungiert als doppelter Datenraten-Takt für einen quellensynchronen Ausgabebus. Seine Ausgabe muss mit einer Ausgabe der höchsten Ebene verbunden sein. Einschränkungen für reusable_block müssen generierte Taktfrequenzen umfassen, da die Ausgabe als quellensynchroner Takt funktioniert.

Abbildung 1. Beispielschaltkreis für Design-Beispiel.

Abbildung 2. Inhalt der reusable_block.

Bestimmen von I/O-Namen der obersten Ebene

Einschränkungen für reusable_block müssen Änderungen an I/O-Namen der obersten Stufe berücksichtigen. Daher muss der I/O-Name der obersten Ebene während der Kompilierung oder Timing-Analyse bestimmt werden. Der Befehl get_fanouts Tcl gibt eine Sammlung von IDs zurück, die Ports oder Register darstellen, die Fanouts eines bestimmten Namens sind. Der Befehl get_fanouts Tcl verwendet eine Timing-Netliste, die während der Kompilierungs- oder Timing-Analyse vorhanden ist, wodurch die Konnektivität dynamisch bestimmt wird, unabhängig von den Namen der Lüfterknoten. Der folgende Tcl-Code zeigt, wie Sie get_fanouts verwenden, um die Top-Level-Ausgabe zu erhalten, die ein direktes Fanout eines Low-Level-Registers ist.

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

Der vollständige Hierarchiename des Low-Level-Registers muss nicht bekannt sein, da Sie einen Platzhalter und einen bekannten Teil der Hierarchie verwenden können, der im wiederverwendbaren Design-Block vorhanden ist, um darauf zu passen. Das letzte Codebeispiel auf dieser Seite zeigt ein Beispiel für die Übereinstimmung mit dem Registernamen auf niedriger Ebene.

Im Design in Abbildung 1 ist der Ausgabestift des Low-Level-Moduls direkt mit einer Top-Level-Ausgabe verbunden. Der folgende TCL-Code fügt eine Fehlerüberprüfung hinzu, um sicherzustellen, dass die Lüfter auf niedriger Ebene an nur einer Stelle aus sind und dass der Lüfterplatz ein Ausgabeport ist. Dieser Tcl-Code sollte Teil der SDC-Datei sein, die reusable_block beschränkt.

# Holen Sie sich die Fanouts des low-level register
set fanout_collection [get_fanouts $low_level_register_name]

# Stellen Sie sicher, dass es num_fanouts
[get_collection_size $fanout_collection] nur einen Fanout-Satz
gibt, wenn { 1 != $num_fanouts } {
    return -code error "$low_level_register_name fans out to $num_fanouts \
        nodes but must fan out to one."
}

# Holen Sie sich den Namen des
Fanout-Knotens foreach_in_collection fanout_id $fanout_collection { break }
set fanout_name [get_node_info -name $fanout_id]

# Stellen Sie sicher, dass der Lüfterknoten ein Ausgabeport
ist, wenn { [catch { get_port_info -is_output_port $fanout_id } is_output] } {
    # Es gab einen Fehler – er lüftert nicht an einen
    Port-Rückgabecodefehler "$low_level_register_name Lüfter an $fanout_name \
        aus, der kein Port ist"
} elseif { ! $is_ output } {
    # Es gibt keinen Fehler, aber der Port ist kein Ausgabeport-Rückgabecodefehler
    "$fanout_name ist kein Ausgabeport"
} else { set
    top_level_io_name $fanout_name
} # top_level_io_name ist der einzige Lüfter von low_level_register_name und es ist # ein
Ausgabeport

Erstellen von generierten Taktfrequenzen

Ein quellensynchroner Ausgabe-Takt muss als ein generierter Takt definiert werden, der auf dem Takt basiert, der die doppelten Datenraten-Ausgaberegister speist. Die generierte Taktfrequenz muss ohne manuell eingegebene Informationen zu Taktfrequenzen im Design erstellt werden, da der Design-Block in jedem Design mit jedem Taktschema instanziiert werden kann.

Der folgende SDC-Befehl zeigt eine einfache Möglichkeit, einen generierten Takt für den quellensynchronen Ausgabe-Takt für das Design in Abbildung 1 zu erstellen, wenn die Position in der Hierarchie nicht bekannt ist.

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

Es ist ein unkomplizierter Ansatz, der für eine einzelne Instanziierung von reusable_block überall in der Designhierarchie funktioniert, aber nicht mehrere Instanziierungen oder Multiclock-Situationen bewältigt. Wenn das Taktungsschema nicht bekannt ist, sollte die generierte Taktbeschränkung in der Lage sein, Situationen zu bewältigen, in denen mehrere Takte auf einem einzigen Taktsignal definiert wurden, das den Design-Block speist. Mehrere Takte auf einem einzigen Taktsignal gibt es oft in Designs, die unterschiedliche I/O-Protokollgeschwindigkeiten unterstützen, oder Designs, die die Taktumschaltung für Redundanz unterstützen. Das oben beschriebene einfache generierte Taktbeispiel schlägt in Multiclock-Situationen fehl, da es die Option -master_clock nicht umfasst, um zwischen mehreren Source-Takten zu unterscheiden.

Um mehrere Instanziierungen zu bewältigen, verwenden Sie eine Schleife, um eindeutige generierte Taktfrequenzen für jede Instanziierung zu erstellen. Um Multiclock-Situationen zu bewältigen, verwenden Sie ein benutzerdefiniertes Verfahren namens get_clocks_driving_pin, das im Beispiel für das Takten eines Stiftkontakts beschrieben wird. Um das benutzerdefinierte Verfahren verwenden zu können, müssen Sie es von der Beispielseite für Taktfrequenz-Zuführen einer Stiftstift-Konstruktion kopieren. Sie können sie als separate SDC-Datei speichern, die dem Projekt hinzugefügt wird, oder sie mit allen anderen Einschränkungen, die einen wiederverwendbaren Block einschränken, kopieren und in eine SDC-Datei einfügen. Wenn Sie sie als eine SDC-Datei speichern, die dem Projekt hinzugefügt wird, stellen Sie sicher, dass sie vor einer SDC-Datei aufgeführt ist, die das get_clocks_driving_pin benutzerdefinierte Verfahren verwendet.

Der folgende Tcl-Code zeigt, wie Sie generierte Taktbeschränkungen für Ausgänge der obersten Ebene erstellen, die von Low-Level-Registern im in Abbildung 1 gezeigten Design angetrieben werden. Die generierten Takte verwenden die Top-Level-Ausgänge als ihre Ziele, und die Muxsel-Pins von altddio_output registrieren sich als ihre Quellen. Der Code verwendet eine Schleife, um alle Instanziierungen von reusable_block im Design zu durchlaufen, und eine verschachtelte Schleife, um Multiclock-Situationen mit dem get_clocks_driving_pin benutzerdefinierten Verfahren zu bewältigen. Sie nimmt an, dass das get_clocks_driving_pin Verfahren bereits definiert wurde.

# get_pins gibt für jede Instanziierung reusable_block # einen
Muxsel-Pin zurück, foreach_in_collection über jedem Muxsel-Pin-foreach_in_collection pin_id
iteriert [get_pins -compatibility_mode \
    *|reusable_block_clock_out|altddio_out_component|auto_generated|ddio_outa[0]|muxsel] {

    # pin_name hat die vollständige Designhierarchie des Muxsel-Pins für eine
    Anzahl Instanziierung von reusable_block
    festgelegt pin_name [get_node_info -name $pin_id]
    
    # Verwenden Sie den oben angezeigten Code, ohne eine Fehlerüberprüfung durchzuführen, um die Nummer des Namens der Ausgabe der obersten Ebene zu erhalten
    foreach_in_collection port_id [get_fanouts $pin_name] { break }
    festgelegt port_name [get_node_info -name $port_id]
    
    # Es können mehrere Takte vorhanden sein, die das altddio_output Register zuführen. Für jeden Takt, der
    eine Muxsel-Pin-Nummer speist, ist eine generierte Uhr
    erforderlich. Jede Uhr, die die Muxsel-Pins füttert, ist eine Master-Uhr.
    foreach master_clock [get_clocks_feeding_pin $pin_name] {

        post_message "Generated clock on $port_name fed by $pin_name" #
        Erstellen Sie die generierte Taktfrequenz mit der entsprechenden Master-Taktfrequenz.
        # Die Quelle ist der Muxsel-Pin der altddio_output Zelle in
        # der aktuellen Instanziierung von reusable_block.
        # Der Name ist eine Kombination aus der Master-Taktfrequenz und dem Namen der
        #vollständigen Hierarchie des Muxsel-Pins.
        # Das Ziel ist der Top-Level-Port, der der Lüfter des Muxsel-Pins ist.
        create_generated_clock -add -master_clock $master_clock \
            -source [get_pins $pin_name] -name ${master_clock}-${pin_name} \
            [get_ports $port_name]
} }

Mit diesem Code in einer im Projekt enthaltenen SDC-Datei werden alle Instanziierungen von reusable_block automatisch mit generierten Taktfrequenzen eingeschränkt. Die generierten Taktfrequenzen sind immer korrekt und aktuell, selbst in folgenden Situationen:

  • reusable_block wird an anderen Stellen in der Designhierarchie instanziiert oder an andere Stellen verschoben
  • I/Os der obersten Stufe werden in "Top-Level" umbenennen
  • Der Designer verwendet mehrere Taktdefinitionen im Design

Der Inhalt dieser Seite ist eine Kombination aus menschlicher und computerbasierter Übersetzung des originalen, englischsprachigen Inhalts. Dieser Inhalt wird zum besseren Verständnis und nur zur allgemeinen Information bereitgestellt und sollte nicht als vollständig oder fehlerfrei betrachtet werden. Sollte eine Diskrepanz zwischen der englischsprachigen Version dieser Seite und der Übersetzung auftreten, gilt die englische Version. Englische Version dieser Seite anzeigen.