Menu

Verilog Number Literals: Binary, Hex, Decimal, and Sized Constants

How Verilog writes constants: sized vs unsized, the 'b 'h 'd 'o bases, signed numbers, underscores for readability, and the gotchas that bite beginners.

This page includes runnable editors - edit, run, and see output instantly.

The Anatomy of a Sized Literal

A Verilog literal has up to three parts:

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

Reading left to right: "an 8-bit value, written in binary, with the digits 10101100". That's 172 in decimal, 0xAC in hex, the same bits whichever way you write it. The width tells the compiler exactly how many bits to allocate; the base tells it how to interpret the digits.

Underscores are visual separators. 32'b1010_1100_0011_0101 is the same as 32'b1010110000110101. Use them.

The Four Bases

Hex (h) is the standard for anything wider than 4 bits. Binary (b) is the standard when you want to read bit patterns directly. Decimal (d) is for human-meaningful counts. Octal (o) exists but you'll almost never see it.

Hex digits are case-insensitive: 8'hAB and 8'hab are identical.

What Happens When the Value Doesn't Fit?

If your digits don't fill the declared width, Verilog zero-extends on the left:

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

If your digits exceed the declared width, Verilog truncates the high bits with a warning:

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

The warning is your friend. Don't suppress it.

Sized vs Unsized

A literal without a width:

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

Unsized literals default to 32 bits in most tools. This is the source of an entire class of bugs:

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

The fix is to write 8'hFF instead of -1, or 8'd255, or {8{1'b1}}. Always size literals when they're used in width-specific expressions.

The one place unsized literals are fine is integer counters in testbench for loops, where the integer is wide enough that nothing surprising happens.

Signed Literals

By default, sized literals are unsigned:

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

If you want the literal interpreted as signed, add s after the apostrophe:

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

The s flag matters for:

  • The <<< and >>> operators (arithmetic shifts) - they sign-extend signed operands.
  • Comparison operators on signed mixed expressions.
  • The $signed/$unsigned casts.

For most ordinary arithmetic on bus signals, you'll leave the s off.

Number Literals With X and Z

A literal digit can be x (unknown) or z (high-impedance):

8'bx is shorthand for "all 8 bits unknown" - the value gets propagated to fill the declared width. x digits are common in default cases of state machines and in initialization. We cover the semantics in X and Z Values.

Where Sized Literals Show Up in Practice

Once you start writing real modules, sized literals appear everywhere:

// 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

The pattern is consistent: write the width, write the base, write the digits. Every literal you reach for has the same shape.

A Test Drive

You now have everything you need to write any constant a Verilog module could want. The last piece of the data-types story is what happens when a signal isn't a clean 0 or 1 - the x and z values.

Frequently Asked Questions

What does 8'b1010 mean in Verilog?

It's a sized binary literal: an 8-bit value whose binary representation is 00001010. The number before the apostrophe is the width in bits; the letter after the apostrophe is the base (b binary, h hex, d decimal, o octal); the digits after are the value. The literal is zero-padded on the left if the digits don't fill the width.

What is the difference between sized and unsized numbers in Verilog?

A sized literal like 8'd10 is exactly 8 bits wide. An unsized literal like 'd10 or just 10 defaults to 32 bits, which is usually too many. Mixing unsized literals into width-specific expressions causes subtle bugs - prefer sized literals everywhere outside of throwaway test code.

How do you write a hex number in Verilog?

Use the 'h base specifier: 8'hFF is an 8-bit value of 255. Hex digits are case-insensitive; 8'hff and 8'hFF are identical. You can group digits with underscores for readability: 32'hDEAD_BEEF. The underscores are ignored by the parser.

How do underscores work in Verilog numbers?

Underscores are visual separators that the parser ignores. 32'b1010_1100_0011_0101 is exactly the same value as 32'b1010110000110101 but much easier to read. The first character after the base prefix can't be an underscore, but you can put them anywhere else in the digit string.

How do you write a signed number in Verilog?

Add s after the apostrophe: 8'sd10 is a signed 8-bit decimal 10, and 8'sb1111_1111 is signed -1. By default, sized literals are unsigned; the s modifier flips that. Most arithmetic uses unsigned operands - reach for signed only when you genuinely need negative values to propagate through <, >>>, and similar operators.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED