memory-mapped I/O
/ MEM-ory mapped I-O /
How does a CPU, which only knows how to read and write memory addresses, talk to a printer or a disk? The trick is a disguise: pretend the device is memory. Memory-mapped I/O assigns each device's control registers their own addresses in the same address space the CPU uses for ordinary memory. To command a device, the CPU just does a normal load or store to a magic address — and instead of a memory cell, it reads or writes a register inside a device controller. It is like a hotel where some room numbers are not real rooms but service buttons: pressing the button at room 500 calls housekeeping.
Concretely, the hardware reserves a range of addresses that route not to RAM but to device controllers. Writing the value 1 to address 0xFE000000 might set a 'start transfer' bit in a disk controller; reading address 0xFE000004 might return a status word saying 'busy' or 'done'. The CPU needs no special instructions — the same load and store it uses for memory work for devices. The alternative, called port-mapped or port I/O, gives devices a separate address space reached only by special in and out instructions; memory-mapped I/O is the more common approach today because it reuses the ordinary instruction set.
Two honest caveats. First, device registers are not ordinary memory: reading one can have side effects (reading a status register might clear it), and the values can change on their own, so this memory must not be cached or speculatively accessed — software marks these regions specially. Second, a chunk of the address space is consumed by devices, which historically is one reason a 32-bit machine could not use a full 4 GB of RAM: some of those addresses were spoken for by I/O.
A tiny driver writes a byte to the device's data register at address 0x3F8 and then spins reading the status register at 0x3F8+5 until a 'transmit ready' bit is set. To the CPU these are just stores and loads; to the UART controller they mean 'send this character' and 'are you ready?'.
The same load/store instructions reach a device because its registers live at ordinary-looking addresses.
Memory-mapped device regions must be marked non-cacheable. If the cache held a stale copy of a status register, the CPU would read old values and miss the device's updates — a classic, baffling driver bug.