Program-controlled I/O (also called polling) is the simplest way to talk to an I/O device: the processor sits in a tight loop reading the device’s STATUS register, waiting for it to indicate “ready,” then reads or writes the DATA register. The whole interaction is driven by the processor’s running program.
The structure of a polling loop:
WAIT:
LoadByte R4, DEVICE_STATUS # read status
And R4, R4, #READY_BIT # mask out the ready bit
Branch_if_Zero R4, WAIT # loop until ready
LoadByte R5, DEVICE_DATA # now read data
Read status, check the ready flag, branch back to start if not ready. Once the flag is set, do the transfer.
Worked example: read a line from the keyboard
Move R2, #LOC ; R2 points to memory buffer
Move R3, #CR ; Load Carriage Return ASCII
READ:
# Poll keyboard
LoadByte R4, KBD_STATUS
And R4, R4, #2 ; Check Bit 1 (KIN)
Branch_if_Zero R4, READ ; loop if not ready
LoadByte R5, KBD_DATA ; Read Data (clears KIN)
StoreByte R5, (R2) ; Store in memory
Add R2, R2, #1 ; Increment pointer
ECHO:
# Poll display
LoadByte R4, DISP_STATUS
And R4, R4, #4 ; Check Bit 2 (DOUT)
Branch_if_Zero R4, ECHO ; loop if not ready
StoreByte R5, DISP_DATA ; Write to display (clears DOUT)
# Check for Carriage Return to exit
Branch_if_Equal R5, R3, EXIT
Branch READ ; Get next character
EXIT:
The structure: poll keyboard → read character → poll display → echo character → check if it was Enter → repeat.
Pros
- Simple. No interrupts, no special hardware, no asynchronous behavior to reason about.
- Predictable timing. You know exactly when each byte gets read.
- Easy to debug. Single thread of control.
Cons
- Wastes CPU cycles. A keyboard might wait seconds between keypresses, but the processor spins flat-out checking the status. A 3 GHz CPU running a tight 4-instruction polling loop iterates about 750 million times per second — so per second of idle, that’s hundreds of millions of useless iterations.
- Can’t do other work. While polling, the processor isn’t running anything else.
- Latency depends on the polling rate. If the loop is slow (the processor is doing other things between polls), characters can be missed if the device buffer fills up.
The waste is what motivates interrupts — let the device alert the processor when it’s ready, and the processor can do useful work in the meantime.
When polling is still right
Polling isn’t always wrong. It’s the right choice when:
- The device transfers data continuously and at a high rate (e.g., reading from a fast disk into a tight loop — interrupts would just add overhead).
- The processor has nothing else to do.
- The interrupt mechanism is unavailable or unreliable.
- Latency must be minimal and deterministic (real-time systems sometimes prefer polling over interrupts for jitter reasons).
For most general-purpose computing, especially with slow human-input devices like keyboards and mice, interrupts win. But polling is the right starting point for understanding I/O — get the basic mechanism, then add asynchrony.