Wednesday, March 26, 2025

Entry 12: Tri-state output and tri-state buffer

The goal now is to make the "register" from entry 9 "bus-friendly" by making the output "tri-state" using a tri-state buffer.

Tri-state outputs

Grok:

Tri-state outputs (or three-state outputs) are a feature in digital electronics where an output pin can be in one of three states—not just the usual two (0 or 1). This is super useful when multiple devices share a common connection, like a data bus. Let’s break it down.


The Three States

  1. Logic 0 (Low): The output is actively driven to ground (~0V). Current flows out of the pin to ground.
  2. Logic 1 (High): The output is actively driven to the supply voltage (~5V for TTL/CMOS). Current flows into the pin from the supply.
  3. High-Impedance (Z): The output is effectively disconnected—it neither drives high nor low. It acts like an open switch, letting other devices control the line without interference.
  • Normal Outputs: Only 0 or 1 (e.g., your 74HC74’s Q pins).
  • Tri-State Outputs: 0, 1, or Z (e.g., 74LS173’s Q0–Q3 when controlled by G1/G2).

Why It’s Useful

Imagine a shared wire

  • Without Tri-State: If two devices output at once (e.g., one says 0, another says 1), they fight—current flows between them, causing damage or garbage data.
  • With Tri-State: Only one device is enabled at a time (outputs 0 or 1), while others are in Z-state (disconnected). No conflict!
-end-

So, here is how we can check if an output pin is 0, 1, or "Z":

Logic 0:

If an LED turns on when connected to the output, as in the picture, the output is low.

Logic 1:

If an LED turns on when connected to the output, as in the picture, the output is high.

High-Impedance (Z):

If the LED does not turn on in any of the cases, the output is in state Z.

In order to make the output of our register tri-state, we need four tri-state buffers between Q0–Q3 and the bus. This lets you enable/disable the register’s output. 

Let's begin by investigating a single tri-state buffer.

Tri-state buffer

A single tri-state buffer is a simple yet powerful digital building block that lets you control whether a signal passes through to its output or gets disconnected, making it perfect for connecting devices to a shared bus—like your 4-bit register setup. It’s the key to the tri-state outputs we’ve been discussing, and understanding how it works at the gate and transistor level ties together a lot of what you’ve been exploring. Let’s dig into its operation.


What It Does

  • Inputs:
    • A (Data Input): The signal you want to pass (0 or 1).
    • EN (Enable): Controls whether the output is active or high-impedance (Z).
  • Output (Y):
    • When enabled: Y = A (0 or 1).
    • When disabled: Y = Z (high-impedance, disconnected).

Truth table:

A tri-state buffer cannot be constructed from basic gates. Instead, it is typically implemented with transistors. Like basic gates, I will not investigate the electronics behind it.

The 74LS126 has 4 tri-state buffers:

ACEL also has tri-state buffers.

Tri-state buffer in ACEL

The tri-state buffer in ACEL is called ThreeStateSwitch

  • The input is labeled D (for data)
  • Enable is labeled E
  • The output is labeled W (for write)

Here is how we can try it out. Add two buttons "D" and "E" to control the inputs. Here is the code, where D is connected to pin 2 and E to pin 3:

  auto* TriStateBuffer = new ThreeStateSwitch();

  //Add all chips to be emulated here
  Chip* chips[] = {
    TriStateBuffer
  };

  //Add all connections here
  ConnectionBase* connections[] = {
    new Connection(ard, 2, TriStateBuffer->D),
    new Connection(ard, 3, TriStateBuffer->E),
  };

It is not possible to connect the output W to an Arduino pin using a "Connection", since W is tri-state (cannot make an output pin floating in Arduino). Hower, this is not really an issue, as the output of a tri state buffer will "go on a bus".

Instead, we can use the "print" functionality to investigate the tri-state buffer. Instead of clicking a button to get a print, we can add the line

  emulation.printOnArdEvent(1);

in the setup section. We then automatically get a "print" each time anything happens. 


You can check this out on Wokwi, project name "Tri state buffer".

The goal of the next entry is to complete the connection between the register and the bus adding 4 tri-state buffer.


Entry 11: Data Bus

In entry 9, we designed a first version of a 4 bit register. Looking at the architecture of a simple CPU shows that registers are connected to an internal data bus

Bus

Grok: A bus in electronics and computing is a set of shared electrical pathways (wires or traces) that multiple devices use to communicate data, addresses, or control signals within a system. Think of it as a highway where different components—like the CPU, memory, or registers—take turns sending or receiving information. It’s a key concept in a microprocessor. Let’s break it down.


What Is a Bus?

  • Definition: A collection of parallel conductors (wires) that carry signals between components.
  • Purpose: Simplifies connections—instead of wiring every device to every other device, they all connect to the bus and share it.
  • Analogy: A bus is like a phone party line—everyone’s on the same line, but only one talks at a time.

Types of Buses

  1. Data Bus:
    • Carries actual data (e.g., your 4-bit binary numbers).
    • Width: Number of bits it handles at once.
    • Bidirectional: Data flows both ways (e.g., memory to CPU or CPU to memory).
  2. Address Bus:
    • More on this later
  3. Control Bus:
    • More on this later

How a Bus Works

  • Shared Lines: All devices connect to the same wires (e.g., 4 wires for a 4-bit data bus).
  • Turn-Taking: Only one device drives the bus at a time to avoid conflicts (e.g., two devices outputting 0 and 1 simultaneously).
  • Tri-State Outputs: 
    • Drive the bus (0 or 1) when enabled.
    • Disconnect (Z) when not their turn, letting others take over.

-end-

Here is a nice picture of SAP-1, Simple as possible-1 "computer".



A bunch of "stuff" is connected to a bus, labeled "W bus", running along the middle of the image. This is a 8 bit bus, consisting of 8 wires. The arrows indicate if the component "puts data on the bus" or "reads data from the bus"

Register and Bus

The next question is how to "connect" my register to a bus. Groks curated answer:

Connecting your simple 4-bit register (built from four D flip-flops, like your setup) to a 4-bit data bus is straightforward, but there’s a catch: your register doesn’t have tri-state outputs natively, which are crucial for bus operation. Without tri-state capability, it will always drive the bus (Q outputs are always 0 or 1), potentially clashing with other devices. I’ll show you how to connect it as-is, then add a tri-state buffer to make it bus-friendly, tying it to your earlier projects. -end-

This makes sense. Each output pin of my register is always 0 or 1. Connecting two registers to the bus, like this, would not work:
Say that Q0 of register 1 is 1 (effectively connected to +5V) and Q0 of register 2 is 0 (effectively connected to ground), we would then have a direct connection from +5V to ground, a "short circuit".  We need to make sure that at most one register is connected to the bus at one moment in time. Each output pin of a register should be either 0, 1, or "disconnected".

So, to make our register "bus-friendly", we must investigate the tri-state buffer. This is the next entry.