package edu.princeton.toy; import java.awt.*; import java.awt.event.*; import java.io.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.text.*; import edu.princeton.swing.*; import edu.princeton.toy.lang.*; /** * TCorePane is a JPanel which acts as an editor for the stdin of a TVirtualMachine. * * @author btsang * @version 7.1 */ public class TCorePane extends JPanel { private static final String CLASS_STRING = TCorePane.class.toString(); /** * The command to update the contents of the inputList with the stdin stream of the * virtualMachine. */ public static final String UPDATE_COMMAND = CLASS_STRING + "#updateCommand"; private JTextField instructionTextField; private JTextField pcTextField; private DefaultListModel registerModel; private DefaultListModel memModel; private boolean distinguishUninitialized; private TWord programCtr; private TWord instruction; private TWord registers[]; private TWord mem[]; private PHyperlink saveMemDumpLink; private PHyperlink saveCoreDumpLink; private TVirtualMachine virtualMachine; private Listener listener; /** * Creates a new TCorePane. */ public TCorePane(TVirtualMachine virtualMachine, Action saveMemDumpAction, Action saveCoreDumpAction) { super(new GridBagLayout(), true); if (virtualMachine == null) throw new NullPointerException(); this.virtualMachine = virtualMachine; registers = new TWord[TVirtualMachine.REGISTER_COUNT]; mem = new TWord[TVirtualMachine.MEM_COUNT]; listener = new Listener(); virtualMachine.addChangeListener(listener); add( new JLabel("Core"), new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0 ) ); saveCoreDumpLink = new PHyperlink(saveCoreDumpAction, PHyperlink.METAL_STYLE); saveCoreDumpLink.setText("Save Core Dump..."); add( saveCoreDumpLink, new GridBagConstraints( 1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0 ) ); add( new JLabel("Program Counter"), new GridBagConstraints( 0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0 ) ); pcTextField = new PTextField(); pcTextField.setEditable(false); pcTextField.setFont(null); add( pcTextField, new GridBagConstraints( 1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 2, 2), 0, 0 ) ); add( new JLabel("Current Instruction"), new GridBagConstraints( 0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0 ) ); instructionTextField = new PTextField(); instructionTextField.setEditable(false); instructionTextField.setFont(null); add( instructionTextField, new GridBagConstraints( 1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 2, 2), 0, 0 ) ); { // Prepare the split pane JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); splitPane.setFont(null); { // Prepare the register panel JPanel panel = new JPanel(new GridBagLayout()); panel.setFont(null); panel.add( new JLabel("Registers"), new GridBagConstraints( 0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0 ) ); registerModel = new DefaultListModel(); registerModel.ensureCapacity(TVirtualMachine.REGISTER_COUNT); for (int ctr = 0; ctr < TVirtualMachine.REGISTER_COUNT; ctr++) registerModel.addElement(""); PList list = new PList(registerModel); list.setFont(null); JScrollPane scrollPane = new JScrollPane( list, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED ); scrollPane.setFont(null); scrollPane.getViewport().setFont(null); panel.add( scrollPane, new GridBagConstraints( 0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 2, 2, 2), 0, 0 ) ); splitPane.setTopComponent(panel); } { // Prepare the memory panel JPanel panel = new JPanel(new GridBagLayout()); panel.setFont(null); panel.add( new JLabel("Memory"), new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0 ) ); saveMemDumpLink = new PHyperlink(saveMemDumpAction, PHyperlink.METAL_STYLE); saveMemDumpLink.setText("Save Memory Dump..."); panel.add( saveMemDumpLink, new GridBagConstraints( 1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0 ) ); memModel = new DefaultListModel(); memModel.ensureCapacity(TVirtualMachine.MEM_COUNT); for (int ctr = 0; ctr < TVirtualMachine.MEM_COUNT; ctr++) memModel.addElement(""); PList list = new PList(memModel); list.setFont(null); JScrollPane scrollPane = new JScrollPane( list, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED ); scrollPane.setFont(null); scrollPane.getViewport().setFont(null); panel.add( scrollPane, new GridBagConstraints( 0, 1, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 2, 2, 2), 0, 0 ) ); splitPane.setBottomComponent(panel); } splitPane.setOneTouchExpandable(true); splitPane.setDividerLocation(0.4); splitPane.setResizeWeight(0.4); add( splitPane, new GridBagConstraints( 0, 3, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 2, 2, 2), 0, 0 ) ); } doCommand(UPDATE_COMMAND, null); } /** * Sets the virtualMachine attached to this TCorePane. * * @param virtualMachine The virtualMachine to be attached to this TCorePane. */ public void setVirtualMachine(TVirtualMachine virtualMachine) { if (virtualMachine == null) throw new NullPointerException(); if (this.virtualMachine == virtualMachine) return; this.virtualMachine.removeChangeListener(listener); virtualMachine.addChangeListener(listener); this.virtualMachine = virtualMachine; doCommand(UPDATE_COMMAND, null); } /** * Returns the virtualMachine attached to this TCorePane. * * @return The virtualMachine attached to this TCorePane. */ public TVirtualMachine getVirtualMachine() { return virtualMachine; } /** * Performs a command based on the argument. * * @param command A string representing the command. Note that pointer equality (not string * equality) is tested here, so it is important to use the string constants defined in this * class. An IllegalArgumentException will be thrown if the argument is invalid. * @return True iff the command was executed sucessfully. */ public synchronized boolean doCommand(String command, Object extraInfo) { //////////////////////////////////////////////////////////////////////////////////////////// if (command == UPDATE_COMMAND) { boolean newDistinguishUninitialized = virtualMachine.getDistinguishUninitialized(); boolean oldDistinguishUninitialized = distinguishUninitialized; distinguishUninitialized = newDistinguishUninitialized; // If distinguishUninitialized has changed, the best thing to do would be to update // everything if (newDistinguishUninitialized != oldDistinguishUninitialized) { TWord newValue; newValue = programCtr = virtualMachine.getProgramCtr(); pcTextField.setText(newValue.toString(false)); pcTextField.setCaretPosition(0); newValue = instruction = virtualMachine.getCurrentInstruction(); instructionTextField.setText( newValue.toHexString(distinguishUninitialized) + " (" + newValue.toPseudoCodeString(distinguishUninitialized) + ")" ); instructionTextField.setCaretPosition(0); for (int ctr = 0; ctr < TVirtualMachine.REGISTER_COUNT; ctr++) { newValue = registers[ctr] = virtualMachine.getRegister(ctr); registerModel.set( ctr, "R[" + TWord.HEX_DIGITS[ctr] + "] = " + newValue.toString(distinguishUninitialized) ); } for (int ctr = 0; ctr < TVirtualMachine.MEM_COUNT; ctr++) { newValue = mem[ctr] = virtualMachine.getMem(ctr); if (ctr < TVirtualMachine.PC_START_VALUE) { memModel.set( ctr, "M[" + TWord.HEX_PAIRS[ctr] + "] = " + newValue.toString(distinguishUninitialized) ); } else { memModel.set( ctr, "M[" + TWord.HEX_PAIRS[ctr] + "] = " + newValue.toHexString(distinguishUninitialized) + " (" + newValue.toPseudoCodeString(distinguishUninitialized) + ")" ); } } } else { // If distinguishUninitialized hasn't changed, then we can just update things if and // only if they changed TWord oldValue; TWord newValue; oldValue = programCtr; newValue = programCtr = virtualMachine.getProgramCtr(); if (oldValue != newValue) { pcTextField.setText(newValue.toString(false)); pcTextField.setCaretPosition(0); } oldValue = instruction; newValue = instruction = virtualMachine.getCurrentInstruction(); if (oldValue != newValue) { instructionTextField.setText( newValue.toHexString(distinguishUninitialized) + " (" + newValue.toPseudoCodeString(distinguishUninitialized) + ")" ); instructionTextField.setCaretPosition(0); } for (int ctr = 0; ctr < TVirtualMachine.REGISTER_COUNT; ctr++) { oldValue = registers[ctr]; newValue = registers[ctr] = virtualMachine.getRegister(ctr); if (oldValue != newValue) { registerModel.set( ctr, "R[" + TWord.HEX_DIGITS[ctr] + "] = " + newValue.toString(distinguishUninitialized) ); } } for (int ctr = 0; ctr < TVirtualMachine.MEM_COUNT; ctr++) { oldValue = mem[ctr]; newValue = mem[ctr] = virtualMachine.getMem(ctr); if (oldValue != newValue) { if (ctr < TVirtualMachine.PC_START_VALUE) { memModel.set( ctr, "M[" + TWord.HEX_PAIRS[ctr] + "] = " + newValue.toString(distinguishUninitialized) ); } else { memModel.set( ctr, "M[" + TWord.HEX_PAIRS[ctr] + "] = " + newValue.toHexString(distinguishUninitialized) + " (" + newValue.toPseudoCodeString(distinguishUninitialized) + ")" ); } } } } return true; } throw new IllegalArgumentException(); } /** * The Listener of a TCorePane pays attention to the changes in the virtualMachine and updates * the components. * * @author btsang * @version 7.1 */ protected class Listener implements ChangeListener { /** * Implement ChangeListener to update the list whenever the virtual machine's state changes. */ public void stateChanged(ChangeEvent e) { doCommand(UPDATE_COMMAND, null); } } }