Menu

Числовые литералы в Verilog: binary, hex, decimal и sized-константы

Как Verilog записывает константы: sized vs unsized, базы 'b 'h 'd 'o, знаковые числа, подчёркивания для читаемости и засады, которые ловят новичков.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Анатомия sized-литерала

У литерала Verilog до трёх частей:

8'b1010_1100
│  │ │
│  │ └─ цифры в выбранной базе
│  └─── base specifier: b (binary), h (hex), d (decimal), o (octal)
└────── ширина в битах (decimal)

Читаем слева направо: "8-битное значение, записанное в binary, цифры 10101100". Это 172 в decimal, 0xAC в hex - одни и те же биты, как ни запиши. Ширина говорит компилятору, сколько бит выделить; база говорит, как интерпретировать цифры.

Подчёркивания - визуальные разделители. 32'b1010_1100_0011_0101 - то же, что 32'b1010110000110101. Пользуйся ими.

Четыре базы

Hex (h) - стандарт для всего шире 4 бит. Binary (b) - стандарт, когда нужно читать битовые паттерны напрямую. Decimal (d) - для человекопонятных счётов. Octal (o) существует, но почти никогда не встретится.

Hex-цифры case-insensitive: 8'hAB и 8'hab идентичны.

Что происходит, когда значение не помещается?

Если цифр меньше, чем объявленная ширина, Verilog zero-extend'ит слева:

8'b101       // эквивалентно 8'b00000101  (= 5)
8'hF         // эквивалентно 8'h0F        (= 15)

Если цифр больше объявленной ширины, Verilog обрезает старшие с warning'ом:

4'hFF        // обрезается до 4'hF, симулятор предупреждает
4'b10000     // обрезается до 4'b0000

Warning - твой друг. Не подавляй его.

Sized vs unsized

Литерал без ширины:

'd10    // unsized, дефолтный размер (≥32 бит)
10      // тоже unsized - без базы значит decimal

Unsized-литералы дефолтно 32 бита в большинстве тулов. Это источник целого класса багов:

reg [7:0] count;
if (count == -1) ...      // -1 - unsized 32-битный; сравнение становится странным

Фикс - писать 8'hFF вместо -1, или 8'd255, или {8{1'b1}}. Всегда задавай ширину литералов, когда они используются в width-specific выражениях.

Единственное место, где unsized-литералы нормальны - счётчики integer в testbench-for-циклах, где integer достаточно широк, чтобы ничего удивительного не случилось.

Знаковые литералы

По умолчанию sized-литералы unsigned:

8'd255   // unsigned 255
8'b1111_1111   // unsigned 255 - тот же битовый паттерн, просто записан иначе

Если хочешь, чтобы литерал интерпретировался как знаковый - добавь s после апострофа:

8'sd10           // знаковое 10
8'sb1111_1111    // знаковое -1 (two's complement)

Флаг s важен для:

  • Операторов <<< и >>> (арифметические сдвиги) - они sign-extend'ят знаковые операнды.
  • Операторов сравнения на знаковых смешанных выражениях.
  • Кастов $signed/$unsigned.

Для большинства обычной арифметики на сигналах шин s оставляешь выключенным.

Числовые литералы с X и Z

Литеральная цифра может быть x (unknown) или z (high-impedance):

8'bx - shorthand для "все 8 бит unknown"; значение распространяется на объявленную ширину. Цифры x распространены в default-ветках state machines и в инициализации. Семантику разбираем в X and Z Values.

Где sized-литералы встречаются на практике

Как только начнёшь писать реальные модули, sized-литералы появляются везде:

// Ширины шин
input  wire [31:0] addr;
wire [31:0] zero = 32'h0;
wire [31:0] all_ones = 32'hFFFF_FFFF;

// Кодировки состояний
localparam IDLE = 3'd0;
localparam BUSY = 3'd1;
localparam DONE = 3'd2;

// Маски
wire is_msb_set = data & 32'h8000_0000;

// Сравнения
if (counter == 8'd255) ...

// Reset-значения
always @(posedge clk) begin
    if (reset) data_out <= 8'd0;
    else       data_out <= data_in;
end

Паттерн стабильный: пиши ширину, базу, цифры. У каждого литерала, к которому тянешься, одна и та же форма.

Тест-драйв

Теперь у тебя есть всё, чтобы написать любую константу, которая может понадобиться module на Verilog. Последний кусочек истории про типы данных - что происходит, когда сигнал не чистый 0 или 1: значения x и z.

Часто задаваемые вопросы

Что значит 8'b1010 в Verilog?

Это sized binary литерал: 8-битное значение, чьё двоичное представление - 00001010. Число до апострофа - ширина в битах; буква после апострофа - база (b binary, h hex, d decimal, o octal); цифры после - значение. Литерал zero-pad'ится слева, если цифр меньше, чем нужно для ширины.

В чём разница между sized и unsized числами в Verilog?

Sized литерал вроде 8'd10 ровно 8 бит шириной. Unsized литерал вроде 'd10 или просто 10 дефолтно 32 бита, что обычно слишком много. Смешивание unsized литералов с width-specific выражениями даёт тонкие баги - предпочитай sized везде, кроме одноразового тестового кода.

Как написать hex-число в Verilog?

Через base specifier 'h: 8'hFF - это 8-битное значение 255. Hex-цифры case-insensitive; 8'hff и 8'hFF идентичны. Цифры можно группировать подчёркиваниями для читаемости: 32'hDEAD_BEEF. Подчёркивания парсер игнорирует.

Как работают подчёркивания в числах Verilog?

Подчёркивания - это визуальные разделители, которые парсер игнорирует. 32'b1010_1100_0011_0101 - это ровно то же самое значение, что 32'b1010110000110101, но гораздо легче читается. Первый символ после префикса базы не может быть подчёркиванием, но в остальной строке цифр их можно ставить где угодно.

Как написать знаковое число в Verilog?

Добавь s после апострофа: 8'sd10 - знаковое 8-битное десятичное 10, 8'sb1111_1111 - знаковое -1. По умолчанию sized-литералы unsigned; модификатор s это переворачивает. Большая часть арифметики использует unsigned-операнды - тянись к signed только когда действительно нужно, чтобы отрицательные значения распространялись через <, >>> и подобные операторы.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