Opanowanie $display w Verilogu: Skuteczne techniki debugowania i sterowania wyświetlaniem

目次

1. Wprowadzenie: Znaczenie i cel „display” w Verilogu

Co oznacza „display” w Verilogu?

W Verilogu $display jest zadaniem systemowym używanym jako narzędzie do „wyświetlania” wewnętrznego stanu projektu podczas symulacji. Podobnie jak printf w C, pozwala wypisywać sygnały, wartości zmiennych i łańcuchy znaków na terminal lub konsolę — odgrywając kluczową rolę w debugowaniu i weryfikacji funkcjonalnej.

Dlaczego $display jest niezbędny w rozwoju w Verilogu?

  • Zwiększona efektywność debugowania : W złożonych projektach układów wizualizacja, czy wewnętrzne sygnały działają poprawnie, jest krytyczna. Korzystając z $display, możesz natychmiast sprawdzić wartości interesujących Cię sygnałów podczas symulacji.
  • Wizualizacja symulacji : Śledząc przejścia wartości w określonych momentach, same wykresy mogą być niewystarczające. Logi wyświetlane zapewniają niezawodny sposób wskazania tych precyzyjnych chwil.
  • Przydatny także w dokumentacji : Gdy przekazujesz zamiar projektu lub zasady działania innym inżynierom, wstawianie opisowych logów wyświetlania może zwiększyć zrozumienie kodu.

Cel i struktura tego artykułu

W tym artykule wyjaśnimy kolejno:

  1. Podstawowa składnia i użycie : Starannie wprowadzimy fundamentalną składnię i zastosowanie $display.
  2. Porównanie z innymi zadaniami systemowymi : Przedstawimy różnice między zadaniami związanymi z wyświetlaniem, takimi jak $write, $strobe i $monitor.
  3. Specyfikatory formatu i zaawansowane techniki : Omówimy specyfikatory formatu takie jak %d, %b, %h, %s oraz specjalne techniki wyświetlania.
  4. Praktyczne przykłady użycia : Pokażemy konkretne zastosowania w testbenchach i kodzie, dostarczając od razu użytecznej wiedzy.
  5. Zastosowania sterowania wyświetlaniem : Przykłady użycia obejmą wyjścia sprzętowe, takie jak kontrola LCD lub monitora oraz wyświetlanie tekstu/obrazu.

Dzięki tej strukturze zarówno początkujący, jak i średniozaawansowani użytkownicy będą mogli właściwie zrozumieć $display w Verilogu i zastosować go w praktyce. W każdej kolejnej sekcji posłużymy się przykładami i diagramami, gdy tylko będzie to możliwe.

2. Podstawy $display: składnia, przypadki użycia i środki ostrożności

Podstawowa składnia $display

Podczas używania $display w Verilogu podstawowa składnia wygląda następująco.

$display("string or format specifiers", signal1, signal2, ...);
  • Część łańcucha znaków : Wpisz dowolny tekst lub specyfikatory formatu (np. %d, %b, %h).
  • Argumenty : Wymień nazwy sygnałów lub zmiennych, które mają być wypisane w odpowiednim formacie.

Przykład: wyświetlanie licznika zegara i wartości sygnałów

$display("Time=%0t : clk=%b, reset=%b", $time, clk, reset);

W tym przykładzie wypisywany jest czas symulacji oraz wartości sygnałów zegara/resetu.

Przypadki użycia $display

  1. Śledzenie postępu symulacji – Wstawiając $display w określonych miejscach projektu, możesz zweryfikować, którą część kodu aktualnie wykonuje symulacja.
  2. Weryfikacja wartości sygnałów – Nawet gdy przeglądarki falowe utrudniają intuicyjne zrozumienie gałęzi warunkowych lub przejść stanów, wypisywanie tekstu ułatwia ich analizę.
  3. Warunkowe wyświetlanie komunikatów – Łącząc z instrukcjami if, możesz logować komunikaty tylko wtedy, gdy spełnione są określone warunki. if (reset) $display("Reset asserted at %0t", $time);

