Instructions for Lab 8

A Graphical Interface for the Machine

The main program creates a hardware machine, a graphical interface for the machine, and connects the two with special streams called pipes. A pipe is a stream with two ends: one part of the program writes data at one end, and another part of the program reads data from the other end. In both Unix and DOS, pipes are commonly used to connect the output of one process to the input of the next. For example, the commands "ls | more" and "dir | more" list the contents of the current directory and send the output to the command "more" that displays it one page at a time.

The code is: (save it in a file "duckMachine/Window.java")

import java.io.*;
  
import duckMachine.architecture.*;
import duckMachine.operatingSystem.*;
import duckMachine.GUI.*;

/**
 * The graphical interaction with the machine.
 * @author Amr Sabry
 * @version jdk-1.1
 */

public class Window {
  /**
   * The machine and the graphical interface communicate via pipes.
   * The machine knows nothing about the interface, but the interface
   * needs to know the machine's state to display it.
   */
  public static void main (String args[]) {
    try {
      // create two pipes, and pass them to the machine constructor.
      PipedInputStream machineInPipe = new PipedInputStream();
      PipedOutputStream machineOutPipe = new PipedOutputStream();
      MachineI mach = new Machine(machineInPipe, machineOutPipe);

      // connect the machineOutPipe to the GUI's input pipe
      PipedInputStream guiInPipe = new PipedInputStream(machineOutPipe);
      // connect the machineInPipe to the GUI's output pipe
      PipedOutputStream guiOutPipe = new PipedOutputStream(machineInPipe);
      // create a (non visible) frame that displays the state of the machine
      // and uses guiInPipe and guiOutPipe to communicate with the machine
      // The class MachineFrame is defined in the GUI package.
      MachineFrame shell = new MachineFrame(mach, guiInPipe, guiOutPipe);

      // display the frame ...
      shell.setLocation(100,100);
      shell.pack();
      shell.show();
    }
    catch (Throwable e) { // no exceptions should reach this point!!!
      e.printStackTrace();
      throw new Error("Unexpected error");
    }
  }
} 

To do

You will have to define three classes for this homework: all belong to the GUI package.

ALUPanel

An ALUPanel object is a graphical component responsible for displaying the values of the ALU flags. More precisely an ALUPanel specializes (and hence inherits) from the class java.awt.Panel:
public class ALUPanel extends Panel 
The constructor for the class takes the machine's ALU as an argument:
  public ALUPanel (duckMachine.architecture.ALUI alu) { 
The constructor should create graphical components to display the values of the ALU flags, and "add" them to the current panel. (You can look at the graphical representation I chose by running my program, but please feel free to modify and improve on my interface.) To function properly, the class must have a method:
  public void updatePanel (ALUI alu) 
that should update the display by reading the new values of the ALU flags. This method will be called by other parts of the program whenever we need to refresh the display with a new machine state.

CommThread

A CommThread object encapsulates a ShellCommand (loadCommand, runCommand, stepCommand) and implements the Runnable interface so that we can run that command in a thread of its own:
public class CommThread implements Runnable
The constructor of the class takes two arguments that it saves in appropriate instance variables:
  private ShellCommand command;
  private MachineFrame machineFrame;

  public CommThread (ShellCommand c, MachineFrame pf) {
    command = c;
    machineFrame = pf;
  }
The class has one public method required by the interface Runnable:
  public void run () {
    try {
      command.execCommand(machineFrame.mach);
      machineFrame.refresh();
      machineFrame.controlPanel.endCommand();
    }
    catch (ShellE e) { // due to machine error
      machineFrame.controlPanel.reportError(e.toString());
    }
  }
The actions performed in the new thread are to execute the machine command, refresh the panel to reflect the new machine status, and notify the control panel that we are done.

ControlPanel

A ControlPanel object is a graphical object to control the machine. It displays 4 buttons "load", "run", "step", and "stop" and arranges for clicks on these buttons to send the appropriate command to the machine. It delegates the processing of the commands "load", "run", and "step" to other objects, but handles the "stop" commands itself. The declaration formalizes the two purposes of the object: first it is a graphical object (a Panel); second it listens to events (implements the ActionListener interface).
public class ControlPanel extends Panel implements ActionListener 
The constructor for the class takes one argument:
  public ControlPanel (MachineFrame mf) 
which it saves in an instance variable. The constructor also creates and adds to the current panel two graphical components: The ControlPanel class has the following five public methods that we will discuss in detail:
  public void startCommand (Runnable command)
  public void endCommand ()

  public void reportStatus (String message)
  public void reportError (String message) 

  public void actionPerformed (ActionEvent evt) 
The control panel must create a thread to run machine commands. Otherwise machine commands that block waiting for input, or that go in infinite loops, would cause the interface to hang. The methods:
  public void startCommand (Runnable command)
  public void endCommand ()
manage the command threads. We will only allow one command thread to run at a time (otherwise we would have to support concurrent programs running on our hardware machine). The method startCommand checks that no other commands are running, and if none are running, creates a new thread and starts it. If some other command is running, we refuse to start the new command, and display an error message on the errPort using the method reportError. The method endCommand simply records that no commands are running so that we can start a new command. When creating a thread, you must be careful to give it a low priority so that you can kill it if required. As expected, the two methods:
  public void reportStatus (String message)
  public void reportError (String message) 
just display messages on the errPort. I display status messages in green, and error messages in red. The method:
  public void actionPerformed (ActionEvent evt) 
will be called when the Stop button is pushed. It is required because we implement the interface ActionListener. The method should stop the thread running the current command.


Visited times since December 15, 1997 (or the last crash).

sabry@cs.uoregon.edu