Source code of MARS Assembler
First commit of the 4.5 version (latest version available)
This commit is contained in:
@@ -0,0 +1,819 @@
|
||||
package mars.tools;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import mars.*;
|
||||
import mars.util.*;
|
||||
import mars.tools.*;
|
||||
import mars.mips.hardware.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
|
||||
|
||||
Developed by Pete Sanderson (psanderson@otterbein.edu)
|
||||
and Kenneth Vollmar (kenvollmar@missouristate.edu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject
|
||||
to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
(MIT license, http://www.opensource.org/licenses/mit-license.html)
|
||||
*/
|
||||
|
||||
/**
|
||||
* An abstract class that provides generic components to facilitate implementation of
|
||||
* a MarsTool and/or stand-alone Mars-based application. Provides default definitions
|
||||
* of both the action() method required to implement MarsTool and the go() method
|
||||
* conventionally used to launch a Mars-based stand-alone application. It also provides
|
||||
* generic definitions for interactively controlling the application. The generic controls
|
||||
* for MarsTools are 3 buttons: connect/disconnect to MIPS resource (memory and/or
|
||||
* registers), reset, and close (exit). The generic controls for stand-alone Mars apps
|
||||
* include: button that triggers a file open dialog, a text field to display status
|
||||
* messages, the run-speed slider to control execution rate when running a MIPS program,
|
||||
* a button that assembles and runs the current MIPS program, a button to interrupt
|
||||
* the running MIPS program, a reset button, and an exit button.
|
||||
* Pete Sanderson, 14 November 2006.
|
||||
*/
|
||||
public abstract class AbstractMarsToolAndApplication extends JFrame implements MarsTool, Observer {
|
||||
protected boolean isBeingUsedAsAMarsTool = false; // can use to determine whether invoked as MarsTool or stand-alone.
|
||||
protected AbstractMarsToolAndApplication thisMarsApp;
|
||||
private JDialog dialog; // used only for MarsTool use. This is the pop-up dialog that appears when menu item selected.
|
||||
protected Window theWindow; // highest level GUI component (a JFrame for app, a JDialog for MarsTool)
|
||||
|
||||
// Major GUI components
|
||||
JLabel headingLabel;
|
||||
private String title; // descriptive title for title bar provided to constructor.
|
||||
private String heading; // Text to be displayed in the top portion of the main window.
|
||||
|
||||
// Some GUI settings
|
||||
private EmptyBorder emptyBorder = new EmptyBorder(4,4,4,4);
|
||||
private Color backgroundColor = Color.WHITE;
|
||||
|
||||
|
||||
private int lowMemoryAddress = Memory.dataSegmentBaseAddress;
|
||||
private int highMemoryAddress = Memory.stackBaseAddress;
|
||||
// For MarsTool, is set true when "Connect" clicked, false when "Disconnect" clicked.
|
||||
// For app, is set true when "Assemble and Run" clicked, false when program terminates.
|
||||
private volatile boolean observing = false;
|
||||
|
||||
// Several structures required for stand-alone use only (not MarsTool use)
|
||||
private File mostRecentlyOpenedFile = null;
|
||||
private Runnable interactiveGUIUpdater = new GUIUpdater();
|
||||
private MessageField operationStatusMessages;
|
||||
private JButton openFileButton, assembleRunButton, stopButton;
|
||||
private boolean multiFileAssemble = false;
|
||||
|
||||
// Structure required for MarsTool use only (not stand-alone use). Want subclasses to have access.
|
||||
protected ConnectButton connectButton;
|
||||
|
||||
|
||||
/**
|
||||
* Simple constructor
|
||||
* @param title String containing title bar text
|
||||
*/
|
||||
protected AbstractMarsToolAndApplication(String title,String heading) {
|
||||
thisMarsApp = this;
|
||||
this.title = title;
|
||||
this.heading = heading;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////// ABSTRACT METHODS ///////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Required MarsTool method to return Tool name. Must be defined by subclass.
|
||||
* @return Tool name. MARS will display this in menu item.
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
/**
|
||||
* Abstract method that must be instantiated by subclass to build the main display area
|
||||
* of the GUI. It will be placed in the CENTER area of a BorderLayout. The title
|
||||
* is in the NORTH area, and the controls are in the SOUTH area.
|
||||
*/
|
||||
protected abstract JComponent buildMainDisplayArea();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////// METHODS WITH DEFAULT IMPLEMENTATIONS //////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Run the simulator as stand-alone application. For this default implementation,
|
||||
* the user-defined main display of the user interface is identical for both stand-alone
|
||||
* and MARS Tools menu use, but the control buttons are different because the stand-alone
|
||||
* must include a mechansim for controlling the opening, assembling, and executing of
|
||||
* an underlying MIPS program. The generic controls include: a button that triggers a
|
||||
* file open dialog, a text field to display status messages, the run-speed slider
|
||||
* to control execution rate when running a MIPS program, a button that assembles and
|
||||
* runs the current MIPS program, a reset button, and an exit button.
|
||||
* This method calls 3 methods that can be defined/overriden in the subclass: initializePreGUI()
|
||||
* for any special initialization that must be completed before building the user
|
||||
* interface (e.g. data structures whose properties determine default GUI settings),
|
||||
* initializePostGUI() for any special initialization that cannot be
|
||||
* completed until after the building the user interface (e.g. data structure whose
|
||||
* properties are determined by default GUI settings), and buildMainDisplayArea()
|
||||
* to contain application-specific displays of parameters and results.
|
||||
*/
|
||||
public void go() {
|
||||
theWindow = this;
|
||||
this.isBeingUsedAsAMarsTool = false;
|
||||
thisMarsApp.setTitle(this.title);
|
||||
mars.Globals.initialize(true);
|
||||
// assure the dialog goes away if user clicks the X
|
||||
thisMarsApp.addWindowListener(
|
||||
new WindowAdapter() {
|
||||
public void windowClosing(WindowEvent e) {
|
||||
performAppClosingDuties();
|
||||
}
|
||||
});
|
||||
initializePreGUI();
|
||||
|
||||
JPanel contentPane = new JPanel(new BorderLayout(5,5));
|
||||
contentPane.setBorder(emptyBorder);
|
||||
contentPane.setOpaque(true);
|
||||
contentPane.add(buildHeadingArea(), BorderLayout.NORTH);
|
||||
contentPane.add(buildMainDisplayArea(), BorderLayout.CENTER);
|
||||
contentPane.add(buildButtonAreaStandAlone(), BorderLayout.SOUTH);
|
||||
|
||||
thisMarsApp.setContentPane(contentPane);
|
||||
thisMarsApp.pack();
|
||||
thisMarsApp.setLocationRelativeTo(null); // center on screen
|
||||
thisMarsApp.setVisible(true);
|
||||
initializePostGUI();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Required MarsTool method to carry out Tool functions. It is invoked when MARS
|
||||
* user selects this tool from the Tools menu. This default implementation provides
|
||||
* generic definitions for interactively controlling the tool. The generic controls
|
||||
* for MarsTools are 3 buttons: connect/disconnect to MIPS resource (memory and/or
|
||||
* registers), reset, and close (exit). Like "go()" above, this default version
|
||||
* calls 3 methods that can be defined/overriden in the subclass: initializePreGUI()
|
||||
* for any special initialization that must be completed before building the user
|
||||
* interface (e.g. data structures whose properties determine default GUI settings),
|
||||
* initializePostGUI() for any special initialization that cannot be
|
||||
* completed until after the building the user interface (e.g. data structure whose
|
||||
* properties are determined by default GUI settings), and buildMainDisplayArea()
|
||||
* to contain application-specific displays of parameters and results.
|
||||
*/
|
||||
|
||||
public void action() {
|
||||
this.isBeingUsedAsAMarsTool = true;
|
||||
dialog = new JDialog(Globals.getGui(), this.title);
|
||||
// assure the dialog goes away if user clicks the X
|
||||
dialog.addWindowListener(
|
||||
new WindowAdapter() {
|
||||
public void windowClosing(WindowEvent e) {
|
||||
performToolClosingDuties();
|
||||
}
|
||||
});
|
||||
theWindow = dialog;
|
||||
initializePreGUI();
|
||||
JPanel contentPane = new JPanel(new BorderLayout(5,5));
|
||||
contentPane.setBorder(emptyBorder);
|
||||
contentPane.setOpaque(true);
|
||||
contentPane.add(buildHeadingArea(), BorderLayout.NORTH);
|
||||
contentPane.add(buildMainDisplayArea(),BorderLayout.CENTER);
|
||||
contentPane.add(buildButtonAreaMarsTool(), BorderLayout.SOUTH);
|
||||
initializePostGUI();
|
||||
dialog.setContentPane(contentPane);
|
||||
dialog.pack();
|
||||
dialog.setLocationRelativeTo(Globals.getGui());
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method that will be called once just before the GUI is constructed in the go() and action()
|
||||
* methods. Use it to initialize any data structures needed for the application whose values
|
||||
* will be needed to determine the initial state of GUI components. By default it does nothing.
|
||||
*/
|
||||
protected void initializePreGUI() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that will be called once just after the GUI is constructed in the go() and action()
|
||||
* methods. Use it to initialize data structures needed for the application whose values
|
||||
* may depend on the initial state of GUI components. By default it does nothing.
|
||||
*/
|
||||
protected void initializePostGUI() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that will be called each time the default Reset button is clicked.
|
||||
* Use it to reset any data structures and/or GUI components. By default it does nothing.
|
||||
*/
|
||||
protected void reset() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs GUI header as label with default positioning and font. May be overridden.
|
||||
*/
|
||||
protected JComponent buildHeadingArea() {
|
||||
// OVERALL STRUCTURE OF MESSAGE (TOP)
|
||||
headingLabel = new JLabel();
|
||||
Box headingPanel = Box.createHorizontalBox();//new JPanel(new BorderLayout());
|
||||
headingPanel.add(Box.createHorizontalGlue());
|
||||
headingPanel.add(headingLabel);
|
||||
headingPanel.add(Box.createHorizontalGlue());
|
||||
// Details for heading area (top)
|
||||
headingLabel.setText(heading);
|
||||
headingLabel.setHorizontalTextPosition(JLabel.CENTER);
|
||||
headingLabel.setFont(new Font(headingLabel.getFont().getFontName(),Font.PLAIN,18));
|
||||
return headingPanel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The MarsTool default set of controls has one row of 3 buttons. It includes a dual-purpose button to
|
||||
* attach or detach simulator to MIPS memory, a button to reset the cache, and one to close the tool.
|
||||
*/
|
||||
protected JComponent buildButtonAreaMarsTool() {
|
||||
Box buttonArea = Box.createHorizontalBox();
|
||||
TitledBorder tc =new TitledBorder("Tool Control");
|
||||
tc.setTitleJustification(TitledBorder.CENTER);
|
||||
buttonArea.setBorder(tc);
|
||||
connectButton = new ConnectButton();
|
||||
connectButton.setToolTipText("Control whether tool will respond to running MIPS program");
|
||||
connectButton.addActionListener(
|
||||
new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (connectButton.isConnected()) {
|
||||
connectButton.disconnect();
|
||||
}
|
||||
else {
|
||||
connectButton.connect();
|
||||
}
|
||||
}
|
||||
});
|
||||
connectButton.addKeyListener(new EnterKeyListener(connectButton));
|
||||
|
||||
JButton resetButton = new JButton("Reset");
|
||||
resetButton.setToolTipText("Reset all counters and other structures");
|
||||
resetButton.addActionListener(
|
||||
new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
reset();
|
||||
}
|
||||
});
|
||||
resetButton.addKeyListener(new EnterKeyListener(resetButton));
|
||||
|
||||
JButton closeButton = new JButton("Close");
|
||||
closeButton.setToolTipText("Close (exit) this tool");
|
||||
closeButton.addActionListener(
|
||||
new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
performToolClosingDuties();
|
||||
}
|
||||
});
|
||||
closeButton.addKeyListener(new EnterKeyListener(closeButton));
|
||||
|
||||
// Add all the buttons...
|
||||
buttonArea.add(connectButton);
|
||||
buttonArea.add(Box.createHorizontalGlue());
|
||||
buttonArea.add(resetButton);
|
||||
buttonArea.add(Box.createHorizontalGlue());
|
||||
JComponent helpComponent = getHelpComponent();
|
||||
if (helpComponent != null) {
|
||||
buttonArea.add(helpComponent);
|
||||
buttonArea.add(Box.createHorizontalGlue());
|
||||
}
|
||||
buttonArea.add(closeButton);
|
||||
return buttonArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Mars stand-alone app default set of controls has two rows of controls. It includes a text field for
|
||||
* displaying status messages, a button to trigger an open file dialog, the MARS run speed slider
|
||||
* to control timed execution, a button to assemble and run the program, a reset button
|
||||
* whose action is determined by the subclass reset() method, and an exit button.
|
||||
*/
|
||||
|
||||
protected JComponent buildButtonAreaStandAlone() {
|
||||
// Overall structure of control area (two rows).
|
||||
Box operationArea = Box.createVerticalBox();
|
||||
Box fileControlArea = Box.createHorizontalBox();
|
||||
Box buttonArea = Box.createHorizontalBox();
|
||||
operationArea.add(fileControlArea);
|
||||
operationArea.add(Box.createVerticalStrut(5));
|
||||
operationArea.add(buttonArea);
|
||||
TitledBorder ac =new TitledBorder("Application Control");
|
||||
ac.setTitleJustification(TitledBorder.CENTER);
|
||||
operationArea.setBorder(ac);
|
||||
|
||||
// Top row of controls consists of button to launch file open operation,
|
||||
// text field to show filename, and run speed slider.
|
||||
openFileButton = new JButton("Open MIPS program...");
|
||||
openFileButton.setToolTipText("Select MIPS program file to assemble and run");
|
||||
openFileButton.addActionListener(
|
||||
new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JFileChooser fileChooser = new JFileChooser();
|
||||
JCheckBox multiFileAssembleChoose = new JCheckBox("Assemble all in selected file's directory",multiFileAssemble);
|
||||
multiFileAssembleChoose.setToolTipText("If checked, selected file will be assembled first and all other assembly files in directory will be assembled also.");
|
||||
fileChooser.setAccessory(multiFileAssembleChoose);
|
||||
if (mostRecentlyOpenedFile != null) {
|
||||
fileChooser.setSelectedFile(mostRecentlyOpenedFile);
|
||||
}
|
||||
// DPS 13 June 2007. The next 4 lines add file filter to file chooser.
|
||||
FileFilter defaultFileFilter = FilenameFinder.getFileFilter(Globals.fileExtensions, "Assembler Files", true);
|
||||
fileChooser.addChoosableFileFilter(defaultFileFilter);
|
||||
fileChooser.addChoosableFileFilter(fileChooser.getAcceptAllFileFilter());
|
||||
fileChooser.setFileFilter(defaultFileFilter);
|
||||
|
||||
if (fileChooser.showOpenDialog(thisMarsApp) == JFileChooser.APPROVE_OPTION) {
|
||||
multiFileAssemble = multiFileAssembleChoose.isSelected();
|
||||
File theFile = fileChooser.getSelectedFile();
|
||||
try {
|
||||
theFile = theFile.getCanonicalFile();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
// nothing to do, theFile will keep current value
|
||||
}
|
||||
String currentFilePath = theFile.getPath();
|
||||
mostRecentlyOpenedFile = theFile;
|
||||
operationStatusMessages.setText("File: "+currentFilePath);
|
||||
operationStatusMessages.setCaretPosition(0);
|
||||
assembleRunButton.setEnabled(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
openFileButton.addKeyListener(new EnterKeyListener(openFileButton));
|
||||
|
||||
operationStatusMessages = new MessageField("No file open.");
|
||||
operationStatusMessages.setColumns(40);
|
||||
operationStatusMessages.setMargin(new Insets(0, 3, 0, 3)); //(top, left, bottom, right)
|
||||
operationStatusMessages.setBackground(backgroundColor);
|
||||
operationStatusMessages.setFocusable(false);
|
||||
operationStatusMessages.setToolTipText("Display operation status messages");
|
||||
|
||||
mars.venus.RunSpeedPanel speed = mars.venus.RunSpeedPanel.getInstance();
|
||||
|
||||
// Bottom row of controls consists of the three buttons defined here.
|
||||
assembleRunButton = new JButton("Assemble and Run");
|
||||
assembleRunButton.setToolTipText("Assemble and run the currently selected MIPS program");
|
||||
assembleRunButton.setEnabled(false);
|
||||
assembleRunButton.addActionListener(
|
||||
new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
assembleRunButton.setEnabled(false);
|
||||
openFileButton.setEnabled(false);
|
||||
stopButton.setEnabled(true);
|
||||
new Thread(new CreateAssembleRunMIPSprogram()).start();
|
||||
}
|
||||
});
|
||||
assembleRunButton.addKeyListener(new EnterKeyListener(assembleRunButton));
|
||||
|
||||
stopButton = new JButton("Stop");
|
||||
stopButton.setToolTipText("Terminate MIPS program execution");
|
||||
stopButton.setEnabled(false);
|
||||
stopButton.addActionListener(
|
||||
new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
mars.simulator.Simulator.getInstance().stopExecution(null);
|
||||
}
|
||||
});
|
||||
stopButton.addKeyListener(new EnterKeyListener(stopButton));
|
||||
|
||||
JButton resetButton = new JButton("Reset");
|
||||
resetButton.setToolTipText("Reset all counters and other structures");
|
||||
resetButton.addActionListener(
|
||||
new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
reset();
|
||||
}
|
||||
});
|
||||
resetButton.addKeyListener(new EnterKeyListener(resetButton));
|
||||
|
||||
JButton closeButton = new JButton("Exit");
|
||||
closeButton.setToolTipText("Exit this application");
|
||||
closeButton.addActionListener(
|
||||
new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
performAppClosingDuties();
|
||||
}
|
||||
});
|
||||
closeButton.addKeyListener(new EnterKeyListener(closeButton));
|
||||
|
||||
|
||||
// Add top row of controls...
|
||||
//fileControlArea.add(Box.createHorizontalStrut(5));
|
||||
|
||||
Box fileDisplayBox = Box.createVerticalBox();
|
||||
fileDisplayBox.add(Box.createVerticalStrut(8));
|
||||
fileDisplayBox.add(operationStatusMessages);
|
||||
fileDisplayBox.add(Box.createVerticalStrut(8));
|
||||
fileControlArea.add(fileDisplayBox);
|
||||
|
||||
fileControlArea.add(Box.createHorizontalGlue());
|
||||
fileControlArea.add(speed);
|
||||
|
||||
// Add bottom row of buttons...
|
||||
|
||||
buttonArea.add(openFileButton);
|
||||
buttonArea.add(Box.createHorizontalGlue());
|
||||
buttonArea.add(assembleRunButton);
|
||||
buttonArea.add(Box.createHorizontalGlue());
|
||||
buttonArea.add(stopButton);
|
||||
buttonArea.add(Box.createHorizontalGlue());
|
||||
buttonArea.add(resetButton);
|
||||
buttonArea.add(Box.createHorizontalGlue());
|
||||
JComponent helpComponent = getHelpComponent();
|
||||
if (helpComponent != null) {
|
||||
buttonArea.add(helpComponent);
|
||||
buttonArea.add(Box.createHorizontalGlue());
|
||||
}
|
||||
buttonArea.add(closeButton);
|
||||
return operationArea;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Rest of the methods. Some are used by stand-alone (JFrame-based) only, some are
|
||||
// used by MarsTool (JDialog-based) only, others are used by both.
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Called when receiving notice of access to MIPS memory or registers. Default
|
||||
* implementation of method required by Observer interface. This method will filter out
|
||||
* notices originating from the MARS GUI or from direct user editing of memory or register
|
||||
* displays. Only notices arising from MIPS program access are allowed in.
|
||||
* It then calls two methods to be overridden by the subclass (since they do
|
||||
* nothing by default): processMIPSUpdate() then updateDisplay().
|
||||
* @param resource the attached MIPS resource
|
||||
* @param accessNotice AccessNotice information provided by the resource
|
||||
*/
|
||||
public void update(Observable resource, Object accessNotice) {
|
||||
if (((AccessNotice)accessNotice).accessIsFromMIPS()) {
|
||||
processMIPSUpdate(resource, (AccessNotice)accessNotice);
|
||||
updateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to process a received notice from MIPS Observable (memory or register)
|
||||
* It will only be called if the notice was generated as the result of MIPS instruction execution.
|
||||
* By default it does nothing. After this method is complete, the updateDisplay() method will be
|
||||
* invoked automatically.
|
||||
*/
|
||||
protected void processMIPSUpdate(Observable resource, AccessNotice notice) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when tool/app is exited either through the close/exit button or the window's X box.
|
||||
* Override it to perform any special housecleaning needed. By default it does nothing.
|
||||
*/
|
||||
protected void performSpecialClosingDuties() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add this app/tool as an Observer of desired MIPS Observables (memory and registers).
|
||||
* By default, will add as an Observer of the entire Data Segment in memory.
|
||||
* Override if you want something different. Note that the Memory methods to add an
|
||||
* Observer to memory are flexible (you can register for a range of addresses) but
|
||||
* may throw an AddressErrorException that you need to catch.
|
||||
* This method is called whenever the default "Connect" button on a MarsTool or the
|
||||
* default "Assemble and run" on a stand-alone Mars app is selected. The corresponding
|
||||
* NOTE: if you do not want to register as an Observer of the entire data segment
|
||||
* (starts at address 0x10000000) then override this to either do some alternative
|
||||
* or nothing at all. This method is also overloaded to allow arbitrary memory
|
||||
* subrange.
|
||||
*/
|
||||
|
||||
protected void addAsObserver() {
|
||||
addAsObserver(lowMemoryAddress, highMemoryAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add this app/tool as an Observer of the specified subrange of MIPS memory. Note
|
||||
* that this method is not invoked automatically like the no-argument version, but
|
||||
* if you use this method, you can still take advantage of provided default deleteAsObserver()
|
||||
* since it will remove the app as a memory observer regardless of the subrange
|
||||
* or number of subranges it is registered for.
|
||||
* @param lowEnd low end of memory address range.
|
||||
* @param highEnd high end of memory address range; must be >= lowEnd
|
||||
*/
|
||||
|
||||
protected void addAsObserver(int lowEnd, int highEnd) {
|
||||
String errorMessage = "Error connecting to MIPS memory";
|
||||
try {
|
||||
Globals.memory.addObserver(thisMarsApp,lowEnd, highEnd);
|
||||
}
|
||||
catch (AddressErrorException aee) {
|
||||
if (this.isBeingUsedAsAMarsTool) {
|
||||
headingLabel.setText(errorMessage);
|
||||
}
|
||||
else {
|
||||
operationStatusMessages.displayTerminatingMessage(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add this app/tool as an Observer of the specified MIPS register.
|
||||
*/
|
||||
protected void addAsObserver(Register reg) {
|
||||
if (reg != null) {
|
||||
reg.addObserver(thisMarsApp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete this app/tool as an Observer of MIPS Observables (memory and registers).
|
||||
* By default, will delete as an Observer of memory.
|
||||
* Override if you want something different.
|
||||
* This method is called when the default "Disconnect" button on a MarsTool is selected or
|
||||
* when the MIPS program execution triggered by the default "Assemble and run" on a stand-alone
|
||||
* Mars app terminates (e.g. when the button is re-enabled).
|
||||
*/
|
||||
|
||||
protected void deleteAsObserver() {
|
||||
Globals.memory.deleteObserver(thisMarsApp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this app/tool as an Observer of the specified MIPS register
|
||||
*/
|
||||
|
||||
protected void deleteAsObserver(Register reg) {
|
||||
if (reg != null) {
|
||||
reg.deleteObserver(thisMarsApp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Query method to let you know if the tool/app is (or could be) currently
|
||||
* "observing" any MIPS resources. When running as a MarsTool, this
|
||||
* will be true by default after clicking the "Connect to MIPS" button until "Disconnect
|
||||
* from MIPS" is clicked. When running as a stand-alone app, this will be
|
||||
* true by default after clicking the "Assemble and Run" button until until
|
||||
* program execution has terminated either normally or by clicking the "Stop"
|
||||
* button. The phrase "or could be" was added above because depending on how
|
||||
* the tool/app operates, it may be possible to run the MIPS program without
|
||||
* first registering as an Observer -- i.e. addAsObserver() is overridden and
|
||||
* takes no action.
|
||||
* @return true if tool/app is (or could be) currently active as an Observer.
|
||||
*/
|
||||
|
||||
protected boolean isObserving() {
|
||||
return observing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to implement updating of GUI after each MIPS instruction is executed,
|
||||
* while running in "timed" mode (user specifies execution speed on the slider control).
|
||||
* Does nothing by default.
|
||||
*/
|
||||
protected void updateDisplay() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to provide a JComponent (probably a JButton) of your choice
|
||||
* to be placed just left of the Close/Exit button. Its anticipated use is for a
|
||||
* "help" button that launches a help message or dialog. But it can be any valid
|
||||
* JComponent that doesn't mind co-existing among a bunch of JButtons.
|
||||
*/
|
||||
protected JComponent getHelpComponent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////// PRIVATE HELPER METHODS //////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Closing duties for MarsTool only.
|
||||
private void performToolClosingDuties() {
|
||||
performSpecialClosingDuties();
|
||||
if (connectButton.isConnected()) {
|
||||
connectButton.disconnect();
|
||||
}
|
||||
dialog.setVisible(false);
|
||||
dialog.dispose();
|
||||
}
|
||||
|
||||
// Closing duties for stand-alone application only.
|
||||
private void performAppClosingDuties() {
|
||||
performSpecialClosingDuties();
|
||||
thisMarsApp.setVisible(false);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////// PRIVATE HELPER CLASSES //////////////////////////////////
|
||||
// Specialized inner classes. Either used by stand-alone (JFrame-based) only //
|
||||
// or used by MarsTool (JDialog-based) only. //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Little class for this dual-purpose button. It is used only by the MarsTool
|
||||
// (not by the stand-alone app).
|
||||
protected class ConnectButton extends JButton {
|
||||
private static final String connectText = "Connect to MIPS";
|
||||
private static final String disconnectText = "Disconnect from MIPS";
|
||||
|
||||
public ConnectButton() {
|
||||
super();
|
||||
disconnect();
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
observing = true;
|
||||
synchronized (Globals.memoryAndRegistersLock) {// DPS 23 July 2008
|
||||
addAsObserver();
|
||||
}
|
||||
setText(disconnectText);
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
synchronized (Globals.memoryAndRegistersLock) {// DPS 23 July 2008
|
||||
deleteAsObserver();
|
||||
}
|
||||
observing = false;
|
||||
setText(connectText);
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return observing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Every control button will get one of these so when it has focus
|
||||
// the Enter key can be used instead of a mouse click to perform
|
||||
// its associated action. It will do nothing if no action listeners
|
||||
// are attached to the button at the time of the call. Otherwise,
|
||||
// it will call actionPerformed for the first action listener in the
|
||||
// button's list.
|
||||
protected class EnterKeyListener extends KeyAdapter {
|
||||
AbstractButton myButton;
|
||||
public EnterKeyListener(AbstractButton who) {
|
||||
myButton = who;
|
||||
}
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyChar()== KeyEvent.VK_ENTER) {
|
||||
e.consume();
|
||||
try {
|
||||
myButton.getActionListeners()[0].actionPerformed(new ActionEvent(myButton, 0, myButton.getText()));
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException oob) {
|
||||
// do nothing, since there is no action listener.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// called when the Assemble and Run button is pressed. Used only by stand-alone app.
|
||||
private class CreateAssembleRunMIPSprogram implements Runnable {
|
||||
public void run() {
|
||||
String noSupportForExceptionHandler = null; // no auto-loaded exception handlers.
|
||||
// boolean extendedAssemblerEnabled = true; // In this context, no reason to constrain.
|
||||
// boolean warningsAreErrors = false; // Ditto.
|
||||
|
||||
String exceptionHandler = null;
|
||||
if (Globals.getSettings().getExceptionHandlerEnabled() &&
|
||||
Globals.getSettings().getExceptionHandler() != null &&
|
||||
Globals.getSettings().getExceptionHandler().length() > 0) {
|
||||
exceptionHandler = Globals.getSettings().getExceptionHandler();
|
||||
}
|
||||
|
||||
Thread.currentThread().setPriority(Thread.NORM_PRIORITY-1);
|
||||
Thread.yield();
|
||||
MIPSprogram program = new MIPSprogram();
|
||||
mars.Globals.program = program; // Shouldn't have to do this...
|
||||
String fileToAssemble = mostRecentlyOpenedFile.getPath();
|
||||
ArrayList filesToAssemble = null;
|
||||
if (multiFileAssemble) {// setting (check box in file open dialog) calls for multiple file assembly
|
||||
filesToAssemble = FilenameFinder.getFilenameList(
|
||||
new File(fileToAssemble).getParent(), Globals.fileExtensions);
|
||||
}
|
||||
else {
|
||||
filesToAssemble = new ArrayList();
|
||||
filesToAssemble.add(fileToAssemble);
|
||||
}
|
||||
ArrayList programsToAssemble = null;
|
||||
try {
|
||||
operationStatusMessages.displayNonTerminatingMessage("Assembling "+fileToAssemble);
|
||||
programsToAssemble = program.prepareFilesForAssembly(filesToAssemble, fileToAssemble, exceptionHandler);
|
||||
}
|
||||
catch (mars.ProcessingException pe) {
|
||||
operationStatusMessages.displayTerminatingMessage("Error reading file(s): "+fileToAssemble);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
program.assemble(programsToAssemble, Globals.getSettings().getExtendedAssemblerEnabled(), Globals.getSettings().getWarningsAreErrors());
|
||||
}
|
||||
catch (mars.ProcessingException pe) {
|
||||
operationStatusMessages.displayTerminatingMessage("Assembly Error: "+fileToAssemble);
|
||||
return;
|
||||
}
|
||||
// Moved these three register resets from before the try block to after it. 17-Dec-09 DPS.
|
||||
RegisterFile.resetRegisters();
|
||||
Coprocessor1.resetRegisters();
|
||||
Coprocessor0.resetRegisters();
|
||||
|
||||
addAsObserver();
|
||||
observing = true;
|
||||
String terminatingMessage = "Normal termination: ";
|
||||
try {
|
||||
operationStatusMessages.displayNonTerminatingMessage("Running "+fileToAssemble);
|
||||
program.simulate(-1); // unlimited steps
|
||||
}
|
||||
catch (NullPointerException npe) {
|
||||
// This will occur if program execution is interrupted by Stop button.
|
||||
terminatingMessage = "User interrupt: ";
|
||||
}
|
||||
catch (mars.ProcessingException pe) {
|
||||
terminatingMessage = "Runtime error: ";
|
||||
}
|
||||
finally {
|
||||
deleteAsObserver();
|
||||
observing = false;
|
||||
operationStatusMessages.displayTerminatingMessage(terminatingMessage+fileToAssemble);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Class for text message field used to update operation status when
|
||||
// assembling and running MIPS programs.
|
||||
private class MessageField extends JTextField {
|
||||
|
||||
public MessageField(String text) {
|
||||
super(text);
|
||||
}
|
||||
|
||||
private void displayTerminatingMessage(String text) {
|
||||
displayMessage(text, true);
|
||||
}
|
||||
|
||||
private void displayNonTerminatingMessage(String text) {
|
||||
displayMessage(text, false);
|
||||
}
|
||||
|
||||
private void displayMessage(String text, boolean terminating) {
|
||||
SwingUtilities.invokeLater(new MessageWriter(text, terminating));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Little inner-inner class to display processing error message on AWT thread.
|
||||
// Used only by stand-alone app.
|
||||
private class MessageWriter implements Runnable {
|
||||
private String text;
|
||||
private boolean terminatingMessage;
|
||||
public MessageWriter(String text, boolean terminating) {
|
||||
this.text = text;
|
||||
this.terminatingMessage = terminating;
|
||||
}
|
||||
public void run() {
|
||||
if (text!=null) {
|
||||
operationStatusMessages.setText(text);
|
||||
operationStatusMessages.setCaretPosition(0);
|
||||
}
|
||||
if (terminatingMessage) {
|
||||
assembleRunButton.setEnabled(true);
|
||||
openFileButton.setEnabled(true);
|
||||
stopButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// For scheduling GUI update on timed runs...used only by stand-alone app.
|
||||
private class GUIUpdater implements Runnable {
|
||||
public void run() {
|
||||
updateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user