To accomplish these tasks, the controller has a command set (more or less a set of instructions that it knows how to execute) that it accepts as its input. When the software wants the controller to start an output, it sends it a command indicating that. The controller also has an output. The output indicates the current state of the controller, e.g., "ready to accept an output command" or "a keyboard input character is available".
Given this, it is the software's responsibility to use the controller correctly. For output, the software must do this:
When the software wants to read a character, it must do this:
The details of how this work depend on the controller. We'll be using SMOK's Character Controller Device. Its documentation tell you what the controller's command set is, and what the controllers output bits mean.
We could create new opcodes for this: RFCC
(Read From Character
Controller) and WTCC
(Write To Character Controller). That
would work, but the downside is that we'd need a different pair of opcodes
for each controller attached to our system. Besides being cumbersome, that
would make it impossible to attach controllers that were designed after the
processor was built (since the processor wouldn't have the needed opcodes).
Instead of using new opcodes, we note that sending commands to the
controller is basically a store
operation: "Take the
contents of this register and send it to.... Similarly, reading
the controller's output is basically a load
: "Get ... and
put it in this register."
So, instead of special opcodes, we'll just use sw
and
lw
.
How can that work? How does the machine know we want to talk with
the character controller, rather than memory, on a sw
or
lw
? The answer is that we use a special address to indicate
that we really mean the controller, not memory. In particular, Cebollita uses
the address 0x40000000. A sw
to that address should take the
register contents and store it to the character controller (and not anywhere
in memory), and a lw
from that address puts the character
controller's output into a register.
To get this to work is relatively simple: you just need to add enough control
to notice that the instruction is a lw
or sw
and
that the address is 0x40000000. Under those conditions, you route the data
to/from the character controller, and (if it's a sw
) you do NOT
cause the memory interface to do a write.