# How Data Moves Inside a Machine

> The roads and traffic signals inside your computer: what a bus is, how the CPU reads and writes RAM by address, how it reaches out to devices, and how interrupts let a device get the CPU's attention the instant something happens.


---

# How Data Moves Inside a Machine

You know the parts by now - CPU, RAM, disk, keyboard, screen. But a list of parts isn't a machine. The
machine is what happens *between* them: the wiring that carries bytes from one chip to another, the
numbering scheme that lets the CPU say exactly *where* it wants data, and the signals that let a device
tap the CPU on the shoulder and say "I'm ready." This guide is about that in-between - the roads and the
traffic signals.

If you've ever wondered how a keypress gets from the keyboard into your program *instantly*, or why
copying a big file doesn't pin your CPU at 100%, the answers all live here.

> ⏭️ New to the hardware picture? Skim [How a Computer Works](/guides/how-a-computer-works) and
> [CPU, RAM, and Storage](/guides/cpu-ram-and-storage) first, then come back - this guide assumes you
> know what those parts are and zooms into how they *talk*.

## How to read this
- **Want the core idea fast?** Read [Phase 1: Buses & Addresses](01-buses-and-addresses.md) - it's the
  foundation the other two phases build on.
- **Want it to finally make sense?** Read in order. Each phase adds one layer: the wiring, then reaching
  devices over that wiring, then how devices signal back.

## The phases
1. **[Buses & Addresses](01-buses-and-addresses.md)** - what a bus *actually is* (shared wiring), how
   every byte of RAM has a number, and how the CPU reads and writes memory over the memory bus.
2. **[How the CPU Talks to Devices (I/O)](02-how-the-cpu-talks-to-devices.md)** - reaching past RAM to
   disks, keyboards, and network cards; memory-mapped I/O vs ports; and DMA, the trick that lets a device
   move data without bothering the CPU for every byte.
