Menu

Wartości X i Z w Verilogu: sygnał nieznany i wysoka impedancja

Sygnały w Verilogu mają cztery możliwe wartości, a nie dwie. Oto co naprawdę oznaczają w symulacji x (wartość nieznana) i z (wysoka impedancja) oraz jak je debugować.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Logika dwustanowa a czterostanowa

W oprogramowaniu bit to 0 albo 1. W Verilogu bit może przyjąć jedną z czterech wartości:

  • 0: przewód ma stan niski.
  • 1: przewód ma stan wysoki.
  • x: wartość przewodu jest nieznana. Symulator nie potrafi jej ustalić.
  • z: przewód jest w stanie wysokiej impedancji. Nic nim nie steruje.

Model czterostanowy istnieje, bo sprzęt ma ten sam problem. Prawdziwy przewód może być podciągnięty do stanu niskiego, do wysokiego, może mieć stan nieokreślony (gdy sterują nim dwa walczące źródła) albo pływać (bez żadnego źródła). Żeby symulator był użyteczny, musi modelować wszystkie cztery.

Skąd bierze się x

Uruchom ten kod i spójrz na wynik:

a jest zadeklarowane, ale nigdy nic do niego nie zapisano, więc ma wartość x. Dodawanie x + 5 daje x: każda arytmetyka z wartością nieznaną daje wartość nieznaną. W wyniku zamiast aaaa zobaczysz same x.

Typowe źródła x w projektach:

  • reg zadeklarowany, ale nigdy nie zresetowany (większość syntezowalnego kodu Verilog czyści rejestry jawnym resetem).
  • Instrukcja case bez default, do której trafia wartość wejściowa niepasująca do żadnego przypadku.
  • wire, który po refaktoryzacji stracił swoje jedyne źródło.
  • Łańcuch if/else, w którym jedna gałąź nie przypisuje sygnału przypisywanego przez drugą (jeśli coś nie jest pokryte, zatrzaskuje się x).
  • Odczyt poza końcem wektora lub tablicy.

Propagacja X: odrobina x psuje wszystko

Okrutne w x jest to, że się rozprzestrzenia. Jeden bit x w operandzie zamienia cały wynik w x:

Zauważ, że 0 & x daje 0 (AND z 0 zawsze daje 0), a 1 | x daje 1 (OR z 1 zawsze daje 1). Symulator jest pesymistyczny bit po bicie, ale wciąż respektuje te tożsamości. Arytmetyka i porównania nie są już tak łaskawe.

Dlatego jeden niezainicjowany rejestr może sprawić, że cała magistrala wyjściowa pokaże xxxx. Idź wstecz od dowolnego x, a znajdziesz źródło.

Skąd bierze się z

z to wartość przewodu, którym nikt nie steruje:

W tym fragmencie są dwa wzorce:

  • floating jest tylko zadeklarowany i nic nim nie steruje. Domyślnie ma wartość z.
  • data_out to celowe wyjście trójstanowe. Gdy enable ma stan niski, wyjście jawnie przechodzi w z. Tak sterownik magistrali "puszcza" przewód, żeby mogło przejąć go inne źródło.

W logice wewnętrznej z prawie zawsze oznacza błąd. Na pinie dwukierunkowym albo na współdzielonej magistrali z jest dokładnie tym, czego chcesz.

Porównywanie przez == a ===

Zwykły operator równości == zwraca x, gdy któryś operand ma bit x lub z:

=== (i jego partner !==) wykonuje ścisłe porównanie bit po bicie, łącznie z x i z. Używaj go zawsze, gdy w testbenchu musisz sprawdzić, czy wartość jest albo nie jest x/z. === nie jest syntezowalne, ale w bloku initial w testbenchu nie ma to znaczenia.

Funkcja systemowa $isunknown(expr) to najczystszy sposób, żeby zapytać "czy to wyrażenie ma jakiś bit x lub z?". Zwraca 1, jeśli tak, i 0, jeśli nie.

x jako celowe "wszystko jedno"

Kontrowersyjny, ale uprawniony wzorzec: 'x w gałęzi default maszyny stanów mówi narzędziu do syntezy "ten stan jest nieosiągalny, optymalizuj śmiało":