Różnica między $display a $write

$display automatycznie dodaje znak nowej linii na końcu wyjścia. Z kolei $write kontynuuje wypisywanie bez dodawania nowej linii.
Przykład:

$display("Hello");
$display("World");

Wyjście:

Hello
World
$write("Hello");
$write("World");

Wyjście:

HelloWorld

Jeśli potrzebujesz czytelnych logów linia po linii, użyj $display. Gdy chcesz formatować wyjścia w jednej linii, użyj $write.

Środki ostrożności

  1. Unikaj nadmiernego generowania wyjścia Jeśli używasz $display w każdym cyklu zegara, logi rosną, a czytelność spada. → Użyj warunkowania, aby ograniczyć wyjście.
  2. Wykorzystaj wyświetlanie czasu Wyświetlanie $time lub $realtime pozwala dokładnie uchwycić momenty operacji.
  3. Zadanie przeznaczone wyłącznie do symulacji $display nie może być używany do syntezy (implementacja FPGA/ASIC). Jest to wyłącznie narzędzie debugowania w symulacji.

3. Porównanie systemowych zadań wyjścia logów: $display, $write, $strobe, $monitor

Verilog oferuje systemowe zadania wyjściowe oprócz $display. Ich różne przypadki użycia i timing sprawiają, że warto zrozumieć, jak ich używać odrębnie.

$display: Standardowe zadanie wyświetlania

  • Charakterystyka Automatycznie dodaje znak nowej linii i zapisuje jedną linię przy każdym wywołaniu.
  • Przypadek użycia Najczęściej używany jako podstawowa metoda debugowania; można go wywołać w dowolnym momencie dla jednorazowego wyjścia.

$write: Wyświetlanie bez nowej linii

  • Charakterystyka Nie dodaje znaku nowej linii, więc kontynuuje wyjście w tej samej linii.
  • Przypadek użycia Przydatny, gdy chcesz wyświetlić wiele wartości obok siebie.
  • Przykład $write("A=%d, ", a); $write("B=%dn", b); → Wyjście: A=5, B=10.

$strobe: Wyjście na końcu cyklu symulacji

  • Charakterystyka Drukuje wartości po zakończeniu wszystkich ocen symulacji w bieżącym kroku.
  • Przypadek użycia Przydatny przy unikaniu warunków wyścigu (gdy wiele sygnałów zmienia się jednocześnie).
  • Przykład $strobe("Time=%0t, signal=%b", $time, sig); → Podczas gdy $display może pokazywać wartości pośrednie, $strobe pokazuje ustalone wartości.

$monitor: Automatyczne śledzenie wyjścia

  • Charakterystyka Automatycznie wypisuje, gdy zmieni się dowolny monitorowany sygnał.
  • Przypadek użycia Wygodne, gdy chcesz ciągle monitorować zestaw sygnałów.
  • Przykład $monitor("At %0t: a=%b, b=%b", $time, a, b); → Loguje, gdy zmieni się a lub b.

Tabela podsumowująca

ZadanieNowa liniaMoment wyjściaGłówny przypadek użycia
$displayTakGdy wywołanePodstawowe wyjście logu
$writeNieGdy wywołaneFormatowanie w jednej linii
$strobeTakPo zakończeniu cyklu symulacjiSprawdzenie ustalonych wartości
$monitorTakAutomatycznie przy zmianie sygnałuCiągłe monitorowanie

Wskazówki dotyczące efektywnego użycia

  • Używaj $display domyślnie: Czytelny i prosty dla początkujących.
  • Używaj $write, gdy chcesz połączone wyjście w jednej linii.
  • Używaj $strobe, gdy potrzebujesz ustalonych wartości po zmianach.
  • Używaj $monitor, gdy potrzebujesz ciągłego monitorowania sygnałów.

4. Specyfikatory formatu i zaawansowane techniki wyświetlania

