2 JPC-RR: A x86 PC Hardware Emulator
5 Copyright (C) 2007-2009 Isis Innovation Limited
6 Copyright (C) 2009-2010 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
34 import java
.nio
.charset
.*;
38 import org
.jpc
.diskimages
.ImageLibrary
;
39 import org
.jpc
.jrsr
.UTFInputLineStream
;
41 import static org
.jpc
.Exceptions
.classes
;
42 import static org
.jpc
.emulator
.memory
.codeblock
.optimised
.MicrocodeSet
.*;
43 import static org
.jpc
.Revision
.getRevision
;
47 private static boolean renameOverSupported
;
49 public static String
randomHexes(int bytes
)
51 java
.security
.SecureRandom prng
= new java
.security
.SecureRandom();
52 byte[] rnd
= new byte[bytes
];
54 StringBuffer buf
= new StringBuffer(2 * rnd
.length
);
55 for(int i
= 0; i
< rnd
.length
; i
++) {
56 int b
= (int)rnd
[i
] & 0xFF;
57 buf
.append(Character
.forDigit(b
/ 16, 16));
58 buf
.append(Character
.forDigit(b
% 16, 16));
60 return buf
.toString();
63 public static String
tempname(String prefix
)
65 //As we don't create files atomically, we need to be unpredictable.
66 return prefix
+ "." + randomHexes(12);
69 public static String
arrayToString(byte[] array
) throws IOException
73 return (new ImageLibrary
.ByteArray(array
)).toString();
76 public static byte[] stringToArray(String name
) throws IOException
81 if((name
.length() % 2) != 0)
82 throw new IOException("Trying to transform odd-length string into byte array");
83 int l
= name
.length() / 2;
84 byte[] parsed
= new byte[l
];
85 for(int i
= 0; i
< l
; i
++)
86 parsed
[i
] = (byte)(Character
.digit(name
.charAt(2 * i
), 16) * 16 +
87 Character
.digit(name
.charAt(2 * i
+ 1), 16));
92 public static boolean isspace(char ch
)
104 if(ch
>= 0x2000 && ch
<= 0x200A)
115 public static String
componentEscape(String in
)
117 boolean needEscape
= false;
118 boolean needParens
= false;
119 Stack
<Integer
> parens
= new Stack
<Integer
>();
120 Stack
<Integer
> parens2
= new Stack
<Integer
>();
122 int strlen
= in
.length();
123 for(int i
= 0; i
< strlen
; i
++) {
124 char ch
= in
.charAt(i
);
131 parens
.push(new Integer(i
));
132 } else if(ch
== ')') {
143 //Copy the paren stack to another to reverse it.
144 while(!parens
.empty())
145 parens2
.push(parens
.pop());
147 if(!needEscape
&& !needParens
)
150 StringBuilder out
= new StringBuilder();
156 for(int i
= 0; i
< strlen
; i
++) {
157 char ch
= in
.charAt(i
);
160 } else if(!parens2
.empty() && parens2
.peek().intValue() == i
) {
163 } else if(ch
== '(') {
166 } else if(ch
== ')') {
181 return out
.toString();
184 public static String
componentUnescape(String in
) throws IOException
186 if(in
.indexOf('\\') < 0)
187 return in
; //No escapes.
188 StringBuilder out
= new StringBuilder();
189 boolean escapeActive
= false;
190 int strlen
= in
.length();
191 for(int i
= 0; i
< strlen
; i
++) {
192 char ch
= in
.charAt(i
);
195 escapeActive
= false;
196 } else if(ch
== '\\') {
202 throw new IOException("Invalid escaped string: unexpected end of string after \\");
203 return out
.toString();
206 public static String
[] nextParseLine(UTFInputLineStream in
) throws IOException
210 String parseLine
= "";
211 while(parseLine
!= null && "".equals(parseLine
))
212 parseLine
= in
.readLine();
213 if(parseLine
== null)
216 ret
= parseString(parseLine
);
219 return nextParseLine(in
);
224 public static String
[] parseString(String parseLine
) throws IOException
226 ArrayList
<String
> ret
= new ArrayList
<String
>();
227 boolean escapeActive
= false;
229 if(parseLine
== null)
232 //System.err.println("Line: \"" + parseLine + "\".");
234 int lastSplitStart
= 0;
235 int strlen
= parseLine
.length();
237 for(int i
= 0; i
< strlen
; i
++) {
238 String component
= null;
239 char ch
= parseLine
.charAt(i
);
241 escapeActive
= false;
242 } else if(ch
== '\\') {
244 } else if(ch
== '(') {
247 else if(parenDepth
== 0) {
249 component
= parseLine
.substring(lastSplitStart
, i
);
250 lastSplitStart
= i
+ 1;
253 } else if(ch
== ')') {
255 throw new IOException("Unbalanced ) in component line \"" + parseLine
+ "\".");
256 else if(parenDepth
== 1) {
258 component
= parseLine
.substring(lastSplitStart
, i
);
259 lastSplitStart
= i
+ 1;
263 } else if(parenDepth
== 0 && isspace(ch
)) {
265 //System.err.println("Splitting at point " + i + ".");
266 component
= componentUnescape(parseLine
.substring(lastSplitStart
, i
));
267 lastSplitStart
= i
+ 1;
270 if(component
!= null && !component
.equals(""))
274 throw new IOException("Unbalanced ( in component line \"" + parseLine
+ "\".");
275 String component
= componentUnescape(parseLine
.substring(lastSplitStart
));
276 if(component
!= null && !component
.equals(""))
280 return (String
[])ret
.toArray(new String
[ret
.size()]);
285 public static boolean hasParensInserted(String in
)
287 return (in
.charAt(0) == '(');
290 public static String
encodeLine(String
[] components
)
293 boolean lastParen
= true; //Hack to supress initial space.
294 for(int i
= 0; i
< components
.length
; i
++) {
295 String escaped
= componentEscape(components
[i
]);
296 boolean thisParen
= hasParensInserted(escaped
);
297 if(!lastParen
&& !thisParen
)
300 lastParen
= thisParen
;
305 public static int callShowOptionDialog(java
.awt
.Component parent
, Object msg
, String title
, int oType
,
306 int mType
, Icon icon
, Object
[] buttons
, Object deflt
)
309 return JOptionPane
.showOptionDialog(parent
, msg
, title
, oType
, mType
, icon
, buttons
, deflt
);
310 } catch(Throwable e
) { //Catch errors too!
312 System
.err
.println("MESSAGE: *** " + title
+ " ***: " + msg
.toString());
313 for(int i
= 0; i
< buttons
.length
; i
++)
314 if(buttons
[i
] == deflt
)
321 public static String
messageForException(Throwable e
, boolean chase
)
323 boolean supressClass
= false;
324 while(chase
&& e
.getCause() != null)
326 String message
= e
.getMessage();
327 Class
<?
> eClass
= e
.getClass();
328 while(eClass
!= null) {
329 if(classes
.containsKey(eClass
.getName())) {
330 if(message
!= null && !message
.equals("") && !message
.equals("null"))
331 message
= classes
.get(eClass
.getName()) + " (" + message
+ ")";
333 message
= classes
.get(eClass
.getName());
334 if(eClass
== e
.getClass())
338 eClass
= eClass
.getSuperclass();
342 if(message
!= null && !message
.equals("") && !message
.equals("null"))
343 message
= message
+ " [" + e
.getClass().getName() + "]";
345 message
= message
+ "<no description available> [" + e
.getClass().getName() + "]";
349 public static void errorDialog(Throwable e
, String title
, java
.awt
.Component component
, String text
)
351 String message
= messageForException(e
, true);
352 int i
= callShowOptionDialog(null, message
, title
, JOptionPane
.YES_NO_OPTION
, JOptionPane
.WARNING_MESSAGE
, null, new String
[]{text
, "Save stack trace"}, "Save stack Trace");
354 saveStackTrace(e
, null, text
);
358 public static void saveStackTrace(Throwable e
, java
.awt
.Component component
, String text
)
360 StringBuffer sb
= new StringBuffer();
361 sb
.append("Exception trace generated on '" + (new Date()).toString() + "' by version '" + getRevision() + "'.\n\n");
364 StackTraceElement
[] traceback
= e
.getStackTrace();
365 sb
.append(messageForException(e
, false) + "\n");
366 for(int i
= 0; i
< traceback
.length
; i
++) {
367 StackTraceElement el
= traceback
[i
];
368 if(el
.getClassName().startsWith("sun.reflect."))
369 continue; //Clean up the trace a bit.
370 if(el
.isNativeMethod())
371 sb
.append(el
.getMethodName() + " of " + el
.getClassName() + " <native>\n");
373 sb
.append(el
.getMethodName() + " of " + el
.getClassName() + " <" + el
.getFileName() + ":" +
374 el
.getLineNumber() + ">\n");
376 if(e
.getCause() != null) {
378 sb
.append("\nCaused By:\n\n");
382 String exceptionMessage
= sb
.toString();
386 buf
= Charset
.forName("UTF-8").newEncoder().encode(CharBuffer
.wrap(exceptionMessage
));
387 byte[] buf2
= new byte[buf
.remaining()];
390 String traceFileName
= "StackTrace-" + System
.currentTimeMillis() + ".text";
391 OutputStream stream
= new FileOutputStream(traceFileName
);
394 callShowOptionDialog(component
, "Stack trace saved to " + traceFileName
+ ".", "Stack trace saved", JOptionPane
.YES_NO_OPTION
, JOptionPane
.WARNING_MESSAGE
, null, new String
[]{text
}, text
);
395 } catch(Exception e2
) {
396 callShowOptionDialog(component
, e
.getMessage(), "Saving stack trace failed", JOptionPane
.YES_NO_OPTION
, JOptionPane
.WARNING_MESSAGE
, null, new String
[]{text
}, text
);
400 public static Map
<String
, String
> parseStringToComponents(String string
) throws IOException
402 Map
<String
,String
> ret
= new HashMap
<String
, String
>();
403 while(!string
.equals("")) {
404 int i
= string
.indexOf(',');
410 element
= string
.substring(0, i
);
411 string
= string
.substring(i
+ 1);
413 int j
= element
.indexOf('=');
415 throw new IOException("Bad string element: \"" + element
+ "\"");
416 String key
= element
.substring(0, j
);
417 String value
= element
.substring(j
+ 1);
423 public static InputStream
openStream(String name
, String defaultName
)
425 InputStream ret
= null;
428 ret
= new FileInputStream(name
);
429 } catch(Exception e
) {
430 ret
= ClassLoader
.getSystemResourceAsStream(name
);
435 if(defaultName
!= null) {
436 System
.err
.println("Error: Can't open '" + name
+ "' falling back to default of '" + defaultName
+ "'.");
437 ret
= ClassLoader
.getSystemResourceAsStream(defaultName
);
440 System
.err
.println("Error: Can't open '" + name
+ "' nor default fallback.");
444 public static void renameFile(File src
, File dest
) throws IOException
448 if(renameOverSupported
) {
449 System
.err
.println("Informational: Renaming file...");
450 if(!src
.renameTo(dest
))
451 throw new IOException("Failed to rename '" + src
.getAbsolutePath() + "' to '" + dest
.getAbsolutePath() + "'.");
453 System
.err
.println("Informational: Copying & deleting file...");
454 FileInputStream srch
= new FileInputStream(src
);
455 FileOutputStream desth
= new FileOutputStream(dest
);
456 byte[] copyBuffer
= new byte[1024];
458 while((r
= srch
.read(copyBuffer
)) >= 0)
459 desth
.write(copyBuffer
, 0, r
);
466 public static void probeRenameOver(boolean forceFalse
)
472 throw new IOException("Rename-over forced off");
473 String name1
= randomHexes(24);
474 String name2
= randomHexes(24);
475 RandomAccessFile fh1
= new RandomAccessFile(name1
, "rw");
476 RandomAccessFile fh2
= new RandomAccessFile(name2
, "rw");
479 file1
= new File(name1
);
480 file2
= new File(name2
);
481 if(!file1
.renameTo(file2
))
482 throw new IOException("Rename-over test failed");
485 } catch(IOException e
) {
486 System
.err
.println("Informational: Probing if rename-over works...no: " + e
.getMessage());
487 System
.err
.println("Notice: Using copy & delete for file overwrites.");
494 System
.err
.println("Informational: Probing if rename-over works...yes.");
495 System
.err
.println("Notice: Using rename-over for file overwrites.");
496 renameOverSupported
= true;
499 public static void moveWindow(JFrame window
, int x
, int y
, int w
, int h
)
505 final JFrame window2
= window
;
507 if(!SwingUtilities
.isEventDispatchThread())
509 SwingUtilities
.invokeAndWait(new Thread() { public void run() {
510 window2
.setBounds(x2
, y2
, w2
, h2
); }});
511 } catch(Exception e
) {
514 window2
.setBounds(x2
, y2
, w2
, h2
);
517 public static boolean isFPUOp(int op
)
523 case FLOAD0_MEM_SINGLE
:
524 case FLOAD0_MEM_DOUBLE
:
525 case FLOAD0_MEM_EXTENDED
:
537 case FLOAD1_MEM_SINGLE
:
538 case FLOAD1_MEM_DOUBLE
:
539 case FLOAD1_MEM_EXTENDED
:
545 case FSTORE0_MEM_SINGLE
:
546 case FSTORE0_MEM_DOUBLE
:
547 case FSTORE0_MEM_EXTENDED
:
551 case FSTORE1_MEM_SINGLE
:
552 case FSTORE1_MEM_DOUBLE
:
553 case FSTORE1_MEM_EXTENDED
: