The Verilog standard defines a value set with four different values for you to use. You can have these values read out from either to a net (wire) or a variable (reg) type. Here are those values:

Value Description
0 Logic level 0
1 Logic level 1
X Unknown value
Z High Impedance

Every Verilog data type allows storing all of these values (⚠:️ There are some exceptions).

The logic level values (1 and 0) are easy to understand; they represent the binary values 1 and 0, respectively. We’ll briefly discuss them, just enough to lay the groundwork for the more interesting ones, the X and Z.

Description and Working

Logic Level 0: 0

The logic level 0 represent a logical 0 or a false value. In most of the cases logic level 0 represents a voltage level of 0 volts (or ground). We’ll follow this convention for the purpose of simplicity.

Conversation with reg

Logic value 0 is usually represented by 0 volts or GND.

Logic Level 1: 1

Logical value 1 represents the logical complement of logic level 0.

\[1 = \text{True} = \overline{0}\]

Logic level 1 as per our convention will represent the supply voltage (VCC or VDD).

Conversation with reg

Logic value 1 is usually represented by VCC or VDD.

Unknown Value: X

Conversation with reg

When Joe meets the reg for the first time, things doesn't go the way he anticipated.

When Verilog cannot decide the output logic level of a net or a variable, the output would be set to ‘X’. Say, for example, you have a reg, and you didn’t specify the default value or set it during runtime. In that case, the hardware wouldn’t know what it should output. What Verilog does to represents this scenario is to tell you that the wire could have either 1 or 0, by using the value ‘X’.

A different point of view for the same thing is saying that the net or reg value can either be 0 or 1, but we don’t know which one of them it is.

Few example use of unkown value is:

  1. Case statements: matching multiple values in a case statement
always @(some_signal) begin
    select @(other_signal) begin
        case 5'b0000x: begin 
            // Selects the case 5'b00000 and 5'b00001
        end 
        case 5'b1111x: begin
            // Selects the case 5'b11110 and 5'b11111
        end
        default: begin
            // All the other cases
        end
    endcase
end

High Impedance: Z

Before understanding what high impedance value in Verilog is, it is important to understand what high impedance means in real-life electronics. High impedance state is often used in digital circuits/electronics to refer to an output which cannot drive any other input (i.e., an open circuit). Say, for example, a wire which is unconnected at one end is used as input to a gate. Now, to the gate that input would appear as an open circuit, or a circuit with infinite resistance. This is what the electrical engineers call a high-impedance state.

So, in verilog whenever you have a net type or a variable type which isn’t being driven (connected to some output for net type and holds a ‘Z’ value for the variable type) provides the high impedance value.

Few important points to note regarding high impedance is that not all of its use will be synthesizable. Following list presents few such example:

Assigning high impedance state to reg:
reg out; // Declare a reg
initial begin
    // Non-synthesizable assignment.
    out = 1'bz;
end
The case equality operator (=== and !==):

A case comparison equality can compare all the 4 values with each other unlike the logical equality operator where the rules are more real world like (e.g. if one of the operands is 1’bz the output will be 1’bx).

always @(some_signal) begin
    // Non-synthesizable comparison
    if (some_signal === 1'bz) begin
        other_signal = ~other_signal;
    end

    // Another non-synthesizable comparison
    if (some_signal !== 1'bz) begin
        clk_gen = ~clk_gen;
    end
end

And now, a few examples where the high impedance state will be useful (and synthesizable):

Desining bi-directional bus:

Bi-directional buses are special kind of buses that allow the signal to flow in either direction. The direction is controlled by a master signal. An example of this is:

module bidirectional_bus(bibus, control);
   inout [4-1:0] bibus;
   input         control;
   
   reg [4-1:0]   internal_var;
   
   // The bibus is assigned a high impedance value if it used as an input
   // otherwise the value from reg 'internal_var' is assigned to it as an
   // output
   bibus = (control == 1'b1) ? 4'bzzzz : internal_var;
   
   always @(some_condition) begin
       internal_var = internal_var + 4'b0001;
   end
endmodule

References

  1. 1364-2005 IEEE Standard for Verilog Hardware Description Language. 2006. doi:10.1109/IEEESTD.2006.99495. ISBN 0-7381-4850-4.