1. A literal carries its own width
A number in Verilog is written as a width, an apostrophe, a radix letter and the digits. The width
is part of the value: 8'hA5 is eight bits, 4'b1010 is four.
Form
<width>'<radix><digits> // 8'hA5, 4'b1010, 8'd7| Radix letter | Base | Example | Value |
|---|---|---|---|
b | Binary | 4'b1010 | 10 |
o | Octal | 6'o17 | 15 |
d | Decimal | 8'd7 | 7 |
h | Hexadecimal | 8'hA5 | 165 |
A few more rules let you read any literal precisely.
- An underscore
_between digits is ignored. It only makes long numbers easier to read, as in8'b1100_0101. xandzare allowed as digits.4'b10x1is a 4-bit value whose bit 1 is unknown.- A literal without a width, such as
12or'hA5, is an unsized literal. The standard says it is at least 32 bits wide. Icarus uses 32 for these small values but expands larger unsized constants as needed to preserve their value.
Note. Inside an expression an unsized literal is extended to the width the context needs, and its
own width of at least 32 bits takes part in deciding the result width. That is why one careless + 1 can widen
a whole calculation (section 6). In circuit code, make a habit of writing the width, as in 8'd7.
2. Every bit is 0, 1, x or z
Each bit in Verilog holds one of four values.
| Value | Meaning | Where you see it |
|---|---|---|
0 | Logic 0 | |
1 | Logic 1 | |
x | Unknown | A variable that has never been assigned, or a signal with conflicting drivers |
z | High impedance: nothing drives the signal | An unconnected wire |
x does not mean "0 or 1, I don't care". It means "the simulator cannot tell what this bit is right
now". When x or z reaches the input of an operator, every result bit that depends on it also
becomes x; a bit the other operand already decides stays known, so 0 & x is 0 and 1 | x is
1.
3. Format specifiers choose how the bits are shown
The format string of $display uses specifiers similar to C's.
| Specifier | Prints as | 8'hA5 prints |
|---|---|---|
%b | Binary | 10100101 |
%h | Hexadecimal | a5 |
%d | Decimal, padded to the largest number of digits the width can need | 165 |
%0d | Decimal, with no leading padding | 165 |
A format specifier only chooses how the same bits are shown. The stored value does not change.
4. Run: one byte in three radixes, padding, and x
Literals.v exercises literals, format specifiers, and the behavior of x in one go. Each output
line starts with a marker such as RADIX or PAD, so you can tell at once which $display produced
it. As you read the code, look for three things:
valueis assigned8'hA5.nibbleis assigned4'b10x1, whose bit 1 isx.never_setis declared but never assigned.
module literals;
reg [7:0] value;
reg [3:0] nibble;
reg [7:0] never_set;
initial begin
value = 8'hA5;
// One stored pattern, printed in three radixes.
$display("RADIX hex=%h bin=%b dec=%0d", value, value, value);
// %d pads to the widest decimal an 8-bit value can need.
$display("PAD [%d] [%0d]", 8'd7, 8'd7);
nibble = 4'b10x1;
$display("FOUR-STATE nibble=%b", nibble);
// A variable nobody has assigned yet holds x in every bit.
$display("UNSET never_set=%b", never_set);
// Any unknown input bit makes the whole sum unknown.
$display("X-ADD %b", nibble + 4'd1);
$display("SIZES %0d %0d", $bits(8'hA5), $bits('hA5));
$finish;
end
endmodulePredict before you run.
- On the
RADIXline, what are the hexadecimal, binary, and decimal forms of8'hA5? - On the
PADline, how many spaces appear in front of the 7 printed with%d? - Does the never-assigned
never_setprint as 0? - Only bit 1 of
nibbleisx. Is only one bit ofnibble + 4'd1unknown as well?
Check
On the PAD line, 8'd7 is printed with %d. How many spaces come before the 7?
Check
The SIZES line prints $bits(8'hA5) and then $bits('hA5). What is the second number in Icarus?
Check the result. Press Run and check each line against this table.
| Output line | What it shows |
|---|---|
RADIX | The same eight bits print as a5, 10100101, and 165 |
PAD | The largest 8-bit value, 255, has three digits, so %d reserves three columns and prints 7. %0d prints just 7 |
FOUR-STATE | The x is printed in bit 1, exactly where it was written |
UNSET | A variable nobody assigned is not 0; it is eight x characters |
X-ADD | Verilog addition produces an all-x result if either operand contains x or z |
SIZES | $bits returns a width: 8 for 8'hA5, 32 for the unsized 'hA5 |
Also read UNSET: an unassigned variable is x in every bit, not 0. On X-ADD, one unknown
operand bit makes the entire sum unknown. This is Verilog's arithmetic rule, not a bit-by-bit
analysis of which sum bits a circuit could determine.
Try it yourself.
| Change | What happens |
|---|---|
4'b10x1 to 4'b1001 | No bit is unknown any more, so X-ADD prints 1010 |
4'b10x1 to 4'b10z1 | A floating bit is just as unusable in arithmetic, so the sum is xxxx again |
5. The same bits read as signed or unsigned
5.1 A signed declaration
A pattern has no sign of its own. The declaration says how to read it. reg [3:0] u reads 1111
as 15; reg signed [3:0] s reads the same 1111 as two's complement, which is −1, and %d prints
whichever reading the declaration gives.
reg [3:0] u; // 1111 prints as 15
reg signed [3:0] s; // 1111 prints as -1Two rules follow the declaration into every expression.
| Rule | Effect |
|---|---|
| A binary addition is signed only if both operands are signed | one unsigned operand makes the addition unsigned |
| A wider target extends the right-hand side | an unsigned value is zero-extended; a signed value is sign-extended |
So s assigned to an 8-bit target becomes 1111_1111, keeping the value −1, while u assigned to
the same target becomes 0000_1111, keeping 15. Mixing s + u drops the sign reading entirely.
You have already run both rules: in the operators example, the same bits in a plain and in a signed
vector gave different results for >>> and for <. Every other runnable example in this course is
unsigned; these two rules are all the signed arithmetic you need to read them.
Check
s is declared reg signed [3:0] and holds 1111. What does %0d print for s?
5.2 Assigning between different widths
When the value and the target of an assignment have different widths, Verilog makes them match. The adjustment is applied to the operands before the expression is evaluated, which is why a wide target also widens the arithmetic feeding it (section 6).
| Case | Behavior | Example: assign the 8-bit 1100_0101 |
|---|---|---|
| Target is narrower | The upper bits are dropped (truncation) | A 4-bit target keeps 0101 |
| Target is wider, value unsigned | The upper bits are filled with 0 (zero extension) | A 12-bit target holds 0000_1100_0101 |
Target is wider, value signed | The upper bits copy the sign bit (sign extension) | A 12-bit target holds 1111_1100_0101 |
Neither case is a compile error, and Icarus prints no warning for either by default; lint tools and
synthesis tools usually do warn about a truncation. The width you declare for a signal is therefore
part of how the circuit behaves. The narrow and wide outputs of
Vectors, bit selects and
operators were the first two rows of this table.
6. An expression is computed at the width of its widest participant
The width of an addition is not decided by the +. Verilog looks at the whole assignment: the
operands and the target. The widest of them sets the width at which the expression is evaluated,
and a carry survives only if that width has room for it.
6.1 Context-determined and self-determined widths
Most expressions are evaluated at a width chosen from the whole assignment, not from each operator alone. Which rule applies depends on where an operand sits.
| Kind | Operand positions | Evaluated at |
|---|---|---|
| Context-determined | Operands of arithmetic and bitwise operators, both branches of ?:, the right-hand side of an assignment | The widest of those operands and the assignment target |
| Self-determined | Each item inside { }, a shift amount, a comparison result, a condition | Its own width only |
wire [7:0] a, b;
wire [8:0] total;
wire [7:0] y;
assign total = a + b; // evaluated at 9 bits; the carry lands in bit 8
assign y = (a + b) >> 1; // evaluated at 8 bits; the carry is gone before the shiftIn the first assignment the 9-bit target makes the addition 9 bits wide. In the second, every
participant is 8 bits, so bit 8 of the sum is never produced. {a + b} with 8-bit operands is 8
bits for the same reason: an item inside braces is self-determined.
6.2 Widening on purpose, narrowing by accident
| Expression | Addition width | Why |
|---|---|---|
{1'b0, a} + b | 9 bits | One 9-bit operand widens the whole expression |
a + b + 0 | At least 32 bits | The unsized 0 widens the addition; Icarus can further expand unsized expressions |
{a + b} | 8 bits | An item inside braces is self-determined |
Note. A sum written inside braces is computed at its operands' width, however wide the assignment target is. The concatenation may look as if it widens the result, but the carry was already dropped before the braces were applied.
6.3 Run: averaging at two widths
Average.v takes its width from #(parameter W = 8) and writes every port width in terms of W;
how a parameter is declared and overridden is the subject of
Instances, hierarchy and parameters, and
here it only means "the same module at two widths". It averages the same two inputs in two ways and
also outputs their sum.
| Output | Computation | Addition width |
|---|---|---|
avg_short | (a + b) >> 1 | W |
avg_full | ({1'b0, a} + b) >> 1 | W+1 |
total | a + b assigned to a W+1-bit output | W+1 |
avg_short adds at W bits and shifts; avg_full puts a 1'b0 in front of one operand, which
widens the whole addition to W+1 bits; total is assigned to a W+1-bit output, so the target
widens the addition.
// Average of two W-bit values, computed at two different widths.
module average #(parameter W = 8) (
input [W-1:0] a,
input [W-1:0] b,
output [W-1:0] avg_short,
output [W-1:0] avg_full,
output [W:0] total
);
// Every operand here is W bits, so the carry of a + b is lost.
assign avg_short = (a + b) >> 1;
// One W+1-bit operand widens the whole expression.
assign avg_full = ({1'b0, a} + b) >> 1;
// A W+1-bit target also widens the addition.
assign total = a + b;
endmoduleTb.v places two instances. average #(.W(8)) wide keeps the default, and average #(.W(4)) narrow
overrides W to 4, which gives that instance 4-bit inputs and a 5-bit total. Both instances first
get a pair whose sum fits, then a pair whose sum overflows.
module tb;
reg [7:0] a8, b8;
wire [7:0] short8, full8;
wire [8:0] total8;
reg [3:0] a4, b4;
wire [3:0] short4, full4;
wire [4:0] total4;
average #(.W(8)) wide (.a(a8), .b(b8), .avg_short(short8), .avg_full(full8), .total(total8));
average #(.W(4)) narrow (.a(a4), .b(b4), .avg_short(short4), .avg_full(full4), .total(total4));
initial begin
a8 = 8'd100; b8 = 8'd50; a4 = 4'd6; b4 = 4'd4;
#1 $display("W8 %0d,%0d short=%0d full=%0d total=%0d", a8, b8, short8, full8, total8);
$display("W4 %0d,%0d short=%0d full=%0d total=%0d", a4, b4, short4, full4, total4);
a8 = 8'd200; b8 = 8'd100; a4 = 4'd12; b4 = 4'd10;
#1 $display("W8 %0d,%0d short=%0d full=%0d total=%0d", a8, b8, short8, full8, total8);
$display("W4 %0d,%0d short=%0d full=%0d total=%0d", a4, b4, short4, full4, total4);
$finish;
end
endmodulePractice this concept
Use this concept in a short Verilog problem as your next step.
Predict before you run. The second 8-bit pair is 200 + 100 = 300, and 300 needs nine bits.
- Is
avg_short22 or 150? - What are
avg_fullandtotal? - For the 4-bit pair 12 + 10, what are
shortandfull?
Check
For the 8-bit instance with 200 and 100, what does short print?
Check
For the 4-bit instance with 12 and 10, what does full print?
Check the result. Press Run and compare the two W8 and two W4 lines with your answers.
| Output line | What it shows |
|---|---|
The first W8 and W4 lines | The sums fit, so short and full agree |
W8 200,100 | short is 22: 300 truncated to 8 bits is 44, shifted once. full keeps 300 in 9 bits and prints 150. total is 300 |
W4 12,10 | 22 loses 16 in four bits and becomes 6, so short is 3, while full is 11 |
The + operator did not lose the carry. The operands and the target were all too narrow, so nothing
gave the addition a wider context. One definition produced two differently sized circuits, and each
instance followed the same rule at its own W.
7. Change one thing
In Average.v, change avg_short to (a + b + 0) >> 1 and run again. Decide first what the
unsized 0 does to the width of the addition.
Check
At what width is a + b + 0 computed when a and b are 8 bits?
| Change | What happens |
|---|---|
avg_short to (a + b + 0) >> 1 | The unsized 0 widens the addition to at least 32 bits, and the second-pair short values become 150 and 11 |
avg_full to {a + b} >> 1 | The braced sum is evaluated at W bits, so full drops to 22 and 3, the same as short |
8. Common mistakes
8.1 Losing upper bits in a narrow target
wire [3:0] low4;
assign low4 = 8'hC5; // low4 is 4'h5; the upper four bits vanish silentlyThere is no error and, in Icarus, no warning, so when a result looks wrong, check the width of every signal the data passes through.
8.2 Leading spaces from %d
%d reserves as many columns as the largest value of that width could need, so an 8-bit 7 prints as
7. Use %0d when you want no padding.
8.3 An unsized literal widening an expression
wire [7:0] a, b, y;
assign y = (a + b + 1) >> 1; // 1 is 32 bits in Icarus, so the whole addition is 32 bits
assign y = (a + b + 8'd1) >> 1; // an 8-bit addition; the carry is lostWhich line is right depends on what you want, but you should know that one literal changes the result. Write sized literals in width-sensitive expressions, and when you need a wider result, widen an operand or the target explicitly.
9. Practice: keep the carry
The checkpoint is the Practice problem carry-out. A 4-bit adder drives a 5-bit sum, yet every
result above 15 prints exactly 16 too small. Its assign writes {1'b0, a + b}: the addition sits
inside braces, so it is self-determined at four bits, and the carry is gone before the leading zero
is attached. The 5-bit target cannot help from outside the braces. Find where the width of the result
is decided, rewrite the line so that all five bits of the sum appear, and check that 9 + 8 prints 17
and 15 + 15 prints 30.
10. Summary
| Element | Meaning |
|---|---|
8'hA5 | a sized literal: width, radix (b, o, d, h), digits; _ is ignored, x and z are digits |
12, 'hA5 | unsized: 32 bits for these values in Icarus; larger constants can need more, and the width participates in the expression |
0, 1, x, z | the four values of a bit; a variable that was never assigned is x, and an x input spreads to every result bit it can reach |
%b, %h, %d, %0d | how the same bits are printed; %d pads to the widest decimal the width can need |
reg signed [3:0] | the same bits read as two's complement; a binary addition is signed only if both operands are signed |
| narrower or wider target | truncates the upper bits, or extends with 0 for an unsigned value and with the sign bit for a signed one; Icarus warns about neither by default, lint and synthesis tools usually do |
total = a + b into a wider total | the widest of the operands and the target sets the width: the target widens the addition and keeps the carry |
{a + b}, a shift amount, a comparison | self-determined: items inside braces keep their own width, so the carry is lost |
11. Check your understanding
-
Only one bit of
nibbleisx. Why are all four bits ofnibble + 4'd1x?Show answer
Verilog defines the entire addition result as
xif any operand bit isxorz. This conservative simulation rule also marks bits unknown that a bit-by-bit circuit analysis could determine; unknown carry propagation alone does not explain the lowest result bit becomingx. -
In
average #(.W(4)) narrow, how wide istotal, and how wide is the addition that drivesavg_short?Show answer
totalis declared[W:0], so it is 5 bits. The addition foravg_shorthas 4-bit operands and a 4-bit target, so it is evaluated at 4 bits. -
Why does
{1'b0, a} + bkeep the carry while{a + b}does not?Show answer
{1'b0, a}is aW+1-bit operand, so the whole addition runs atW+1bits.{a + b}is an item inside braces, so it is self-determined atWbits and the carry bit is never produced.