/* JPC: An x86 PC Hardware Emulator for a pure Java Virtual Machine Release Version 2.4 A project from the Physics Dept, The University of Oxford Copyright (C) 2007-2010 The University of Oxford This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Details (including contact information) can be found at: jpc.sourceforge.net or the developer website sourceforge.net/projects/jpc/ Conceived and Developed by: Rhys Newman, Ian Preston, Chris Dennis End of licence header */ package org.jpc.j2se; import java.text.DecimalFormat; import java.awt.Dimension; import java.awt.event.*; import java.security.AccessControlException; import java.util.logging.*; import java.util.jar.*; import java.net.URLClassLoader; import javax.swing.*; import java.io.*; import java.net.URL; import org.jpc.emulator.PC; import org.jpc.support.ArgProcessor; /** * * @author Mike Moleschi */ public class PCMonitorFrame extends JFrame implements Runnable { private static final Logger LOGGING = Logger.getLogger(PCMonitorFrame.class.getName()); private static final DecimalFormat TWO_DP = new DecimalFormat("0.00"); private static final DecimalFormat THREE_DP = new DecimalFormat("0.000"); private static final int COUNTDOWN = 10000000; protected final PC pc; protected final PCMonitor monitor; private JScrollPane monitorPane; private final JProgressBar speedDisplay; private JFileChooser configFileChooser; private static final boolean updateMHz = true; private volatile boolean running; private Thread runner; public PCMonitorFrame(String title, PC pc, String[] args) { super(title); configFileChooser = new JFileChooser(System.getProperty("user.dir")); running = false; monitor = new PCMonitor(pc); monitorPane = new JScrollPane(monitor); getContentPane().add("Center", monitorPane); if (monitor != null) monitor.setFrame(monitorPane); this.pc = pc; JMenuBar bar = new JMenuBar(); JMenu file = new JMenu("File"); file.add("Start").addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { start(); } }); file.add("Stop").addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { stop(); } }); file.add("Reset").addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { reset(); } }); file.addSeparator(); file.add("Save Configuration").addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { saveConfig(); } }); file.add("Load Configuration").addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { loadConfig(); } }); file.addSeparator(); file.add("Quit").addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); bar.add(file); speedDisplay = new JProgressBar(); speedDisplay.setStringPainted(true); speedDisplay.setString(" 0.00 Mhz"); speedDisplay.setPreferredSize(new Dimension(100, 20)); setJMenuBar(bar); getContentPane().add("South", speedDisplay); try { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } catch (AccessControlException e) { LOGGING.log(Level.WARNING, "Not able to add some components to frame.", e); } } public JScrollPane getMonitorPane() { return monitorPane; } private boolean updateMHz(long time, long count) { long t2 = System.currentTimeMillis(); if (t2 - time < 100) return false; //count = COUNTDOWN - count; float mhz = count * 1000.0F / (t2 - time) / 1000000; speedDisplay.setValue((int)(mhz/1000)); synchronized (TWO_DP) { speedDisplay.setString(TWO_DP.format(mhz) + " MHz or " + THREE_DP.format(mhz/1000) + " GHz Clock"); } return true; } protected synchronized void stop() { running = false; if ((runner != null) && runner.isAlive()) { try { runner.join(5000); } catch (InterruptedException e) {} if (runner.isAlive()) { try { runner.stop(); } catch (SecurityException e) {} } } runner = null; monitor.stopUpdateThread(); } protected synchronized void start() { if (running) return; monitor.startUpdateThread(); running = true; runner = new Thread(this, "PC Execute"); runner.start(); } protected synchronized boolean isRunning() { return running; } protected void saveConfig() { if (configFileChooser.showDialog(PCMonitorFrame.this, "Save JPC Configuration") == JFileChooser.APPROVE_OPTION) { try { Option.saveConfig(configFileChooser.getSelectedFile()); } catch (IOException e) { LOGGING.log(Level.WARNING, "Exception saving configuration.", e); } } } protected void loadConfig() { if (configFileChooser.showDialog(PCMonitorFrame.this, "Load JPC Configuration") == JFileChooser.APPROVE_OPTION) { try { Option.loadConfig(configFileChooser.getSelectedFile()); } catch (IOException e) { LOGGING.log(Level.WARNING, "Exception saving configuration.", e); } } } protected void reset() { stop(); pc.reset(); start(); } public void run() { pc.start(); try { long markTime = System.currentTimeMillis(); long execCount = COUNTDOWN; long totalExec = 0; while (running) { execCount -= pc.execute(); if (execCount > 0) continue; totalExec += (COUNTDOWN - execCount); execCount = COUNTDOWN; if (updateMHz) if (updateMHz(markTime, totalExec)) { markTime = System.currentTimeMillis(); totalExec = 0; } } } finally { pc.stop(); LOGGING.log(Level.INFO, "PC Stopped"); } } public static void main(String[] args) throws Exception { //JPCStatisticsMonitor.install(); Option.parse(args); UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); args = Option.parse(args); if (args.length == 0) { ClassLoader cl = JPCApplication.class.getClassLoader(); if (cl instanceof URLClassLoader) { for (URL url : ((URLClassLoader)cl).getURLs()) { InputStream in = url.openStream(); try { JarInputStream jar = new JarInputStream(in); Manifest manifest = jar.getManifest(); if (manifest == null) continue; String defaultArgs = manifest.getMainAttributes().getValue("Default-Args"); if (defaultArgs == null) continue; args = defaultArgs.split("\\s"); break; } catch (IOException e) { System.err.println("Not a JAR file " + url); } finally { try { in.close(); } catch (IOException e) { } } } } if (args.length == 0) { LOGGING.log(Level.INFO, "No configuration specified, using defaults"); args = new String[]{"-fda", "mem:resources/images/floppy.img", "-hda", "mem:resources/images/dosgames.img", "-boot", "fda" }; } else { LOGGING.log(Level.INFO, "Using configuration specified in manifest"); } } else { LOGGING.log(Level.INFO, "Using configuration specified on command line"); } PC pc = new PC(new VirtualClock(), args); PCMonitorFrame result = new PCMonitorFrame("JPC Monitor", pc, args); result.validate(); result.setVisible(true); result.setBounds(100, 100, 760, 500); result.start(); } }