Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations36
  • Combinational Design25
    • Combinational Timing Overview
    • Muxes, Decoders and Encoders
    • Arithmetic Blocks
    • Comparators and Shifters
    • Tri-State and Shared Buses
      • Tri-State Basics
      • Bus Holders, Floating Nets and Wired Logic
      • When Not to Use Internal Tri-State in ASIC RTL
    • Latch Inference
    • Arithmetic Datapaths
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Tri-State and Shared Buses
  1. Topics
  2. RTL Design
  3. Combinational Design
  4. Tri-State and Shared Buses
  5. Bus Holders, Floating Nets and Wired Logic

Part 2 · Combinational · Intermediate

Bus Holders, Floating Nets and Wired Logic

A released net floats: pulls, keepers and wired-logic nets that give it a value.

On this page

    Why this matters

    A bus that nobody drives reads z in simulation, but in silicon the wire drifts and a receiver can draw extra current or flip. An I2C line only works because a pull-up supplies the 1.

    After this lesson you can: choose a pull-up, pull-down, keeper or default driver for a floating net, and model open-drain lines with tri1 and wand.

    Give a floating net a resting value

    When every driver releases a net, simulation reads z. In silicon the wire is a small capacitor that drifts with leakage and noise.

    A receiver sitting at an intermediate voltage can draw excess current or flip randomly. A shared bus therefore needs a resting value:

    Fix

    How

    Trade-off

    Pull-up / pull-down resistor

    Weakly drives the net to 1 or 0 when nobody else does

    Simple; wastes current when another driver pulls the other way; slow edge.

    Bus keeper (bus holder)

    A weak latch that remembers the last driven value

    Almost no settled static current, apart from leakage; holds the last value rather than a fixed one, so it does not guarantee a startup state, and a driver must be strong enough to override it (briefly drawing override current).

    Always drive it

    Add a default driver, or use a mux (see next lesson)

    Cleanest; costs a little logic.

    Verilog has net types that model the pull behaviour: tri0 resolves to 0 and tri1 to 1 when undriven.

    Watch w_tri, w_tri1 and w_tri0. On a phone, swipe the diagram sideways.

    • Slot 1: released (en is 0, d is ignored): w_tri reads z, w_tri1 reads 1, w_tri0 reads 0.

    • Slot 2: driven 1 (en is 1, d is 1): all three read 1.

    • Slot 3: driven 0 (d is 0): all three read 0.

    • Slot 4: released again: w_tri reads z, w_tri1 reads 1, w_tri0 reads 0.

    • Slot 5: still released, so the resting values hold.

    Wired logic and net types

    wand (wired-AND) and wor (wired-OR) resolve multiple active drivers with an AND or OR instead of producing x. They model open-drain or open-collector buses, where any device can pull the line low.

    Net type

    Undriven

    Drivers 1 and 0 together

    Models

    wire / tri

    z

    x

    Ordinary net

    tri0

    0

    x

    Pull-down

    tri1

    1

    x

    Pull-up

    wand

    z

    0

    Open-drain / wired-AND

    wor

    z

    1

    Wired-OR

    Open-drain buses such as I²C use a pull-up resistor plus devices that only pull low. Any device pulling low wins, which is a wired-AND of the devices' release signals.

    An open-drain line. The resistor pulls the line to 1; each device is a switch to ground that closes when its pull-low signal is 1. The table lists all four combinations.

    Read the circuit as switches: a device whose pull-low signal is 1 shorts the line to ground; a device at 0 is an open switch.

    • Both released (first table row): no path to ground, so the resistor pulls the line to 1.

    • Either pulls low: the closed switch wins over the weak resistor, so the line reads 0.

    • No clash: two devices pulling low together still give 0, so open-drain lines cannot short a 1 against a 0.

    In RTL model the line as tri1, and let each device drive either 0 or z, never a hard 1: with both devices released, the pull-up supplies the 1. A bare wand is different. With every driver released it reads z, not 1, so a wand open-drain line also needs a pull-up (for example a pullup primitive on that net). Declaring the net in simulation does not install a pull-up in the real system.

    Check yourself Why does an open-drain bus need a pull-up, and what does a device drive to send a 1?

    Because devices can only pull the line low or release it. To send a 1 a device releases the line (drives z), and the pull-up brings it high. Without the pull-up, a released line would float.

    The testbench below checks the open-drain contract directly with two devices that each drive 0 or z: both released, either one low, and both low.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    module tb_open_drain;
      tri1 bus;                          // the pull-up supplies the released level
      wand wbare;                        // no pull-up on this one
      logic a_low, b_low;                // 1 = device pulls the line low, 0 = releases it
      assign bus   = a_low ? 1'b0 : 1'bz;
      assign bus   = b_low ? 1'b0 : 1'bz;
      assign wbare = a_low ? 1'b0 : 1'bz;
      assign wbare = b_low ? 1'b0 : 1'bz;
      int errors = 0;
    
      initial begin
        for (int i = 0; i < 4; i++) begin
          a_low = i[1];
          b_low = i[0];
          #1;
          if (bus !== ((a_low || b_low) ? 1'b0 : 1'b1)) errors++;   // released -> pulled to 1
          if ((a_low || b_low) && wbare !== 1'b0) errors++;          // any low device wins
          if (!a_low && !b_low && wbare !== 1'bz) errors++;          // bare wand: released is z
        end
        if (errors == 0) $display("PASS: open-drain bus is 1 only when both release; a bare wand needs its own pull-up");
        else $display("FAIL: errors=%0d", errors);
        $finish;
      end
    endmodule

    Common mistakes

    Interview

    Likely question: “What holds a bus when nobody drives it?”

    • Pull-up or pull-down gives a fixed resting value.

    • Keeper retains the last driven value with only leakage once settled; it cannot set a startup value, and a driver must overpower it.

    • Open-drain drives 0 or releases, and the pull-up makes the 1.

    Do

    Avoid

    Give every shared net a resting value (tri1, tri0, keeper, or default driver)

    Leaving a CMOS input floating, where it can sit mid-rail and draw current

    Drive an open-drain line with 0 or z only

    Driving a hard 1 onto a shared line that others can pull low

    Check yourself Nobody drives a plain tri net. Predict what a receiver reads in simulation.

    z. Nobody drives the net. In silicon the voltage floats, so give it a pull-up, pull-down, keeper, or default driver.

    Check yourself Every driver releases a tri1 net. Predict its value.

    1. tri1 resolves to 1 when undriven, and tri0 resolves to 0. With drivers 1 and 0 together, both still give x.

    Testbench

    This testbench checks pulls, wired logic, and the plain-net clash.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    module tb_nets;
      timeunit 1ns; timeprecision 1ps;
      tri0 pd;                              // undriven -> 0
      tri1 pu;                              // undriven -> 1
      wand w;  assign w = 1'b1;  assign w = 1'b0;     // two drivers: 1 AND 0
      wor  o;  assign o = 1'b1;  assign o = 1'b0;     // two drivers: 1 OR 0
      tri  plain;  assign plain = 1'b1;  assign plain = 1'b0;   // plain net: conflict
      int errors = 0;
    
      initial begin
        #1;
        if (pd !== 1'b0) errors++;          // pulled down when nobody drives
        if (pu !== 1'b1) errors++;          // pulled up when nobody drives
        if (w  !== 1'b0) errors++;          // wired-AND of 1 and 0
        if (o  !== 1'b1) errors++;          // wired-OR of 1 and 0
        if (plain !== 1'bx) errors++;       // normal net: contention
        if (errors != 0) $fatal(1, "FAIL: tb_nets errors=%0d (pd=%b pu=%b w=%b o=%b plain=%b)", errors, pd, pu, w, o, plain);
        $display("PASS: tri0/tri1/wand/wor behave as described");
        $finish;
      end
    endmodule

    Remember

    • tri1 resolves to 1 and tri0 to 0 when undriven; drivers of 1 and 0 together still give x.

    • An open-drain device drives 0 or z, never a hard 1. The pull-up makes the 1.

    • A bare wand reads z when every driver releases, so it needs a pull-up too.

    Rule of thumb: give every shared net a resting value.

    Keep going

    • Interview: run a mock interview on this topic

    Related topics

    • When not to use internal tri-state

    Previous

    52 / 350

    Next: When Not to Use Internal Tri-State in ASIC RTL

    Up next

    Up nextWhen Not to Use Internal Tri-State in ASIC RTL

    Sign in to save progress

    Practice this lessonReport an error
    clkendw_triw_tri1w_tri0
    One driver released and driven, seen through tri, tri1 and tri0