public interface MachineI {
MemoryI getMem ();
ProcessorI getProc ();
ioUnitI getIO ();
/**
* Tests each component of the machine. For example, attempts to
* store a number in a known memory location, and then read that
* location, etc.
*/
void selfTest ();
}
//------------------------------------------
public interface ioUnitI {
/**
* The default underlying byte-oriented input stream.
*/
java.io.InputStream DEFAULT_ISTREAM = System.in;
/**
* The default underlying byte-oriented output stream.
*/
java.io.OutputStream DEFAULT_OSTREAM = System.out;
java.io.PrintWriter getWriter ();
java.io.StreamTokenizer getReader ();
/**
* A call to readData reads one integer from the input stream. The call
* will block until there is something to read.
* @exception ioE If the input cannot be parsed as a number.
*/
Word readData () throws ioE;
void writeData (Word w);
}
//------------------------------------------
public interface ProcessorI {
ALUI getALU ();
Word fetchPC ();
Word fetchACC ();
Instruction fetchIR ();
void storePC (Word newpc);
void storeACC (Word newacc);
void storeIR (Instruction newir);
}
Machine,
Processor, and ioUnit that implement the
appropriate interfaces. Write any additional classes that you need to
make your code compile and run properly:
The I/O unit communicates with the outside world using streams.
Intuitively streams are unbounded sequences of values. The
java.io package supports streams extensively.
Underlying any Java stream is a stream of bytes. Such byte streams
called InputStream and OutputStream are
low-level and rarely used directly in applications. For our purposes,
we would like to view the input stream as carrying a sequence of
numbers and we would also like to write arbitrary values to the output
stream. We can achieve this with a bit of work.
First, we move from byte streams to character streams using the
classes InputStreamReader and
OutputStreamWriter. The read and write operations on
these streams handle only one character at a time (which maycorrespond
to more than one byte on the underlying byte stream). For efficiency,
these streams are usually wrapped using a BufferedReader
and BufferedWriter.
Next, we can automatically convert a stream of characters to a
stream of "tokens" where tokens represent entities such as strings,
numbers, etc. This is achieved using the rather flexible class
StreamTokenizer. The behavior of this class can be
parameterized by a number of flags so you will need to consult the API
before using it. Symmetrically, we can write arbitrary Java objects
to a character stream by first wrapping it in a
PrintWriter stream.
All inputs to our machine are numbers that are converted to
integers and stored in the memory. A call to the method
readData may throw an exception if the input cannot be
parsed as a number. More importantly, the call will block waiting for
input if there are no characters to read from the input stream. This
is consistent with the intuitive behavior of programs: if a program is
requesting an input value, then it will wait (block) until that value
is supplied.