Uprość ponowne wykorzystanie projektu dzięki dynamicznym ograniczeniom SDC

author-image

Według

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.

Rys. 1. Przykładowy obwód dla projektu.

Rys. 2. Treść reusable_block.

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

Materiały zawarte na tej stronie są tłumaczeniem z języka angielskiego, wykonanym częściowo przez człowieka, a częściowo automatycznie. Materiały te są udostępnione dla Twojej wygody i należy je traktować jedynie jako ogólne źródło informacji. Nie ma jednak gwarancji, że są one kompletne bądź poprawne. Jeśli istnieje jakakolwiek rozbieżność między wersją angielską tej strony a jej tłumaczeniem, wersja angielska jest wersją obowiązującą i ma rozstrzygające znaczenie. Wyświetl anglojęzyczną wersję tej strony.