[O] BitmapDisplay > Kt
This commit is contained in:
@@ -1,647 +0,0 @@
|
|||||||
package mars.tools;
|
|
||||||
|
|
||||||
import mars.mips.hardware.AccessNotice;
|
|
||||||
import mars.mips.hardware.Memory;
|
|
||||||
import mars.mips.hardware.MemoryAccessNotice;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.border.EmptyBorder;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.util.Observable;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright (c) 2010-2011, 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)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bitmapp display simulator. It can be run either as a stand-alone Java application having access to the mars package,
|
|
||||||
* or through MARS as an item in its Tools menu. It makes maximum use of methods inherited from its abstract superclass
|
|
||||||
* AbstractMarsToolAndApplication. Pete Sanderson, verison 1.0, 23 December 2010.
|
|
||||||
*/
|
|
||||||
public class BitmapDisplay extends AbstractMarsToolAndApplication
|
|
||||||
{
|
|
||||||
|
|
||||||
private static final String version = "Version 1.0";
|
|
||||||
|
|
||||||
private static final String heading = "Bitmap Display";
|
|
||||||
|
|
||||||
private final String[] visualizationUnitPixelWidthChoices = {"1", "2", "4", "8", "16", "32"};
|
|
||||||
|
|
||||||
private final int defaultVisualizationUnitPixelWidthIndex = 0;
|
|
||||||
|
|
||||||
private final String[] visualizationUnitPixelHeightChoices = {"1", "2", "4", "8", "16", "32"};
|
|
||||||
|
|
||||||
private final int defaultVisualizationUnitPixelHeightIndex = 0;
|
|
||||||
|
|
||||||
private final String[] displayAreaPixelWidthChoices = {"64", "128", "256", "512", "1024"};
|
|
||||||
|
|
||||||
private final int defaultDisplayWidthIndex = 3;
|
|
||||||
|
|
||||||
private final String[] displayAreaPixelHeightChoices = {"64", "128", "256", "512", "1024"};
|
|
||||||
|
|
||||||
// Values for Combo Boxes
|
|
||||||
|
|
||||||
private final int defaultDisplayHeightIndex = 2;
|
|
||||||
|
|
||||||
// Major GUI components
|
|
||||||
private JComboBox visualizationUnitPixelWidthSelector, visualizationUnitPixelHeightSelector,
|
|
||||||
visualizationPixelWidthSelector, visualizationPixelHeightSelector, displayBaseAddressSelector;
|
|
||||||
|
|
||||||
private Graphics drawingArea;
|
|
||||||
|
|
||||||
private JPanel canvas;
|
|
||||||
|
|
||||||
private JPanel results;
|
|
||||||
|
|
||||||
// Some GUI settings
|
|
||||||
private final EmptyBorder emptyBorder = new EmptyBorder(4, 4, 4, 4);
|
|
||||||
|
|
||||||
private final Font countFonts = new Font("Times", Font.BOLD, 12);
|
|
||||||
|
|
||||||
private final Color backgroundColor = Color.WHITE;
|
|
||||||
|
|
||||||
// Values for display canvas. Note their initialization uses the identifiers just above.
|
|
||||||
|
|
||||||
private int unitPixelWidth = Integer.parseInt(visualizationUnitPixelWidthChoices[defaultVisualizationUnitPixelWidthIndex]);
|
|
||||||
|
|
||||||
private int unitPixelHeight = Integer.parseInt(visualizationUnitPixelHeightChoices[defaultVisualizationUnitPixelHeightIndex]);
|
|
||||||
|
|
||||||
private int displayAreaWidthInPixels = Integer.parseInt(displayAreaPixelWidthChoices[defaultDisplayWidthIndex]);
|
|
||||||
|
|
||||||
private int displayAreaHeightInPixels = Integer.parseInt(displayAreaPixelHeightChoices[defaultDisplayHeightIndex]);
|
|
||||||
|
|
||||||
|
|
||||||
// The next four are initialized dynamically in initializeDisplayBaseChoices()
|
|
||||||
private String[] displayBaseAddressChoices;
|
|
||||||
|
|
||||||
private int[] displayBaseAddresses;
|
|
||||||
|
|
||||||
private int defaultBaseAddressIndex;
|
|
||||||
|
|
||||||
private int baseAddress;
|
|
||||||
|
|
||||||
private Grid theGrid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple constructor, likely used to run a stand-alone bitmap display tool.
|
|
||||||
*
|
|
||||||
* @param title String containing title for title bar
|
|
||||||
* @param heading String containing text for heading shown in upper part of window.
|
|
||||||
*/
|
|
||||||
public BitmapDisplay(String title, String heading)
|
|
||||||
{
|
|
||||||
super(title, heading);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple constructor, likely used by the MARS Tools menu mechanism
|
|
||||||
*/
|
|
||||||
public BitmapDisplay()
|
|
||||||
{
|
|
||||||
super("Bitmap Display, " + version, heading);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main provided for pure stand-alone use. Recommended stand-alone use is to write a driver program that
|
|
||||||
* instantiates a Bitmap object then invokes its go() method. "stand-alone" means it is not invoked from the MARS
|
|
||||||
* Tools menu. "Pure" means there is no driver program to invoke the application.
|
|
||||||
*/
|
|
||||||
public static void main(String[] args)
|
|
||||||
{
|
|
||||||
new BitmapDisplay("Bitmap Display stand-alone, " + version, heading).go();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Required MarsTool method to return Tool name.
|
|
||||||
*
|
|
||||||
* @return Tool name. MARS will display this in menu item.
|
|
||||||
*/
|
|
||||||
public String getName()
|
|
||||||
{
|
|
||||||
return "Bitmap Display";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override the inherited method, which registers us as an Observer over the static data segment (starting address
|
|
||||||
* 0x10010000) only. This version will register us as observer over the the memory range as selected by the base
|
|
||||||
* address combo box and capacity of the visualization display (number of visualization elements times the number of
|
|
||||||
* memory words each one represents). It does so by calling the inherited 2-parameter overload of this method. If
|
|
||||||
* you use the inherited GUI buttons, this method is invoked when you click "Connect" button on MarsTool or the
|
|
||||||
* "Assemble and Run" button on a Mars-based app.
|
|
||||||
*/
|
|
||||||
protected void addAsObserver()
|
|
||||||
{
|
|
||||||
int highAddress = baseAddress + theGrid.getRows() * theGrid.getColumns() * Memory.WORD_LENGTH_BYTES;
|
|
||||||
// Special case: baseAddress<0 means we're in kernel memory (0x80000000 and up) and most likely
|
|
||||||
// in memory map address space (0xffff0000 and up). In this case, we need to make sure the high address
|
|
||||||
// does not drop off the high end of 32 bit address space. Highest allowable word address is 0xfffffffc,
|
|
||||||
// which is interpreted in Java int as -4.
|
|
||||||
if (baseAddress < 0 && highAddress > -4)
|
|
||||||
{
|
|
||||||
highAddress = -4;
|
|
||||||
}
|
|
||||||
addAsObserver(baseAddress, highAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method that constructs the main display area. It is organized vertically into two major components: the display
|
|
||||||
* configuration which an be modified using combo boxes, and the visualization display which is updated as the
|
|
||||||
* attached MIPS program executes.
|
|
||||||
*
|
|
||||||
* @return the GUI component containing these two areas
|
|
||||||
*/
|
|
||||||
protected JComponent buildMainDisplayArea()
|
|
||||||
{
|
|
||||||
results = new JPanel();
|
|
||||||
results.add(buildOrganizationArea());
|
|
||||||
results.add(buildVisualizationArea());
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Rest of the protected methods. These override do-nothing methods inherited from
|
|
||||||
// the abstract superclass.
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update display when connected MIPS program accesses (data) memory.
|
|
||||||
*
|
|
||||||
* @param memory the attached memory
|
|
||||||
* @param accessNotice information provided by memory in MemoryAccessNotice object
|
|
||||||
*/
|
|
||||||
protected void processMIPSUpdate(Observable memory, AccessNotice accessNotice)
|
|
||||||
{
|
|
||||||
if (accessNotice.getAccessType() == AccessNotice.WRITE)
|
|
||||||
{
|
|
||||||
updateColorForAddress((MemoryAccessNotice) accessNotice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize all JComboBox choice structures not already initialized at declaration. Overrides inherited method
|
|
||||||
* that does nothing.
|
|
||||||
*/
|
|
||||||
protected void initializePreGUI()
|
|
||||||
{
|
|
||||||
initializeDisplayBaseChoices();
|
|
||||||
// NOTE: Can't call "createNewGrid()" here because it uses settings from
|
|
||||||
// several combo boxes that have not been created yet. But a default grid
|
|
||||||
// needs to be allocated for initial canvas display.
|
|
||||||
theGrid = new Grid(displayAreaHeightInPixels / unitPixelHeight,
|
|
||||||
displayAreaWidthInPixels / unitPixelWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The only post-GUI initialization is to create the initial Grid object based on the default settings of the
|
|
||||||
* various combo boxes. Overrides inherited method that does nothing.
|
|
||||||
*/
|
|
||||||
|
|
||||||
protected void initializePostGUI()
|
|
||||||
{
|
|
||||||
theGrid = createNewGrid();
|
|
||||||
updateBaseAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to reset counters and display when the Reset button selected. Overrides inherited method that does
|
|
||||||
* nothing.
|
|
||||||
*/
|
|
||||||
protected void reset()
|
|
||||||
{
|
|
||||||
resetCounts();
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates display immediately after each update (AccessNotice) is processed, after display configuration changes as
|
|
||||||
* needed, and after each execution step when Mars is running in timed mode. Overrides inherited method that does
|
|
||||||
* nothing.
|
|
||||||
*/
|
|
||||||
protected void updateDisplay()
|
|
||||||
{
|
|
||||||
canvas.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overrides default method, to provide a Help button for this tool/app.
|
|
||||||
*/
|
|
||||||
protected JComponent getHelpComponent()
|
|
||||||
{
|
|
||||||
final String helpContent =
|
|
||||||
"Use this program to simulate a basic bitmap display where\n" +
|
|
||||||
"each memory word in a specified address space corresponds to\n" +
|
|
||||||
"one display pixel in row-major order starting at the upper left\n" +
|
|
||||||
"corner of the display. This tool may be run either from the\n" +
|
|
||||||
"MARS Tools menu or as a stand-alone application.\n" +
|
|
||||||
"\n" +
|
|
||||||
"You can easily learn to use this small program by playing with\n" +
|
|
||||||
"it! Each rectangular unit on the display represents one memory\n" +
|
|
||||||
"word in a contiguous address space starting with the specified\n" +
|
|
||||||
"base address. The value stored in that word will be interpreted\n" +
|
|
||||||
"as a 24-bit RGB color value with the red component in bits 16-23,\n" +
|
|
||||||
"the green component in bits 8-15, and the blue component in bits 0-7.\n" +
|
|
||||||
"Each time a memory word within the display address space is written\n" +
|
|
||||||
"by the MIPS program, its position in the display will be rendered\n" +
|
|
||||||
"in the color that its value represents.\n" +
|
|
||||||
"\n" +
|
|
||||||
"Version 1.0 is very basic and was constructed from the Memory\n" +
|
|
||||||
"Reference Visualization tool's code. Feel free to improve it and\n" +
|
|
||||||
"send me your code for consideration in the next MARS release.\n" +
|
|
||||||
"\n" +
|
|
||||||
"Contact Pete Sanderson at psanderson@otterbein.edu with\n" +
|
|
||||||
"questions or comments.\n";
|
|
||||||
JButton help = new JButton("Help");
|
|
||||||
help.addActionListener(
|
|
||||||
new ActionListener()
|
|
||||||
{
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog(theWindow, helpContent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return help;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private methods defined to support the above.
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// UI components and layout for left half of GUI, where settings are specified.
|
|
||||||
private JComponent buildOrganizationArea()
|
|
||||||
{
|
|
||||||
JPanel organization = new JPanel(new GridLayout(8, 1));
|
|
||||||
|
|
||||||
visualizationUnitPixelWidthSelector = new JComboBox(visualizationUnitPixelWidthChoices);
|
|
||||||
visualizationUnitPixelWidthSelector.setEditable(false);
|
|
||||||
visualizationUnitPixelWidthSelector.setBackground(backgroundColor);
|
|
||||||
visualizationUnitPixelWidthSelector.setSelectedIndex(defaultVisualizationUnitPixelWidthIndex);
|
|
||||||
visualizationUnitPixelWidthSelector.setToolTipText("Width in pixels of rectangle representing memory word");
|
|
||||||
visualizationUnitPixelWidthSelector.addActionListener(
|
|
||||||
new ActionListener()
|
|
||||||
{
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
unitPixelWidth = getIntComboBoxSelection(visualizationUnitPixelWidthSelector);
|
|
||||||
theGrid = createNewGrid();
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
visualizationUnitPixelHeightSelector = new JComboBox(visualizationUnitPixelHeightChoices);
|
|
||||||
visualizationUnitPixelHeightSelector.setEditable(false);
|
|
||||||
visualizationUnitPixelHeightSelector.setBackground(backgroundColor);
|
|
||||||
visualizationUnitPixelHeightSelector.setSelectedIndex(defaultVisualizationUnitPixelHeightIndex);
|
|
||||||
visualizationUnitPixelHeightSelector.setToolTipText("Height in pixels of rectangle representing memory word");
|
|
||||||
visualizationUnitPixelHeightSelector.addActionListener(
|
|
||||||
new ActionListener()
|
|
||||||
{
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
unitPixelHeight = getIntComboBoxSelection(visualizationUnitPixelHeightSelector);
|
|
||||||
theGrid = createNewGrid();
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
visualizationPixelWidthSelector = new JComboBox(displayAreaPixelWidthChoices);
|
|
||||||
visualizationPixelWidthSelector.setEditable(false);
|
|
||||||
visualizationPixelWidthSelector.setBackground(backgroundColor);
|
|
||||||
visualizationPixelWidthSelector.setSelectedIndex(defaultDisplayWidthIndex);
|
|
||||||
visualizationPixelWidthSelector.setToolTipText("Total width in pixels of display area");
|
|
||||||
visualizationPixelWidthSelector.addActionListener(
|
|
||||||
new ActionListener()
|
|
||||||
{
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
displayAreaWidthInPixels = getIntComboBoxSelection(visualizationPixelWidthSelector);
|
|
||||||
canvas.setPreferredSize(getDisplayAreaDimension());
|
|
||||||
canvas.setSize(getDisplayAreaDimension());
|
|
||||||
theGrid = createNewGrid();
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
visualizationPixelHeightSelector = new JComboBox(displayAreaPixelHeightChoices);
|
|
||||||
visualizationPixelHeightSelector.setEditable(false);
|
|
||||||
visualizationPixelHeightSelector.setBackground(backgroundColor);
|
|
||||||
visualizationPixelHeightSelector.setSelectedIndex(defaultDisplayHeightIndex);
|
|
||||||
visualizationPixelHeightSelector.setToolTipText("Total height in pixels of display area");
|
|
||||||
visualizationPixelHeightSelector.addActionListener(
|
|
||||||
new ActionListener()
|
|
||||||
{
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
displayAreaHeightInPixels = getIntComboBoxSelection(visualizationPixelHeightSelector);
|
|
||||||
canvas.setPreferredSize(getDisplayAreaDimension());
|
|
||||||
canvas.setSize(getDisplayAreaDimension());
|
|
||||||
theGrid = createNewGrid();
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
displayBaseAddressSelector = new JComboBox(displayBaseAddressChoices);
|
|
||||||
displayBaseAddressSelector.setEditable(false);
|
|
||||||
displayBaseAddressSelector.setBackground(backgroundColor);
|
|
||||||
displayBaseAddressSelector.setSelectedIndex(defaultBaseAddressIndex);
|
|
||||||
displayBaseAddressSelector.setToolTipText("Base address for display area (upper left corner)");
|
|
||||||
displayBaseAddressSelector.addActionListener(
|
|
||||||
new ActionListener()
|
|
||||||
{
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
// This may also affect what address range we should be registered as an Observer
|
|
||||||
// for. The default (inherited) address range is the MIPS static data segment
|
|
||||||
// starting at 0x10010000. To change this requires override of
|
|
||||||
// AbstractMarsToolAndApplication.addAsObserver(). The no-argument version of
|
|
||||||
// that method is called automatically when "Connect" button is clicked for MarsTool
|
|
||||||
// and when "Assemble and Run" button is clicked for Mars application.
|
|
||||||
updateBaseAddress();
|
|
||||||
// If display base address is changed while connected to MIPS (this can only occur
|
|
||||||
// when being used as a MarsTool), we have to delete ourselves as an observer and re-register.
|
|
||||||
if (connectButton != null && connectButton.isConnected())
|
|
||||||
{
|
|
||||||
deleteAsObserver();
|
|
||||||
addAsObserver();
|
|
||||||
}
|
|
||||||
theGrid = createNewGrid();
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// ALL COMPONENTS FOR "ORGANIZATION" SECTION
|
|
||||||
|
|
||||||
JPanel unitWidthInPixelsRow = getPanelWithBorderLayout();
|
|
||||||
unitWidthInPixelsRow.setBorder(emptyBorder);
|
|
||||||
unitWidthInPixelsRow.add(new JLabel("Unit Width in Pixels "), BorderLayout.WEST);
|
|
||||||
unitWidthInPixelsRow.add(visualizationUnitPixelWidthSelector, BorderLayout.EAST);
|
|
||||||
|
|
||||||
JPanel unitHeightInPixelsRow = getPanelWithBorderLayout();
|
|
||||||
unitHeightInPixelsRow.setBorder(emptyBorder);
|
|
||||||
unitHeightInPixelsRow.add(new JLabel("Unit Height in Pixels "), BorderLayout.WEST);
|
|
||||||
unitHeightInPixelsRow.add(visualizationUnitPixelHeightSelector, BorderLayout.EAST);
|
|
||||||
|
|
||||||
JPanel widthInPixelsRow = getPanelWithBorderLayout();
|
|
||||||
widthInPixelsRow.setBorder(emptyBorder);
|
|
||||||
widthInPixelsRow.add(new JLabel("Display Width in Pixels "), BorderLayout.WEST);
|
|
||||||
widthInPixelsRow.add(visualizationPixelWidthSelector, BorderLayout.EAST);
|
|
||||||
|
|
||||||
JPanel heightInPixelsRow = getPanelWithBorderLayout();
|
|
||||||
heightInPixelsRow.setBorder(emptyBorder);
|
|
||||||
heightInPixelsRow.add(new JLabel("Display Height in Pixels "), BorderLayout.WEST);
|
|
||||||
heightInPixelsRow.add(visualizationPixelHeightSelector, BorderLayout.EAST);
|
|
||||||
|
|
||||||
JPanel baseAddressRow = getPanelWithBorderLayout();
|
|
||||||
baseAddressRow.setBorder(emptyBorder);
|
|
||||||
baseAddressRow.add(new JLabel("Base address for display "), BorderLayout.WEST);
|
|
||||||
baseAddressRow.add(displayBaseAddressSelector, BorderLayout.EAST);
|
|
||||||
|
|
||||||
|
|
||||||
// Lay 'em out in the grid...
|
|
||||||
organization.add(unitWidthInPixelsRow);
|
|
||||||
organization.add(unitHeightInPixelsRow);
|
|
||||||
organization.add(widthInPixelsRow);
|
|
||||||
organization.add(heightInPixelsRow);
|
|
||||||
organization.add(baseAddressRow);
|
|
||||||
return organization;
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI components and layout for right half of GUI, the visualization display area.
|
|
||||||
private JComponent buildVisualizationArea()
|
|
||||||
{
|
|
||||||
canvas = new GraphicsPanel();
|
|
||||||
canvas.setPreferredSize(getDisplayAreaDimension());
|
|
||||||
canvas.setToolTipText("Bitmap display area");
|
|
||||||
return canvas;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For greatest flexibility, initialize the display base choices directly from
|
|
||||||
// the constants defined in the Memory class. This method called prior to
|
|
||||||
// building the GUI. Here are current values from Memory.java:
|
|
||||||
//dataSegmentBaseAddress=0x10000000, globalPointer=0x10008000
|
|
||||||
//dataBaseAddress=0x10010000, heapBaseAddress=0x10040000, memoryMapBaseAddress=0xffff0000
|
|
||||||
private void initializeDisplayBaseChoices()
|
|
||||||
{
|
|
||||||
int[] displayBaseAddressArray = {Memory.dataSegmentBaseAddress, Memory.globalPointer, Memory.dataBaseAddress,
|
|
||||||
Memory.heapBaseAddress, Memory.memoryMapBaseAddress};
|
|
||||||
// Must agree with above in number and order...
|
|
||||||
String[] descriptions = {" (global data)", " ($gp)", " (static data)", " (heap)", " (memory map)"};
|
|
||||||
displayBaseAddresses = displayBaseAddressArray;
|
|
||||||
displayBaseAddressChoices = new String[displayBaseAddressArray.length];
|
|
||||||
for (int i = 0; i < displayBaseAddressChoices.length; i++)
|
|
||||||
{
|
|
||||||
displayBaseAddressChoices[i] = mars.util.Binary.intToHexString(displayBaseAddressArray[i]) + descriptions[i];
|
|
||||||
}
|
|
||||||
defaultBaseAddressIndex = 2; // default to 0x10010000 (static data)
|
|
||||||
baseAddress = displayBaseAddressArray[defaultBaseAddressIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
// update based on combo box selection (currently not editable but that may change).
|
|
||||||
private void updateBaseAddress()
|
|
||||||
{
|
|
||||||
baseAddress = displayBaseAddresses[displayBaseAddressSelector.getSelectedIndex()];
|
|
||||||
/* If you want to extend this app to allow user to edit combo box, you can always
|
|
||||||
parse the getSelectedItem() value, because the pre-defined items are all formatted
|
|
||||||
such that the first 10 characters contain the integer's hex value. And if the
|
|
||||||
value is user-entered, the numeric part cannot exceed 10 characters for a 32-bit
|
|
||||||
address anyway. So if the value is > 10 characters long, slice off the first
|
|
||||||
10 and apply Integer.parseInt() to it to get custom base address.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns Dimension object with current width and height of display area as determined
|
|
||||||
// by current settings of respective combo boxes.
|
|
||||||
private Dimension getDisplayAreaDimension()
|
|
||||||
{
|
|
||||||
return new Dimension(displayAreaWidthInPixels, displayAreaHeightInPixels);
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset all counters in the Grid.
|
|
||||||
private void resetCounts()
|
|
||||||
{
|
|
||||||
theGrid.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Will return int equivalent of specified combo box's current selection.
|
|
||||||
// The selection must be a String that parses to an int.
|
|
||||||
private int getIntComboBoxSelection(JComboBox comboBox)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Integer.parseInt((String) comboBox.getSelectedItem());
|
|
||||||
}
|
|
||||||
catch (NumberFormatException nfe)
|
|
||||||
{
|
|
||||||
// Can occur only if initialization list contains badly formatted numbers. This
|
|
||||||
// is a developer's error, not a user error, and better be caught before release.
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use this for consistent results.
|
|
||||||
private JPanel getPanelWithBorderLayout()
|
|
||||||
{
|
|
||||||
return new JPanel(new BorderLayout(2, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to determine grid dimensions based on current control settings.
|
|
||||||
// Each grid element corresponds to one visualization unit.
|
|
||||||
private Grid createNewGrid()
|
|
||||||
{
|
|
||||||
int rows = displayAreaHeightInPixels / unitPixelHeight;
|
|
||||||
int columns = displayAreaWidthInPixels / unitPixelWidth;
|
|
||||||
return new Grid(rows, columns);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given memory address, update color for the corresponding grid element.
|
|
||||||
private void updateColorForAddress(MemoryAccessNotice notice)
|
|
||||||
{
|
|
||||||
int address = notice.getAddress();
|
|
||||||
int value = notice.getValue();
|
|
||||||
int offset = (address - baseAddress) / Memory.WORD_LENGTH_BYTES;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
theGrid.setElement(offset / theGrid.getColumns(), offset % theGrid.getColumns(), value);
|
|
||||||
}
|
|
||||||
catch (IndexOutOfBoundsException e)
|
|
||||||
{
|
|
||||||
// If address is out of range for display, do nothing.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Specialized inner classes for modeling and animation.
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Class that represents the panel for visualizing and animating memory reference
|
|
||||||
// patterns.
|
|
||||||
private class GraphicsPanel extends JPanel
|
|
||||||
{
|
|
||||||
|
|
||||||
// override default paint method to assure display updated correctly every time
|
|
||||||
// the panel is repainted.
|
|
||||||
public void paint(Graphics g)
|
|
||||||
{
|
|
||||||
paintGrid(g, theGrid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Paint the color codes.
|
|
||||||
private void paintGrid(Graphics g, Grid grid)
|
|
||||||
{
|
|
||||||
int upperLeftX = 0, upperLeftY = 0;
|
|
||||||
for (int i = 0; i < grid.getRows(); i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < grid.getColumns(); j++)
|
|
||||||
{
|
|
||||||
g.setColor(grid.getElementFast(i, j));
|
|
||||||
g.fillRect(upperLeftX, upperLeftY, unitPixelWidth, unitPixelHeight);
|
|
||||||
upperLeftX += unitPixelWidth; // faster than multiplying
|
|
||||||
}
|
|
||||||
// get ready for next row...
|
|
||||||
upperLeftX = 0;
|
|
||||||
upperLeftY += unitPixelHeight; // faster than multiplying
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
// Represents grid of colors
|
|
||||||
private class Grid
|
|
||||||
{
|
|
||||||
|
|
||||||
Color[][] grid;
|
|
||||||
|
|
||||||
int rows, columns;
|
|
||||||
|
|
||||||
private Grid(int rows, int columns)
|
|
||||||
{
|
|
||||||
grid = new Color[rows][columns];
|
|
||||||
this.rows = rows;
|
|
||||||
this.columns = columns;
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getRows()
|
|
||||||
{
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getColumns()
|
|
||||||
{
|
|
||||||
return columns;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns value in given grid element; null if row or column is out of range.
|
|
||||||
private Color getElement(int row, int column)
|
|
||||||
{
|
|
||||||
return (row >= 0 && row <= rows && column >= 0 && column <= columns) ? grid[row][column] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns value in given grid element without doing any row/column index checking.
|
|
||||||
// Is faster than getElement but will throw array index out of bounds exception if
|
|
||||||
// parameter values are outside the bounds of the grid.
|
|
||||||
private Color getElementFast(int row, int column)
|
|
||||||
{
|
|
||||||
return grid[row][column];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the grid element.
|
|
||||||
private void setElement(int row, int column, int color)
|
|
||||||
{
|
|
||||||
grid[row][column] = new Color(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the grid element.
|
|
||||||
private void setElement(int row, int column, Color color)
|
|
||||||
{
|
|
||||||
grid[row][column] = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just set all grid elements to black.
|
|
||||||
private void reset()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < rows; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < columns; j++)
|
|
||||||
{
|
|
||||||
grid[i][j] = Color.BLACK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,465 @@
|
|||||||
|
package mars.tools
|
||||||
|
|
||||||
|
import mars.mips.hardware.AccessNotice
|
||||||
|
import mars.mips.hardware.Memory
|
||||||
|
import mars.mips.hardware.MemoryAccessNotice
|
||||||
|
import mars.util.Binary
|
||||||
|
import java.awt.*
|
||||||
|
import java.util.*
|
||||||
|
import javax.swing.*
|
||||||
|
import javax.swing.border.EmptyBorder
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010-2011, 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)
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Bitmapp display simulator. It can be run either as a stand-alone Java application having access to the mars package,
|
||||||
|
* or through MARS as an item in its Tools menu. It makes maximum use of methods inherited from its abstract superclass
|
||||||
|
* AbstractMarsToolAndApplication. Pete Sanderson, verison 1.0, 23 December 2010.
|
||||||
|
*/
|
||||||
|
class BitmapDisplay : AbstractMarsToolAndApplication
|
||||||
|
{
|
||||||
|
// Major GUI components
|
||||||
|
private lateinit var uiUnitWidthSelector: JComboBox<Int>
|
||||||
|
private lateinit var uiUnitHeightSelector: JComboBox<Int>
|
||||||
|
private lateinit var uiWidthSelector: JComboBox<Int>
|
||||||
|
private lateinit var uiHeightSelector: JComboBox<Int>
|
||||||
|
private lateinit var uiBaseAddressSelector: JComboBox<String>
|
||||||
|
private lateinit var canvas: JPanel
|
||||||
|
private lateinit var results: JPanel
|
||||||
|
|
||||||
|
// Some GUI settings
|
||||||
|
private val emptyBorder = EmptyBorder(4, 4, 4, 4)
|
||||||
|
private val backgroundColor = Color.WHITE
|
||||||
|
|
||||||
|
// Values for display canvas. Note their initialization uses the identifiers just above.
|
||||||
|
private val unitWidth get() = uiUnitWidthSelector.getInt()
|
||||||
|
private val unitHeight get() = uiUnitHeightSelector.getInt()
|
||||||
|
private val displayWidth get() = uiWidthSelector.getInt()
|
||||||
|
private val displayHeight get() = uiHeightSelector.getInt()
|
||||||
|
private val displayDimension get() = Dimension(displayWidth, displayHeight)
|
||||||
|
|
||||||
|
private val baseAddresses = intArrayOf(Memory.dataSegmentBaseAddress, Memory.globalPointer, Memory.dataBaseAddress,
|
||||||
|
Memory.heapBaseAddress, Memory.memoryMapBaseAddress)
|
||||||
|
|
||||||
|
private val baseAddress get() = baseAddresses[uiBaseAddressSelector.selectedIndex]
|
||||||
|
|
||||||
|
private lateinit var grid: Grid
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple constructor, likely used to run a stand-alone bitmap display tool.
|
||||||
|
*
|
||||||
|
* @param title String containing title for title bar
|
||||||
|
* @param heading String containing text for heading shown in upper part of window.
|
||||||
|
*/
|
||||||
|
constructor(title: String, heading: String) : super(title, heading)
|
||||||
|
|
||||||
|
constructor() : super("Azalea's Modified Bitmap Display", heading)
|
||||||
|
|
||||||
|
override fun getName() = "Bitmap Display"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the inherited method, which registers us as an Observer over the static data segment (starting address
|
||||||
|
* 0x10010000) only. This version will register us as observer over the the memory range as selected by the base
|
||||||
|
* address combo box and capacity of the visualization display (number of visualization elements times the number of
|
||||||
|
* memory words each one represents). It does so by calling the inherited 2-parameter overload of this method. If
|
||||||
|
* you use the inherited GUI buttons, this method is invoked when you click "Connect" button on MarsTool or the
|
||||||
|
* "Assemble and Run" button on a Mars-based app.
|
||||||
|
*/
|
||||||
|
override fun addAsObserver()
|
||||||
|
{
|
||||||
|
var highAddress: Int = baseAddress + grid.rows * grid.cols * Memory.WORD_LENGTH_BYTES
|
||||||
|
// Special case: baseAddress<0 means we're in kernel memory (0x80000000 and up) and most likely
|
||||||
|
// in memory map address space (0xffff0000 and up). In this case, we need to make sure the high address
|
||||||
|
// does not drop off the high end of 32 bit address space. Highest allowable word address is 0xfffffffc,
|
||||||
|
// which is interpreted in Java int as -4.
|
||||||
|
if (baseAddress < 0 && highAddress > -4)
|
||||||
|
{
|
||||||
|
highAddress = -4
|
||||||
|
}
|
||||||
|
addAsObserver(baseAddress, highAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that constructs the main display area. It is organized vertically into two major components: the display
|
||||||
|
* configuration which an be modified using combo boxes, and the visualization display which is updated as the
|
||||||
|
* attached MIPS program executes.
|
||||||
|
*
|
||||||
|
* @return the GUI component containing these two areas
|
||||||
|
*/
|
||||||
|
override fun buildMainDisplayArea(): JComponent
|
||||||
|
{
|
||||||
|
results = JPanel()
|
||||||
|
results.add(buildOrganizationArea())
|
||||||
|
results.add(buildVisualizationArea())
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Rest of the protected methods. These override do-nothing methods inherited from
|
||||||
|
// the abstract superclass.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Update display when connected MIPS program accesses (data) memory.
|
||||||
|
*
|
||||||
|
* @param memory the attached memory
|
||||||
|
* @param accessNotice information provided by memory in MemoryAccessNotice object
|
||||||
|
*/
|
||||||
|
override fun processMIPSUpdate(memory: Observable, accessNotice: AccessNotice)
|
||||||
|
{
|
||||||
|
if (accessNotice.accessType == AccessNotice.WRITE)
|
||||||
|
{
|
||||||
|
updateColorForAddress(accessNotice as MemoryAccessNotice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all JComboBox choice structures not already initialized at declaration. Overrides inherited method
|
||||||
|
* that does nothing.
|
||||||
|
*/
|
||||||
|
override fun initializePreGUI()
|
||||||
|
{
|
||||||
|
grid = Grid(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The only post-GUI initialization is to create the initial Grid object based on the default settings of the
|
||||||
|
* various combo boxes. Overrides inherited method that does nothing.
|
||||||
|
*/
|
||||||
|
override fun initializePostGUI()
|
||||||
|
{
|
||||||
|
grid = createNewGrid()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to reset counters and display when the Reset button selected. Overrides inherited method that does
|
||||||
|
* nothing.
|
||||||
|
*/
|
||||||
|
override fun reset()
|
||||||
|
{
|
||||||
|
resetCounts()
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates display immediately after each update (AccessNotice) is processed, after display configuration changes as
|
||||||
|
* needed, and after each execution step when Mars is running in timed mode. Overrides inherited method that does
|
||||||
|
* nothing.
|
||||||
|
*/
|
||||||
|
override fun updateDisplay() = canvas.repaint()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides default method, to provide a Help button for this tool/app.
|
||||||
|
*/
|
||||||
|
override fun getHelpComponent(): JComponent
|
||||||
|
{
|
||||||
|
val helpContent = """
|
||||||
|
Use this program to simulate a basic bitmap display where
|
||||||
|
each memory word in a specified address space corresponds to
|
||||||
|
one display pixel in row-major order starting at the upper left
|
||||||
|
corner of the display. This tool may be run either from the
|
||||||
|
MARS Tools menu or as a stand-alone application.
|
||||||
|
|
||||||
|
You can easily learn to use this small program by playing with
|
||||||
|
it! Each rectangular unit on the display represents one memory
|
||||||
|
word in a contiguous address space starting with the specified
|
||||||
|
base address. The value stored in that word will be interpreted
|
||||||
|
as a 24-bit RGB color value with the red component in bits 16-23,
|
||||||
|
the green component in bits 8-15, and the blue component in bits 0-7.
|
||||||
|
Each time a memory word within the display address space is written
|
||||||
|
by the MIPS program, its position in the display will be rendered
|
||||||
|
in the color that its value represents.
|
||||||
|
|
||||||
|
Version 1.0 is very basic and was constructed from the Memory
|
||||||
|
Reference Visualization tool's code. Feel free to improve it and
|
||||||
|
send me your code for consideration in the next MARS release.
|
||||||
|
|
||||||
|
Contact Pete Sanderson at psanderson@otterbein.edu with
|
||||||
|
questions or comments.
|
||||||
|
|
||||||
|
""".trimIndent()
|
||||||
|
val help = JButton("Help")
|
||||||
|
help.addActionListener { JOptionPane.showMessageDialog(theWindow, helpContent) }
|
||||||
|
return help
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Private methods defined to support the above.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// UI components and layout for left half of GUI, where settings are specified.
|
||||||
|
private fun buildOrganizationArea(): JComponent
|
||||||
|
{
|
||||||
|
val organization = JPanel(GridLayout(8, 1))
|
||||||
|
|
||||||
|
uiUnitWidthSelector = JComboBox(arrayOf(1, 2, 4, 8, 16, 32)).apply {
|
||||||
|
isEditable = false
|
||||||
|
background = backgroundColor
|
||||||
|
selectedIndex = 2
|
||||||
|
toolTipText = "Width in pixels of rectangle representing memory word"
|
||||||
|
addActionListener {
|
||||||
|
grid = createNewGrid()
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uiUnitHeightSelector = JComboBox(arrayOf(1, 2, 4, 8, 16, 32)).apply {
|
||||||
|
isEditable = false
|
||||||
|
background = backgroundColor
|
||||||
|
selectedIndex = 2
|
||||||
|
toolTipText = "Height in pixels of rectangle representing memory word"
|
||||||
|
addActionListener {
|
||||||
|
grid = createNewGrid()
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uiWidthSelector = JComboBox(arrayOf(64, 128, 256, 512, 1024)).apply {
|
||||||
|
isEditable = false
|
||||||
|
background = backgroundColor
|
||||||
|
selectedIndex = 3
|
||||||
|
toolTipText = "Total width in pixels of display area"
|
||||||
|
addActionListener {
|
||||||
|
canvas.preferredSize = displayDimension
|
||||||
|
canvas.size = displayDimension
|
||||||
|
grid = createNewGrid()
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uiHeightSelector = JComboBox(arrayOf(64, 128, 256, 512, 1024)).apply {
|
||||||
|
isEditable = false
|
||||||
|
background = backgroundColor
|
||||||
|
selectedIndex = 2
|
||||||
|
toolTipText = "Total height in pixels of display area"
|
||||||
|
addActionListener {
|
||||||
|
canvas.preferredSize = displayDimension
|
||||||
|
canvas.size = displayDimension
|
||||||
|
grid = createNewGrid()
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val descriptions = arrayOf("global data", "\$gp", "static data", "heap", "memory map")
|
||||||
|
|
||||||
|
val displayBaseAddressChoices = baseAddresses
|
||||||
|
.mapIndexed { i, it -> "${Binary.intToHexString(it)} (${descriptions[i]})" }.toTypedArray()
|
||||||
|
|
||||||
|
uiBaseAddressSelector = JComboBox(displayBaseAddressChoices).apply {
|
||||||
|
isEditable = false
|
||||||
|
background = backgroundColor
|
||||||
|
selectedIndex = 1
|
||||||
|
toolTipText = "Base address for display area (upper left corner)"
|
||||||
|
addActionListener {
|
||||||
|
// If display base address is changed while connected to MIPS (this can only occur
|
||||||
|
// when being used as a MarsTool), we have to delete ourselves as an observer and re-register.
|
||||||
|
if (connectButton != null && connectButton.isConnected)
|
||||||
|
{
|
||||||
|
deleteAsObserver()
|
||||||
|
addAsObserver()
|
||||||
|
}
|
||||||
|
grid = createNewGrid()
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ALL COMPONENTS FOR "ORGANIZATION" SECTION
|
||||||
|
val unitWidthInPixelsRow = panelWithBorderLayout
|
||||||
|
unitWidthInPixelsRow.border = emptyBorder
|
||||||
|
unitWidthInPixelsRow.add(JLabel("Unit Width in Pixels "), BorderLayout.WEST)
|
||||||
|
unitWidthInPixelsRow.add(uiUnitWidthSelector, BorderLayout.EAST)
|
||||||
|
val unitHeightInPixelsRow = panelWithBorderLayout
|
||||||
|
unitHeightInPixelsRow.border = emptyBorder
|
||||||
|
unitHeightInPixelsRow.add(JLabel("Unit Height in Pixels "), BorderLayout.WEST)
|
||||||
|
unitHeightInPixelsRow.add(uiUnitHeightSelector, BorderLayout.EAST)
|
||||||
|
val widthInPixelsRow = panelWithBorderLayout
|
||||||
|
widthInPixelsRow.border = emptyBorder
|
||||||
|
widthInPixelsRow.add(JLabel("Display Width in Pixels "), BorderLayout.WEST)
|
||||||
|
widthInPixelsRow.add(uiWidthSelector, BorderLayout.EAST)
|
||||||
|
val heightInPixelsRow = panelWithBorderLayout
|
||||||
|
heightInPixelsRow.border = emptyBorder
|
||||||
|
heightInPixelsRow.add(JLabel("Display Height in Pixels "), BorderLayout.WEST)
|
||||||
|
heightInPixelsRow.add(uiHeightSelector, BorderLayout.EAST)
|
||||||
|
val baseAddressRow = panelWithBorderLayout
|
||||||
|
baseAddressRow.border = emptyBorder
|
||||||
|
baseAddressRow.add(JLabel("Base address for display "), BorderLayout.WEST)
|
||||||
|
baseAddressRow.add(uiBaseAddressSelector, BorderLayout.EAST)
|
||||||
|
|
||||||
|
// Lay 'em out in the grid...
|
||||||
|
organization.add(unitWidthInPixelsRow)
|
||||||
|
organization.add(unitHeightInPixelsRow)
|
||||||
|
organization.add(widthInPixelsRow)
|
||||||
|
organization.add(heightInPixelsRow)
|
||||||
|
organization.add(baseAddressRow)
|
||||||
|
return organization
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI components and layout for right half of GUI, the visualization display area.
|
||||||
|
private fun buildVisualizationArea(): JComponent
|
||||||
|
{
|
||||||
|
canvas = GraphicsPanel()
|
||||||
|
canvas.preferredSize = displayDimension
|
||||||
|
canvas.toolTipText = "Bitmap display area"
|
||||||
|
return canvas
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset all counters in the Grid.
|
||||||
|
private fun resetCounts() = grid.reset()
|
||||||
|
|
||||||
|
private fun <T> JComboBox<T>.getInt() = selectedItem!!.toString().toInt()
|
||||||
|
|
||||||
|
// Use this for consistent results.
|
||||||
|
private val panelWithBorderLayout: JPanel
|
||||||
|
get() = JPanel(BorderLayout(2, 2))
|
||||||
|
|
||||||
|
// Method to determine grid dimensions based on current control settings.
|
||||||
|
// Each grid element corresponds to one visualization unit.
|
||||||
|
private fun createNewGrid(): Grid
|
||||||
|
{
|
||||||
|
val rows = displayHeight / unitHeight
|
||||||
|
val columns = displayWidth / unitWidth
|
||||||
|
return Grid(rows, columns)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given memory address, update color for the corresponding grid element.
|
||||||
|
private fun updateColorForAddress(notice: MemoryAccessNotice)
|
||||||
|
{
|
||||||
|
val address = notice.address
|
||||||
|
val value = notice.value
|
||||||
|
val offset = (address - baseAddress) / Memory.WORD_LENGTH_BYTES
|
||||||
|
try
|
||||||
|
{
|
||||||
|
grid.setElement(offset / grid.cols, offset % grid.cols, value)
|
||||||
|
} catch (e: IndexOutOfBoundsException)
|
||||||
|
{
|
||||||
|
// If address is out of range for display, do nothing.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Specialized inner classes for modeling and animation.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Class that represents the panel for visualizing and animating memory reference
|
||||||
|
// patterns.
|
||||||
|
private inner class GraphicsPanel : JPanel()
|
||||||
|
{
|
||||||
|
// override default paint method to assure display updated correctly every time
|
||||||
|
// the panel is repainted.
|
||||||
|
override fun paint(g: Graphics) = paintGrid(g, grid)
|
||||||
|
|
||||||
|
// Paint the color codes.
|
||||||
|
private fun paintGrid(g: Graphics, grid: Grid)
|
||||||
|
{
|
||||||
|
var upperLeftX = 0
|
||||||
|
var upperLeftY = 0
|
||||||
|
for (i in 0 until grid.rows)
|
||||||
|
{
|
||||||
|
for (j in 0 until grid.cols)
|
||||||
|
{
|
||||||
|
g.color = grid.getElementFast(i, j)
|
||||||
|
g.fillRect(upperLeftX, upperLeftY, unitWidth, unitHeight)
|
||||||
|
upperLeftX += unitWidth // faster than multiplying
|
||||||
|
}
|
||||||
|
// get ready for next row...
|
||||||
|
upperLeftX = 0
|
||||||
|
upperLeftY += unitHeight // faster than multiplying
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// Represents grid of colors
|
||||||
|
private class Grid(rows: Int, columns: Int)
|
||||||
|
{
|
||||||
|
var grid: Array<Array<Color?>>
|
||||||
|
var rows: Int
|
||||||
|
var cols: Int
|
||||||
|
|
||||||
|
init
|
||||||
|
{
|
||||||
|
grid = Array(rows) { arrayOfNulls(columns) }
|
||||||
|
this.rows = rows
|
||||||
|
this.cols = columns
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns value in given grid element; null if row or column is out of range.
|
||||||
|
private fun getElement(row: Int, column: Int): Color?
|
||||||
|
{
|
||||||
|
return if (row in 0..rows && column >= 0 && column <= cols) grid[row][column] else null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns value in given grid element without doing any row/column index checking.
|
||||||
|
// Is faster than getElement but will throw array index out of bounds exception if
|
||||||
|
// parameter values are outside the bounds of the grid.
|
||||||
|
fun getElementFast(row: Int, column: Int): Color?
|
||||||
|
{
|
||||||
|
return grid[row][column]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the grid element.
|
||||||
|
fun setElement(row: Int, column: Int, color: Int)
|
||||||
|
{
|
||||||
|
grid[row][column] = Color(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the grid element.
|
||||||
|
private fun setElement(row: Int, column: Int, color: Color)
|
||||||
|
{
|
||||||
|
grid[row][column] = color
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just set all grid elements to black.
|
||||||
|
fun reset()
|
||||||
|
{
|
||||||
|
for (i in 0 until rows)
|
||||||
|
{
|
||||||
|
for (j in 0 until cols)
|
||||||
|
{
|
||||||
|
grid[i][j] = Color.BLACK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object
|
||||||
|
{
|
||||||
|
private const val version = "Version 1.0"
|
||||||
|
private const val heading = "Bitmap Display"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main provided for pure stand-alone use. Recommended stand-alone use is to write a driver program that
|
||||||
|
* instantiates a Bitmap object then invokes its go() method. "stand-alone" means it is not invoked from the MARS
|
||||||
|
* Tools menu. "Pure" means there is no driver program to invoke the application.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun main(args: Array<String>)
|
||||||
|
{
|
||||||
|
BitmapDisplay("Bitmap Display stand-alone, " + version, heading).go()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user