Shared buses place many devices on one set of wires, so each device must be able to let go. That release is high impedance, and it gives a wire four values.
Value | Meaning |
|---|---|
0 | Driven low. |
1 | Driven high. |
| Released: nobody drives. |
| Unknown: usually a clash or unset. |
Watch the bottom row, bus. On a phone, swipe the diagram sideways to see the clash.
e1/d1 are driver 1 enable/data and e2/d2 are driver 2 enable/data.
Slot 1: nobody drives, so bus = z.
Slot 2: driver 1 is enabled with 0, so bus = 0.
Slot 3: driver 1 drives 1, so bus = 1.
Slot 4: driver 2 adds 0 while driver 1 drives 1, so bus = x.
Slot 5: both released, so bus = z.
Only one driver at a time. If two drivers disagree, the net becomes x. In real hardware that is a short circuit.
This table is the whole story.
Driver 1 | Driver 2 | Net value | Why |
|---|---|---|---|
0 | z | 0 | Only driver 1 is active. |
1 | z | 1 | Only driver 1 is active. |
z | z | z | Nobody drives the net. |
1 | 1 | 1 | Both agree. |
0 | 1 | x | Contention: conflicting drivers. |
The 1-plus-1 row holds because both drivers agree.
x. A 0-versus-1 clash is contention.
z. Nobody drives the net, so its value is undefined until something drives or pulls it.
1. Only driver 1 is active, so its value wins.
module tri_driver (
input wire d, oe,
output wire y
);
assign y = oe ? d : 1'bz; // drive d when enabled, otherwise release the net
endmoduleDrives d when oe is 1.
Releases the net (z, disconnected) when oe is 0, so others can drive.
Net type is wire or tri: only nets allow several drivers.
One pad drives and receives through the same net:
module bidir_pin (
inout wire pad,
input wire drive_en,
input wire drive_val,
output wire sampled
);
assign pad = drive_en ? drive_val : 1'bz; // drive the pad when enabled
assign sampled = pad; // always read the pad level
endmoduleDo | Avoid |
|---|---|
Sample | Assuming |
Enable one driver at a time | Enabling two drivers that can disagree sends the net to |
x. Any 0-versus-1 clash gives x, no matter how many drivers agree.
This testbench checks every row of the resolution table.
module tb_tristate;
reg d1, e1, d2, e2;
tri bus;
assign bus = e1 ? d1 : 1'bz;
assign bus = e2 ? d2 : 1'bz;
int errors = 0;
initial begin
e1 = 1; d1 = 0; e2 = 1; d2 = 1; #1;
if (bus !== 1'bx) errors++; // 0 versus 1: contention
e1 = 1; d1 = 1; e2 = 1; d2 = 1; #1;
if (bus !== 1'b1) errors++; // both drive 1: agree
e1 = 0; e2 = 0; #1;
if (bus !== 1'bz) errors++; // nobody drives
e1 = 1; d1 = 0; e2 = 0; #1;
if (bus !== 1'b0) errors++; // one driver
e1 = 1; d1 = 1; e2 = 0; #1;
if (bus !== 1'b1) errors++; // sole driver high: the remaining table row
if (errors == 0) $display("PASS: tri-state resolution table confirmed");
else $display("FAIL: tri-state resolution errors=%0d", errors);
$finish;
end
endmodule