W tym przykładzie projektu pokazano niestandardową procedurę, której można użyć w plikach SDC, która zwraca listę wszystkich zegarów, które zasilają pin. Procedura może być przydatna, jeśli chcesz stworzyć wygenerowane zegary, nie znając innych nazw zegarów w projekcie. Przykład projektu Uprość ponowne wykorzystanie projektu z dynamicznymi ograniczeniami SDC zawiera więcej szczegółów i przykład sposobu korzystania z niestandardowej procedury opisanej na tej stronie.
Pełny kod procedury znajduje się na dole strony, po całkowitym objaśnieniu funkcjonowania procedury. Aby użyć get_clocks_driving_pins niestandardowej procedury w pliku SDC, upewnij się, że procedura została zdefiniowana, a następnie nazwij ją jak każde inne polecenie SDC. Istnieją dwa łatwe sposoby zapewnienia, że procedura została zdefiniowana przed użyciem:
- Zapisz kod procedury w osobnym pliku SDC i dołącz plik SDC w projekcie.
- Skopiuj i wkleij kod procedury w górnej części każdego pliku SDC, zanim zostanie użyta get_clocks_driving_pins procedura niestandardowa.
Oddzielny plik SDC
Zapisywanie kodu procedury w osobnym pliku SDC oddziela kod od pozostałych ograniczeń i ułatwia ponowne wykorzystanie w innych projektach. Jeśli używasz oddzielnego pliku SDC, musisz dodać plik SDC z procedurą do listy plików w projekcie i musi on być wyświetlany nad wszystkimi plikami SDC, które korzystają z tej procedury. Umieszczenie go powyżej innych plików SDC sprawia, że oprogramowanie Quartus® II definiuje procedurę przed jej użyciem, gdy pliki SDC są odczytywane.
Skopiuj i wklej
Kopiowanie i wklejanie kodu procedury w tym samym pliku SDC, w którym jest on używany, skutkuje mniejszą liczbą plików SDC w projekcie. Jeśli tworzysz plik SDC dla modułu, który będzie ponownie obsługiwany przez innych projektantów, może być najprostsze uwzględnienie wszystkich ograniczeń i obsługa kodu w jednym pliku SDC. Przed pierwszym użyciem procedury należy dołączyć kod procedury w pliku SDC, aby został zdefiniowany przed użyciem. Zazwyczaj można umieścić go w górnej części pliku, aby spełnić ten wymóg.
Obsługa skryptu
Uzyskanie listy wszystkich zegarów w konstrukcji zasilanej kodem PIN wymaga trzech głównych kroków:
- Uzyskaj wszystkie zegary i stwórz mapowanie z węzłów docelowych do zegarów na węzłach docelowych.
- Pobierz listę węzłów z zegarami znajdującymi się na ścieżce wentylatora do określonego pinu.
- Z tej listy węzłów znajdź węzeł najbliższy do określonego pinu i zwróć zegary w tym węźle.
Krok 1. Uzyskaj wszystkie zegary i stwórz mapowanie
Poniższy kod Tcl pobiera wszystkie zegary w projekcie i tworzy mapowanie (z tablicą Tcl) z węzła do zegarów na węźle.
catch { array unset nodes_with_clocks } array set nodes_with_clocks [list] # Iterate over each clock in the design foreach_in_collection clock_id [all_clocks] { set clock_name [get_clock_info -name $clock_id] # Każdy zegar jest zastosowany do węzłów. Pobierz kolekcję węzłów docelowych foreach_in_collection target_id [get_clock_info -targets $clock_id] { # Skojarz nazwę zegara z ustawionym węzłem docelowym target_name [get_node_info -name $target_id] laptagd nodes_with_clocks($target_name) $clock_name } }
Wirtualne zegary nie mają celów, więc wirtualne zegary nigdy nie są mapowane. W pełnym kodzie procedury podanym poniżej informacje na temat rodzaju węzłów docelowych (rejestracja, PIN, komórka lub port) są zapisywane do późniejszego użytku.
Krok 2. Uzyskaj węzły dzięki zegarom w ścieżce wentylatora
Drugim krokiem jest znalezienie podgrupy węzłów z zegarami, które znajdują się na ścieżce wentylatora do określonego pinu. Do każdego węzła z zegarami (w kroku 1) uzyskaj wentylator do określonego pinu przez węzeł. Jeśli istnieje wentylator, węzeł znajduje się na ścieżce wentylatora do pinu. Jeśli nie ma wentylatora, węzeł nie znajduje się na ścieżce wentylatora do pinu.
Poniższy kod Tcl iteruje przez wszystkie węzły z zegarami z kroku 1 i wykorzystuje polecenie get_fanins w celu ustalenia, czy każdy węzeł znajduje się na ścieżce wentylatora określonego pinu. Jeśli węzeł znajduje się na ścieżce wentylatora określonego pinu, węzeł zostanie zapisany na pin_drivers liście.
ustaw pin_drivers [lista] # Iteruj na wszystkich węzłach na mapowaniu utworzonym w kroku 1 foreach node_with_clocks [nazwy tablicy nodes_with_clocks] { # Uzyskaj dowolne wentylatory do określonego pinu przez bieżący węzeł ustawiony fanin_col [get_fanins -clock -through $node_with_clock $pin_name] # Jeśli istnieje co najmniej jeden węzeł wentylatora, bieżący węzeł znajduje się na ścieżce # wentylatora do określonego pinu, więc zapisz go. if { 0 < [get_collection_size $fanin_col] } { lap dalej pin_drivers $node_with_clocks } }
Pełny kod procedury wymieniony poniżej wykorzystuje dodatkowe informacje na temat typu węzła do określenia kolekcji specyficznej dla typu dla wartości -through w poleceniu get_fanins.
Krok 3. Znajdź węzeł najbliższy do określonego pinu
Zmienna pin_drivers zawiera teraz listę wszystkich węzłów z zegarami znajdującymi się na ścieżce wentylatora do określonego pinu. W tym kroku znajduje się węzeł najbliższy określoneowi pinowi. Chociaż na liście pin_drivers znajduje się więcej niż jeden węzeł, kod przenosi pierwsze dwa węzły na listę i sprawdza, czy jeden znajduje się na ścieżce wentylatora do drugiego. Jeśli znajduje się on na ścieżce wentylatora, pierwszy węzeł musi znajdować się dalej od pinu niż drugi węzeł, aby można go było usunąć z listy.
while { 1 < [llength $pin_drivers] } { # Pobierz dwa pierwsze węzły na liście pin_drivers ustawionej node_a [lindex $pin_drivers 0] ustawionej node_b [lindex $pin _drivers 1] # Sprawdź, czy node_b znajduje się na ścieżce node_a ustawionej fanin_col [get_fanins -clock -through $node_b $node_a] # Jeśli istnieje co najmniej jeden węzeł wentylatora, node_b musi być dalej od podanego pinu niż jest node_a. # Jeśli nie ma węzła wentylatora, node_b musi być bliżej numeru określonego pinu niż jest node_a. if { 0 < [get_collection_size] } { # node_a jest bliżej pinu. # Usuń node_b z zestawu listy pin_drivers pin_drivers [lreplace $pin_drivers 1 1] } else { # node_b jest bliżej pinu. # Usuń node_a z zestawu listy pin_drivers pin_drivers [lreplace $pin_drivers 0 0] } } # Jeden węzeł pozostawiony w pin_drivers to węzeł, który powoduje utworzenie określonego zestawu pinów node_driving_pin [lindex $pin_drivers 0] # Wyszukaj zegary na węźle na mapowaniu z kroku 1 i odesłaj je z powrotem $nodes_with_clocks($node_driving_pin)
Pełny kod procedury wymieniony poniżej wykorzystuje dodatkowe informacje na temat typu węzła do określenia kolekcji specyficznej dla typu dla wartości -through w poleceniu get_fanins.
Pełny kod procedury
Pełny kod procedury niestandardowej get_clocks_driving_pin podano poniżej. Zawiera on dodatkowe funkcje sprawdzania błędów i pomocy technicznej, które nie zostały szczegółowo opisane powyżej.
proc get_clocks_feeding_pin { pin_name } { # Przed krokiem 1, wykonaj kontrolę błędu, aby upewnić się, że numer pin_name jest przekazywany do procedury, co odpowiada tylko jednemu pinowi. # Zwracaj błąd, jeśli nie jest zgodny tylko z jednym pinem. ustaw pin_col [get_pins -compatibility_mode $pin_name], jeśli { 0 == [get_collection_size $pin_col] } { błąd zwrotu -kod "Brak pinów $pin_name" } elseif { 1 < [get_collection_size $pin_col] } { zwrot -code error "$pin_name matches [get_collection_size $pin_col]\ piny but must match only one" } # Initialize variables used in the procedure catch { array unset nodes_with_clocks } catch { array unset node_types } array set nodes_with_clocks [list] zestaw macierzy node_types [lista] ustawiony pin_drivers [lista] # Krok 1. Uzyskaj wszystkie zegary w projekcie i stwórz mapowanie z # węzłów docelowych na zegary na węzłach docelowych # Iterate przez każdy zegar w foreach_in_collection clock_id projektowej [all_clocks] { set clock_name [get_clock_info -name $clock_id] ustawionej clock_target_col [get_clock_info -targets $clock_id] # Każdy zegar jest stosowany do węzłów. Pobierz kolekcję węzłów docelowych foreach_in_collection target_id [get_clock_info -targets $clock_id] { # Skojarz nazwę zegara z ustawionym węzłem docelowym target_name [get_node_info -name $target_id] laptagd nodes_with_clocks($target $target_name) $clock_name # Zapisz typ węzła docelowego do późniejszego użycia zestawu target_type [get_node_info -type $target_id] ustawionego node_types($target_name) $target_type } } # Krok 2. Pobierz listę węzłów z zegarami znajdującymi się na ścieżce # fanin do określonego pinu # Iterate na wszystkich węzłach w mapowaniu utworzonym w kroku 1 foreach node_with_clocks [nazwy tablicy nodes_with_clocks] { # Użyj typu węzła docelowego, aby stworzyć kolekcję charakterystyczną dla danego typu dla wartości -through w poleceniu get_fanins. 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] } "komórka" { ustawiona through_col [[get_cells $node_with_clocks] } "reg" { ustawiony through_col [get_registers $node_with_clocks] } domyślny { błąd return -code "$node_types($node_with_clocks) nie jest obsługiwany\ jako typ wentylatora przez skrypt" } #Get any fanins to the specified pin through the current node set fanin_col [get_fanins -clock -through $through_col $pin_name] # Jeśli istnieje co najmniej jeden węzeł wentylatora, bieżący węzeł znajduje się na ścieżce # wentylatora do określonego pinu, więc zapisz go. if { 0 < [get_collection_size $fanin_col] } { lapznad pin_drivers $node_with_clocks } } Przed krokiem 3, wykonaj kontrolę błędu, aby upewnić się, że co najmniej jeden z węzłów z zegarami w projekcie znajduje się na ścieżce wentylatora do określonego pinu. if { 0 == [llength $pin_drivers] } { błąd return -code "Nie można znaleźć żadnego węzła z zegarami, które napędzają $pin_name" } # Krok 3. Z listy węzłów utworzonych w kroku 2 znajdź węzeł # najbliższy do określonego pinu i zwróć zegary na tym węźle. while { 1 < [llength $pin_drivers] } { # Pobierz pierwsze dwa węzły na liście pin_drivers ustawionej node_a [lindex $pin_drivers 0] ustawionej node_b [lindex $pin_drivers 1] # Użyj rodzaju węzła docelowego, by stworzyć kolekcję #określonego typu dla wartości -through w poleceniu get_fanins. przełącznik -exact -- $node_types($node_b) { "pin" { set through_col [get_pins $node_b] } "port" { set through_col [get_ports $node_b] } "komórka" { ustawiona 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" } } # Sprawdź, czy node_b znajduje się na ścieżce wentylatora node_a ustaw fanin_col [get_fanins -clock -through $through_col $node_a] # Jeśli istnieje co najmniej jeden węzeł wentylatora, node_b musi być dalej # od określonego pinu niż jest node_a. # Jeśli nie ma węzła wentylatora, node_b musi być bliżej numeru określonego pinu niż jest node_a. if { 0 < [get_collection_size $fanin_col] } { # node_a jest bliżej pinu. # Usuń node_b z zestawu listy pin_drivers pin_drivers [lreplace $pin_drivers 1 1] } else { # node_b jest bliżej pinu # Usuń node_a z listy pin_drivers ustawionej pin_drivers [lrang) $pin_drivers 1 end] } } # Jeden węzeł pozostawiony w pin_drivers to węzeł, który powoduje utworzenie określonego zestawu pinów node_driving_pin [lindex $pin_drivers 0] # Wyszukaj zegary na węźle na mapowaniu z kroku 1 i zwrócić je z powrotem $nodes_with_clocks($node_driving_pin) }