Number Literals
In Verilog the way you write a number decides how many bits it has, and the number of bits decides whether a concatenation is the width you think, whether a comparison means what you think, and whether the synthesised circuit is the right size. An unsized literal in the wrong place is one of the commonest sources of quiet RTL bugs, so this article is about writing every constant precisely.
The format
<size>'<base><value>
The size is the number of bits in decimal; the apostrophe is required; the base is b, o, d or h; and the value uses the digits of that base, with underscores allowed for readability and x and z allowed as digits.
4'b1010 // 4 bits, binary, decimal 10
8'hFF // 8 bits, hex, 255
8'hff // the same; case does not matter
16'hDEAD
8'd255 // 8 bits, decimal
8'o377 // 8 bits, octal, 255
1'b0 // a single-bit 0
1'b1 // a single-bit 1
32'h0000_0001 // underscores every four digits
12'hABC // the size need not be a power of two
Why the size matters
Every signal in the netlist has a width. Assign a constant of a different width and the tool silently truncates or zero-extends, with at most a warning:
wire [3:0] nibble;
assign nibble = 255; // 255 is a 32-bit literal; the top 28 bits are thrown away, nibble = 4'hF
assign nibble = 4'hF; // what was meant
Concatenation is where it really goes wrong, because an unsized literal is 32 bits wide:
wire [3:0] nib_a = 4'hA;
wire [7:0] byte_val;
assign byte_val = {nib_a, 0}; // 0 is 32 bits: a 36-bit concatenation truncated to 8, giving 8'h00
assign byte_val = {nib_a, 4'h0}; // 8'hA0, as intended
In a comparison such as if (state == 3) the narrow operand is zero-extended and the result is right, which is why people get away with unsized literals for years and then get bitten in a concatenation or an arithmetic expression. Size everything.
The four values
Verilog signals take four values, not two, and this models real hardware.
| Value | Meaning |
|---|---|
0 |
driven low |
1 |
driven high |
x |
unknown: not yet initialised, or two drivers fighting |
z |
high impedance: nothing driving |
Every reg starts as x at time zero, because a real flip-flop powers up in an unknown state. A wire with two drivers at opposite values is x, because it cannot be both. A case with no default produces x on its outputs for the patterns it does not cover.
`timescale 1ns / 1ps
`default_nettype none
module x_z_demo;
reg [3:0] uninit_reg; // 4'bxxxx at time zero
wire [3:0] high_z_wire; // undriven: 4'bzzzz
initial begin
$display("uninit_reg at t=0: %b", uninit_reg); // xxxx
uninit_reg = 4'b1010;
$display("after assignment: %b", uninit_reg); // 1010
uninit_reg = 4'bxxxx; // all unknown
uninit_reg = 4'b10xz; // mixed
uninit_reg = 4'hx; // shorthand for all unknown
$finish;
end
endmodule
X spreads. An AND gate with an x input and a 1 on the other gives x, and so on downstream, so an x on an output in the waveform viewer is information: trace it back and you find the register nobody reset. That is what it is for.
Z is a wire nobody is driving. On an internal signal it means something you expected to drive it did not. Deliberately, it is how a tri-state driver lets go of a shared bus:
`timescale 1ns / 1ps
`default_nettype none
module tristate_driver #(
parameter WIDTH = 8
)(
input wire [WIDTH-1:0] data_in,
input wire oe_n, // output enable, active low
output wire [WIDTH-1:0] bus
);
assign bus = oe_n ? {WIDTH{1'bz}} : data_in;
endmodule
Inside an FPGA or ASIC, buses are muxes now, not tri-states. Z belongs at the pins, where an I²C data line or a memory bus really is shared.
Negative numbers
Literals are unsigned. A minus sign is the negation operator applied to one:
-8'd5 // 8'b11111011, which is 251 unsigned or -5 in two's complement
The bits are the same either way; only the interpretation differs, and that is set by the signed qualifier on the signals involved, which the arithmetic article covers.
Choosing a base
Hex for bus values and addresses, because it shows the byte structure:
parameter RESET_VECTOR = 32'h0000_0100;
parameter STATUS_MASK = 8'h3F;
Binary for masks and one-hot encodings, because it shows the bit positions:
parameter INTERRUPT_MASK = 8'b0000_1111;
localparam S_IDLE = 4'b0001;
localparam S_RUN = 4'b0010;
localparam S_DONE = 4'b0100;
Decimal for counts:
parameter BAUD_DIVISOR = 16'd868; // 50 MHz / 57600
parameter TIMEOUT_CYCLES = 10'd1000;
Underscores every four digits in anything wide, 32'hDEAD_BEEF, 16'b1010_0101_1100_0011. And in comparisons, size the literal to the signal: count == 8'd255, state == 3'd7, flag == 1'b1.
x in synthesis
To a synthesiser an x on the right-hand side means “don’t care”, and it will use the freedom to shrink the logic:
case (sel)
2'b00: out = a;
2'b01: out = b;
2'b10: out = c;
2'b11: out = 2'bxx; // never happens, so choose whatever is cheapest
endcase
That is useful and dangerous in equal measure. If the case you called impossible does happen, the circuit does something you did not choose. Use it only when you can prove the pattern cannot occur.
Practice Exercise
Find the literal problems and rewrite:
module bad_literals (
input wire [7:0] data,
output wire [7:0] masked,
output wire [3:0] upper
);
assign masked = data & 15;
assign upper = data >> 4;
endmodule
Solution
`timescale 1ns / 1ps
`default_nettype none
module good_literals (
input wire [7:0] data,
output wire [7:0] masked,
output wire [3:0] upper
);
assign masked = data & 8'b0000_1111; // sized mask; binary shows which bits survive
assign upper = data[7:4]; // a part-select says what is meant
endmodule
The 15 was a 32-bit literal used as an 8-bit mask; it happened to work but only because of zero extension. The shift produced an 8-bit result silently truncated to 4 bits; numerically right, and hiding the intent, which a part-select states directly.
Next, the lines that start with a backtick: compiler directives, including the one that turns a typo in a signal name from an afternoon of debugging into a compile error.