Menu

Literały liczbowe w Verilogu: binarne, hex, dziesiętne i stałe z rozmiarem

Jak Verilog zapisuje stałe: z rozmiarem i bez, podstawy 'b 'h 'd 'o, liczby ze znakiem, podkreślenia dla czytelności i pułapki, w które wpadają początkujący.

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

Budowa literału z rozmiarem

Literał w Verilogu ma do trzech części:

8'b1010_1100
│  │ │
│  │ └─ digits in the chosen base
│  └─── base specifier: b (binary), h (hex), d (decimal), o (octal)
└────── width in bits (decimal)

Czytając od lewej do prawej: "8-bitowa wartość zapisana binarnie cyframi 10101100". To 172 dziesiętnie i 0xAC szesnastkowo: te same bity, niezależnie od zapisu. Szerokość mówi kompilatorowi dokładnie, ile bitów przydzielić, a podstawa, jak interpretować cyfry.

Podkreślenia to wizualne separatory. 32'b1010_1100_0011_0101 to to samo co 32'b1010110000110101. Używaj ich.

Cztery podstawy

Zapis szesnastkowy (h) to standard dla wszystkiego, co ma więcej niż 4 bity. Zapis binarny (b) to standard, gdy chcesz bezpośrednio czytać wzorce bitów. Zapis dziesiętny (d) służy do liczb mających znaczenie dla człowieka. Zapis ósemkowy (o) istnieje, ale prawie nigdy go nie zobaczysz.

Wielkość liter w cyfrach szesnastkowych nie ma znaczenia: 8'hAB i 8'hab są identyczne.

Co się dzieje, gdy wartość się nie mieści?

Jeśli cyfry nie wypełniają zadeklarowanej szerokości, Verilog dopełnia zerami z lewej strony:

8'b101       // equivalent to 8'b00000101  (= 5)
8'hF         // equivalent to 8'h0F        (= 15)

Jeśli cyfry przekraczają zadeklarowaną szerokość, Verilog obcina starsze bity i wyświetla ostrzeżenie:

4'hFF        // truncates to 4'hF, simulator warns
4'b10000     // truncates to 4'b0000

To ostrzeżenie jest twoim sprzymierzeńcem. Nie wyłączaj go.

Z rozmiarem i bez rozmiaru

Literał bez szerokości:

'd10    // unsized, takes default size (≥32 bits)
10      // also unsized - no base means decimal

W większości narzędzi literały bez rozmiaru mają domyślnie 32 bity. To źródło całej klasy błędów:

reg [7:0] count;
if (count == -1) ...      // -1 is unsized 32-bit; comparison gets weird

Rozwiązanie to zapis 8'hFF zamiast -1, albo 8'd255, albo {8{1'b1}}. Zawsze podawaj rozmiar literałów używanych w wyrażeniach o określonej szerokości.

Jedyne miejsce, w którym literały bez rozmiaru są w porządku, to liczniki całkowite w pętlach for testbenchy, bo liczba całkowita jest tam na tyle szeroka, że nic zaskakującego się nie dzieje.

Literały ze znakiem

Domyślnie literały z rozmiarem są bez znaku:

8'd255   // unsigned 255
8'b1111_1111   // unsigned 255 - same bit pattern, just written differently

Jeśli literał ma być interpretowany jako liczba ze znakiem, dodaj s po apostrofie:

8'sd10           // signed 10
8'sb1111_1111    // signed -1 (two's complement)

Flaga s ma znaczenie dla:

  • Operatorów <<< i >>> (przesunięć arytmetycznych), które rozszerzają argumenty ze znakiem bitem znaku.
  • Operatorów porównania w mieszanych wyrażeniach ze znakiem.
  • Rzutowań $signed/$unsigned.

W większości zwykłych obliczeń na sygnałach magistral zostawisz s w spokoju.

Literały liczbowe z X i Z

Cyfrą literału może być x (wartość nieznana) albo z (wysoka impedancja):

8'bx to skrót od "wszystkie 8 bitów nieznane": wartość jest powielana, żeby wypełnić zadeklarowaną szerokość. Cyfry x są częste w gałęziach default maszyn stanów i przy inicjalizacji. Ich semantykę omawiamy w artykule Wartości X i Z.

Gdzie literały z rozmiarem pojawiają się w praktyce

Gdy zaczniesz pisać prawdziwe moduły, literały z rozmiarem pojawią się wszędzie:

// Bus widths
input  wire [31:0] addr;
wire [31:0] zero = 32'h0;
wire [31:0] all_ones = 32'hFFFF_FFFF;

// State encodings
localparam IDLE = 3'd0;
localparam BUSY = 3'd1;
localparam DONE = 3'd2;

// Masks
wire is_msb_set = data & 32'h8000_0000;

// Comparisons
if (counter == 8'd255) ...

// Reset values
always @(posedge clk) begin
    if (reset) data_out <= 8'd0;
    else       data_out <= data_in;
end

Wzorzec jest zawsze ten sam: podaj szerokość, podaj podstawę, podaj cyfry. Każdy literał, po który sięgniesz, ma taki sam kształt.

Jazda próbna

Masz już wszystko, czego potrzebujesz, żeby zapisać dowolną stałą, jakiej może potrzebować moduł w Verilogu. Ostatni element historii o typach danych to to, co się dzieje, gdy sygnał nie jest czystym 0 albo 1, czyli wartości x i z.

Najczęściej zadawane pytania

Co oznacza 8'b1010 w Verilogu?

To binarny literał z rozmiarem: 8-bitowa wartość, której reprezentacja binarna to 00001010. Liczba przed apostrofem to szerokość w bitach, litera po apostrofie to podstawa (b binarna, h szesnastkowa, d dziesiętna, o ósemkowa), a cyfry dalej to wartość. Jeśli cyfry nie wypełniają szerokości, literał jest dopełniany zerami z lewej strony.

Jaka jest różnica między liczbami z rozmiarem i bez rozmiaru w Verilogu?

Literał z rozmiarem, taki jak 8'd10, ma dokładnie 8 bitów. Literał bez rozmiaru, taki jak 'd10 albo po prostu 10, ma domyślnie 32 bity, co zwykle jest za dużo. Mieszanie literałów bez rozmiaru z wyrażeniami o określonej szerokości powoduje subtelne błędy, więc poza jednorazowym kodem testowym używaj literałów z rozmiarem.

Jak zapisać liczbę szesnastkową w Verilogu?

Użyj specyfikatora podstawy 'h: 8'hFF to 8-bitowa wartość 255. Wielkość liter w cyfrach szesnastkowych nie ma znaczenia, więc 8'hff i 8'hFF są identyczne. Dla czytelności możesz grupować cyfry podkreśleniami: 32'hDEAD_BEEF. Parser ignoruje podkreślenia.

Jak działają podkreślenia w liczbach w Verilogu?

Podkreślenia to wizualne separatory, które parser ignoruje. 32'b1010_1100_0011_0101 to dokładnie ta sama wartość co 32'b1010110000110101, ale czyta się ją dużo łatwiej. Pierwszy znak po prefiksie podstawy nie może być podkreśleniem, ale w pozostałych miejscach ciągu cyfr możesz je wstawiać dowolnie.

Jak zapisać liczbę ze znakiem w Verilogu?

Dodaj s po apostrofie: 8'sd10 to 8-bitowa dziesiętna liczba 10 ze znakiem, a 8'sb1111_1111 to -1 ze znakiem. Domyślnie literały z rozmiarem są bez znaku, a modyfikator s to zmienia. Większość arytmetyki używa argumentów bez znaku. Po liczby ze znakiem sięgaj tylko wtedy, gdy naprawdę potrzebujesz, żeby wartości ujemne przechodziły przez <, >>> i podobne operatory.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