Podczas tworzenia bloku projektowego lub komponentu HDL, który można ponownie zastosować w wielu projektach, może być konieczne stworzenie ograniczeń SDC. Przydatne jest tworzenie ograniczeń, które nie wymagają edycji przez projektanta ponownie korzystającego z komponentu. Ograniczenia powinny być ogólne, więc działają niezależnie od miejsca, w którym blok jest wprowadzany do hierarchii projektu i są dynamiczne, aby działały niezależnie od tego, jak blok projektowy jest połączony. Jeśli ograniczenia muszą być edytowane ręcznie w celu uwzględnienia zmian w projekcie, nie będą one zsynchronizowane, jeśli projektant wprowadzi zmiany w projekcie bez aktualizacji ograniczeń.
W tym przykładzie projektu opisano techniki tworzenia dynamicznych ograniczeń SDC, które dotyczą następujących dwóch problemów:
- Określenie nazwy najwyższego poziomu we/wy podłączonego bezpośrednio do modułu niskiego poziomu
- Tworzenie wygenerowanych zegarów logicznych w modułach niskiego poziomu
Schemat na rys. 1 przedstawia bardzo prosty projekt dla tego przykładu. Zawiera dwa instancje bloku projektowego do ponownego użytkowania o nazwie reusable_block, pokazany na żółto. Rys. 2 przedstawia zawartość projektu reusable_block. reusable_block pełni funkcję zegara podwójnej prędkości transmisji danych dla synchronicznej magistrali wyjściowej źródło. Jego moc wyjściową należy podłączyć do wyjścia najwyższego poziomu. Ograniczenia dla reusable_block muszą obejmować wygenerowane zegary, ponieważ dane wyjściowe działają jako zegar synchroniczna dla źródła.
Określanie nazw I/O najwyższego poziomu
Ograniczenia dotyczące reusable_block muszą uwzględniać zmiany nazw I/O najwyższego poziomu. W związku z tym nazwę I/O najwyższego poziomu należy określić podczas kompilacji lub analizy timingów. Polecenie get_fanouts Tcl zwraca kolekcję identyfikatorów przedstawiających porty lub rejestry wyładowane określoną nazwą. Polecenie get_fanouts Tcl wykorzystuje listę timingów, która istnieje podczas kompilacji lub analizy timingów, więc dynamicznie określa łączność niezależnie od nazw węzłów wywiewu. Poniższy kod Tcl ukazuje, jak korzystać z get_fanouts, aby uzyskać wyjście najwyższego poziomu, które jest bezpośrednim wysyłką rejestru niskiego poziomu.
foreach_in_collection fanout_id [get_fanouts $low_level_register_name] { przerwa } ustawiona top_level_io_name [get_node_info —nazwa $fanout_id]
Pełna nazwa hierarchii rejestru niskiego poziomu nie musi być znana, ponieważ można użyć symbola wieloznacznego i znanej części hierarchii, która istnieje w bloku projektowym z możliwością ponownego użycia, aby go dopasować. Ostatni przykład kodu na tej stronie zawiera przykład, jak dopasować nazwę rejestru niskiego poziomu.
Na rys. 1 pin wyjściowy modułu niskiego poziomu jest podłączony bezpośrednio do jednego wyjścia najwyższego poziomu. Poniższy kod Tcl dodaje sprawdzenie błędu, aby upewnić się, że wentylatory rejestru niskiego poziomu są dostępne tylko w jednej lokalizacji, a lokalizacja wysyłki jest portem wyjściowym. Ten kod Tcl powinien być częścią pliku SDC, który ogranicza reusable_block.
#Get the fanouts of the low level register set fanout_collection [get_fanouts $low_level_register_name] # Upewnij się, że jest tylko jeden zestaw wywiewu num_fanouts [get_collection_size $fanout_collection], jeśli { 1 != $num_fanouts } { błąd return -code "$low_level_register_name fans out to $num_fanouts \ nodes but must fan out to one." } #Get the name of the fanout node foreach_in_collection fanout_id $fanout_collection { break } set fanout_name [get_node_info -name $fanout_id] # Upewnij się, że węzeł wywiewu jest portem wyjściowym, jeśli { [catch { get_port_info -is_output_port $fanout_id } is_output] } { Nie było błędu — nie wyłapuje się na port return -error "$low_level_register_name fans out to $fanout_name \ which is not a port" } elseif { ! $is_ wyjściowa } { # Nie ma błędu, ale port nie jest portem wyjściowym, który zwraca kod -błąd "$fanout_name nie jest portem wyjściowym" } inaczej { ustawiono top_level_io_name $fanout_name } top_level_io_name jest jedynym wycierniającym z low_level_register_name i jest to port wyjściowy #
Tworzenie wygenerowanych zegarów
Synchroniczny zegar wyjściowy źródła musi być zdefiniowany jako wygenerowany zegar, oparty na zegarze, który zasila rejestry wyjściowe z podwójną prędkością danych. Wygenerowany zegar musi zostać utworzony bez żadnych ręcznych informacji o zegarach w projekcie, ponieważ blok projektowy może zostać utworzony w dowolnym projekcie z dowolnym schematem taktowania.
Poniższe polecenie SDC ukazuje prosty sposób na utworzenie wygenerowanego zegara dla źródła synchronicznego zegara wyjściowego dla projektu na Rys. 1, gdy lokalizacja w hierarchii nie jest znana.
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
Jest to proste podejście, które działa dla jednej informacji reusable_block w dowolnym miejscu w hierarchii projektowej, ale nie obsługuje wielu informacji ani sytuacji wielotaktowych. Jeśli schemat taktowania nie jest znany, wygenerowane ograniczenie zegara powinno być w stanie obsłużyć sytuacje, w których zdefiniowano wiele zegarów za pomocą pojedynczego sygnału zegara zasilającego blok projektowy. Wiele zegarów na pojedynczym zegarze często występuje w projektach obsługujących różne prędkości protokołu I/O lub projektach obsługujących przełącznik zegara w celu zapewnienia redundancji. Prosty wygenerowany przykład zegara powyżej nie działa w sytuacjach wielotaktowych, ponieważ nie obejmuje opcji -master_clock przechodzenia pomiędzy zegarami wielu źródeł.
Aby obsłużyć wiele informacji, użyj pętli do stworzenia unikatowych wygenerowanych zegarów dla każdej informacji. Aby poradzić sobie z sytuacjami wielu podkręcania, użyj niestandardowej procedury zwanej get_clocks_driving_pin, opisanej w przykładzie projektu pinu z trybem taktowania zegarów. Aby skorzystać z niestandardowej procedury, należy skopiować ją ze strony przykładowego projektu "Przemówianie z zegarami" przy użyciu pinów. Możesz zapisać go jako osobny plik SDC dodany do projektu lub skopiować i wkleić go do jednego pliku SDC z wszystkimi innymi ograniczeniami, które ograniczają blok ponownego użyciu. Jeśli zapiszesz go jako plik SDC dodany do projektu, upewnij się, że jest on wymieniony przed dowolnym plikiem SDC, który korzysta z get_clocks_driving_pin niestandardowej procedury.
Poniższy kod Tcl ukazuje, jak stworzyć wygenerowane ograniczenia zegarowe dla wyjść najwyższego poziomu, napędzanych rejestrami niskiego poziomu w projekcie przedstawionym na rys. 1. Wygenerowane zegary wykorzystują wyjścia najwyższego poziomu jako cele oraz piny muxsel altddio_output rejestrują się jako swoje źródła. Kod wykorzystuje pętlę do iteracji przez wszystkie inwencje reusable_block w projekcie oraz pętlę zagnieżdżoną, aby obsłużyć sytuacje wielotaktowe z get_clocks_driving_pin niestandardową procedurą. Zakłada się, że procedura get_clocks_driving_pin została już zdefiniowana.
#get_pins zwraca jeden pin muxsel dla każdej inicjalizacji reusable_block # foreach_in_collection iteruje na każdym foreach_in_collection pin_id muxsel [get_pins -compatibility_mode \ *|reusable_block_clock_out|altddio_out_component|auto_generated|ddio_outa[16]. |muxsel] { # pin_name ma pełną hierarchię projektową pinu muxsel dla jednej inicjalizacji # reusable_block ustawionej pin_name [get_node_info —name $pin_id] # Użyj podanego powyżej kodu, bez sprawdzania błędów, aby uzyskać # nazwę najwyższego poziomu danych wyjściowych foreach_in_collection port_id [get_fanouts $pin_name] { break } ustawionego port_name [get_node_info -name $port_id] # Może istnieć wiele zegarów, które przechwycą rejestrację altddio_output # Jeden wygenerowany zegar jest wymagany dla każdego zegara, który kanały # kod muxsel. Każdy zegar oskrzydla pin muxsel jest zegarem nadrzędnym. foreach master_clock [get_clocks_feeding_pin $pin_name] { post_message "Tworzenie wygenerowanego zegara na $port_name fed by $pin_name" # Stwórz wygenerowany zegar z odpowiednim zegarem nadrzędnym. # Źródło to pin muxsel komórki altddio_output w # bieżącym inicjalizacji reusable_block. # Nazwa jest kombinacją zegara głównego i nazwy pełnej hierarchii pinu muxsel. # Celem jest port najwyższego poziomu, który jest wyprowadzkiem pinu muxsel. create_generated_clock -add -master_clock $master_clock \ -source [get_pins $pin_name] -name ${master_clock}-${pin_name} \ [get_ports $port_name] } }
Dzięki temu kodowi w pliku SDC zawartym w projekcie wszystkie wystąpienia reusable_block są automatycznie ograniczone przez wygenerowane zegary. Wygenerowane zegary są zawsze poprawne i aktualne, nawet w następujących sytuacjach:
- reusable_block jest inkorpionowany lub przenoszony na inne punkty w hierarchii projektowej.
- Zmiany nazwy I/O najwyższego poziomu
- Projektant wykorzystuje wiele definicji zegara w projekcie