I/O Interface: Interrupt & DMA Mode
Input and output are slow by many orders of magnitude. A processor executes an instruction in a nanosecond; a disk answers a request in milliseconds. Every technique in this chapter exists to stop that gap from wasting processor time.
Two questions separate the three transfer methods. Who waits for the device to become ready — the processor, or the device itself? And who actually moves each byte between the device and memory?
| Method | Who waits | Who moves the data |
|---|---|---|
| Programmed I/O | Processor | Processor |
| Interrupt-driven I/O | Device | Processor |
| DMA | Device | DMA controller |
Each step down that table removes the processor from more of the work, and the cost is more hardware in the controller.
That single table organises the whole topic, and almost every question is asking which row applies or what it costs.
1. Programmed I/O
The processor checks a status register in a loop until the device reports readiness, then transfers a byte itself.
The loop is the problem. During it the processor executes instructions that accomplish nothing, and the number of wasted instructions is the device latency divided by the loop iteration time.
For a device ready every millisecond and a loop taking 100 nanoseconds, the processor executes about 10,000 useless iterations per byte.
Programmed I/O is nevertheless correct and sometimes right. It has no hardware cost beyond a status register, its timing is completely predictable, and for a device that is almost always ready — or in an embedded system with nothing else to do — polling can beat the overhead of an interrupt.
2. Interrupt-Driven I/O
The device signals the processor when it becomes ready, so the processor does other work in the meantime.
The processor checks for a pending interrupt at the end of every instruction, which is why interrupts are recognised between instructions rather than during one, and why a long instruction delays recognition.
On recognising an interrupt, the hardware saves enough state to resume — at minimum the program counter and status flags — disables further interrupts, and jumps to the service routine. The routine saves any registers it will use, transfers the byte, acknowledges the device, restores the registers and returns.
The saving is real but not total. Each transfer now costs a context save, the service routine and a context restore, typically tens to hundreds of cycles, instead of thousands of polling iterations — but still per byte.
That per-byte overhead is precisely what DMA removes.
3. Interrupt Structure
Several devices may interrupt, so the mechanism must identify the source and resolve simultaneous requests.
Non-vectored interrupts jump to a fixed address, and the routine there polls each device to find which one signalled. Simple, and slow in proportion to the number of devices.
Vectored interrupts have the device supply an identifier, which indexes an interrupt vector table holding the address of the correct routine. Identification costs one table lookup regardless of the number of devices.
Priority resolution takes two forms.
Daisy chaining passes an acknowledge signal physically through the devices in series. The first device that requested service intercepts it, so priority is fixed by physical position on the chain. It is cheap — one signal line — and inflexible.
Independent requesting gives each device its own request and acknowledge line, with a priority encoder resolving conflicts. Priority is programmable and identification is immediate, at the cost of two lines per device.
A maskable interrupt can be disabled by software, which is what allows a critical section to run without interference. A non-maskable interrupt cannot, and is reserved for conditions where ignoring the signal would be worse than any timing disruption — power failure, memory parity error.
Nested interrupts are permitted by re-enabling interrupts inside a service routine, but only for higher-priority sources, or a low-priority device could preempt a high-priority one.
4. Direct Memory Access
A DMA controller moves data between the device and memory without the processor touching each byte.
The processor sets up the transfer and is then uninvolved until it completes. It writes the memory address, the transfer count and the direction into the controller's registers, and issues a start command.
The controller then requests the bus, transfers a word, increments the address, decrements the count, and repeats. When the count reaches zero it raises a single interrupt, so the processor is interrupted once per block rather than once per byte.
That is the entire benefit: the per-byte overhead becomes a per-block overhead.
The controller and the processor both need the bus, and this is the one cost DMA cannot avoid. Each transferred word requires one bus cycle that the processor cannot use, which is called cycle stealing.
The processor is not interrupted in the software sense — no context is saved and no routine runs — but it does stall for that cycle if it needed the bus then.
5. DMA Transfer Modes
Three modes differ in how the controller shares the bus.
| Mode | Behaviour | Effect on processor |
|---|---|---|
| Cycle stealing | One word per bus acquisition | Slight slowdown, spread out |
| Burst (block) | Whole block in one acquisition | Processor stalls for the duration |
| Transparent | Transfers only in cycles the processor does not use the bus | No slowdown, slowest transfer |
Cycle stealing is the usual compromise. The controller takes one bus cycle, releases it, and requests again for the next word, so the processor's slowdown is spread thinly rather than concentrated.
Burst mode gives the fastest transfer and the worst latency for everything else, which suits a device that must not be starved — a disk with a rotating platter cannot wait.
Transparent mode is free but slow, and it is practical only when the processor leaves enough bus cycles idle, which a cache-equipped processor often does.
The distinction to hold is that cycle stealing steals bus cycles, not instructions: the processor keeps executing whenever it does not need the bus.
6. I/O Addressing
Two schemes decide how the processor names a device register.
Memory-mapped I/O places device registers in the ordinary memory address space. Any instruction that can access memory can access a device, so no special instructions are needed and the full range of addressing modes applies.
The cost is address space: every address given to a device is unavailable to memory. On a machine with a small address space this matters, and on a large one it does not.
Isolated or port-mapped I/O gives devices a separate address space reached by dedicated instructions, and a control line tells the system which space an address refers to.
The full memory space stays available, and device accesses are visibly distinct in the instruction stream, which helps protection. The cost is extra instructions, extra control lines, and the loss of general addressing modes on device registers.
Memory-mapped I/O also interacts with caching, and the interaction is a real hazard. A device register whose value changes on its own must never be cached, since a cached copy would hide the change. Such regions are therefore marked non-cacheable, which is a requirement the isolated scheme avoids by construction.
7. Buses and Arbitration
A bus is a shared set of lines, and sharing requires arbitration: deciding which master drives it next.
Daisy-chain arbitration passes a grant signal serially, giving fixed priority by position, with one line.
Polling arbitration has the arbiter address each master in turn on a set of poll lines; priority is programmable by changing the polling order, at the cost of lines.
Independent request arbitration gives each master its own request and grant pair, resolving with a priority encoder. It is fastest and needs lines.
The pattern matches interrupt priority resolution exactly, because it is the same problem: several requesters, one resource, and a choice between wiring cost and flexibility.
A synchronous bus times every transfer against a shared clock, which is simple and fast but forces every device to complete within the fixed period, so the slowest device sets the pace.
An asynchronous bus uses a handshake — request and acknowledge — so each transfer takes exactly as long as the device needs. Fast devices are not slowed by slow ones, at the cost of the handshake overhead on every transfer.
8. Worked Examples
Example 1. A device transfers data at 40 KB per second. Compare the processor overhead under programmed I/O, interrupt-driven I/O costing 60 cycles per byte, and DMA costing 800 cycles per 4 KB block, on a 2 GHz processor.
Under programmed I/O the processor is fully occupied polling, so the overhead is effectively 100 per cent of the time the transfer is active. No useful work proceeds.
Under interrupt-driven I/O the device delivers 40,000 bytes per second, each costing 60 cycles.
Cycles per second million.
As a fraction of 2 GHz, that is per cent.
Under DMA, 40 KB per second is 10 blocks of 4 KB per second, each costing 800 cycles of setup and completion handling.
Cycles per second , which is per cent of the processor.
Interrupt-driven I/O reduces the overhead by three orders of magnitude compared with polling, and DMA reduces it by another 300 times. The remaining DMA cost is cycle stealing on the bus, which this calculation excludes because it is a bus-bandwidth cost rather than a processor-time cost.
Example 2. A DMA controller transfers 4 KB blocks using cycle stealing on a 32-bit bus, with each bus cycle taking 10 ns. How much bus time does one block consume, and what fraction of the bus does a 5 MB per second stream occupy?
A 32-bit bus moves 4 bytes per cycle, so a 4 KB block needs bus cycles.
At 10 ns each, one block occupies ns, about 10.24 microseconds.
A 5 MB per second stream is blocks per second.
Bus time consumed per second , which is 12.5 ms.
As a fraction of one second, that is 1.25 per cent of the bus.
The processor therefore retains almost 99 per cent of the bus bandwidth, which is why cycle-stealing DMA is described as causing only a slight slowdown. The figure would be far worse with an 8-bit bus, which would need four times as many cycles for the same data.
Example 3. Four devices are daisy chained for interrupt priority. Devices 2 and 4 request service simultaneously. Which is served, and what changes with independent requesting?
In a daisy chain, the acknowledge signal passes through the devices in physical order, and the first device that has an outstanding request intercepts it.
Device 2 is earlier in the chain than device 4, so device 2 intercepts the acknowledge and is served. Device 4's request remains pending until the chain is re-enabled.
Priority is therefore fixed by physical position, and changing it means physically rewiring the chain.
With independent requesting, each device has its own request line into a priority encoder. The encoder resolves the conflict according to whatever priority the encoder implements, which can be programmable.
If device 4 were configured as higher priority, it would be served first — an impossibility in the daisy chain without rewiring.
The trade is wiring: a daisy chain needs one acknowledge line for any number of devices, while independent requesting needs a request and an acknowledge line each, so eight lines for four devices.
Example 4. Why does a memory-mapped device register have to be marked non-cacheable, and what goes wrong if it is not?
A cache exists on the assumption that memory changes only when the processor writes to it. A device register violates that assumption, because the device can change the register's value on its own — a status bit setting when data arrives, for instance.
If the register were cacheable, the first read would fetch the value into the cache. Every subsequent read would hit in the cache and return the stale copy, and the processor would never observe the device becoming ready.
A polling loop would spin forever on a value that stopped reflecting reality.
Writes have a mirror problem under a write-back cache. A command written to a device register would sit in the cache marked dirty and reach the device only on eviction, at an unpredictable time — or never, if the line is discarded.
The fix is to mark the address region non-cacheable, so every access goes to the device. Isolated I/O avoids the issue by construction, since device accesses use a separate address space that the cache does not cover.
The same hazard appears with DMA even without device registers. A DMA controller writing to memory bypasses the cache, so a cached copy of that memory becomes stale, which is why systems must either invalidate the affected lines or route DMA through a coherent path.
Example 5. A processor polls a keyboard that produces a character every 100 ms, with a poll loop of 5 instructions taking 4 ns total. Compute the wasted instructions per character and the fraction of processor time consumed if 10 such devices are polled.
The loop takes 4 ns and must run until the device is ready, which is up to 100 ms.
Iterations per character million.
At 5 instructions each, that is 125 million wasted instructions per character.
For 10 devices polled in rotation, the processor spends essentially all of its time in the polling loop, since it never has an opportunity to do anything else.
Contrast with interrupts. At a service cost of, say, 200 cycles per character and 10 characters per second across all devices, the total is 2,000 cycles per second, which on a 2 GHz processor is one part in a million.
The arithmetic explains why interactive devices were the original motivation for interrupts: their data rates are trivially low but their latencies are enormous, which is the worst possible case for polling.
Example 6. Compare synchronous and asynchronous bus timing for a system containing both a 5 ns memory and a 200 ns device.
On a synchronous bus, every transfer occupies a fixed number of clock periods, and the period must be long enough for the slowest device to respond.
With a 200 ns device, the clock period must accommodate it, so even an access to the 5 ns memory takes the full period. The fast memory is slowed by a factor of 40 by the presence of the slow device.
A common mitigation is wait states: the bus runs at the fast period, and slow devices assert a wait signal that extends their own transfers by whole clock periods. This recovers most of the fast memory's speed at the cost of a wait mechanism.
On an asynchronous bus, each transfer uses a request-acknowledge handshake, so it completes as soon as the responding device signals completion.
The memory access finishes in roughly 5 ns plus handshake overhead, and the device access takes 200 ns plus the same overhead. Neither is slowed by the other.
The cost is that handshake overhead on every transfer, which for the fast memory may be comparable to the access itself, and the greater complexity of the control logic. This is why real systems commonly use a synchronous bus with wait states rather than a fully asynchronous one.
Summary
Every I/O method answers two questions: who waits for the device, and who moves the bytes.
Programmed I/O has the processor do both, wasting cycles in proportion to device latency, but costs no hardware and is predictable.
Interrupt-driven I/O lets the device wait, reducing overhead to a context save and service routine per byte, and interrupts are recognised at instruction boundaries.
Vectored interrupts identify the source by table lookup; non-vectored ones poll. Daisy chaining fixes priority by physical position with one line, while independent requesting makes it programmable at two lines per device.
Non-maskable interrupts exist for conditions where ignoring the signal is worse than any timing disruption.
DMA removes the processor from the per-byte path entirely: it sets up the transfer and receives one interrupt per block. The residual cost is cycle stealing on the bus, not processor time.
Cycle-stealing mode spreads the slowdown thinly, burst mode transfers fastest but stalls everything else, and transparent mode is free but slow.
Memory-mapped I/O costs address space and requires non-cacheable regions; isolated I/O keeps the memory space intact at the cost of special instructions and control lines.
Bus arbitration mirrors interrupt priority exactly, with the same trade between wiring cost and flexibility.
A synchronous bus is simple but paced by its slowest device unless wait states are added; an asynchronous bus lets each transfer take the time it needs, at a handshake cost on every one.