2 JPC-RR: A x86 PC Hardware Emulator
5 Copyright (C) 2007-2009 Isis Innovation Limited
6 Copyright (C) 2009 H. Ilari Liusvaara
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as published by
10 the Free Software Foundation.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 Based on JPC x86 PC Hardware emulator,
22 A project from the Physics Dept, The University of Oxford
24 Details about original JPC can be found at:
26 www-jpc.physics.ox.ac.uk
32 import java
.awt
.Component
;
33 import java
.awt
.BorderLayout
;
34 import java
.awt
.Desktop
;
35 import java
.awt
.Dimension
;
36 import java
.awt
.Toolkit
;
37 import java
.awt
.event
.ActionEvent
;
38 import java
.awt
.event
.ActionListener
;
42 import java
.net
.URLClassLoader
;
44 import java
.util
.jar
.*;
45 import java
.util
.zip
.*;
46 import java
.security
.AccessControlException
;
48 import java
.lang
.reflect
.*;
51 import org
.jpc
.emulator
.PC
;
52 import org
.jpc
.emulator
.TraceTrap
;
53 import org
.jpc
.emulator
.pci
.peripheral
.VGACard
;
54 import org
.jpc
.emulator
.peripheral
.FloppyController
;
55 import org
.jpc
.emulator
.peripheral
.Keyboard
;
56 import org
.jpc
.emulator
.memory
.PhysicalAddressSpace
;
57 import org
.jpc
.emulator
.SRLoader
;
58 import org
.jpc
.emulator
.SRDumper
;
59 import org
.jpc
.emulator
.StatusDumper
;
60 import org
.jpc
.emulator
.Clock
;
61 import org
.jpc
.diskimages
.BlockDevice
;
62 import org
.jpc
.diskimages
.GenericBlockDevice
;
63 import org
.jpc
.diskimages
.ImageLibrary
;
64 import org
.jpc
.diskimages
.DiskImage
;
65 import org
.jpc
.pluginsbase
.*;
67 import static org
.jpc
.Misc
.errorDialog
;
68 import static org
.jpc
.Misc
.callShowOptionDialog
;
69 import static org
.jpc
.Misc
.parseString
;
71 public class JPCApplication
73 public static Plugin
instantiatePlugin(Plugins pluginManager
, Class
<?
> plugin
, String arguments
) throws IOException
77 if(arguments
!= null) {
79 cc
= plugin
.getConstructor(Plugins
.class, String
.class);
80 } catch(Exception e
) {
81 throw new IOException("Plugin \"" + plugin
.getName() + "\" does not take arguments.");
85 cc
= plugin
.getConstructor(Plugins
.class);
86 } catch(Exception e
) {
87 throw new IOException("Plugin \"" + plugin
.getName() + "\" requires arguments.");
93 return (Plugin
)cc
.newInstance(pluginManager
, arguments
);
95 return (Plugin
)cc
.newInstance(pluginManager
);
96 } catch(InvocationTargetException e
) {
97 Throwable e2
= e
.getCause();
98 //If the exception is something unchecked, just pass it through.
99 if(e2
instanceof RuntimeException
)
100 throw (RuntimeException
)e2
;
101 if(e2
instanceof Error
) {
102 IOException ne
= new IOException("Error while invoking loader: " + e2
);
103 ne
.setStackTrace(e2
.getStackTrace()); //Copy stack trace.
106 //Also pass IOException through.
107 if(e2
instanceof IOException
)
108 throw (IOException
)e2
;
109 //What the heck is that?
110 IOException ne
= new IOException("Unknown exception while invoking loader: " + e2
);
111 ne
.setStackTrace(e2
.getStackTrace()); //Copy stack trace.
113 } catch(Exception e
) {
114 throw new IOException("Failed to invoke plugin \"" + plugin
.getName() + "\" constructor.");
118 private static void loadPlugin(Plugins pluginManager
, String arg
) throws IOException
120 String moduleString
= arg
;
121 String currentModule
;
124 int paramsStart
= -1;
126 int stringLen
= moduleString
.length();
127 boolean requireNextSep
= false;
129 for(int i
= 0; true; i
++) {
132 cp
= moduleString
.codePointAt(i
);
133 else if(parenDepth
== 0) {
136 currentModule
= moduleString
.substring(0, i
);
138 moduleString
= moduleString
.substring(i
+ 1);
139 if(moduleString
.equals(""))
140 throw new IOException("Error in module string: Blank module name not allowed.");
145 throw new IOException("Error in module string: unclosed '('.");
147 i
++; //Skip the next surrogate.
148 if((cp
>= 0xD800 && cp
< 0xE000) || ((cp
& 0xFFFE) == 0xFFFE) || (cp
>>> 16) > 16 || cp
< 0)
149 throw new IOException("Error In module string: invalid Unicode character.");
150 if(requireNextSep
&& cp
!= ',')
151 throw new IOException("Error in module string: Expected ',' after ')' closing parameter list.");
152 else if(cp
== ',' && i
== 0)
153 throw new IOException("Error in module string: Blank module name not allowed.");
155 if(parenDepth
== 0) {
160 } else if(cp
== ')') {
162 throw new IOException("Error in module string: Unpaired ')'.");
163 else if(parenDepth
== 1) {
165 requireNextSep
= true;
171 String name
= currentModule
.substring(0, nameEnd
+ 1);
172 String params
= null;
174 params
= currentModule
.substring(paramsStart
, paramsEnd
+ 1);
179 plugin
= Class
.forName(name
);
180 } catch(Exception e
) {
181 throw new IOException("Unable to find plugin \"" + name
+ "\".");
184 if(!Plugin
.class.isAssignableFrom(plugin
)) {
185 throw new IOException("Plugin \"" + name
+ "\" is not valid plugin.");
187 Plugin c
= instantiatePlugin(pluginManager
, plugin
, params
);
188 pluginManager
.registerPlugin(c
);
191 public static void doCommand(Plugins pluginManager
, String cmd
)
193 if(cmd
.toLowerCase().startsWith("load ")) {
195 loadPlugin(pluginManager
, cmd
.substring(5));
196 } catch(Exception e
) {
197 errorDialog(e
, "Plugin Loading failed", null, "Dismiss");
199 } else if(cmd
.toLowerCase().equals("exit")) {
200 pluginManager
.shutdownEmulator();
201 } else if(cmd
.toLowerCase().equals("")) {
202 } else if(cmd
.toLowerCase().startsWith("command ")) {
204 String
[] arr
= parseString(cmd
.substring(8));
206 throw new Exception("No command to send given");
207 String rcmd
= arr
[0];
208 String
[] rargs
= null;
210 rargs
= new String
[arr
.length
- 1];
211 System
.arraycopy(arr
, 1, rargs
, 0, arr
.length
- 1);
213 pluginManager
.invokeExternalCommandSynchronous(rcmd
, rargs
);
214 } catch(Exception e
) {
215 errorDialog(e
, "Command sending failed", null, "Dismiss");
218 System
.err
.println("Invalid command");
222 public static void main(String
[] args
) throws Exception
226 UIManager
.setLookAndFeel(UIManager
.getSystemLookAndFeelClassName());
227 } catch (Throwable e
) { //Yes, we need to catch errors too.
228 System
.err
.println("Warning: System Look-and-Feel not loaded" + e
.getMessage());
231 System
.out
.println("JPC-RR: Rerecording PC emulator based on JPC PC emulator. Release 8+.");
232 System
.out
.println("Based on JPC PC emulator.");
233 System
.out
.println("Copyright (C) 2007-2009 Isis Innovation Limited");
234 System
.out
.println("Copyright (C) 2009-2010 H. Ilari Liusvaara");
235 System
.out
.println("JPC-RR is released under GPL Version 2 and comes with absoutely no warranty.");
238 String library
= ArgProcessor
.findVariable(args
, "library", null);
239 if(library
== null) {
240 callShowOptionDialog(null, "No library specified (-library foo)", "Disk library missing",
241 JOptionPane
.OK_OPTION
, JOptionPane
.WARNING_MESSAGE
, null, new String
[]{"Quit"}, "Quit");
244 DiskImage
.setLibrary(new ImageLibrary(library
));
245 Plugins pluginManager
= new Plugins();
246 BufferedReader kbd
= new BufferedReader(new InputStreamReader(System
.in
, "UTF-8"));
248 String autoexec
= ArgProcessor
.findVariable(args
, "autoexec", null);
249 if(autoexec
!= null) {
251 BufferedReader kbd2
= new BufferedReader(new InputStreamReader(
252 new FileInputStream(autoexec
), "UTF-8"));
254 String cmd
= kbd2
.readLine();
257 doCommand(pluginManager
, cmd
);
259 } catch (Exception e
) {
260 System
.err
.println("Failed to load autoexec script: " + e
.getMessage());
265 System
.out
.print("JPC-RR> ");
267 String cmd
= kbd
.readLine();
268 doCommand(pluginManager
, cmd
);