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
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
.*;
46 public static String
randomHexes(int bytes
)
48 java
.security
.SecureRandom prng
= new java
.security
.SecureRandom();
49 byte[] rnd
= new byte[bytes
];
51 StringBuffer buf
= new StringBuffer(2 * rnd
.length
);
52 for(int i
= 0; i
< rnd
.length
; i
++) {
53 int b
= (int)rnd
[i
] & 0xFF;
54 buf
.append(Character
.forDigit(b
/ 16, 16));
55 buf
.append(Character
.forDigit(b
% 16, 16));
57 return buf
.toString();
60 public static String
tempname(String prefix
)
62 //As we don't create files atomically, we need to be unpredictable.
63 return prefix
+ "." + randomHexes(12);
66 public static String
arrayToString(byte[] array
) throws IOException
70 return (new ImageLibrary
.ByteArray(array
)).toString();
73 public static byte[] stringToArray(String name
) throws IOException
78 if((name
.length() % 2) != 0)
79 throw new IOException("Trying to transform odd-length string into byte array");
80 int l
= name
.length() / 2;
81 byte[] parsed
= new byte[l
];
82 for(int i
= 0; i
< l
; i
++)
83 parsed
[i
] = (byte)(Character
.digit(name
.charAt(2 * i
), 16) * 16 +
84 Character
.digit(name
.charAt(2 * i
+ 1), 16));
89 public static boolean isspace(char ch
)
101 if(ch
>= 0x2000 && ch
<= 0x200A)
112 public static String
componentEscape(String in
)
114 boolean needEscape
= false;
115 boolean needParens
= false;
116 Stack
<Integer
> parens
= new Stack
<Integer
>();
117 Stack
<Integer
> parens2
= new Stack
<Integer
>();
119 int strlen
= in
.length();
120 for(int i
= 0; i
< strlen
; i
++) {
121 char ch
= in
.charAt(i
);
128 parens
.push(new Integer(i
));
129 } else if(ch
== ')') {
140 //Copy the paren stack to another to reverse it.
141 while(!parens
.empty())
142 parens2
.push(parens
.pop());
144 if(!needEscape
&& !needParens
)
147 StringBuilder out
= new StringBuilder();
153 for(int i
= 0; i
< strlen
; i
++) {
154 char ch
= in
.charAt(i
);
157 } else if(!parens2
.empty() && parens2
.peek().intValue() == i
) {
160 } else if(ch
== '(') {
163 } else if(ch
== ')') {
178 return out
.toString();
181 public static String
componentUnescape(String in
) throws IOException
183 if(in
.indexOf('\\') < 0)
184 return in
; //No escapes.
185 StringBuilder out
= new StringBuilder();
186 boolean escapeActive
= false;
187 int strlen
= in
.length();
188 for(int i
= 0; i
< strlen
; i
++) {
189 char ch
= in
.charAt(i
);
192 escapeActive
= false;
193 } else if(ch
== '\\') {
199 throw new IOException("Invalid escaped string: unexpected end of string after \\");
200 return out
.toString();
203 public static String
[] nextParseLine(UTFInputLineStream in
) throws IOException
207 String parseLine
= "";
208 while(parseLine
!= null && "".equals(parseLine
))
209 parseLine
= in
.readLine();
210 if(parseLine
== null)
213 ret
= parseString(parseLine
);
216 return nextParseLine(in
);
221 public static String
[] parseString(String parseLine
) throws IOException
224 boolean escapeActive
= false;
226 if(parseLine
== null)
229 //System.err.println("Line: \"" + parseLine + "\".");
231 int lastSplitStart
= 0;
232 int strlen
= parseLine
.length();
234 for(int i
= 0; i
< strlen
; i
++) {
235 String component
= null;
236 char ch
= parseLine
.charAt(i
);
238 escapeActive
= false;
239 } else if(ch
== '\\') {
241 } else if(ch
== '(') {
244 else if(parenDepth
== 0) {
246 component
= parseLine
.substring(lastSplitStart
, i
);
247 lastSplitStart
= i
+ 1;
250 } else if(ch
== ')') {
252 throw new IOException("Unbalanced ) in initialization segment line \"" + parseLine
+ "\".");
253 else if(parenDepth
== 1) {
255 component
= parseLine
.substring(lastSplitStart
, i
);
256 lastSplitStart
= i
+ 1;
260 } else if(parenDepth
== 0 && isspace(ch
)) {
262 //System.err.println("Splitting at point " + i + ".");
263 component
= componentUnescape(parseLine
.substring(lastSplitStart
, i
));
264 lastSplitStart
= i
+ 1;
267 if(component
!= null && !component
.equals(""))
269 String
[] ret2
= new String
[ret
.length
+ 1];
270 System
.arraycopy(ret
, 0, ret2
, 0, ret
.length
);
271 ret2
[ret
.length
] = component
;
274 ret
= new String
[]{component
};
277 throw new IOException("Unbalanced ( in initialization segment line \"" + parseLine
+ "\".");
278 String component
= componentUnescape(parseLine
.substring(lastSplitStart
));
279 if(component
!= null && !component
.equals(""))
281 String
[] ret2
= new String
[ret
.length
+ 1];
282 System
.arraycopy(ret
, 0, ret2
, 0, ret
.length
);
283 ret2
[ret
.length
] = component
;
286 ret
= new String
[]{component
};
291 public static boolean hasParensInserted(String in
)
293 return (in
.charAt(0) == '(');
296 public static String
encodeLine(String
[] components
)
299 boolean lastParen
= true; //Hack to supress initial space.
300 for(int i
= 0; i
< components
.length
; i
++) {
301 String escaped
= componentEscape(components
[i
]);
302 boolean thisParen
= hasParensInserted(escaped
);
303 if(!lastParen
&& !thisParen
)
306 lastParen
= thisParen
;
311 public static int callShowOptionDialog(java
.awt
.Component parent
, Object msg
, String title
, int oType
,
312 int mType
, Icon icon
, Object
[] buttons
, Object deflt
)
315 return JOptionPane
.showOptionDialog(parent
, msg
, title
, oType
, mType
, icon
, buttons
, deflt
);
316 } catch(Throwable e
) { //Catch errors too!
318 System
.err
.println("MESSAGE: *** " + title
+ " ***: " + msg
.toString());
319 for(int i
= 0; i
< buttons
.length
; i
++)
320 if(buttons
[i
] == deflt
)
327 public static String
messageForException(Throwable e
)
329 boolean supressClass
= false;
330 String message
= e
.getMessage();
331 Class
<?
> eClass
= e
.getClass();
332 while(eClass
!= null) {
333 if(classes
.containsKey(eClass
.getName())) {
334 if(message
!= null && !message
.equals("") && !message
.equals("null"))
335 message
= classes
.get(eClass
.getName()) + " (" + message
+ ")";
337 message
= classes
.get(eClass
.getName());
338 if(eClass
== e
.getClass())
342 eClass
= eClass
.getSuperclass();
346 if(message
!= null && !message
.equals("") && !message
.equals("null"))
347 message
= message
+ " [" + e
.getClass().getName() + "]";
349 message
= message
+ "<no description available> [" + e
.getClass().getName() + "]";
353 public static void errorDialog(Throwable e
, String title
, java
.awt
.Component component
, String text
)
355 String message
= messageForException(e
);
356 int i
= callShowOptionDialog(null, message
, title
, JOptionPane
.YES_NO_OPTION
, JOptionPane
.WARNING_MESSAGE
, null, new String
[]{text
, "Save stack trace"}, "Save stack Trace");
358 saveStackTrace(e
, null, text
);
362 public static void saveStackTrace(Throwable e
, java
.awt
.Component component
, String text
)
364 StackTraceElement
[] traceback
= e
.getStackTrace();
365 StringBuffer sb
= new StringBuffer();
366 sb
.append(messageForException(e
) + "\n");
367 for(int i
= 0; i
< traceback
.length
; i
++) {
368 StackTraceElement el
= traceback
[i
];
369 if(el
.getClassName().startsWith("sun.reflect."))
370 continue; //Clean up the trace a bit.
371 if(el
.isNativeMethod())
372 sb
.append(el
.getMethodName() + " of " + el
.getClassName() + " <native>\n");
374 sb
.append(el
.getMethodName() + " of " + el
.getClassName() + " <" + el
.getFileName() + ":" +
375 el
.getLineNumber() + ">\n");
377 String exceptionMessage
= sb
.toString();
381 buf
= Charset
.forName("UTF-8").newEncoder().encode(CharBuffer
.wrap(exceptionMessage
));
382 byte[] buf2
= new byte[buf
.remaining()];
385 String traceFileName
= "StackTrace-" + System
.currentTimeMillis() + ".text";
386 OutputStream stream
= new FileOutputStream(traceFileName
);
389 callShowOptionDialog(component
, "Stack trace saved to " + traceFileName
+ ".", "Stack trace saved", JOptionPane
.YES_NO_OPTION
, JOptionPane
.WARNING_MESSAGE
, null, new String
[]{text
}, text
);
390 } catch(Exception e2
) {
391 callShowOptionDialog(component
, e
.getMessage(), "Saving stack trace failed", JOptionPane
.YES_NO_OPTION
, JOptionPane
.WARNING_MESSAGE
, null, new String
[]{text
}, text
);
395 public static Map
<String
, String
> parseStringToComponents(String string
) throws IOException
397 Map
<String
,String
> ret
= new HashMap
<String
, String
>();
398 while(!string
.equals("")) {
399 int i
= string
.indexOf(',');
405 element
= string
.substring(0, i
);
406 string
= string
.substring(i
+ 1);
408 int j
= element
.indexOf('=');
410 throw new IOException("Bad string element: \"" + element
+ "\"");
411 String key
= element
.substring(0, j
);
412 String value
= element
.substring(j
+ 1);
418 public static void moveWindow(JFrame window
, int x
, int y
, int w
, int h
)
424 final JFrame window2
= window
;
426 if(!SwingUtilities
.isEventDispatchThread())
428 SwingUtilities
.invokeAndWait(new Thread() { public void run() {
429 window2
.setBounds(x2
, y2
, w2
, h2
); }});
430 } catch(Exception e
) {
433 window2
.setBounds(x2
, y2
, w2
, h2
);
436 public static boolean isFPUOp(int op
)
442 case FLOAD0_MEM_SINGLE
:
443 case FLOAD0_MEM_DOUBLE
:
444 case FLOAD0_MEM_EXTENDED
:
456 case FLOAD1_MEM_SINGLE
:
457 case FLOAD1_MEM_DOUBLE
:
458 case FLOAD1_MEM_EXTENDED
:
464 case FSTORE0_MEM_SINGLE
:
465 case FSTORE0_MEM_DOUBLE
:
466 case FSTORE0_MEM_EXTENDED
:
470 case FSTORE1_MEM_SINGLE
:
471 case FSTORE1_MEM_DOUBLE
:
472 case FSTORE1_MEM_EXTENDED
: