Communicating with a device involves reading and writing
registers that are part of the device controller.
Memory-mapped I/O sets aside some memory addresses
to represent those registers. There is no memory associated
with those addresses. Instead, whenever a value is
stored to one of those addresses, the value is stored
in a device register instead. When the value at
one of those memory addresses is fetched, the contents
of the device register is returned to the processor.
Memory-mapped I/O has the advantage that communication
with devices can be done with ordinary memory store and
fetch instructions. That allows device drivers to be
written in a higher level language, such as C, rather
than in assembly language.