Za pomocą zadań takich jak $display czy $write możesz umieszczać w łańcuchach „specyfikatory formatu”, aby wyświetlać sygnały lub zmienne w żądanych formatach. Ponieważ przypomina to printf z C, prawidłowe ich użycie

  • Zero-wypełnianie i szerokość pola Możesz określić zero‑wypełnianie lub szerokość pola, np. %0d. Przykład: $display("Count=%04d", count); → Wynik: Count=0012
  • Rozróżnienie signed vs unsigned %d traktuje wartości jako ze znakiem, %u jako bez znaku. Jeśli ujemna wartość nie jest wyświetlana zgodnie z oczekiwaniami, zmień specyfikator.
  • Formatowanie wieloliniowych komunikatów Użyj n aby podzielić linie dla czytelności. Przykład: $display("Start of testnSignal A=%bnSignal B=%b", A, B);

Środki ostrożności

  • Zwróć uwagę na szerokość bitów: sygnały Verilog mogą mieć różne szerokości; użycie %d może powodować przycięcie lub problemy z rozszerzaniem znaku.
  • Obsługa nieokreślonych wartości (X, Z): Jeśli uwzględnisz nieokreślone bity, użycie %b wyświetli x lub z bezpośrednio.

5. Praktyczne przykłady: użycie $display w testbenchach i modułach

Od tego miejsca przedstawimy skuteczne zastosowania $display na przykładach rzeczywistego kodu Verilog, obejmując podstawy testbenchów oraz warunkowe logowanie debugowe.

Podstawowy przykład: wyjście w testbenchu

Wstawiając $display do testbencha, możesz obserwować zachowanie podczas symulacji.

module tb_counter;
  reg clk;
  reg reset;
  wire [3:0] count;

  // DUT (Device Under Test)
  counter uut (
    .clk(clk),
    .reset(reset),
    .count(count)
  );

  // Clock generation
  initial begin
    clk = 0;
    forever #5 clk = ~clk;  // invert every 5 units
  end

  // Test scenario
  initial begin
    reset = 1;
    #10 reset = 0;

    #50 $finish;
  end

  // Display state
  always @(posedge clk) begin
    $display("Time=%0t | reset=%b | count=%d", $time, reset, count);
  end
endmodule

W tym przykładzie każdy narastający zbocze zegara wyzwala wyświetlenie reset i count. Ponieważ możesz przeglądać zarówno logi tekstowe, jak i przebiegi, śledzenie zachowania jest prostsze.

Przykład warunkowego wyświetlania

Łącząc z instrukcjami if, możesz logować tylko wtedy, gdy spełnione są określone warunki.