3. **[Interrupts - Getting the CPU's Attention](03-interrupts.md)** - how a device says "I have data
   ready" without the CPU constantly checking, why that's the difference between polling and interrupts,
   and why it's what makes a computer feel responsive.

> This guide stays at the "how it works" level. Cache hierarchies, bus protocols like PCIe by the wire,
> and how the OS wires up interrupt handlers are deeper topics for follow-up guides - we'll point you
> toward [What an Operating System Is](/guides/what-an-operating-system-is) where the software side picks
> up.


---

# Buses & Addresses

When your CPU wants a number out of RAM, how does it *get* it? The CPU is one chip; the RAM is another,
centimeters away. Something physical has to connect them, and the CPU needs a way to name *which* of the
billions of numbers it wants. Those two things - wiring and addressing - are the foundation of how data
moves.

## A bus: the shared wiring

A **bus** is a set of wires shared by multiple components, used to carry data between them. Not a
metaphor - literal parallel wires (or traces on the motherboard) that every connected chip can drive and
read.

📝 **Terminology.** *Bus* = shared wiring that carries data between components - from the old "omnibus"
idea: one shared line everything rides, rather than a private wire between every pair of parts.

The tempting picture is dedicated cables - CPU to RAM, CPU to disk, CPU to keyboard. Early designs mostly
worked the *other* way: one shared bus many components hang off, so you can add a component without
rewiring everything else.

```mermaid
flowchart TD
    CPU["CPU"] --- BUS
    RAM["RAM"] --- BUS
    Disk["Disk"] --- BUS
    BUS{{"the bus<br/>(shared wiring)"}}
    BUS -.- note["every connected part<br/>can send and receive"]
```

The catch: only one conversation can happen at a time - two components driving the same wires at once
would garble each other. So a bus needs rules about *who talks when*; in the simple picture, the CPU
decides. (Real machines add nuance - multiple buses, devices that can take the wheel - but "the CPU runs
the bus" is the right starting model.)

## Addresses: every byte of RAM has a number

RAM is an enormous row of byte-sized slots, and **every slot has its own number, called its address**:
the first byte is address 0, the next is 1, and so on. An address is nothing more exotic than "which
slot."

📝 **Terminology.** *Address* = the number that identifies one specific storage location. *Byte* = the
unit each address points at - 8 bits, enough to hold one number from 0 to 255, or one character.

```text
   address:    0      1      2      3      4      5    ...
             ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐
      RAM:   │ 72 │ │ 01 │ │ FF │ │ 00 │ │ 6A │ │ .. │   each slot holds one byte;
             └────┘ └────┘ └────┘ └────┘ └────┘ └────┘   each has a fixed number
```

An address turns "somewhere in memory" into "exactly here." When a program holds a variable, what it
really holds underneath is an address - *where* the value lives.

📝 **Terminology.** *Pointer* = a value whose contents are a memory address. It "points at" the data
living at that address instead of holding the data directly.

⚠️ **Gotcha.** Addresses are just numbers, so a program can compute a *wrong* one - pointing at a slot it
has no business touching. That's the root of a whole family of bugs and security holes (out-of-bounds
reads, use-after-free). The OS and CPU wall each program into its own range of addresses; reach outside
it and you get the famous "segmentation fault." That's physical addressing; the OS adds virtual memory on
top, which is its own guide.

## How the CPU reads and writes RAM

Put the two ideas together. The CPU and RAM are connected by the **memory bus**. To move a byte, the bus
carries three things: an **address** (which slot), a **command** (read or write), and - for a write -
the **data** itself.

```mermaid
flowchart LR
    CPU["CPU"] -->|"address: slot 4096"| RAM["RAM"]
    CPU -->|"command: READ"| RAM
    RAM -->|"data: the byte 0x6A"| CPU
```

A **read**: the CPU puts the address on the bus and signals "read"; RAM finds that slot and puts its
byte back on the bus. A **write** is the mirror image: the CPU puts the address *and* the data on the
bus, signals "write," and RAM stores the byte.

The wires have jobs: the lines carrying *which slot* are the **address bus**, the lines carrying *the
actual byte(s)* are the **data bus**, and a few control lines carry *read vs. write*. People say "the
bus" for all of them together.

A concrete picture - the CPU runs an instruction meaning "load the byte at address 4096 into a register":

```text
   CPU → bus:   address = 4096,  control = READ
   RAM → bus:   data    = 0x6A         (the byte that was sitting in slot 4096)
   CPU:         stores 0x6A in a register, moves on to the next instruction
```

*What just happened:* the CPU didn't "reach into" RAM. It *asked* over shared wiring - named the slot,
named the operation - and RAM answered on the same wiring. Every variable read, every value written,
every instruction fetched is a version of this request-and-answer, billions of times a second.

Once you see memory as "numbered slots reached over a bus," a lot stops being mysterious. Why is RAM
faster than disk? Partly because it's wired close on a fast bus built for exactly this. Why does "more
bandwidth" speed things up? Wider/faster buses move more bytes per second. Why can a pointer bug corrupt
unrelated data? Addresses are just numbers, and the wrong number points at the wrong slot.

## Recap

1. A **bus** is shared wiring between components - flexible because many parts hang off it, constrained
   because only one transfer happens at a time.
2. Every byte of RAM has an **address** - a plain number naming one slot. A **pointer** is just a value
   holding an address.
3. The CPU reads and writes RAM over the **memory bus** by putting an **address** and a **read/write**
   command on the wires (plus the **data**, for a write). It asks; RAM answers.

Next, we follow those wires *past* RAM - to the disk, the keyboard, the network card - and meet the trick
that lets a device move data without making the CPU babysit every byte.


---

# How the CPU Talks to Devices (I/O)

In Phase 1 the only thing on the far end of the bus was RAM. But the CPU also needs to talk to the disk,
the keyboard, the network card, the GPU - and you already have the mental model: addresses and a bus,
pointed at hardware instead of RAM. The payoff is the last section, where a device learns to move data
*by itself*.

## I/O: reaching past RAM

**I/O** - input/output - is the CPU exchanging data with anything that isn't its own registers or RAM.
Input is data coming *in* (a keypress, a packet arriving, bytes read from disk); output is data going
*out* (pixels to the screen, bytes written to disk, a packet sent).

📝 **Terminology.** *Device* = any piece of hardware that isn't the CPU or main memory - disk, keyboard,
network card, GPU, USB stick.

A device isn't a blob of storage like RAM; it has controls. A disk controller has a spot you write "read
sectors 100–200" into, a spot you read status from ("busy" / "done" / "error"), and a spot data flows
through: the device's **registers**. The CPU's whole conversation with a device is reading and writing
them. The question is *how* the CPU addresses them - two classic answers, and every machine uses one or
both.

## Two ways to address a device

### Memory-mapped I/O

The system reserves a chunk of the address space and wires it to a device instead of to RAM. The device's
registers get **real memory addresses**, so the CPU talks to the device using the *exact same*
read/write-an-address mechanism from Phase 1 - address 0xFE00 just leads to the network card instead of
a memory slot.

```text
   one address space, carved up:

   0x0000 ┌──────────────────────────┐
          │   RAM                     │   normal memory slots
          │                           │
   0xFE00 ├──────────────────────────┤
          │   network card registers  │   ← a write here goes to the DEVICE,
          │   disk controller regs    │     not to a memory chip
   0xFFFF └──────────────────────────┘
```

The elegance: the CPU needs *no special instructions* - "write this value to that address" already
exists. The downside: those addresses are spent, they can't also be RAM - one reason a 32-bit machine
with 4 GB installed sometimes can't use all 4 GB: some of the range is claimed by devices.

### Port I/O

The other approach gives devices their own separate numbering - **ports** - living *outside* the memory
address space, reached with dedicated CPU instructions (on x86, literally `in` and `out`). Port 0x60 is
the keyboard controller; an `in` from port 0x60 reads the latest key.

📝 **Terminology.** *Port* (in this hardware sense) = a device's address in a separate I/O address space,
accessed with special I/O instructions rather than normal memory reads and writes. (This is *not* the
same thing as a network port like 443 - same word, different world.)

Neither is "better"; it's a design trade-off:

```text
   ┌──────────────────┬─────────────────────────────┬──────────────────────────────┐
   │                  │  Memory-mapped I/O           │  Port I/O                    │
   ├──────────────────┼─────────────────────────────┼──────────────────────────────┤
   │  Addressing      │  shares the memory address   │  separate I/O address space   │
   │                  │  space with RAM              │                               │
   │  CPU support     │  none extra - normal load/   │  needs special instructions   │
   │                  │  store instructions          │  (e.g. in / out)              │
   │  Cost            │  uses up memory addresses    │  keeps memory space free, but  │
   │                  │                              │  adds a separate mechanism    │
   └──────────────────┴─────────────────────────────┴──────────────────────────────┘
```

Modern systems lean heavily on memory-mapped I/O because reusing the memory mechanism is simpler and
scales to big, fast devices. Port I/O survives mostly for older/simpler peripherals.

## DMA: letting the device do the carrying

Suppose you're reading a one-megabyte file off the disk into RAM. With everything so far, the CPU would
do it the slow way:

```text
   the CPU doing it by hand ("programmed I/O"):

   read byte from disk register  →  write byte to RAM  →  repeat
   read byte from disk register  →  write byte to RAM  →  repeat
   ... one million times, with the CPU busy the entire time ...
```

A performance catastrophe: the fastest, most valuable thing in the machine is stuck shoveling bytes one
at a time - and while it shovels, your music can't decode and your UI can't redraw.

**DMA - Direct Memory Access** - is a small dedicated helper (a *DMA controller*, often built into the
device itself) that can read and write RAM *over the bus on its own*, without routing every byte through
the CPU. The CPU sets up the job once, then steps away.

📝 **Terminology.** The "direct" in *Direct Memory Access* means *direct to memory, around the CPU*.

The conversation becomes a delegation:

```mermaid
sequenceDiagram
    participant CPU
    participant DMA as DMA controller
    participant RAM
    CPU->>DMA: read 1 MB from disk into RAM at Y
    Note over CPU: goes off and does other work
    loop block by block, no CPU involved
        DMA->>RAM: move the megabyte itself
    end
    DMA-->>CPU: done (an interrupt, Phase 3)
```

*What just happened:* the CPU described the transfer, handed the grunt work to the DMA controller, and
went back to real work. The megabyte still travels over the bus - but the *CPU* isn't carrying each byte.
One setup, one "done" at the end, instead of a million round trips.

⚠️ **Gotcha.** DMA and the CPU share the same bus (Phase 1: only one transfer at a time). While DMA hauls
a big block, the CPU may have to wait its turn for the bus - so DMA isn't "free," it just frees the CPU
from *doing the copy*. The win is overwhelming anyway: the CPU runs real work during almost all of the
transfer.

This is why a big file copy, a video stream, or a busy network connection doesn't peg one CPU core at
100%. Disks, network cards, GPUs, and sound cards all use DMA so the CPU stays free for actual
computation. Throughput high while CPU usage stays modest = DMA doing its job. And a driver that "sets up
a DMA buffer" is doing exactly this: handing the device an address range in RAM and saying "fill this
yourself."

## Recap

1. **I/O** is the CPU exchanging data with devices, and to the CPU a device looks like a set of
   **registers** it reads and writes.
2. Those registers are reached either by **memory-mapped I/O** (real memory addresses, reusing the Phase 1
   mechanism) or by **port I/O** (a separate I/O address space with special instructions) - a trade-off,
   not a winner.
3. **DMA** lets a device move data to and from RAM by itself. The CPU sets up the transfer once and walks
   away, which is why moving lots of data doesn't tie up the processor.

But when the DMA controller finishes, it has to *tell* the CPU. How does a device get the CPU's
attention without the CPU constantly checking? The last piece: interrupts.


---

# Interrupts - Getting the CPU's Attention

Phase 2 left a thread dangling: when DMA finished moving a file, it had to tell the CPU "I'm done." And
your keyboard has a byte ready the moment you press a key. So *how does a device get the CPU's
attention?* The CPU is busy running your program - it can't read minds. There are exactly two ways, and
the difference is a sluggish machine versus a snappy one.

## The slow way: polling

**Polling** means the CPU repeatedly *asks* - "are you ready yet?" - checking a device's status register
in a loop until the answer is yes.

```text
   polling loop (the CPU asking, over and over):

   check keyboard status →  nothing
   check keyboard status →  nothing
   check keyboard status →  nothing          ← thousands of pointless checks
   check keyboard status →  nothing             while you decide what to type
   check keyboard status →  KEY READY!  →  read it
```

Think about your keyboard: between keystrokes, whole tenths of a second pass - an eternity to a CPU.
Polling it would mean asking "ready?" millions of times and hearing "no" almost every time, while real
work waits. Polling burns the CPU to *watch* instead of letting it *work*.

⚠️ **Gotcha - polling isn't always wrong.** If you *know* the answer is coming in nanoseconds (a
super-fast device, a tight low-latency loop), polling can beat the alternative: you skip the overhead of
being interrupted. The point isn't "polling bad" - it's that polling for rare or unpredictable events
wastes enormous CPU. A keyboard is exactly the wrong fit.

## The fast way: interrupts

An **interrupt** is a signal from a device meaning "stop for a moment - I have something for you."
Instead of the CPU checking the device, the device *taps the CPU on the shoulder* the instant it has
news.

📝 **Terminology.** *Interrupt* = a hardware signal that makes the CPU pause its current work, jump to a
small piece of code to handle the event, then resume exactly where it left off. *Interrupt handler* (or
*interrupt service routine*) = that small piece of code that deals with the event.

When you press a key, the keyboard controller raises an interrupt. The CPU, mid-instruction-stream on
your program, finishes the current instruction, then:

```mermaid
sequenceDiagram
    participant Program as Your program
    participant CPU
    participant Keyboard
    Note over CPU: running your program
    Keyboard->>CPU: interrupt signal (you pressed a key)
    Note over CPU: save place
    CPU->>Keyboard: handler reads the key
    Keyboard-->>CPU: the key
    Note over CPU: restore place
    CPU->>Program: resume, right where it was
```

*What just happened:* the CPU bookmarked exactly where it was (saved its registers and position), ran a
short **handler** that grabbed the key, then restored the bookmark and carried on. Your program never
knew it was briefly set aside. The key was noticed the *moment* you pressed it - not on the next poll,
because there is no poll.

This is precisely how DMA reports in: the controller raises an interrupt to say "done," calling the CPU
back exactly when there's finally something to do - no polling the disk in a loop.

