import java.awt.event.*; import java.awt.*; import javax.swing.event.*; import javax.swing.*; import java.io.*; import java.util.Vector; import javax.swing.border.*; import java.util.prefs.*; /** * Provides a GUI for the SaM Simulator that can run * SaM programs and capture their state after each * instruction execution for later review. To start, create a * new SamGui and call start() */ public class SamGUI extends JFrame implements Video, ThreadedFrontend { private final static String BR = System.getProperty("line.separator"); private final static int EXECUTION_SPEED_NONE = 0; private final static int EXECUTION_SPEED_VF = 1; private final static int EXECUTION_SPEED_F = 2; private final static int EXECUTION_SPEED_M = 3; private final static int EXECUTION_SPEED_S = 4; private final static int EXECUTION_SPEED_VS = 5; protected Container contentPane; protected JPanel mainPanel; protected JPanel codePanel; protected JList programCode; protected JScrollPane programCodeView; protected JList stack; protected JScrollPane stackView; protected JLabel pcLabel; protected JLabel fbrLabel; protected JLabel spLabel; protected JLabel hpLabel; protected JTextArea simulatorOutput; protected JPanel programCodePanel; protected JPanel registerPanel; protected JPanel stackPanel; protected JPanel consolePanel; protected JPanel buttonPanel; protected GridBagLayout componentLayout; protected GridBagConstraints componentLayoutCons; protected JFileChooser fileChooserDialog; protected File sourceFile = null; protected String filename; protected StatusBar statusBar; protected Sys sys; protected Processor proc; protected Memory mem; protected RunThread runThread; protected JMenuItem openMenuItem; protected JButton openButton; protected JMenuItem saveAsMenuItem; protected JMenuItem resetMenuItem; protected JButton resetButton; protected JMenuItem runMenuItem; protected JButton runButton; protected JMenuItem captureMenuItem; protected JButton captureButton; protected JMenuItem stepMenuItem; protected JButton stepButton; protected JMenuItem stopMenuItem; protected JButton stopButton; protected JMenu optionsMenu; protected JMenu optionsSpeedMenu; protected int runDelay = 64; protected Preferences prefs; protected boolean capture = false; protected boolean guiCreated = false; protected JDialog aboutDialog = null; protected JDialog stackColorsDialog = null; protected static final int DEFAULT = 0; protected static final int RUNCOMPLETED = 1; protected static final int READYTORUN = 2; protected static final int RUNNING = 3; protected static final int CAPTURING = 4; protected static final int STOPPED = 5; Vector steps; /** * Creates a new SamGUI using a new system */ public SamGUI() { buildGUI(new Sys()); } /** * Creates a new SamGUI with an existing system * Use start() to actually show the window * Use loadFile() to load a file at startup * @param sys The system to use */ public SamGUI(Sys sys) { buildGUI(sys); } // Creates the GUI private void buildGUI(Sys sys) { System.setProperty("sun.awt.noerasebackground", "true"); // Set up basic top level layout contentPane = getContentPane(); setTitle("SaM Simulator"); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); contentPane.setLayout(new BorderLayout()); mainPanel = new JPanel(); contentPane.add(mainPanel, BorderLayout.CENTER); statusBar = new StatusBar(); contentPane.add(statusBar, BorderLayout.SOUTH); // Set up SaM this.sys = sys; proc = sys.cpu(); mem = sys.mem(); sys.setVideo(this); // Set up file chooser dialogs fileChooserDialog = new JFileChooser("."); fileChooserDialog.setFileFilter(new SimpleFilter("sam", "SaM Source Code (*.sam)")); prefs = Preferences.userRoot().node("/edu/cornell/cs/SaM/SamGUI"); // Add components createComponents(); createMenus(); reset(); addNotify(); setWindowListeners(); pack(); guiCreated = true; } // Sets the listeners to listent for window closing and resizing private void setWindowListeners() { addComponentListener(new ComponentAdapter() { public void componentResized(ComponentEvent e) { } }); // Add Window Listener to handle window closing addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { closeWindow(); } }); } // Creates the components private void createComponents() { // Set up panels programCodePanel = buildProgramCodePanel(); registerPanel = buildRegisterPanel(); stackPanel = buildStackPanel(); consolePanel = buildConsolePanel(); buttonPanel = buildButtonPanel(); componentLayoutCons = new GridBagConstraints(); componentLayoutCons.fill = GridBagConstraints.BOTH; componentLayoutCons.anchor = GridBagConstraints.CENTER; componentLayoutCons.insets = new Insets(5, 5, 5, 5); // Set up main panel componentLayout = new GridBagLayout(); mainPanel.setLayout(componentLayout); reorderComponents(); } private void reorderComponents(){ int width = 0; mainPanel.removeAll(); int position = 0; if(prefs.getBoolean("showProgramCodePanel", true)){ width += 225; addComponent(programCodePanel, mainPanel, componentLayout, componentLayoutCons, position, 0, 1, 2, 1, 1); position++; } if(prefs.getBoolean("showStackPanel", true)){ width += 175; addComponent(stackPanel, mainPanel, componentLayout, componentLayoutCons, position, 0, 1, 2, 1, 1); position++; } addComponent(registerPanel, mainPanel, componentLayout, componentLayoutCons, position, 0, 1, 1, 0, 0); Insets oldInsets = componentLayoutCons.insets; componentLayoutCons.insets = new Insets(5, 5, 1, 5); addComponent(buttonPanel, mainPanel, componentLayout, componentLayoutCons, position,1,1,1,0,1); position++; width += 125; componentLayoutCons.insets = oldInsets; addComponent(consolePanel, mainPanel, componentLayout, componentLayoutCons, 0, 2, position, 1, 1, 0.1); validate(); pack(); setSize(new Dimension((width<560)?560:width, 560)); } // Create Register Panel private JPanel buildRegisterPanel() { JPanel registerPanel = new JPanel(); registerPanel.setPreferredSize(new Dimension(100, 150)); JPanel regIntPanel = new JPanel(); registerPanel.setLayout(new BorderLayout()); regIntPanel.setBorder(new SoftBevelBorder(BevelBorder.LOWERED)); GridBagLayout lr = new GridBagLayout(); GridBagConstraints cr = new GridBagConstraints(); cr.fill = GridBagConstraints.BOTH; cr.insets = new Insets(5, 5, 5, 5); regIntPanel.setLayout(lr); regIntPanel.setBackground(new Color(220, 220, 220)); cr.anchor = GridBagConstraints.WEST; addComponent(new JLabel("PC:"), regIntPanel, lr, cr, 0, 0, 1, 1, 1, 1); addComponent(new JLabel("FBR:"), regIntPanel, lr, cr, 0, 1, 1, 1, 1, 1); addComponent(new JLabel("SP:"), regIntPanel, lr, cr, 0, 2, 1, 1, 1, 1); addComponent(new JLabel("HP:"), regIntPanel, lr, cr, 0, 3, 1, 1, 1, 1); pcLabel = new JLabel(""); fbrLabel = new JLabel(""); spLabel = new JLabel(""); hpLabel = new JLabel(""); cr.anchor = GridBagConstraints.EAST; addComponent(pcLabel, regIntPanel, lr, cr, 1, 0, 1, 1, 1, 1); addComponent(fbrLabel, regIntPanel, lr, cr, 1, 1, 1, 1, 1, 1); addComponent(spLabel, regIntPanel, lr, cr, 1, 2, 1, 1, 1, 1); addComponent(hpLabel, regIntPanel, lr, cr, 1, 3, 1, 1, 1, 1); registerPanel.add(regIntPanel, BorderLayout.CENTER); registerPanel.add(new JLabel("Registers:"), BorderLayout.NORTH); return registerPanel; } // Build Stack Panel private JPanel buildStackPanel() { JPanel stackPanel = new JPanel(); stackPanel.setPreferredSize(new Dimension(100, 350)); stackPanel.setMinimumSize(new Dimension(100, 100)); stack = new JList(new DefaultListModel()); stack.setCellRenderer(new StackCellRenderer()); stack.setFont(new Font("Monospaced", Font.BOLD, 12)); stack.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); stackPanel.setLayout(new BorderLayout()); JPanel stackListPanel = new JPanel(); stackListPanel.setLayout(new BorderLayout()); stackListPanel.setBackground(Color.white); stackListPanel.add("South", stack); stackView = new JScrollPane(stackListPanel); stackView.setBorder(new SoftBevelBorder(BevelBorder.LOWERED)); stackPanel.add(stackView, BorderLayout.CENTER); stackPanel.add(new JLabel("Stack:"), BorderLayout.NORTH); return stackPanel; } // Build Program Code Panel private JPanel buildProgramCodePanel() { programCode = new JList(new DefaultListModel()); programCode.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); JPanel programCodePanel = new JPanel(); programCodePanel.setPreferredSize(new Dimension(150, 350)); programCodePanel.setMinimumSize(new Dimension(150, 100)); programCodePanel.setLayout(new BorderLayout()); programCodeView = new JScrollPane(programCode); programCodeView.setBorder(new SoftBevelBorder(BevelBorder.LOWERED)); programCodePanel.add(programCodeView, BorderLayout.CENTER); programCodePanel.add(new JLabel("Program Code:"), BorderLayout.NORTH); return programCodePanel; } // Build Console Panel private JPanel buildConsolePanel() { JPanel consolePanel = new JPanel(); consolePanel.setPreferredSize(new Dimension(525, 100)); consolePanel.setMinimumSize(new Dimension(100, 100)); consolePanel.setLayout(new BorderLayout()); simulatorOutput = new JTextArea(); JScrollPane simulatorScrollPane = new JScrollPane(simulatorOutput); simulatorScrollPane.setBorder(new SoftBevelBorder(BevelBorder.LOWERED)); consolePanel.add(simulatorScrollPane, BorderLayout.CENTER); consolePanel.add(new JLabel("Console:"), BorderLayout.NORTH); simulatorOutput.setEditable(false); simulatorOutput.setLineWrap(true); return consolePanel; } // Build Button Panel private JPanel buildButtonPanel() { JPanel buttonPanel = new JPanel(); buttonPanel.setPreferredSize(new Dimension(100, 175)); buttonPanel.setLayout(new GridLayout(6, 1, 0, 5)); openButton = new JButton("Open"); openButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { openFile(); } }); buttonPanel.add(openButton); stepButton = new JButton("Step"); stepButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { step(); } }); buttonPanel.add(stepButton); runButton = new JButton("Run"); runButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { run(); } }); buttonPanel.add(runButton); captureButton = new JButton("Capture"); captureButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { capture(); } }); buttonPanel.add(captureButton); stopButton = new JButton("Stop"); stopButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { stop(); } }); buttonPanel.add(stopButton); resetButton = new JButton("Reset"); resetButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { reset(); } }); buttonPanel.add(resetButton); return buttonPanel; } // Create the menu structure and add event listeners private void createMenus() { JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); JMenu fileMenu = new JMenu("File"); menuBar.add(fileMenu); fileMenu.setMnemonic(KeyEvent.VK_F); JMenu newMenu = new JMenu("New"); fileMenu.add(newMenu); newMenu.setMnemonic(KeyEvent.VK_N); JMenuItem newSimulatorMenuItem = newMenu.add("Simulator Window"); newSimulatorMenuItem.setMnemonic(KeyEvent.VK_S); newSimulatorMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK)); newSimulatorMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { SamGUI gui = new SamGUI(); gui.start(); } }); JMenuItem newCaptureMenuItem = newMenu.add("Capture Viewer"); newCaptureMenuItem.setMnemonic(KeyEvent.VK_C); newCaptureMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK)); newCaptureMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { CaptureDisplay cd = new CaptureDisplay(); cd.start(); } }); openMenuItem = fileMenu.add("Open..."); openMenuItem.setMnemonic(KeyEvent.VK_O); openMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK)); openMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { openFile(); } }); saveAsMenuItem = fileMenu.add("Save As..."); saveAsMenuItem.setMnemonic(KeyEvent.VK_S); saveAsMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK)); saveAsMenuItem.setEnabled(false); saveAsMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { saveFile(); } }); JMenuItem closeMenuItem = fileMenu.add("Close"); closeMenuItem.setMnemonic(KeyEvent.VK_C); closeMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, ActionEvent.CTRL_MASK)); closeMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { closeWindow(); } }); JMenuItem exitMenuItem = fileMenu.add("Exit"); exitMenuItem.setMnemonic(KeyEvent.VK_X); exitMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK)); exitMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); JMenu runMenu = new JMenu("Run"); runMenu.setMnemonic(KeyEvent.VK_R); menuBar.add(runMenu); stepMenuItem = runMenu.add("Step"); stepMenuItem.setMnemonic(KeyEvent.VK_S); stepMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, ActionEvent.CTRL_MASK)); stepMenuItem.setEnabled(false); stepMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { step(); } }); runMenuItem = runMenu.add("Run"); runMenuItem.setMnemonic(KeyEvent.VK_R); runMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.CTRL_MASK)); runMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { run(); } }); captureMenuItem = runMenu.add("Capture"); captureMenuItem.setMnemonic(KeyEvent.VK_T); captureMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, ActionEvent.CTRL_MASK)); captureMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { capture(); } }); stopMenuItem = runMenu.add("Stop"); stopMenuItem.setMnemonic(KeyEvent.VK_S); stopMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, ActionEvent.CTRL_MASK)); stopMenuItem.setEnabled(false); stopMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { stop(); } }); resetMenuItem = runMenu.add("Reset"); resetMenuItem.setMnemonic(KeyEvent.VK_R); resetMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK)); resetMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { reset(); } }); optionsMenu = new JMenu("Options"); optionsMenu.setMnemonic(KeyEvent.VK_O); menuBar.add(optionsMenu); optionsSpeedMenu = new JMenu("Execution Speed"); optionsSpeedMenu.setMnemonic(KeyEvent.VK_S); optionsMenu.add(optionsSpeedMenu); ButtonGroup optionsSpeedGroup = new ButtonGroup(); JMenuItem veryFastOptionsSpeedMenuItem = new JRadioButtonMenuItem("Very Fast Execution"); optionsSpeedMenu.add(veryFastOptionsSpeedMenuItem); optionsSpeedGroup.add(veryFastOptionsSpeedMenuItem); if(prefs.getInt("executionSpeed",EXECUTION_SPEED_NONE) == EXECUTION_SPEED_VF) veryFastOptionsSpeedMenuItem.setSelected(true); veryFastOptionsSpeedMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { runDelay = 0; prefs.putInt("executionSpeed", EXECUTION_SPEED_VF); prefs.putInt("customExecutionSpeedSetting", 0); } }); JMenuItem fastOptionsSpeedMenuItem = new JRadioButtonMenuItem("Fast Execution"); optionsSpeedMenu.add(fastOptionsSpeedMenuItem); optionsSpeedGroup.add(fastOptionsSpeedMenuItem); if(prefs.getInt("executionSpeed",EXECUTION_SPEED_NONE) == EXECUTION_SPEED_F) fastOptionsSpeedMenuItem.setSelected(true); fastOptionsSpeedMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { runDelay = 25; prefs.putInt("executionSpeed", EXECUTION_SPEED_F); prefs.putInt("customExecutionSpeedSetting", 0); } }); JMenuItem mediumOptionsSpeedMenuItem = new JRadioButtonMenuItem("Medium Execution"); optionsSpeedMenu.add(mediumOptionsSpeedMenuItem); optionsSpeedGroup.add(mediumOptionsSpeedMenuItem); if(prefs.getInt("executionSpeed",EXECUTION_SPEED_NONE) == EXECUTION_SPEED_M || prefs.getInt("executionSpeed", EXECUTION_SPEED_NONE) == EXECUTION_SPEED_NONE) mediumOptionsSpeedMenuItem.setSelected(true); mediumOptionsSpeedMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { runDelay = 64; prefs.putInt("executionSpeed", EXECUTION_SPEED_M); prefs.putInt("customExecutionSpeedSetting", 0); } }); JMenuItem slowOptionsSpeedMenuItem = new JRadioButtonMenuItem("Slow Execution"); optionsSpeedMenu.add(slowOptionsSpeedMenuItem); optionsSpeedGroup.add(slowOptionsSpeedMenuItem); if(prefs.getInt("executionSpeed",EXECUTION_SPEED_NONE) == EXECUTION_SPEED_S) slowOptionsSpeedMenuItem.setSelected(true); slowOptionsSpeedMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { runDelay = 100; prefs.putInt("executionSpeed", EXECUTION_SPEED_S); prefs.putInt("customExecutionSpeedSetting", 0); } }); JMenuItem verySlowOptionsSpeedMenuItem = new JRadioButtonMenuItem("Very Slow Execution"); optionsSpeedMenu.add(verySlowOptionsSpeedMenuItem); optionsSpeedGroup.add(verySlowOptionsSpeedMenuItem); if(prefs.getInt("executionSpeed",EXECUTION_SPEED_NONE) == EXECUTION_SPEED_VS) verySlowOptionsSpeedMenuItem.setSelected(true); verySlowOptionsSpeedMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { runDelay = 200; prefs.putInt("executionSpeed", EXECUTION_SPEED_VS); prefs.putInt("customExecutionSpeedSetting", 0); } }); JMenu optionsViewMenu = new JMenu("View"); optionsViewMenu.setMnemonic(KeyEvent.VK_V); optionsMenu.add(optionsViewMenu); JCheckBoxMenuItem stackOptionsViewMenuItem = new JCheckBoxMenuItem("Stack"); stackOptionsViewMenuItem.setMnemonic(KeyEvent.VK_S); optionsViewMenu.add(stackOptionsViewMenuItem); if(prefs.getBoolean("showStackPanel", true)) stackOptionsViewMenuItem.setState(true); stackOptionsViewMenuItem.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ if(((JCheckBoxMenuItem)e.getSource()).getState()) prefs.putBoolean("showStackPanel", true); else prefs.putBoolean("showStackPanel", false); reorderComponents(); } }); JCheckBoxMenuItem programCodeOptionsViewMenuItem = new JCheckBoxMenuItem("Program Code"); programCodeOptionsViewMenuItem.setMnemonic(KeyEvent.VK_C); optionsViewMenu.add(programCodeOptionsViewMenuItem); if(prefs.getBoolean("showProgramCodePanel", true)) programCodeOptionsViewMenuItem.setState(true); programCodeOptionsViewMenuItem.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ if(((JCheckBoxMenuItem)e.getSource()).getState()) prefs.putBoolean("showProgramCodePanel", true); else prefs.putBoolean("showProgramCodePanel", false); reorderComponents(); } }); JMenu helpMenu = new JMenu("Help"); helpMenu.setMnemonic(KeyEvent.VK_H); menuBar.add(helpMenu); JMenuItem colorsMenuItem = helpMenu.add("Stack Colors Reference"); colorsMenuItem.setMnemonic(KeyEvent.VK_S); colorsMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { displayStackColorsReference(); } }); JMenuItem aboutMenuItem = helpMenu.add("About"); aboutMenuItem.setMnemonic(KeyEvent.VK_A); aboutMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { displayAbout(); } }); } /** * Destroys the window, system, and any dialogs */ public void closeWindow() { if (stackColorsDialog != null) { stackColorsDialog.dispose(); } if (aboutDialog != null) { aboutDialog.dispose(); } dispose(); } /** * Makes the window visible */ public void start() { pack(); setVisible(true); // Set up the dialogs now to avoid loading time later stackColorsDialog = new StackColorsReferenceDialog(this); aboutDialog = new AboutDialog("SaM GUI", this); } // Clears out all textboxes and resets processor private void reset() { proc.reset(); mem.reset(); updateStack(); updateRegisters(); updateProgram(true); if (proc.getProgram() != null) setStatus(READYTORUN); else setStatus(DEFAULT); simulatorOutput.setText(""); steps = new Vector(); capture = false; } // Updates the register display private void updateRegisters() { pcLabel.setText("" + proc.get(Processor.PC)); fbrLabel.setText("" + proc.get(Processor.FBR)); spLabel.setText("" + proc.get(Processor.SP)); hpLabel.setText("" + proc.get(Processor.HP)); } // Update the stack display private void updateStack() { DefaultListModel stak = (DefaultListModel) (stack.getModel()); stak.clear(); int stackSize = proc.get(Processor.SP); for (int i = 0; i < stackSize; i++) try { int value = mem.getMem(i); byte type = mem.getType(i); stak.add(0, new StackCellRenderer.StackCell(i, value, type)); } catch (SystemException e) { simulatorOutput.setText(simulatorOutput.getText() + "Stack Machine Error: " + e.toString() + BR); } stack.ensureIndexIsVisible(0); stackView.revalidate(); stackView.repaint(); } // Updates the program without reloading the data private void updateProgram() { updateProgram(false); } // Updates the program - if true, then reload data private void updateProgram(boolean update) { if (update) { DefaultListModel prog = (DefaultListModel) (programCode.getModel()); prog.clear(); Program code = proc.getProgram(); if (code != null) { SymbolTable ST = code.getTable(); for (int i = 0; i < code.getLength(); i++) { String label = ST.resolveSymbol(i); prog.addElement(i + ": " + code.getInst(i) + (label == null ? "" : " (<= " + label + " )")); } } } programCode.setSelectedIndex(proc.get(Processor.PC)); programCode.ensureIndexIsVisible(programCode.getSelectedIndex()); programCodeView.revalidate(); programCodeView.repaint(); } // Opens a file (show dialog box, calls loadFile) private void openFile() { if (fileChooserDialog.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) return; reset(); loadFile(fileChooserDialog.getSelectedFile()); } /** * Loads the provided file * @param samFile The file to load */ public void loadFile(File samFile) { try { Program prog = SamAssembler.assemble(new FileReader(samFile)); loadProgram(prog, samFile.getName()); sourceFile = samFile; } catch (AssemblerException e) { statusBar.setText("Could not open file"); simulatorOutput.setText("Assembler Error:" + BR + e); } catch (FileNotFoundException e) { statusBar.setText("Could not find file"); simulatorOutput.setText("Could not find file"); } catch (IOException e) { statusBar.setText("Could not load file"); simulatorOutput.setText("I/O Error while processing file"); } catch (TokenizerException e) { statusBar.setText("Error parsing file."); simulatorOutput.setText("Tokenizer Error:" + BR + e); } } /** * Loads the provided program * @param program the program to load * @param filename the name of the file being loaded */ public void loadProgram(Program prog, String filename) { proc.reset(); mem.reset(); if (prog == null) { setStatus(DEFAULT); } else { proc.load(prog); updateProgram(true); setStatus(READYTORUN); } sourceFile = null; this.filename = filename; setTitle("SaM Simulator - " + filename); } // saves a file (show dialog box, calls saveFile(File)) private void saveFile() { File file; while (true) { if (fileChooserDialog.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return; file = fileChooserDialog.getSelectedFile(); if(!file.getName().endsWith(".sam")) file = new File(file.getAbsolutePath() + ".sam"); if (file.exists()) { int r = JOptionPane.showConfirmDialog(this, "File already exists. Overwrite?", "Warning", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); switch (r) { case JOptionPane.YES_OPTION : saveFile(file); return; case JOptionPane.NO_OPTION : continue; case JOptionPane.CANCEL_OPTION : return; } } else { saveFile(file); return; } } } /** * Saves the provided file * @param samFile The file to save to */ public void saveFile(File samFile) { if (steps == null) return; try { BufferedWriter out = new BufferedWriter(new FileWriter(samFile)); Program code = proc.getProgram(); if (code != null) { SymbolTable ST = code.getTable(); for (int i = 0; i < code.getLength(); i++) { String labels[] = ST.resolveSymbols(i); if (labels.length > 0) { for (int x = 0; x < labels.length; x++) out.write(labels[x] + ":" + BR); } out.write(code.getInst(i) + BR); } } out.flush(); out.close(); sourceFile = samFile; filename = sourceFile.getName(); setTitle("SaM Simulator - " + samFile.getName()); } catch (FileNotFoundException e) { JOptionPane.showMessageDialog(this, "Could not find file", "Error", JOptionPane.ERROR_MESSAGE); } catch (IOException e) { JOptionPane.showMessageDialog(this, "Error saving file", "Error", JOptionPane.ERROR_MESSAGE); } } // Runs the program by creating a sam simulator private void run() { capture = false; runThread = new RunThread(this, sys, runDelay); setStatus(RUNNING); statusBar.setPermanentText("Running..."); runThread.start(); } // Runs the program and captures states; private void capture() { capture = true; runThread = new RunThread(this, sys, 1); setStatus(CAPTURING); statusBar.setPermanentText("Capturing..."); runThread.start(); } // Signal that run is done by run thread public void runDone(int code, Object o) { switch (code) { case RunThread.NORMAL : try { if (mem.getType(0) == Memory.FLOAT) simulatorOutput.setText(simulatorOutput.getText() + "Exit Code: " + Float.intBitsToFloat(mem.getMem(0)) + BR); else if (mem.getType(0) == Memory.CH) simulatorOutput.setText(simulatorOutput.getText() + "Exit Code: " + (char)mem.getMem(0)); else simulatorOutput.setText(simulatorOutput.getText() + "Exit Code: " + mem.getMem(0) + BR); } catch (Exception e) { simulatorOutput.setText(simulatorOutput.getText() + "No exit code provided" + BR); } if (capture) { statusBar.setText("Capture Completed"); Vector copySteps = steps; reset(); CaptureDisplay captureDisplay = new CaptureDisplay(); captureDisplay.start(copySteps, copyProgram(proc.getProgram()), filename); } else { statusBar.setText("Run Completed"); setStatus(RUNCOMPLETED); } break; case RunThread.ERROR : simulatorOutput.setText(simulatorOutput.getText() + "Processor Error: " + o.toString() + BR); statusBar.setText("Processor Error"); setStatus(RUNCOMPLETED); break; case RunThread.INTERRUPT : if (capture) { setStatus(RUNCOMPLETED); statusBar.setText("Capture Interrupted"); } else { setStatus(STOPPED); statusBar.setText("Execution Stopped"); } break; default : statusBar.clearText(); setStatus(RUNCOMPLETED); break; } validate(); runThread = null; } // We need to be able to duplicate a program // We're going to hack this a bit and just write it out // and back in, which should eliminate elements that // could not be repliated private Program copyProgram(Program program) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(program); oos.close(); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); Program newProgram = (Program)ois.readObject(); ois.close(); return newProgram; } catch (Exception e) { return null; } } // Stop the running program private void stop() { if (runThread != null) { runThread.stopExecution(); runThread = null; } } // Step void step() { capture = false; setStatus(STOPPED); try { proc.step(); if (proc.get(Processor.HALT) != 0) { if (mem.getType(0) == Memory.FLOAT) simulatorOutput.setText(simulatorOutput.getText() + "Exit Code: " + Float.intBitsToFloat(mem.getMem(0)) + BR); else if (mem.getType(0) == Memory.CH) simulatorOutput.setText(simulatorOutput.getText() + "Exit Code: " + (char)mem.getMem(0)); else simulatorOutput.setText(simulatorOutput.getText() + "Exit Code: " + mem.getMem(0) + BR); setStatus(RUNCOMPLETED); statusBar.setText("Execution completed"); } } catch (SystemException e) { simulatorOutput.setText(simulatorOutput.getText() + e + BR); setStatus(RUNCOMPLETED); return; } updateStatus(); } // updates display public void updateStatus() { updateStack(); updateRegisters(); updateProgram(); // Save status if (capture) steps.add(new ProgramState(mem.getStack(), mem.getStackTypes(), proc.getRegisters())); } // sets GUI status private void setStatus(int status) { switch (status) { case DEFAULT : enableButtons(false, false, false, true, false, true, false); break; case RUNCOMPLETED : enableButtons(false, false, false, true, true, true, true); break; case READYTORUN : enableButtons(true, true, false, true, false, true, true); break; case RUNNING : enableButtons(false, false, true, false, false, false, false); break; case CAPTURING : enableButtons(false, false, true, false, false, false, false); break; case STOPPED : enableButtons(true, false, false, true, true, true, true); break; } } // Sets the GUI components to values depending on the arguments provided private void enableButtons(boolean runStep, boolean capture, boolean stop, boolean open, boolean reset, boolean runOptions, boolean save) { resetMenuItem.setEnabled(reset); resetButton.setEnabled(reset); stopMenuItem.setEnabled(stop); stopButton.setEnabled(stop); captureMenuItem.setEnabled(capture); captureButton.setEnabled(capture); runMenuItem.setEnabled(runStep); runButton.setEnabled(runStep); optionsSpeedMenu.setEnabled(runOptions); stepMenuItem.setEnabled(runStep); stepButton.setEnabled(runStep); openMenuItem.setEnabled(open); openButton.setEnabled(open); saveAsMenuItem.setEnabled(save); // also make sure their background looks enabled/disabled if (runStep) { runButton.setBackground(new Color(204, 255, 204)); stepButton.setBackground(new Color(255, 255, 204)); } else { runButton.setBackground(new Color(204, 220, 204)); stepButton.setBackground(new Color(220, 220, 204)); } if (capture) captureButton.setBackground(new Color(220, 204, 255)); else captureButton.setBackground(new Color(212, 204, 220)); if (stop) stopButton.setBackground(new Color(255, 204, 204)); else stopButton.setBackground(new Color(220, 204, 204)); if (open) openButton.setBackground(new Color(204, 204, 255)); else openButton.setBackground(new Color(204, 204, 220)); if (reset) resetButton.setBackground(new Color(255, 255, 255)); else resetButton.setBackground(new Color(220, 220, 220)); } private JLabel addLabel(Icon icon, JPanel panel, GridBagLayout layout, GridBagConstraints c, int x, int y, int width, int height, double weightx, double weighty) { JLabel comp = new JLabel(icon); addComponent(comp, panel, layout, c, x, y, width, height, weightx, weighty); return comp; } private JButton addButton(String label, JPanel panel, GridBagLayout layout, GridBagConstraints c, int x, int y, int width, int height, double weightx, double weighty) { JButton comp = new JButton(label); addComponent(comp, panel, layout, c, x, y, width, height, weightx, weighty); return comp; } private void addComponent(JComponent comp, JPanel panel, GridBagLayout layout, GridBagConstraints c, int x, int y, int width, int height, double weightx, double weighty) { c.gridx = x; c.gridy = y; c.gridwidth = width; c.gridheight = height; c.weightx = weightx; c.weighty = weighty; layout.setConstraints(comp, c); panel.add(comp); } // Help Menu private void displayStackColorsReference() { if (stackColorsDialog == null) { stackColorsDialog = new StackColorsReferenceDialog(this); } stackColorsDialog.setVisible(true); } private void displayAbout() { if (aboutDialog == null) { aboutDialog = new AboutDialog("SaM GUI", this); } aboutDialog.setVisible(true); } // Video Stuff public void writeString(String str) { simulatorOutput.setText(simulatorOutput.getText() + "Processor Output: " + str + BR); } public void writeInt(int i) { simulatorOutput.setText(simulatorOutput.getText() + "Processor Output: " + i + BR); } public void writeChar(char c ) { simulatorOutput.setText(simulatorOutput.getText() + "Processor Output: " + c + BR); } public void writeFloat(float f) { simulatorOutput.setText(simulatorOutput.getText() + "Processor Output: " + f + BR); } public String readString() { String str = JOptionPane.showInputDialog(this, "Enter a String:", "Prompt", JOptionPane.QUESTION_MESSAGE); return (str == null) ? "" : str; } public int readInt() { int i; while (true) try { String ans = JOptionPane.showInputDialog(this, "Enter an Integer:", "Prompt", JOptionPane.QUESTION_MESSAGE); i = (ans == null) ? 0 : Integer.parseInt(ans); return i; } catch (NumberFormatException e) { JOptionPane.showMessageDialog(this, "Please enter an integer", "Error", JOptionPane.ERROR_MESSAGE); } } public float readFloat() { float f; while (true) try { String ans = JOptionPane.showInputDialog(this, "Enter a Float:", "Prompt", JOptionPane.QUESTION_MESSAGE); f = (ans == null) ? 0 : Float.parseFloat(ans); return f; } catch (NumberFormatException e) { JOptionPane.showMessageDialog(this, "Please enter a float", "Error", JOptionPane.ERROR_MESSAGE); } } public char readChar() { while (true){ String ans = JOptionPane.showInputDialog(this, "Enter a Character:", "Prompt", JOptionPane.QUESTION_MESSAGE); if(ans == null) return (char)0; else if(ans.length() == 1) return ans.charAt(0); JOptionPane.showMessageDialog(this, "Please enter an Character", "Error", JOptionPane.ERROR_MESSAGE); } } // Allows the Gui to be started public static void main(String args[]) { try { UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); JFrame.setDefaultLookAndFeelDecorated(true); JDialog.setDefaultLookAndFeelDecorated(true); } catch (Exception e) { } if (args.length > 2) { } if (args.length > 0 && args.length <= 2 && args[0].equals("-capture")) { CaptureDisplay cd = new CaptureDisplay(); cd.start(); if (args.length == 2) cd.loadFile(new java.io.File(args[1])); } else if (args.length <= 1) { SamGUI gui = new SamGUI(); gui.start(); if (args.length == 1) gui.loadFile(new java.io.File(args[0])); } else { System.err.println("Usage: SamGUI [-capture] []"); System.exit(1); } } } /** * This is a class to handle the rendering for the JList used to display the * stack. This renderer differs from the standard one because it colors the * stack based on the content of each cell. */ class StackCellRenderer extends JLabel implements ListCellRenderer { /** * The background color used for integers */ public static final Color COLOR_INT = Color.WHITE; /** * The background color used for floats */ public static final Color COLOR_FLOAT = new Color(255, 255, 204); /** * The background color used for memory addresses */ public static final Color COLOR_MA = new Color(255, 204, 204); /** * The background color used for program addresses */ public static final Color COLOR_PA = new Color(204, 255, 204); /** * The background color used for characters */ public static final Color COLOR_CH = new Color(220, 204, 255); /** * The color used for any items that do not have a corrct type */ public static final Color COLOR_DEFAULT = Color.WHITE; public StackCellRenderer() { setOpaque(true); } public java.awt.Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if (value instanceof StackCellRenderer.StackCell) { setText(((StackCell)value).count + ": " + value.toString()); } else { setText(value.toString()); } if (isSelected) { setBackground(list.getSelectionBackground()); } else if (value instanceof StackCellRenderer.StackCell) { switch (((StackCell)value).type) { case Memory.INT : setBackground(COLOR_INT); setToolTipText("Integer"); break; case Memory.FLOAT : setBackground(COLOR_FLOAT); setToolTipText("Float"); break; case Memory.MA : setBackground(COLOR_MA); setToolTipText("Memory Address"); break; case Memory.PA : setBackground(COLOR_PA); setToolTipText("Program Address"); break; case Memory.CH : setBackground(COLOR_CH); setToolTipText("Character"); break; default : setBackground(COLOR_DEFAULT); } } else { setBackground(isSelected ? list.getSelectionBackground() : list.getBackground()); } setForeground(isSelected ? list.getSelectionForeground() : list.getForeground()); return this; } /** * This is a StackCell that is used by the StackCellRenderer * to obtain information about each individual stack element */ public static class StackCell { private int count; private int value; private byte type; public StackCell(int count, int value, byte type) { this.count = count; this.value = value; this.type = type; } public String toString() { String s; switch (type) { case Memory.INT : s = "I : " + Integer.toString(value); break; case Memory.FLOAT : s = "F : " + Float.toString(Float.intBitsToFloat(value)); break; case Memory.MA : s = "M : " + Integer.toString(value); break; case Memory.PA : s = "P : " + Integer.toString(value); break; case Memory.CH : s = "C : " + "'" + (char)value + "'"; break; default : s = Integer.toString(value); } return s; } } } /** * A File filter that checks for a simple extension */ class SimpleFilter extends javax.swing.filechooser.FileFilter { private String description = null; private String extension = null; public SimpleFilter(String extension, String description) { this.description = description; this.extension = "." + extension.toLowerCase(); } public String getDescription() { return description; } public boolean accept(File f) { if (f == null) return false; if (f.isDirectory()) return true; return f.getName().toLowerCase().endsWith(extension); } } /** * A status bar with a beveled border */ class StatusBar extends Box { protected JLabel label; protected LabelThread curThread; /** * Creates a new status bar */ StatusBar() { super(BoxLayout.X_AXIS); label = new JLabel(); setBorder(new SoftBevelBorder(BevelBorder.LOWERED)); add(label); label.setText(" "); } /** * Sets the text - this will be removed after 5 seconds * @param s the text to display */ synchronized void setText(String s) { if (curThread != null) curThread.interrupt(); label.setText(s); curThread = new LabelThread(this); curThread.start(); } /** * Set text that won't be cleared till requested * @param s The text to display */ synchronized void setPermanentText(String s) { if (curThread != null) curThread.interrupt(); label.setText(s); curThread = null; } /** * Clears the current text */ void clearText() { label.setText(" "); } } /** * The thread to clear the label */ class LabelThread extends Thread { protected StatusBar statusBar; /** * Creates a new thread * @param bar the bar to clear */ LabelThread(StatusBar bar) { statusBar = bar; } /** * Starts the thread */ public void run() { try { java.lang.Thread.sleep(5000); statusBar.clearText(); } catch (Exception e) { } } } /** * Holds the processor state */ class ProgramState implements Serializable { int[] memory; byte[] types; int[] registers; public ProgramState(int[] mem, byte[] tp, int[] regs) { memory = mem; types = tp; registers = regs; } } /** * Allows the display of past program states */ class CaptureDisplay extends JFrame { protected Container contentPane; protected JPanel mainPanel; private GridBagConstraints c = new GridBagConstraints(); private GridBagLayout l = new GridBagLayout(); protected JList instructionList; protected JScrollPane instructionListView; protected JMenuItem increaseDisplayMenuItem; protected JMenuItem removeDisplayMenuItem; protected StepDisplay stepDisplays[]; protected Vector steps; protected JPanel instructionListPanel; protected JFileChooser fileChooserDialog; protected File sourceFile = null; protected String filename = null; protected Program program; protected StatusBar statusBar; protected JMenuItem saveAsMenuItem; protected JMenuItem openSimMenuItem; protected JDialog stackColorsDialog; protected JDialog aboutDialog; /** * Creates a new CaptureDisplay */ public CaptureDisplay() { // Set up basic top level layout contentPane = getContentPane(); setTitle("Capture Viewer"); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); contentPane.setLayout(new BorderLayout()); mainPanel = new JPanel(); contentPane.add(mainPanel, BorderLayout.CENTER); statusBar = new StatusBar(); contentPane.add(statusBar, BorderLayout.SOUTH); // figure out how many step displays to show int sdCount = (((int)getToolkit().getScreenSize().getWidth())-205-10)/155; stepDisplays = new StepDisplay[sdCount]; // Set up file chooser dialogs fileChooserDialog = new JFileChooser("."); fileChooserDialog.setFileFilter(new SimpleFilter("sec", "SaM Execution Capture (*.sec)")); // Add components createComponents(); createMenus(); addNotify(); setWindowListeners(); resize(); pack(); } public void start(Vector steps, Program prog, String filename) { setTitle("Capture Viewer - " + filename); this.filename = filename; this.steps = steps; while(stepDisplays.length > steps.size()) removeStepDisplay(); program = prog; DefaultListModel instructions = (DefaultListModel) (instructionList.getModel()); if (prog != null) { for (int i = 0; i < steps.size(); i++) { Instruction ins = program.getInst(((ProgramState)steps.get(i)).registers[Processor.PC]); ins.setTable(prog.getTable()); instructions.addElement(ins); } loadInstruction(0); instructionList.setSelectedIndex(0); saveAsMenuItem.setEnabled(true); openSimMenuItem.setEnabled(true); } start(); } public void start() { pack(); setVisible(true); // Set up the dialogs now to avoid loading time later stackColorsDialog = new StackColorsReferenceDialog(this); aboutDialog = new AboutDialog("SaM Capture Viewer", this); } public Dimension getMinimumSize(){ return new Dimension(stepDisplays.length*150+200, 560); } public Dimension getPreferredSize(){ return new Dimension(stepDisplays.length*150+200, 560); } private void resize(){ setSize(stepDisplays.length*160+210, 560); } // Opens a file (show dialog box, calls loadFile) private void openFile() { if (fileChooserDialog.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) return; loadFile(fileChooserDialog.getSelectedFile()); } /** * Loads the provided file * @param secFile The file to load */ public void loadFile(File secFile) { try { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(secFile)); Program inProg = (Program)ois.readObject(); Vector inSteps = (Vector)ois.readObject(); ois.close(); sourceFile = secFile; filename = sourceFile.getName(); start(inSteps, inProg, secFile.getName()); } catch (FileNotFoundException e) { JOptionPane.showMessageDialog(this, "Could not find file", "Error", JOptionPane.ERROR_MESSAGE); } catch (IOException e) { JOptionPane.showMessageDialog(this, "Error opening file", "Error", JOptionPane.ERROR_MESSAGE); } catch (ClassNotFoundException e) { JOptionPane.showMessageDialog(this, "Invalid file", "Error", JOptionPane.ERROR_MESSAGE); } } // saves a file (show dialog box, calls saveFile(File)) private void saveFile() { File file; while (true) { if (fileChooserDialog.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return; file = fileChooserDialog.getSelectedFile(); if(!file.getName().endsWith(".sec")) file = new File(file.getAbsolutePath() + ".sec"); if (file.exists()) { int r = JOptionPane.showConfirmDialog(this, "File already exists. Overwrite?", "Warning", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); switch (r) { case JOptionPane.YES_OPTION : saveFile(file); return; case JOptionPane.NO_OPTION : continue; case JOptionPane.CANCEL_OPTION : return; } } else { saveFile(file); return; } } } /** * Saves the provided file * @param secFile The file to save to */ public void saveFile(File secFile) { if (steps == null) return; try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(secFile)); oos.writeObject(program); oos.writeObject(steps); oos.close(); sourceFile = secFile; filename = sourceFile.getName(); setTitle("Capture Viewer - " + secFile.getName()); } catch (FileNotFoundException e) { JOptionPane.showMessageDialog(this, "Could not find file", "Error", JOptionPane.ERROR_MESSAGE); } catch (IOException e) { JOptionPane.showMessageDialog(this, "Error saving file", "Error", JOptionPane.ERROR_MESSAGE); } } private void setWindowListeners() { addComponentListener(new ComponentAdapter() { public void componentResized(ComponentEvent e) { } }); // Add Window Listener to handle window closing addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { dispose(); } }); } // Create the menu structure and add event listeners private void createMenus() { JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); JMenu fileMenu = new JMenu("File"); menuBar.add(fileMenu); fileMenu.setMnemonic(KeyEvent.VK_F); JMenu newMenu = new JMenu("New"); fileMenu.add(newMenu); newMenu.setMnemonic(KeyEvent.VK_N); JMenuItem newSimulatorMenuItem = newMenu.add("Simulator Window"); newSimulatorMenuItem.setMnemonic(KeyEvent.VK_S); newSimulatorMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK)); newSimulatorMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { SamGUI gui = new SamGUI(); gui.start(); } }); JMenuItem newCaptureMenuItem = newMenu.add("Capture Viewer"); newCaptureMenuItem.setMnemonic(KeyEvent.VK_C); newCaptureMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK)); newCaptureMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { CaptureDisplay cd = new CaptureDisplay(); cd.start(); } }); JMenuItem openMenuItem = fileMenu.add("Open..."); openMenuItem.setMnemonic(KeyEvent.VK_O); openMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK)); openMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { openFile(); } }); openSimMenuItem = fileMenu.add("Open in Simulator"); openSimMenuItem.setMnemonic(KeyEvent.VK_M); openSimMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.CTRL_MASK)); openSimMenuItem.setEnabled(false); openSimMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { SamGUI gui = new SamGUI(); gui.loadProgram(copyProgram(program), new String(filename)); gui.start(); } }); saveAsMenuItem = fileMenu.add("Save As..."); saveAsMenuItem.setMnemonic(KeyEvent.VK_S); saveAsMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK)); saveAsMenuItem.setEnabled(false); saveAsMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { saveFile(); } }); JMenuItem closeMenuItem = fileMenu.add("Close"); closeMenuItem.setMnemonic(KeyEvent.VK_C); closeMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, ActionEvent.CTRL_MASK)); closeMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dispose(); } }); JMenuItem exitMenuItem = fileMenu.add("Exit"); exitMenuItem.setMnemonic(KeyEvent.VK_X); exitMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK)); exitMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); JMenu displayMenu = new JMenu("Display"); displayMenu.setMnemonic(KeyEvent.VK_D); menuBar.add(displayMenu); increaseDisplayMenuItem = displayMenu.add("Add Instruction Display"); increaseDisplayMenuItem.setMnemonic(KeyEvent.VK_I); increaseDisplayMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, ActionEvent.CTRL_MASK)); increaseDisplayMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { addStepDisplay(); } }); removeDisplayMenuItem = displayMenu.add("Remove Instruction Display"); removeDisplayMenuItem.setMnemonic(KeyEvent.VK_I); if(stepDisplays.length <= 1) removeDisplayMenuItem.setEnabled(false); removeDisplayMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, ActionEvent.CTRL_MASK)); removeDisplayMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { removeStepDisplay(); } }); JMenu helpMenu = new JMenu("Help"); helpMenu.setMnemonic(KeyEvent.VK_H); menuBar.add(helpMenu); JMenuItem colorsMenuItem = helpMenu.add("Stack Colors Reference"); colorsMenuItem.setMnemonic(KeyEvent.VK_S); colorsMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { displayStackColorsReference(); } }); JMenuItem aboutMenuItem = helpMenu.add("About"); aboutMenuItem.setMnemonic(KeyEvent.VK_A); aboutMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { displayAbout(); } }); } // Creates the GUI components private void createComponents() { c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; c.insets = new Insets(5, 5, 5, 5); // Set up main panel mainPanel.setLayout(l); instructionListPanel = buildInstructionListPanel(); // Add components addComponent(instructionListPanel, mainPanel, l, c, 0, 0, 1, 1, 1, 1); for(int i = 0; i < stepDisplays.length; i++) { stepDisplays[i] = new StepDisplay(); addComponent(stepDisplays[i], mainPanel, l, c, 1 + i, 0, 1, 1, 1, 1); } } // Build Program Code Panel private JPanel buildInstructionListPanel() { instructionList = new JList(new DefaultListModel()); instructionList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); instructionList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { loadInstruction(((JList)e.getSource()).getSelectedIndex()); } }); JPanel instructionListPanel = new JPanel(); instructionListPanel.setPreferredSize(new Dimension(200, 350)); instructionListPanel.setMinimumSize(new Dimension(200, 350)); instructionListPanel.setLayout(new BorderLayout()); instructionListView = new JScrollPane(instructionList); instructionListView.setBorder(new SoftBevelBorder(BevelBorder.LOWERED)); instructionListPanel.add(instructionListView, BorderLayout.CENTER); instructionListPanel.add(new JLabel("Instructions Executed:"), BorderLayout.NORTH); return instructionListPanel; } void loadInstruction(int index) { if(index < 0) return; // find center point int currentPosition; int startIndex; int endIndex; if (stepDisplays.length % 2 == 1) { currentPosition = (stepDisplays.length - 1) / 2; } else { currentPosition = ((stepDisplays.length) / 2) - 1; } while ((index - currentPosition) < 0) currentPosition--; while ((index + (stepDisplays.length - 1 - currentPosition)) >= (steps.size())) currentPosition++; startIndex = index - currentPosition; endIndex = index + (stepDisplays.length - currentPosition - 1); if(endIndex > steps.size()-1) endIndex = steps.size() -1; for (int i = 0; startIndex + i <= endIndex; i++) { // we want to have the state displayed after the instruction // is executed. The last instruction is STOP, so we don't need to see // output from that - just the fact that it sexecuted. so: int offset = 1; if (startIndex + i + offset >= steps.size()) offset = 0; stepDisplays[i].load((ProgramState)steps.get(startIndex + i + offset), program, ((ProgramState)steps.get(startIndex + i)).registers[Processor.PC]); if (i == currentPosition) stepDisplays[i].setCurrent(true); else stepDisplays[i].setCurrent(false); } } void addStepDisplay(){ if(stepDisplays.length == steps.size()){ increaseDisplayMenuItem.setEnabled(false); return; } StepDisplay nsd[] = new StepDisplay[stepDisplays.length+1]; System.arraycopy(stepDisplays, 0, nsd, 0, stepDisplays.length); stepDisplays = nsd; stepDisplays[stepDisplays.length-1] = new StepDisplay(); resize(); addComponent(stepDisplays[stepDisplays.length-1], mainPanel, l, c, stepDisplays.length, 0, 1, 1, 1, 1); validate(); loadInstruction(instructionList.getSelectedIndex()); if(stepDisplays.length == 2) removeDisplayMenuItem.setEnabled(true); if(stepDisplays.length == steps.size()) increaseDisplayMenuItem.setEnabled(false); } void removeStepDisplay(){ if(stepDisplays.length == 1) return; StepDisplay nsd[] = new StepDisplay[stepDisplays.length-1]; System.arraycopy(stepDisplays, 0, nsd, 0, stepDisplays.length-1); mainPanel.remove(stepDisplays[stepDisplays.length-1]); stepDisplays = nsd; resize(); pack(); loadInstruction(instructionList.getSelectedIndex()); if(stepDisplays.length == 1) removeDisplayMenuItem.setEnabled(false); } private void addComponent(JComponent comp, JPanel panel, GridBagLayout layout, GridBagConstraints c, int x, int y, int width, int height, double weightx, double weighty) { c.gridx = x; c.gridy = y; c.gridwidth = width; c.gridheight = height; c.weightx = weightx; c.weighty = weighty; layout.setConstraints(comp, c); panel.add(comp); } // We need to be able to duplicate a program // We're going to hack this a bit and just write it out // and back in, which should eliminate elements that // could not be repliated private Program copyProgram(Program program) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(program); oos.close(); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); Program newProgram = (Program)ois.readObject(); ois.close(); return newProgram; } catch (Exception e) { return null; } } // Help Menu private void displayStackColorsReference() { if (stackColorsDialog == null) { stackColorsDialog = new StackColorsReferenceDialog(this); } stackColorsDialog.setVisible(true); } private void displayAbout() { if (aboutDialog == null) { aboutDialog = new AboutDialog("SaM GUI", this); } aboutDialog.setVisible(true); } } class StepDisplay extends JPanel { protected JLabel instructionLabel; protected JList stack; protected JScrollPane stackView; protected JLabel pcLabel; protected JLabel spLabel; protected JLabel fbrLabel; protected JLabel hpLabel; /** * Builds the a panel that allows the display of the state of the processor at one instruction */ public StepDisplay() { setPreferredSize(new Dimension(150, 450)); setMinimumSize(new Dimension(150, 300)); setLayout(new BorderLayout()); setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), "")); add(buildStackPanel(), BorderLayout.CENTER); add(buildRegisterPanel(), BorderLayout.SOUTH); } // Build Stack Panel private JPanel buildStackPanel() { JPanel stackPanel = new JPanel(); stackPanel.setPreferredSize(new Dimension(150, 350)); stackPanel.setMinimumSize(new Dimension(150, 100)); stack = new JList(new DefaultListModel()); stack.setCellRenderer(new StackCellRenderer()); stack.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { ((JList)e.getSource()).clearSelection(); } }); stack.setFont(new Font("Monospaced", Font.BOLD, 12)); stack.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); stackPanel.setLayout(new BorderLayout()); JPanel stackListPanel = new JPanel(); stackListPanel.setLayout(new BorderLayout()); stackListPanel.setBackground(Color.white); stackListPanel.add("South", stack); stackView = new JScrollPane(stackListPanel); stackView.setBorder(new SoftBevelBorder(BevelBorder.LOWERED)); stackPanel.add(stackView, BorderLayout.CENTER); stackPanel.add(new JLabel("Stack:"), BorderLayout.NORTH); return stackPanel; } // Create Register Panel private JPanel buildRegisterPanel() { JPanel registerPanel = new JPanel(); registerPanel.setPreferredSize(new Dimension(150, 150)); JPanel regIntPanel = new JPanel(); registerPanel.setLayout(new BorderLayout()); regIntPanel.setBorder(new SoftBevelBorder(BevelBorder.LOWERED)); GridBagLayout lr = new GridBagLayout(); GridBagConstraints cr = new GridBagConstraints(); cr.fill = GridBagConstraints.BOTH; cr.insets = new Insets(5, 5, 5, 5); regIntPanel.setLayout(lr); regIntPanel.setBackground(new Color(220, 220, 220)); cr.anchor = GridBagConstraints.WEST; addComponent(new JLabel("PC:"), regIntPanel, lr, cr, 0, 0, 1, 1, 1, 1); addComponent(new JLabel("FBR:"), regIntPanel, lr, cr, 0, 1, 1, 1, 1, 1); addComponent(new JLabel("SP:"), regIntPanel, lr, cr, 0, 2, 1, 1, 1, 1); addComponent(new JLabel("HP:"), regIntPanel, lr, cr, 0, 3, 1, 1, 1, 1); pcLabel = new JLabel(""); fbrLabel = new JLabel(""); spLabel = new JLabel(""); hpLabel = new JLabel(""); cr.anchor = GridBagConstraints.EAST; addComponent(pcLabel, regIntPanel, lr, cr, 1, 0, 1, 1, 1, 1); addComponent(fbrLabel, regIntPanel, lr, cr, 1, 1, 1, 1, 1, 1); addComponent(spLabel, regIntPanel, lr, cr, 1, 2, 1, 1, 1, 1); addComponent(hpLabel, regIntPanel, lr, cr, 1, 3, 1, 1, 1, 1); registerPanel.add(regIntPanel, BorderLayout.CENTER); registerPanel.add(new JLabel("Registers:"), BorderLayout.NORTH); return registerPanel; } private void addComponent(JComponent comp, JPanel panel, GridBagLayout layout, GridBagConstraints c, int x, int y, int width, int height, double weightx, double weighty) { c.gridx = x; c.gridy = y; c.gridwidth = width; c.gridheight = height; c.weightx = weightx; c.weighty = weighty; layout.setConstraints(comp, c); panel.add(comp); } public void setCurrent(boolean active) { Color defaultTextColor = Color.BLACK; Color defaultBorderColor = getBackground(); Color currentColor = Color.BLUE; if (active) { ((TitledBorder)getBorder()).setTitleColor(currentColor); ((TitledBorder)getBorder()).setBorder(new EtchedBorder(EtchedBorder.LOWERED, currentColor.brighter(), currentColor.darker())); } else { ((TitledBorder)getBorder()).setTitleColor(defaultTextColor); ((TitledBorder)getBorder()).setBorder(new EtchedBorder(EtchedBorder.LOWERED, defaultBorderColor.brighter(), defaultBorderColor.darker())); } } public void load(ProgramState state, Program program, int pc) { setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), program.getInst(pc).toString())); DefaultListModel m = ((DefaultListModel) (stack.getModel())); m.clear(); for (int i = 0; i < state.memory.length; i++) { m.add(0, new StackCellRenderer.StackCell(i, state.memory[i], state.types[i])); } pcLabel.setText(Integer.toString(state.registers[Processor.PC])); spLabel.setText(Integer.toString(state.registers[Processor.SP])); hpLabel.setText(Integer.toString(state.registers[Processor.HP])); fbrLabel.setText(Integer.toString(state.registers[Processor.FBR])); } } class StackColorsReferenceDialog extends JDialog { public StackColorsReferenceDialog(JFrame parent) { super(parent, false); JPanel colorPanel = new JPanel(); Container p = getContentPane(); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; c.insets = new Insets(5, 5, 5, 5); GridBagLayout l = new GridBagLayout(); colorPanel.setLayout(l); setTitle("Stack Colors Reference"); setSize(300, 300); p.setLayout(new BorderLayout()); p.add(new JLabel("Stack Colors:"), BorderLayout.NORTH); colorPanel.setLayout(l); c.anchor = GridBagConstraints.EAST; addComponent(new JLabel("Integers:"), colorPanel, l, c, 0, 0, 1, 1, 1, 1); c.anchor = GridBagConstraints.CENTER; addComponent(createColorPanel(StackCellRenderer.COLOR_INT), colorPanel, l, c, 1, 0, 1, 1, 1, 1); c.anchor = GridBagConstraints.EAST; addComponent(new JLabel("Floats:"), colorPanel, l, c, 0, 1, 1, 1, 1, 1); c.anchor = GridBagConstraints.CENTER; addComponent(createColorPanel(StackCellRenderer.COLOR_FLOAT), colorPanel, l, c, 1, 1, 1, 1, 1, 1); c.anchor = GridBagConstraints.EAST; addComponent(new JLabel("Memory Addresses:"), colorPanel, l, c, 0, 2, 1, 1, 1, 1); c.anchor = GridBagConstraints.CENTER; addComponent(createColorPanel(StackCellRenderer.COLOR_MA), colorPanel, l, c, 1, 2, 1, 1, 1, 1); c.anchor = GridBagConstraints.EAST; addComponent(new JLabel("Program Addresses:"), colorPanel, l, c, 0, 3, 1, 1, 1, 1); c.anchor = GridBagConstraints.CENTER; addComponent(createColorPanel(StackCellRenderer.COLOR_PA), colorPanel, l, c, 1, 3, 1, 1, 1, 1); c.anchor = GridBagConstraints.EAST; addComponent(new JLabel("Characters:"), colorPanel, l, c, 0, 4, 1, 1, 1, 1); c.anchor = GridBagConstraints.CENTER; addComponent(createColorPanel(StackCellRenderer.COLOR_CH), colorPanel, l, c, 1, 4, 1, 1, 1, 1); p.add(colorPanel, BorderLayout.CENTER); JButton closeButton = new JButton("Close"); closeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setVisible(false); } }); p.add(closeButton, BorderLayout.SOUTH); pack(); } private JPanel createColorPanel(Color c) { JPanel p = new JPanel(); p.add(new JLabel(" ")); p.setBackground(c); p.setMinimumSize(new Dimension(90, 15)); return p; } private void addComponent(JComponent comp, JPanel panel, GridBagLayout layout, GridBagConstraints c, int x, int y, int width, int height, double weightx, double weighty) { c.gridx = x; c.gridy = y; c.gridwidth = width; c.gridheight = height; c.weightx = weightx; c.weighty = weighty; layout.setConstraints(comp, c); panel.add(comp); } } class AboutDialog extends JDialog { public AboutDialog(String component, JFrame parent) { super(parent, true); Container p = getContentPane(); setTitle("About"); setSize(300, 300); p.setLayout(new BorderLayout()); p.add( new JLabel("
SaM v" + Sys.SAM_VERSION + "
" + component + "
Programmers:
Ivan Gyurdiev
David Levitan
Original Design:
Professor K. Pingali
Professor D. Schwartz
"), BorderLayout.CENTER); JButton closeButton = new JButton("Close"); closeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setVisible(false); } }); p.add(closeButton, BorderLayout.SOUTH); pack(); } }