always @(posedge clk) begin
  if (count == 4'd10) begin
    $display("Count has reached 10 (Time=%0t)", $time);
  end
end

→ Dzięki temu unikasz zbędnych logów, jednocześnie precyzyjnie wskazując interesujące Cię zdarzenia.

Przykład komunikatu debugowego

Podczas debugowania projektu skuteczne jest wykrycie, kiedy sygnał przechodzi w „nieoczekiwany stan”.

always @(posedge clk) begin
  if (count > 4'd12) begin
    $display("WARNING: count overflow detected! Time=%0t, value=%d", $time, count);
  end
end

→ Możesz szybko wykryć błędy w projekcie lub nieoczekiwane zachowanie symulacji.

Monitorowanie wielu sygnałów jednocześnie

Podczas wyświetlania wielu sygnałów, zebranie ich w jednej linii przy użyciu $display sprawia, że logi są czytelniejsze.

$display("Time=%0t | clk=%b | reset=%b | A=%h | B=%h | SUM=%h",
         $time, clk, reset, A, B, SUM);

Podsumowanie praktycznych wskazówek

  • Umieść $display w testbenchu, aby wizualizować postęp
  • Używaj warunkowych gałęzi, aby udoskonalić logi
  • Generuj komunikaty ostrzegawcze, aby wykrywać anomalie
  • Konsoliduj wiele sygnałów w jednej linii, aby zwiększyć czytelność

6. Zastosowania sterowania wyświetlaczem (piksele/tekst/obraz)

Do tej pory przedstawiliśmy $display do logów symulacji. Jednocześnie Verilog jest szeroko stosowany do „sterowania wyświetlaczem” w implementacjach sprzętowych (LCD, VGA, wyjście HDMI). W tej sekcji krótko omówimy, jak zrealizować wyświetlanie na ekranie na poziomie sprzętowym.

Podstawowa koncepcja sterowania wyświetlaczem

Aby wyświetlać tekst lub obrazy na ekranie, musisz generować sygnały wideo, a nie tylko używać $display. Typowe sygnały sterujące obejmują:

  • HSYNC (Horizontal Sync): sygnał oznaczający koniec każdej linii
  • VSYNC (Vertical Sync): sygnał oznaczający koniec każdej klatki
  • RGB Data: sygnał reprezentujący kolor każdego piksela (np. 8‑bit × 3 = 24‑bitowy kolor)

W Verilogu kontrolujesz te sygnały za pomocą liczników i automatów stanów oraz wyprowadzisz je w odpowiednim czasie, aby zrealizować „wyświetlanie na ekranie”.

Przykład 1: wyświetlanie pasków kolorów

Najbardziej podstawowy przykład to wyświetlanie poziomych pasków kolorów na ekranie.

always @(posedge clk) begin
  if (h_counter < 100)       rgb <= 24'hFF0000; // red
  else if (h_counter < 200)  rgb <= 24'h00FF00; // green
  else if (h_counter < 300)  rgb <= 24'h0000FF; // blue
  else                       rgb <= 24'h000000; // black
end

→ To skutkuje czerwonymi, zielonymi i niebieskimi paskami kolorów wyrównanymi poziomo na ekranie.

Przykład 2: Wyświetlanie tekstu

Aby wyświetlić tekst, przygotowujesz font ROM i konwertujesz wzór kropek każdego znaku na piksele.

// Referencing the pattern of 'A' from the font ROM and displaying
if (font_rom[char_code][y][x] == 1'b1)
    rgb <= 24'hFFFFFF;  // white for display
else
    rgb <= 24'h000000;  // black background

→ To rysuje konkretny znak (np. „A”) na ekranie.

Przykład 3: Wyświetlanie obrazu

Aby wyświetlić obraz, odczytujesz wcześniej zapisane dane bitmapy (ROM lub pamięć zewnętrzną) i konwertujesz je na wyjście pikseli.

rgb <= image_rom[addr];  // Retrieve color data from ROM

W systemach wbudowanych wykorzystujących FPGA ta metoda pozwala wyświetlać proste ikony lub logotypy.

Różnica w porównaniu do debugowania $display

  • $display to wyjście tekstowe (tylko symulacja)
  • Kontrola wyświetlania to **generowanie sygnału wideo (implementowalne w sprzęcie mylą te dwie rzeczy.

  • „Chcę zweryfikować zachowanie podczas symulacji” → Użyj $display

  • „Chcę wyświetlić na rzeczywistym ekranie w FPGA” → Zaprojektuj logikę sygnału wideo

Rozszerzenie zastosowań

  • Przy nauce płyt FPGA, Verilog jest często używany do wyświetlaczy 7‑segmentowych LED lub małych wyświetlaczy LCD.
  • Idąc dalej, możesz budować systemy obsługujące wyjście VGA/HDMI do tworzenia gier lub wyświetlania GUI.
  • Łącząc wiedzę o $display z logiką sterowania wyświetlaczem, możesz obsługiwać „wyświetlanie” zarówno w symulacji, jak i w rzeczywistym sprzęcie.

7. Odpowiednie użycie i wskazówki w zależności od scenariuszy zastosowań

Kiedy mówimy o „wyświetlaniu” w Verilog, istnieją dwa aspekty: zadania $display wyłącznie w symulacji oraz kontrola wyświetlania w implementacji sprzętowej. Odpowiednie ich użycie prowadzi do efektywnego rozwoju i debugowania.

Użycie w symulacji

  1. $display jako log debugowania
    • Wyświetlaj krytyczne zmienne lub sygnały za pomocą $display, aby sprawdzić, czy projekt zachowuje się zgodnie z oczekiwaniami.
    • Weryfikacja „wartości w określonych warunkach” lub „licznika osiągającego punkty” poprzez logi jest efektywna.
  2. Unikaj nadmiernego wyjścia
    • Wyświetlanie przy każdym cyklu zegara zalewa logi i zmniejsza czytelność. Ogranicz warunki.
    • Przykład: if (state == ERROR) $display("Error occured at %0t", $time);
  3. Rozróżnij zadania
    • $monitor → Dla sygnałów, które chcesz monitorować ciągle
    • $strobe → Gdy potrzebujesz wyświetlić ustalone wartości
    • $write → Dla sformatowanego wyjścia poziomego

Użycie w kontroli wyświetlania sprzętowego

  1. Wyświetlacz 7‑segmentowy do nauki
    • W projektach dla początkujących w FPGA wyświetlanie wartości licznika na 7‑segmentowym LED jest standardem.
    • Połącz z wyjściem symulacji $display, aby pogłębić zrozumienie różnicy między wyświetlaniem a symulacją.
  2. Kontrola monitora LCD lub VGA
    • Użyj font ROM lub image ROM do wyświetlania tekstu lub obrazu.
    • Korzystając również z $display w symulacji, możesz podwójnie zweryfikować poprawność generowania sygnału wideo.
  3. Nakładka debugowa w sprzęcie
    • Możesz nałożyć „wartość licznika”, „współrzędne”, „wiadomości debugowe” na rzeczywiste wyjście wideo.
    • W rozwoju FPGA powszechne jest „uczynić ekran sam w sobie narzędziem debugowania”.

Praktyczne wskazówki

  • Śledź symulację → przepływ sprzętowy Najpierw użyj $display, aby zweryfikować zachowanie w symulacji, potem przejdź do logiki sterowania wyświetlaczem dla implementacji sprzętowej.
  • Używaj jednocześnie logów i przebiegów Logi tekstowe z $display wskazują „czas wystąpienia zdarzenia”, podczas gdy przebiegi pokazują „szczegółowe przejścia”. Używanie obu zwiększa precyzję debugowania.
  • Ujednolicenie formatu komunikatów w pracy zespołowej Standaryzacja formatu komunikatów $display (prefiks, wyświetlanie czasu itp.) ułatwia analizę logów, gdy pracuje ich wiele osób.

Podsumowanie

  • Zadania typu $display są jedynie narzędziami obserwacyjnymi w symulacji
  • Sterowanie wyświetlaczem oznacza implementację sprzętową „metodę wyświetlania”
  • Używając ich odpowiednio i łącząc je, można uzyskać efektywny rozwój

8. FAQ (Często Zadawane Pytania)

Q1. Jaka jest różnica między $display a $monitor?

A. $display wypisuje raz w momencie wywołania. Natomiast $monitor automatycznie wypisuje za każdym razem, gdy zmieni się zarejestrowany sygnał.

  • Do jednorazowego debugowania → $display
  • Do ciągłego monitorowania → $monitor

Q2. Kiedy powinienem używać $strobe?

A. $strobe wypisuje ustaloną wartość pod koniec cyklu symulacji. Na przykład, gdy wiele sygnałów zmienia się jednocześnie na zboczu zegara, $display może pokazywać wartości pośrednie. W takich przypadkach $strobe jest wygodny do wyświetlania wartości końcowych.

Q3. Do czego służy specyfikator formatu %m?

A. %m wypisuje nazwę bieżącej hierarchii modułu. W dużych projektach logowanie „z której hierarchii pochodzi komunikat” znacznie ułatwia analizę.

$display("Current module: %m");

Example output:

Current module: top.u1.counter

Q4. Moje logi stały się ogromne, ponieważ użyłem wielu $display. Co zrobić?

A. Następujące środki są skuteczne:

  • Używaj instrukcji if do filtrowania wyjścia
  • Wypisuj tylko wykrycie błędów lub konkretne zdarzenia
  • Używaj $monitor, aby obserwować jedynie niezbędne sygnały
  • Zapisuj do pliku logu i stosuj narzędzia filtrujące podczas analizy

Q5. Czy $display może być używany w syntezie (FPGA/ASIC)?

A. Nie. $display jest wyłącznie zadaniem symulacyjnym. Narzędzia syntezy go ignorują, więc nie pojawia się w rzeczywistym sprzęcie. Jeśli chcesz wyświetlać wyniki na prawdziwym hardware, musisz zaprojektować „7‑segmentowy wyświetlacz LED”, „LCD”, „logikę sterowania VGA” itp. w Verilogu.

Q6. Jak wyświetlić tekst lub obrazy na rzeczywistym sprzęcie?

A. Nie za pomocą $display, lecz generując sygnały wideo.

  • Wyświetlacz 7‑segmentowy → Do prostego wyświetlania liczb lub znaków
  • VGA/LCD → Generuj sygnały HSYNC, VSYNC, RGB i steruj nimi
  • Tekst → Użyj ROMu czcionek i wypisuj wzory punktów
  • Obrazy → Przechowuj bitmapy w ROMie lub pamięci zewnętrznej i wyświetlaj piksele odpowiednio

9. Zakończenie i Kolejne Kroki

Podsumowanie tego artykułu

W tym artykule omówiliśmy „display” w Verilogu od podstaw po zastosowania. Kluczowe punkty obejmowały:

  1. Podstawy $display
    • Zadanie symulacyjne wyświetlające sygnały lub zmienne, użyteczne podobnie jak printf w C.
  2. Różnice w stosunku do powiązanych zadań
    • $write → Wyświetla bez znaku nowej linii
    • $strobe → Wypisuje ustalone wartości pod koniec cyklu symulacji
    • $monitor → Automatycznie monitoruje zmiany sygnałów
  3. Używanie specyfikatorów formatu
    • Dzięki %b, %d, %h, %m, %t możesz generować czytelniejsze i praktyczniejsze logi.
  4. Praktyczne przykłady
    • Wstaw $display do testbenchów, aby monitorować postęp.
    • Używaj warunkowych komunikatów, aby umożliwić efektywne debugowanie.
  5. Zastosowania w sterowaniu wyświetlaczem
    • $display jest wyłącznie symulacyjne; implementacja sprzętowa używa HSYNC, VSYNC, RGB do wyświetlania tekstu/obrazu.
    • Od nauki wyświetlacza 7‑segmentowego po zaawansowane sterowanie VGA/HDMI, możliwe są dalsze rozszerzenia.

Kolejne kroki

  • Przejdź do SystemVerilog → W następnym języku SystemVerilog możesz używać bardziej zaawansowanych funkcji debugowania (asercje, ulepszony $display, itp.).
  • Połącz z przeglądarką przebiegów → Łącząc logi $display z danymi przebiegów, możesz analizować zarówno wartości liczbowe, jak i przejścia, zwiększając precyzję debugowania.
  • Poznaj wyjście wyświetlacza sprzętowego → W małym projekcie na płytce FPGA spróbuj wyświetlać na 7‑segmentowym wyświetlaczu lub LCD, aby doświadczyć różnicy między „wyświetlaniem symulacji” a „kontrolą wyświetlacza sprzętowego”.
  • Zastosuj w pracy zespołowej → Standaryzując format komunikatów $display, poprawiasz efektywność analizy logów w wieloosobowym rozwoju.

Na zakończenie

$display to coś więcej niż zwykłe „wyjście tekstowe”. To potężne narzędzie do debugowania symulacji. A gdy wkroczysz w świat kontroli wyświetlacza, możesz doświadczyć radości z wyświetlania grafiki na prawdziwych monitorach za pomocą FPGA.
Mam nadzieję, że ten artykuł pomoże uczącym się Verilog zrozumieć zarówno „debugowanie symulacji”, jak i „wyjście wyświetlacza sprzętowego” jasno.