A complete reference to Verilog’s value system — how numbers are written, what logic values mean, data types, scalars, vectors, parameters, and every operator category.
Verilog supports two forms of number literals: sized (with explicit bit-width) and unsized (default 32-bit). In digital design, always use sized literals — they make the intent explicit and prevent accidental sign or width mismatches.
<size>'<base><value>. Example: 8'hFF, 4'b1010.255, -8. Avoid in RTL — use sized literals instead.s after the base character for signed interpretation. Example: 4'sb1011 = −5 in 2’s complement.16'b1010_0101_1100_0011.Every sized number in Verilog follows this exact structure:
// ── Sized numbers ───────────────────────────────────────────── 4'b1010 // 4-bit binary → decimal 10 8'hFF // 8-bit hex → decimal 255 6'd35 // 6-bit decimal → binary 100011 12'o777 // 12-bit octal → binary 111_111_111 // ── X and Z values in binary ────────────────────────────────── 4'b1x0z // bit 3=1, bit 2=unknown, bit 1=0, bit 0=high-Z 8'bxxxx_zzzz // upper nibble unknown, lower nibble high-Z 4'bx // all 4 bits unknown (x extends to fill width) 4'bz // all 4 bits high-Z (z extends to fill width) // ── Signed numbers ──────────────────────────────────────────── 4'sb1011 // signed 4-bit: = -5 in 2's complement 8'sd-20 // signed 8-bit decimal -20 // ── Underscore for readability (ignored by compiler) ────────── 16'b1010_0101_1100_0011 // groups of 4 bits 32'h_DEAD_BEEF // hex groups of 4 // ── Unsized (avoid in RTL — 32-bit default) ─────────────────── 255 // 32-bit decimal 255 'b1010 // unsized binary — width inferred from context
| Literal | Size | Base | Decimal value | Binary equivalent |
|---|---|---|---|---|
| 4’b1010 | 4-bit | Binary | 10 | 1010 |
| 8’hFF | 8-bit | Hex | 255 | 1111_1111 |
| 6’d35 | 6-bit | Decimal | 35 | 100011 |
| 12’o777 | 12-bit | Octal | 511 | 111_111_111 |
| 4’sb1011 | 4-bit | Binary (signed) | −5 | 1011 |
A string in Verilog is a sequence of ASCII characters enclosed in double quotes on a single line. Strings are used primarily in simulation — for $display messages, file names, and test output — not in synthesizable RTL.
reg.reg, characters are packed left-to-right, MSB first.$display, $monitor, $readmemh are not synthesizable — testbench use only.// String in $display — most common use $display("Simulation started at time %0t", $time); $display("Result = %0d (expected 255)", result); // Storing a string in a reg // "numb" = 4 chars × 8 bits = 32 bits needed reg [31:0] str_reg; str_reg = "numb"; // Stored as: n=8'h6E, u=8'h75, m=8'h6D, b=8'h62 // str_reg = 32'h6E_75_6D_62 // String in file I/O integer fh; fh = $fopen("output.txt", "w"); $fwrite(fh, "Test PASS\n"); $fclose(fh); // Escape sequences inside strings "\n" // newline "\t" // tab "\\" // backslash "\"" // double quote "%d %b %h %o" // format specifiers for $display
Every signal in Verilog can hold one of four possible logic values. This four-value system (called 4-state logic) is what allows Verilog to accurately model real digital hardware — including uninitialized signals and tri-state buses that binary 0/1 cannot represent.
// ── Value 0 and 1: normal driven states ────────────────────── assign y = 1'b0; // y = 0 assign y = 1'b1; // y = 1 // ── Value x: unknown / uninitialized ───────────────────────── reg q; // q starts as x at simulation start wire w = a & b; // if a or b is x, w is x 4'bx // all 4 bits = x (extends to fill) // ── Value z: high-impedance (tri-state) ─────────────────────── assign bus = oe ? data : 8'bz; // float bus when oe=0 wire undriven; // unconnected wire → z by default
| Situation | Result | Explanation |
|---|---|---|
| 0 AND x | 0 | Output is always 0 regardless of other input |
| 1 AND x | x | Result depends on unknown input — propagates x |
| z into gate | x | z input treated as x for all logic gates |
| z into nmos/pmos | z | MOS switches propagate z to output (exception) |
| Two drivers: 0 and 1 | x | Conflict — result is unknown |
| Two drivers: same value | that value | No conflict — resolved correctly |
casex/casez statement uses x/z as wildcards. They look similar but behave very differently — don’t confuse them.When multiple sources drive the same wire net simultaneously, Verilog uses a strength resolution system to determine the final value. Every driven signal has both a value (0/1/x/z) and a strength. The stronger source wins. If two equal-strength sources drive opposite values, the result is x.
| Strength Level | Keyword | Category | Typical Source |
|---|---|---|---|
| 7 — Strongest | supply | Driving | supply0 / supply1 nets — power rails |
| 6 | strong | Driving | Default strength for all gate outputs and assign |
| 5 | pull | Driving | Pull-up / pull-down resistors |
| 4 | weak | Driving | Weak drivers — can be overridden by normal drivers |
| 3 | large | Capacitive | Large capacitive storage node |
| 2 | medium | Capacitive | Medium capacitive storage node |
| 1 | small | Capacitive | Small capacitive storage node (trireg) |
| 0 — Weakest | highz | High-Z | No driver — floating signal |
// supply0 always wins over weak1 supply0 gnd; // strength 7, value 0 wire net; assign (weak1, weak0) net = 1'b1; // strength 4, value 1 assign gnd; // strength 7, value 0 — wins // Result: net = 0 (supply beats weak) // Equal strength conflict → x assign (strong1, strong0) net = 1'b1; // strong 1 assign (strong1, strong0) net = 1'b0; // strong 0 // Result: net = x (equal strengths conflict)
Verilog data types fall into two fundamental categories based on whether they model physical connections or store values:
z when undriven. Used with assign.wire. Naming convention signals multiple drivers / tri-state intent.z. Models charge storage.always or initial block.real but stores simulation time values.$time. Not synthesizable.wire is for continuous assignments (assign) and module ports driven externally. reg is for signals assigned inside always blocks. A reg does not necessarily become a flip-flop in hardware — it only does so if there is a clock edge sensitivity.// wire: driven by assign or module port ───────────────────── wire y; assign y = a & b; // ✅ wire driven by assign wire sum; adder u1 (.sum(sum), ...); // ✅ wire driven by module output // reg: driven by always or initial block ───────────────────── reg q; always @(posedge clk) q <= d; // ✅ reg driven by always → flip-flop reg combo; always @(*) combo = a | b; // ✅ reg driven by always → combinational // ❌ Common mistakes ───────────────────────────────────────── wire bad; always @(*) bad = x; // ❌ cannot drive wire from always reg bad2; assign bad2 = x; // ❌ cannot use assign on reg (illegal)
A scalar is a single-bit signal (no range declared). A vector is a multi-bit signal declared with an explicit bit range [MSB:LSB]. Both nets and variables can be scalars or vectors.
// ── Scalar (1-bit, no range) ────────────────────────────────── wire wr; // 1-bit net reg flag; // 1-bit register // ── Vectors (multi-bit) ─────────────────────────────────────── wire [7:0] data; // 8-bit bus — data[7]=MSB, data[0]=LSB reg [3:0] nibble; // 4-bit reg reg [31:0] word; // 32-bit reg // ── Signed vectors ──────────────────────────────────────────── wire signed [7:0] s_data; // signed: range -128 to +127 reg signed [3:0] s_reg; // signed: range -8 to +7 // ── Bit-select (access a single bit) ───────────────────────── data[0] // LSB of data data[7] // MSB of data // ── Part-select (slice a range of bits) ────────────────────── data[7:4] // upper nibble data[3:0] // lower nibble // ── Indexed part-select (Verilog-2001) ──────────────────────── data[4 +: 4] // bits [7:4] — start at 4, width 4, going up data[7 -: 4] // bits [7:4] — start at 7, width 4, going down
// 2D array: [word_range] [bit_range] reg [7:0] mem [0:255]; // 256 words × 8 bits = 2KB memory reg [31:0] regfile [0:31]; // 32-entry × 32-bit register file // Access mem[5] = 8'hAB; // write byte to address 5 data = mem[5]; // read byte from address 5 // Note: mem[5][3:0] — bit-select within a memory word is NOT // supported in all simulators without an intermediate variable
Parameters are named constants set at compile time. They make modules configurable and reusable — you change a parameter value at instantiation and the entire module adapts, without touching the source.
module adder_n #( parameter N = 8 ) ( ... ); wire [N-1:0] sum; endmodule
// 16-bit instance adder_n #(.N(16)) u1(...); // 32-bit instance adder_n #(.N(32)) u2(...);
// parameter — overridable at instantiation time parameter DATA_W = 8; parameter DEPTH = 16; // localparam — internal constant, cannot be overridden from outside localparam ADDR_W = $clog2(DEPTH); // derived from DEPTH localparam MAX_VAL = ((1 << DATA_W) - 1); // Multiple parameters in one declaration parameter MEM_SIZE = 256, WORD_W = 32, FACTOR = WORD_W / 2; // defparam (legacy — avoid in new code) adder_n u3 (...); defparam u3.N = 64; // override N — works but discouraged
localparam for constants derived from other parameters (like address width from depth). They cannot be accidentally overridden from outside, which prevents misconfiguration of internal constants.Verilog operators closely follow C syntax with important extensions for hardware — including bitwise reduction, concatenation, and replication. They are classified by the number of operands they take.
op a. Example: ~a (bitwise NOT), &a (reduction AND).a op b. Most common form. Example: a & b, a + b.cond ? a : b. The only ternary operator — implements a 2-to-1 mux.| Operator | Name | Example | Notes |
|---|---|---|---|
| + | Addition | a + b | Result width = max(width_a, width_b) |
| – | Subtraction | a – b | Unsigned by default; use signed for arithmetic right |
| * | Multiplication | a * b | Result may need wider target to avoid truncation |
| / | Division | a / b | Synthesizable but costly — generates large hardware |
| % | Modulus | a % b | Remainder. Also costly — use power-of-2 when possible |
| ** | Power | 2 ** 8 | Exponentiation — often used with constants only |
Always produce a 1-bit result (true=1 / false=0). Treat any non-zero value as true.
| Operator | Name | Example | Result |
|---|---|---|---|
| && | Logical AND | a && b | 1 if both a and b are non-zero |
| || | Logical OR | a || b | 1 if either a or b is non-zero |
| ! | Logical NOT | !a | 1 if a is zero; 0 if a is non-zero |
Operate bit-by-bit across two operands. Result has same width as the wider operand.
| Operator | Name | Example | Bit-level operation |
|---|---|---|---|
| & | Bitwise AND | 4’b1100 & 4’b1010 = 4’b1000 | Each bit ANDed independently |
| | | Bitwise OR | 4’b1100 | 4’b1010 = 4’b1110 | Each bit ORed independently |
| ^ | Bitwise XOR | 4’b1100 ^ 4’b1010 = 4’b0110 | Each bit XORed independently |
| ~ | Bitwise NOT | ~4’b1010 = 4’b0101 | Every bit inverted |
| ~^ | Bitwise XNOR | 4’b1100 ~^ 4’b1010 = 4’b1001 | Each bit XNORed (equivalence) |
Unary operators that collapse a multi-bit vector down to a single bit by applying the operation across all bits.
| Operator | Name | Example | Result |
|---|---|---|---|
| &a | Reduction AND | &4’b1111 = 1 | 1 only if ALL bits are 1 — “are all bits set?” |
| ~&a | Reduction NAND | ~&4’b1111 = 0 | Inverse of reduction AND |
| |a | Reduction OR | |4’b0001 = 1 | 1 if ANY bit is 1 — “is non-zero?” |
| ~|a | Reduction NOR | ~|4’b0000 = 1 | 1 only if ALL bits are 0 — “is zero?” |
| ^a | Reduction XOR | ^4’b1011 = 1 | Parity of all bits — 1 if odd number of 1s |
| ~^a | Reduction XNOR | ~^4’b1011 = 0 | Even parity check |
| Operator | Name | Example | Fill bits |
|---|---|---|---|
| << | Logical left shift | 4’b1010 << 1 = 4’b0100 | Fills with 0s on right — equivalent to ×2 |
| >> | Logical right shift | 4’b1010 >> 1 = 4’b0101 | Fills with 0s on left — equivalent to ÷2 |
| <<< | Arithmetic left shift | 4’sb1010 <<< 1 | Same as logical left shift (fills 0s) |
| >>> | Arithmetic right shift | 4’sb1010 >>> 1 = 4’sb1101 | Fills with sign bit — preserves sign for 2’s complement |
Always return a 1-bit result. The key distinction is between logical equality (==) and case equality (===).
| Operator | Name | x/z behaviour |
|---|---|---|
| < | Less than | Returns x if either operand contains x or z |
| > | Greater than | Returns x if either operand contains x or z |
| <= | Less than or equal | Returns x if either operand contains x or z |
| >= | Greater or equal | Returns x if either operand contains x or z |
| == | Logical equality | Returns x if either operand has x or z bits — cannot distinguish unknown |
| != | Logical inequality | Returns x if either operand has x or z bits |
| === | Case equality | Compares x and z literally — returns 0 or 1 only, never x. Simulation-only. |
| !== | Case inequality | Inverse of ===. Returns 0 or 1 only. Simulation-only. |
if (q === 1'bx) tells you the signal is genuinely unknown. With ==, x == 1'bx returns x (not 1), so your if-condition may not fire.| Operator | Name | Example | Result |
|---|---|---|---|
| {a,b} | Concatenation | {4’b1100, 4’b1010} = 8’b1100_1010 | Joins bits of multiple operands left-to-right |
| {n{a}} | Replication | {4{2’b10}} = 8’b10101010 | Repeats operand n times — n must be a constant |
// Concatenation examples wire [7:0] byte_out = {upper, lower}; // join two 4-bit signals assign {cout, sum} = a + b; // split result across ports wire [15:0] word = {byte_a, byte_b}; // combine bytes into word // Replication examples wire [7:0] ones = {8{1'b1}}; // 8'b11111111 = 8'hFF wire [7:0] zeros = {8{1'b0}}; // 8'b00000000 // Sign-extension using replication wire [7:0] s4 = 4'sb1011; // 4-bit signed -5 wire [7:0] s8 = {{4{s4[3]}}, s4}; // sign-extend to 8-bit: 8'sb11111011
The only 3-operand operator in Verilog. Equivalent to a 2-to-1 multiplexer — widely used in assign statements.
// Basic mux assign out = sel ? a : b; // if sel=1 → a, else → b // Nested ternary — 4-to-1 mux (use case statement for readability) assign out = (sel==2'b00) ? in0 : (sel==2'b01) ? in1 : (sel==2'b10) ? in2 : in3; // Enable / tri-state assign bus = oe ? data : 8'bz; // drive or float // Default value when condition is unknown (x) // If sel = x, ternary result = x — design so sel is never x
| Priority | Operators | Category |
|---|---|---|
| Highest | + - ! ~ & ~& | ~| ^ ~^ (unary) | Unary |
| 2 | ** | Power |
| 3 | * / % | Multiply / Divide |
| 4 | + - (binary) | Arithmetic |
| 5 | << >> <<< >>> | Shift |
| 6 | < <= > >= | Relational |
| 7 | == != === !== | Equality |
| 8 | & (binary) | Bitwise AND |
| 9 | ^ ~^ (binary) | Bitwise XOR/XNOR |
| 10 | | (binary) | Bitwise OR |
| 11 | && | Logical AND |
| 12 | || | Logical OR |
| Lowest | ? : | Ternary |
a & b | c is technically legal but far less clear than (a & b) | c. Explicit parentheses eliminate ambiguity for both the compiler and any human reading the code.