## Why interrupts are what make a computer feel alive

Almost everything you interact with is event-driven and unpredictable: keystrokes, mouse moves, clicks,
packets arriving, a timer firing. None of it is on a schedule the CPU could guess.

- **With polling**, the CPU would constantly stop and check every device "just in case," shredding its
  time on questions that mostly answer "no."
- **With interrupts**, the CPU runs flat-out on real work and is pulled aside *only* when something
  genuinely happens - and then *immediately*.

```text
   polling:     work? CHECK CHECK CHECK work? CHECK CHECK work? CHECK ...
                (attention sprayed everywhere, most checks wasted)

   interrupts:  ████ real work ████ ▮tap▮ ████ real work ████ ▮tap▮ ████
                (full focus, redirected the instant - and only when - needed)
```

That "only when needed, but instantly" property is why your cursor tracks your hand with no lag, why a
keypress shows up the moment you make it, and why a download finishing pops a notification right away.
Responsiveness *is* interrupts.

It also explains real-world vocabulary: an **interrupt storm** is a misbehaving device tapping so often
the CPU can't get real work done (a real cause of mysterious system slowdowns), and a "busy-wait" or
"spin loop" eating 100% CPU is usually polling where an interrupt or sleep belonged. When you profile a
program pegged at full CPU doing "nothing," ask whether it's polling something it should be waiting on.
The fix is almost always "stop asking; get told."

## Recap

1. A device gets the CPU's attention one of two ways: **polling** (the CPU keeps asking) or **interrupts**
   (the device signals the CPU).
2. **Polling** wastes CPU on events that arrive rarely or unpredictably - though it can win for events you
   know are coming in nanoseconds.
3. An **interrupt** makes the CPU pause, run a short **handler**, and resume exactly where it left off -
   so events are handled the instant they happen.
4. Interrupts let the CPU stay focused on real work yet react immediately - why a computer feels
   **responsive**, and how DMA, the keyboard, the network, and timers all report in.

The full picture: bytes ride **buses**, the CPU names locations by **address**, it reaches devices
through **I/O** and offloads bulk movement to **DMA**, and devices call back through **interrupts**. The
roads and the traffic signals - the whole in-between that turns a pile of parts into a machine.

> ⏭️ Ready to see the software side take over? [What an Operating System Is](/guides/what-an-operating-system-is)
> picks up here - the OS is the code that sets up those DMA buffers and wires up those interrupt handlers.
> See also [How Devices Connect](/guides/how-devices-connect) for how peripherals plug into all this.