case (state)
    IDLE:    next_state = go ? RUNNING : IDLE;
    RUNNING: next_state = done ? IDLE : RUNNING;
    default: next_state = 'x;   // unreachable
endcase

Narzędzie do syntezy może wykorzystać x, żeby połączyć stany i zmniejszyć liczbę bramek. Jeśli w symulacji okaże się, że rozumowanie było błędne i gałąź default jednak zostaje osiągnięta, zobaczysz, jak x rozchodzi się z next_state, i błąd od razu stanie się widoczny.

Używaj tego tylko wtedy, gdy dokładnie przemyślano, czy gałąź default naprawdę jest nieosiągalna. Jeśli nie, ustaw w niej bezpieczny stan.

Typowy przepis na debugowanie

Patrzysz na przebieg pełen x. Przepis:

  1. Znajdź najwcześniejsze x. Przejdź po przebiegu wstecz w czasie. Sygnał, który najwcześniej przyjmuje x, jest najbliżej źródła.
  2. Znajdź jego źródło. Otwórz kod. Co przypisuje ten sygnał? assign? Blok always?
  3. Sprawdź wejścia źródła. Jeśli prawa strona przypisania zawiera jakieś x, propagacja działa tak, jak powinna, a błąd leży wcześniej w torze.
  4. Jeśli źródło ma czyste wejścia, a mimo to daje x, jest niekompletne. case bez gałęzi default, if bez else, rejestr bez resetu.

Większość błędów typu "burza x" sprowadza się do jednej z przyczyn: brak resetu, brak default albo niepodłączony podmoduł.

Co dalej

Znasz już całą historię typów danych: wire/reg, wektory, parametry, literały liczbowe i model logiki czterostanowej. W następnym rozdziale zaczniemy używać tego wszystkiego do budowania wyrażeń: operatorów wszelkiego rodzaju, w tym operatorów bitowych, które w oprogramowaniu nie miałyby sensu.

Najczęściej zadawane pytania

Co oznacza x w Verilogu?

x to wartość nieznana. Sygnał o wartości x może być równy 0 albo 1, a symulator nie potrafi tego rozstrzygnąć. Pojawia się, gdy nic nie steruje sygnałem, gdy dwa źródła walczą ze sobą, gdy rejestr jest odczytany przed resetem albo wszędzie tam, gdzie niezdefiniowane zachowanie rozeszłoby się bez ostrzeżenia. Traktuj x jak sygnał błędu: prawie nigdy nie oznacza tego, czego chcesz.

Co oznacza z w Verilogu?

z to stan wysokiej impedancji: nic nie steruje przewodem. To prawidłowy stan wyjść trójstanowych (magistrale danych, piny dwukierunkowe), ale w sygnałach wewnętrznych z to zwykle pomyłka oznaczająca 'nic tu nie jest podłączone'. Narzędzia do syntezy odrzucają większość wzorców z z poza jawnymi sygnałami włączania wyjść trójstanowych.

Dlaczego wyjście w Verilogu pokazuje xxxx?

Prawie zawsze dlatego, że nic nie steruje jakimś sygnałem albo jakaś operacja przeniosła x z innego sygnału. Idź wstecz: który sygnał ma x, co go zasila, czy jego źródło jest aktywne? Typowi winowajcy to brak gałęzi default w instrukcjach case, rejestry bez resetu i przewody wire, które po refaktoryzacji straciły źródło.

Jak sprawdzić x lub z w Verilogu?

Użyj operatora ===, który porównuje bit po bicie dokładnie, łącznie z x i z. a === 1'bx jest prawdą, gdy a naprawdę ma wartość x. Zwykłe == zwraca x, gdy któryś operand ma bit x, więc a == 1'bx nigdy nie da odpowiedzi, której szukasz. Jest też $isunknown(a), które zwraca zgrabną wartość logiczną.

Czy można przypisać x jako wartość domyślną w Verilogu?

Tak, i to świadoma technika w instrukcjach case: default: out = 'x; mówi narzędziu do syntezy 'obiecuję, że ten przypadek nigdy nie wystąpi, optymalizuj śmiało'. Ceną jest to, że jeśli jednak wystąpi w symulacji, x się rozejdzie i zobaczysz błąd. Używaj tego, gdy już udowodniono, że gałąź default jest nieosiągalna, a nie po to, żeby uniknąć pisania przypadku.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