1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
7 // FEATURE: progress indicator
8 // FEATURE: emit bytecode rather than .java code (for on-the-fly classloading without javac present in "real" JVMs
10 public class Compiler implements Registers {
12 private static StringBuffer runs = new StringBuffer();
13 private static StringBuffer inits = new StringBuffer();
15 private static PrintStream out = System.out;
17 private static int indent;
18 private static String indents[] = new String[16];
19 static { String s=""; for(int i=0;i<indents.length;i++,s=s+" ") indents[i] = s; }
20 private static final void p() { out.println(); }
21 private static final void p(String s) { out.println(indents[indent] + s); }
23 // FEATURE: This should probably provide some detail about where the excpetion happened (address, line numbers, etc)
24 private static class CompilationException extends Exception { public CompilationException(String s) { super(s); } }
26 // Set this to true to enable fast memory access
27 // When this is enabled a Java RuntimeException will be thrown when a page fault occures. When it is disabled
28 // a FaultException will be throw which is easier to catch and deal with, however. as the name implies, this is slower
29 private static boolean fastMem = true;
31 // log_2 of the maximum bytes per method
32 // NOTE: This value can be much higher without breaking the classfile
33 // specs (around 1024) but Hotstop seems to do much better with smaller
35 private static int LOG_MAX_BYTES_PER_METHOD = 9;
36 private static int MAX_BYTES_PER_METHOD = 512;
38 // Store frequently used registers in local variables
39 // Unfortunately this doesn't seem to speed things up much
40 private static String[] freqRegs = { /*"r2", "r29", "r3", "r16", "r5", "r17", "r6", "r18", "r4", "r31", "r19"*/ };
42 // True to try to determine which case statement are needed and only include them
43 private static boolean pruneCases = true;
45 // True to insert some code in the output to help diagnore compiler problems
46 private final static boolean debugCompiler = false;
48 // True to print various statistics about the compilation
49 private final static boolean printStats = true;
51 public static void main(String[] s) throws Exception {
54 System.err.println("usage: java " + Compiler.class.getName() + " <classname> <binary.mips>");
58 String packageName = null;
59 String className = s[0];
60 if (s[0].indexOf('.') != -1) {
61 packageName = s[0].substring(0, s[0].lastIndexOf('.'));
62 className = s[0].substring(s[0].lastIndexOf('.') + 1);
65 ELF elf = new ELF(s[1]);
66 if(elf.header.type != ELF.ELFHeader.ET_EXEC) throw new IOException("Binary is not an executable");
67 if(elf.header.machine != ELF.ELFHeader.EM_MIPS) throw new IOException("Binary is not for the MIPS I Architecture");
69 p("// This file was generated by MipsToJava");
70 if (packageName != null) p("package " + packageName + ";");
71 p("public class " + className + " extends org.xwt.mips.Runtime {");
73 p(" // program counter");
74 p(" private int pc = 0;");
76 p(" private int lastPC = 0;");
78 p(" // General Purpose registers");
79 p(" private final static int r0 = 0;");
80 p(" int r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0,");
81 p(" r8 = 0, r9 = 0, r10 = 0, r11 = 0, r12 = 0, r13 = 0, r14 = 0, r15 = 0,");
82 p(" r16 = 0, r17 = 0, r18 = 0, r19 = 0, r20 = 0, r21 = 0, r22 = 0, r23 = 0,");
83 p(" r24 = 0, r25 = 0, r26 = 0, r27 = 0, r28 = 0, r29 = 0, r30 = 0, r31 = 0,");
84 p(" hi = 0, lo = 0;");
85 p(" // FP registers");
86 p(" private int f0 = 0, f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0, f6 = 0, f7 = 0,");
87 p(" f8 = 0, f9 = 0, f10 = 0, f11 = 0, f12 = 0, f13 = 0, f14 = 0, f15 = 0,");
88 p(" f16 = 0, f17 = 0, f18 = 0, f19 = 0, f20 = 0, f21 = 0, f22 = 0, f23 = 0,");
89 p(" f24 = 0, f25 = 0, f26 = 0, f27 = 0, f28 = 0, f29 = 0, f30 = 0, f31 = 0;");
90 p(" // FP Control Register");
91 p(" private int fcsr = 0;");
94 // These should all be inlind by javac
95 p("private final void setFC(boolean b) { fcsr = (fcsr&~0x800000) | (b ? 0x800000 : 0x000000); }");
96 p("private final int roundingMode() { return fcsr & 3; /* bits 0-1 */ }");
99 Set jumpableAddresses = null;
101 // Find all possible branches
102 jumpableAddresses = new HashSet();
104 jumpableAddresses.add(new Integer(elf.header.entry));
106 ELF.SHeader text = elf.sectionWithName(".text");
107 if(text == null) throw new Error("No .text segment");
108 findBranchesInText(text.addr,new DataInputStream(text.getInputStream()),text.size,jumpableAddresses);
110 findBranchesInSymtab(elf.getSymtab(),jumpableAddresses);
112 for(int i=0;i<elf.sheaders.length;i++) {
113 ELF.SHeader sheader = elf.sheaders[i];
114 String name = sheader.name;
115 // if this section doesn't get loaded into our address space don't worry about it
116 if(sheader.addr == 0x0) continue;
117 if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors"))
118 findBranchesInData(new DataInputStream(sheader.getInputStream()),sheader.size,jumpableAddresses,text.addr,text.addr+text.size);
122 // Generate main body functions
125 for(int i=0;i<elf.sheaders.length;i++) {
126 ELF.SHeader sheader = elf.sheaders[i];
127 String name = sheader.name;
128 // if this section doesn't get loaded into our address space don't worry about it
129 if(sheader.addr == 0x0) continue;
131 highestAddr = Math.max(highestAddr, sheader.addr + sheader.size);
133 if(name.equals(".text")) {
134 emitText(sheader.addr, new DataInputStream(sheader.getInputStream()),sheader.size,jumpableAddresses);
135 endMethod(nextEmitTextAddr);
136 } else if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors")) {
137 emitData(sheader.addr, new DataInputStream(sheader.getInputStream()), sheader.size,name.equals(".rodata"));
138 } else if(name.equals(".bss") || name.equals(".sbss")) {
139 if(sheader.entsize != 0) throw new CompilationException("bss segment has data!");
140 emitBSS(sheader.addr,sheader.size);
142 throw new CompilationException("Unknown segment: " + name);
147 p(" public " + className + "() throws FaultException {");
149 p(" super(false); // don't allow empty pages");
150 p(" if(PAGE_SIZE != " + toHex(Runtime.PAGE_SIZE) + ") throw new Error(\"Runtime.PAGE_SIZE mismatch\");");
152 p(" super(true); // allow empty pages");
155 p(" entryPoint = " + toHex(elf.header.entry) + ";");
157 p(" brk = (" + toHex(highestAddr) + "+PAGE_SIZE-1) >>> PAGE_SHIFT;");
158 p(" state = INITIALIZED;");
162 p(" public static void main(String[] javaArgs) throws Exception {");
163 p(" String[] args = new String[javaArgs.length+1];");
164 p(" System.arraycopy(javaArgs,0,args,1,javaArgs.length);");
165 p(" args[0] = \"" + className + "\";");
166 p(" " + className + " me = new " + className + "();");
168 p(" int addr = me.sbrk(PAGE_SIZE);");
169 p(" for(int i=0;i<10;i++) {");
170 p(" String s = \"User Info item: \" + (i+1) + \"\\0\";");
171 p(" byte[] b = s.getBytes(\"US-ASCII\");");
172 p(" me.copyout(b,addr,b.length);");
173 p(" me.setUserInfo(i,addr);");
174 p(" addr += b.length;");
176 p(" // End user data");
177 p(" int status = me.run(args);");
178 p(" System.err.println(\"Exit status: \" + status);");
179 p(" System.exit(status);");
182 p(" protected void _start(int pc) {");
183 p(" // set the stack pointer");
184 p(" r26 = STUFF_BASE;");
185 p(" r27 = PAGE_SIZE;");
186 p(" r29 = INITIAL_SP;");
187 p(" // set the \"return address\" from _start to point at the \"magic exit address\" (0xdeadbeef)");
188 p(" r31 = 0xdeadbeef;");
193 p(" protected void _execute() throws ExecutionException { trampoline(); }");
195 p(" private final void trampoline() throws ExecutionException {");
196 p(" boolean finished = false;");
197 p(" while(!finished) {");
198 p(" switch(this.pc >> " + LOG_MAX_BYTES_PER_METHOD + ") {");
200 p(" default: throw new Error(\"invalid address 0x\" + Long.toString(this.pc&0xffffffffL,16));");
207 private static int startOfMethod = 0;
208 private static int endOfMethod = 0;
210 private static void startMethod(int addr) {
211 addr &= ~(MAX_BYTES_PER_METHOD-1);
212 endOfMethod= addr + MAX_BYTES_PER_METHOD;
213 String methodName = "run_" + Long.toString(addr & 0xffffffffL, 16);
214 runs.append(indents[4] + "case " + toHex(addr>>LOG_MAX_BYTES_PER_METHOD) + ": finished = !" + methodName + "(); break;\n");
215 p("private final boolean " + methodName + "() throws ExecutionException { /"+"* " + toHex(addr) + " - " + toHex(endOfMethod) + " *" + "/");
218 for(int i=0;i<freqRegs.length;i++)
219 p("int " + freqRegs[i] + " = this." + freqRegs[i] + ";");
222 p("switch(pc>>2) {");
224 startOfMethod = addr;
227 private static void endMethod() { endMethod(endOfMethod); }
228 private static void endMethod(int lastAddr) {
229 if(startOfMethod == 0) return;
230 // This isn't strictly necessary; its just here to work around unreachable code errors
231 p("case " + toHex(lastAddr>>2) + ":");
233 p("pc=" + toHex(lastAddr) + ";");
237 p("default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16) + \" (got here from 0x\" + Long.toString(lastPC&0xffffffffL,16)+\")\");");
239 p("default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16));");
241 p("}"); // end switch
242 p("/* NOT REACHED */");
246 p("}"); // end method
250 private static void branch(int pc, int target) {
252 p("lastPC = " + toHex(pc) + ";");
253 p("pc=" + toHex(target) + ";");
254 if((pc>>LOG_MAX_BYTES_PER_METHOD) == (target>>LOG_MAX_BYTES_PER_METHOD))
260 private static void leaveMethod() { leaveMethod(true); }
261 private static void leaveMethod(boolean cont) {
262 for(int i=0;i<freqRegs.length;i++)
263 p("this." + freqRegs[i] + " = " + freqRegs[i] + ";");
264 p("return " + (cont?"true":"false") + ";");
267 private static int nextEmitTextAddr = -1;
268 private static void emitText(int addr, DataInputStream dis, int size, Set jumpableAddresses) throws CompilationException,IOException {
269 if(addr < nextEmitTextAddr) throw new CompilationException("Out of order sections");
270 if((addr&3)!=0 || (size&3)!=0) throw new CompilationException("Section on weird boundaries");
272 int nextInsn = dis.readInt();
273 if(nextInsn == -1) throw new Error("Actually read -1 at " + toHex(addr));
276 for(int i=0;i<count;i++,addr+=4) {
278 nextInsn = (i == count-1) ? -1 : dis.readInt();
279 if(addr >= endOfMethod) { endMethod(); startMethod(addr); }
280 if(jumpableAddresses==null || addr == startOfMethod || jumpableAddresses.contains(new Integer(addr))) {
281 p("case " + toHex(addr>>2) + ":");
283 } else if(unreachable) {
285 } else if(debugCompiler) {
286 p("/" + "* pc = " + toHex(addr) + "*" + "/");
289 emitInstruction(addr,insn,nextInsn);
292 nextEmitTextAddr = addr;
296 private static int initDataCount = 0;
297 private static void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws CompilationException,IOException {
298 if((addr&3)!=0 || (size&3)!=0) throw new CompilationException("Section on weird boundaries");
300 String varname = "_data" + (++initDataCount);
301 p("private final static int[] " + varname + " = {");
303 for(int i=0;i<count;) {
304 StringBuffer sb = new StringBuffer();
305 for(int j=0;j<8 && i<count;j++,i++) {
306 sb.append(toHex8(dis.readInt()));
307 if(i!=count-1) sb.append(",");
313 inits.append(indents[2] + "initPages(" + varname + "," + toHex(addr) + "," + (readOnly?"true":"false") + ");\n");
317 private static int initBSSCount = 0;
318 private static void emitBSS(int addr, int size) throws CompilationException,IOException {
319 if((addr&3)!=0 || (size&3)!=0) throw new CompilationException("Section on weird boundaries");
321 inits.append(indents[2] + "clearPages(" + toHex(addr) + "," + toHex(count) + ");\n");
324 private static void findBranchesInSymtab(ELF.Symtab symtab, Set jumps) {
325 ELF.Symbol[] symbols = symtab.symbols;
327 for(int i=0;i<symbols.length;i++) {
328 ELF.Symbol s = symbols[i];
329 if(s.type == ELF.Symbol.STT_FUNC) {
330 //System.err.println("Adding symbol: " + s.name + " at " + toHex(s.addr));
331 if(jumps.add(new Integer(s.addr))) n++;
334 if(printStats) System.err.println("Found " + n + " additional possible branch targets in Symtab");
337 private static void findBranchesInText(int addr, DataInputStream dis, int size, Set jumps) throws IOException {
342 for(int i=0;i<count;i++,pc+=4) {
343 int insn = dis.readInt();
344 int op = (insn >>> 26) & 0xff;
345 int rs = (insn >>> 21) & 0x1f;
346 int rt = (insn >>> 16) & 0x1f;
347 int signedImmediate = (insn << 16) >> 16;
348 int branchTarget = signedImmediate;
349 int jumpTarget = (insn & 0x03ffffff);
350 int subcode = insn & 0x3f;
356 if(jumps.add(new Integer(pc+8))) n++; // return address
359 if(jumps.add(new Integer(pc+4))) n++;
367 if(jumps.add(new Integer(pc+8))) n++; // return address
371 if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
376 if(jumps.add(new Integer(pc+8))) n++; // return address
379 if(jumps.add(new Integer((pc&0xf0000000)|(jumpTarget << 2)))) n++;
385 if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
387 case 17: // FPU Instructions
389 case 8: // BC1F, BC1T
390 if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
397 if(printStats) System.err.println("Found " + n + " additional possible branch targets in Text segment");
400 private static void findBranchesInData(DataInputStream dis, int size, Set jumps, int textStart, int textEnd) throws IOException {
403 for(int i=0;i<count;i++) {
404 int word = dis.readInt();
405 if((word&3)==0 && word >= textStart && word < textEnd) {
406 if(jumps.add(new Integer(word))) n++;
410 if(n>0 && printStats) System.err.println("Found " + n + " additional possible branch targets in Data segment");
413 private static boolean unreachable = false;
415 private static void emitInstruction(int pc, int insn, int nextInsn) throws IOException,CompilationException {
416 if(insn == -1) throw new Error("insn is -1");
418 int op = (insn >>> 26) & 0xff; // bits 26-31
419 int rs = (insn >>> 21) & 0x1f; // bits 21-25
420 int rt = (insn >>> 16) & 0x1f; // bits 16-20
421 int ft = (insn >>> 16) & 0x1f;
422 int rd = (insn >>> 11) & 0x1f; // bits 11-15
423 int fs = (insn >>> 11) & 0x1f;
424 int shamt = (insn >>> 6) & 0x1f; // bits 6-10
425 int fd = (insn >>> 6) & 0x1f;
426 int subcode = insn & 0x3f; // bits 0-5
428 int jumpTarget = (insn & 0x03ffffff); // bits 0-25
429 int unsignedImmediate = insn & 0xffff;
430 int signedImmediate = (insn << 16) >> 16;
431 int branchTarget = signedImmediate;
433 int tmp, addr; // temporaries
435 //if(pc%64==0) p("System.err.println(\"Executing: " + toHex(pc) + "\");");
436 //p("/" + "*" + (pc == -1 ? "Delay Slot" : toHex(pc)) + " *" + "/ ");
437 if(pc==-1) p("/" + "* Next insn is delay slot *" + "/ ");
446 p( "r"+rd+" = r"+rt+" << "+shamt+";");
449 p( "r"+rd+" = r"+rt+" >>> "+shamt+";");
452 p( "r"+rd+" = r"+rt+" >> "+shamt+";");
455 p( "r"+rd+" = r"+rt+" << (r"+rs+"&0x1f);");
458 p( "r"+rd+" = r"+rt+" >>> (r"+rs+"&0x1f);");
461 p( "r"+rd+" = r"+rt+" >> (r"+rs+"&0x1f);");
464 if(pc == -1) throw new Error("pc modifying insn in delay slot");
465 emitInstruction(-1,nextInsn,-1);
466 if(debugCompiler) p("lastPC = " + toHex(pc) + ";");
467 p("pc=r" + rs + ";");
472 if(pc == -1) throw new Error("pc modifying insn in delay slot");
473 emitInstruction(-1,nextInsn,-1);
474 if(debugCompiler) p("lastPC = " + toHex(pc) + ";");
475 p("pc=r" + rs + ";");
476 p("r" + RA + "=" + toHex(pc+8 /*skip this insn and delay slot*/) + ";");
481 p( "r"+V0+" = syscall(r"+V0+",r"+A0+",r"+A1+",r"+A2+",r"+A3+");");
482 p("if (state != RUNNING) {");
484 p("pc = " + toHex(pc+4) + ";");
490 p( "throw new ExecutionException(\"Break\");");
505 p( "{ long hilo = (long)(r"+rs+") * ((long)r"+rt+"); " +
506 "hi = (int) (hilo >>> 32); " +
507 "lo = (int) hilo; }");
510 p( "{ long hilo = (r"+rs+" & 0xffffffffL) * (r"+rt+" & 0xffffffffL); " +
511 "hi = (int) (hilo >>> 32); " +
512 "lo = (int) hilo; } ");
515 p( "hi = r"+rs+"%r"+rt+"; lo = r"+rs+"/r"+rt+";");
518 p( "hi = (int)((r"+rs+" & 0xffffffffL) % (r"+rt+" & 0xffffffffL)); " +
519 "lo = (int)((r"+rs+" & 0xffffffffL) / (r"+rt+" & 0xffffffffL));");
522 throw new CompilationException("ADD (add with oveflow trap) not suported");
523 /*This must trap on overflow
524 p( "r"+rd+" = r"+rs+" + r"+rt+";");
527 p( "r"+rd+" = r"+rs+" + r"+rt+";");
530 throw new CompilationException("SUB (add with oveflow trap) not suported");
531 /*This must trap on overflow
532 p( "r"+rd+" = r"+rs+" - r"+rt+";");
535 p( "r"+rd+" = r"+rs+" - r"+rt+";");
538 p( "r"+rd+" = r"+rs+" & r"+rt+";");
541 p( "r"+rd+" = r"+rs+" | r"+rt+";");
544 p( "r"+rd+" = r"+rs+" ^ r"+rt+";");
547 p( "r"+rd+" = ~(r"+rs+" | r"+rt+");");
550 p( "r"+rd+" = r"+rs+" < r"+rt+" ? 1 : 0;");
553 p( "r"+rd+" = ((r"+rs+" & 0xffffffffL) < (r"+rt+" & 0xffffffffL)) ? 1 : 0;");
556 throw new RuntimeException("Illegal instruction 0/" + subcode);
563 if(pc == -1) throw new Error("pc modifying insn in delay slot");
564 p("if(r" + rs + " < 0) {");
566 emitInstruction(-1,nextInsn,-1);
567 branch(pc,pc+branchTarget*4+4);
572 if(pc == -1) throw new Error("pc modifying insn in delay slot");
573 p("if(r" + rs + " >= 0) {");
575 emitInstruction(-1,nextInsn,-1);
576 branch(pc,pc+branchTarget*4+4);
581 if(pc == -1) throw new Error("pc modifying insn in delay slot");
582 p("if(r" + rs + " < 0) {");
584 emitInstruction(-1,nextInsn,-1);
585 p("r" + RA + "=" + toHex(pc+8 /*skip this insn and delay slot*/) + ";");
586 branch(pc,pc+branchTarget*4+4);
591 if(pc == -1) throw new Error("pc modifying insn in delay slot");
592 p("if(r" + rs + " >= 0) {");
594 emitInstruction(-1,nextInsn,-1);
595 p("r" + RA + "=" + toHex(pc+8 /*skip this insn and delay slot*/) + ";");
596 branch(pc,pc+branchTarget*4+4);
601 throw new RuntimeException("Illegal Instruction 1/" + rt);
606 if(pc == -1) throw new Error("pc modifying insn in delay slot");
607 emitInstruction(-1,nextInsn,-1);
608 branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
613 if(pc == -1) throw new Error("pc modifying insn in delay slot");
614 emitInstruction(-1,nextInsn,-1);
615 p("r" + RA + "=" + toHex(pc+8 /*skip this insn and delay slot*/) + ";");
616 branch(pc, (pc&0xf0000000)|(jumpTarget << 2));
621 if(pc == -1) throw new Error("pc modifying insn in delay slot");
623 p("if(r" + rs + " == r" + rt + ") {");
625 emitInstruction(-1,nextInsn,-1);
626 branch(pc,pc+branchTarget*4+4);
631 if(pc == -1) throw new Error("pc modifying insn in delay slot");
632 p("if(r" + rs + " != r" + rt + ") {");
634 emitInstruction(-1,nextInsn,-1);
635 branch(pc,pc+branchTarget*4+4);
640 if(pc == -1) throw new Error("pc modifying insn in delay slot");
641 p("if(r" + rs + " <= 0) {");
643 emitInstruction(-1,nextInsn,-1);
644 branch(pc,pc+branchTarget*4+4);
649 if(pc == -1) throw new Error("pc modifying insn in delay slot");
650 p("if(r" + rs + " > 0) {");
652 emitInstruction(-1,nextInsn,-1);
653 branch(pc,pc+branchTarget*4+4);
658 p( "r"+rt+" = r"+rs+" + "+signedImmediate +";");
661 p( "r"+rt+" = r"+rs+" + "+signedImmediate+";");
664 p( "r"+rt+" = r"+rs+" < "+signedImmediate+" ? 1 : 0;");
667 p( "r"+rt+" = (r"+rs+"&0xffffffffL) < ("+unsignedImmediate+"&0xffffffffL) ? 1 : 0;");
670 p( "r"+rt+" = r"+rs+" & "+unsignedImmediate+";");
673 p( "r"+rt+" = r"+rs+" | "+unsignedImmediate+";");
676 p( "r"+rt+" = r"+rs+" ^ "+unsignedImmediate+";");
679 p( "r"+rt+" = "+unsignedImmediate+" << 16;");
682 throw new CompilationException("TLB/Exception support not implemented");
686 p( "r"+rt+" = f"+rd+";");
689 if(fs != 31) throw new CompilationException("FCR " + fs + " unavailable");
690 p( "r"+rt+" = fcsr;");
693 p( "f"+rd+" = r"+rt+";");
696 if(fs != 31) throw new CompilationException("FCR " + fs + " unavailable");
697 p( "fcsr = r"+rt+";");
699 case 8: {// BC1F, BC1T
702 p("if(((fcsr&0x800000)!=0) == (" + tmp + "!=0)) {");
704 emitInstruction(-1,nextInsn,-1);
705 branch(pc,pc+branchTarget*4+4);
713 p(setFloat(fd,getFloat(fs)+"+"+getFloat(ft)));
716 p(setFloat(fd,getFloat(fs)+"-"+getFloat(ft)));
719 p(setFloat(fd,getFloat(fs)+"*"+getFloat(ft)));
722 p(setFloat(fd,getFloat(fs)+"/"+getFloat(ft)));
725 p(setFloat(fd,"Math.abs("+getFloat(fs)+")"));
728 p("f"+fd+" = f"+fs+"; // MOV.S");
731 p(setFloat(fd,"-"+getFloat(fs))); // FEATURE: just flip the sign bit
734 p(setDouble(fd,"(float)"+getFloat(fs)));
738 p("switch(roundingMode()) {");
740 p("case 0: f"+fd+" = (int)Math.floor("+getFloat(fs)+"+0.5); break; // Round to nearest");
741 p("case 1: f"+fd+" = (int)"+getFloat(fs)+"; break; // Round towards zero");
742 p("case 2: f"+fd+" = (int)Math.ceil("+getFloat(fs)+"); break; // Round towards plus infinity");
743 p("case 3: f"+fd+" = (int)Math.floor("+getFloat(fs)+"); break; // Round towards minus infinity");
748 p("setFC("+getFloat(fs)+"=="+getFloat(ft)+");"); // FEATURE: just compare the ints, be sure things are normalized
751 p("setFC("+getFloat(fs)+"<"+getFloat(ft)+");");
754 p("setFC("+getFloat(fs)+"<="+getFloat(ft)+");");
756 default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
763 p(setDouble(fd,getDouble(fs)+"+"+getDouble(ft)));
766 p(setDouble(fd,getDouble(fs)+"-"+getDouble(ft)));
769 p(setDouble(fd,getDouble(fs)+"*"+getDouble(ft)));
772 p(setDouble(fd,getDouble(fs)+"/"+getDouble(ft)));
775 p(setDouble(fd,"Math.abs("+getDouble(fs)+")"));
778 p("f"+fd+" = f"+fs+";");
779 p("f"+(fd+1)+" = f"+(fs+1)+";");
782 p(setDouble(fd,"-"+getDouble(fs))); // FEATURE: just flip the sign bit
785 p(setFloat(fd,"(float)"+getDouble(fs)));
789 p("switch(roundingMode()) {");
791 p("case 0: f"+fd+" = (int)Math.floor("+getDouble(fs)+"+0.5); break; // Round to nearest");
792 p("case 1: f"+fd+" = (int)"+getDouble(fs)+"; break; // Round towards zero");
793 p("case 2: f"+fd+" = (int)Math.ceil("+getDouble(fs)+"); break; // Round towards plus infinity");
794 p("case 3: f"+fd+" = (int)Math.floor("+getDouble(fs)+"); break; // Round towards minus infinity");
799 p("setFC("+getDouble(fs)+"=="+getDouble(ft)+");"); // FEATURE: just compare the ints, be sure things are normalized
802 p("setFC("+getDouble(fs)+"<"+getDouble(ft)+");");
805 p("setFC("+getDouble(fs)+"<="+getDouble(ft)+");");
807 default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
811 case 20: { // Integer
815 p(setFloat(fd,"((float)f"+fs+")"));
819 p(setDouble(fd,"((double)f"+fs+")"));
821 default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
826 throw new CompilationException("Invalid Instruction 17/" + rs);
831 throw new CompilationException("coprocessor 2 and 3 instructions not available");
833 p("addr=r" + rs +"+"+signedImmediate + ";");
834 memRead("addr&~3","tmp");
835 p("switch(addr&3) {");
837 p("case 0: tmp = (tmp>>>24)&0xff; break;");
838 p("case 1: tmp = (tmp>>>16)&0xff; break;");
839 p("case 2: tmp = (tmp>>> 8)&0xff; break;");
840 p("case 3: tmp = (tmp>>> 0)&0xff; break;");
843 p("if((tmp&0x80)!=0) tmp |= 0xffffff00; // sign extend");
848 p("addr=r" + rs +"+"+signedImmediate + ";");
849 memRead("addr&~3","tmp");
850 p("switch(addr&2) {");
852 p("case 0: tmp = (tmp>>>16)&0xffff; break;");
853 p("case 2: tmp = (tmp>>> 0)&0xffff; break;");
856 p("if((tmp&0x8000)!=0) tmp |= 0xffff0000; // sign extend");
861 p("addr=r" + rs +"+"+signedImmediate + ";");
862 memRead("addr&~3","tmp");
863 p("switch(addr&3) {");
865 p("case 0: r"+rt+" = (r"+rt+"&0x00000000)|(tmp<< 0); break;");
866 p("case 1: r"+rt+" = (r"+rt+"&0x000000ff)|(tmp<< 8); break;");
867 p("case 2: r"+rt+" = (r"+rt+"&0x0000ffff)|(tmp<<16); break;");
868 p("case 3: r"+rt+" = (r"+rt+"&0x00ffffff)|(tmp<<24); break;");
874 memRead("r" + rs +"+"+signedImmediate,"r"+rt);
877 p("addr=r" + rs +"+"+signedImmediate + ";");
878 memRead("addr&~3","tmp");
879 p("switch(addr&3) {");
881 p("case 0: r"+rt+" = (tmp>>>24)&0xff; break;");
882 p("case 1: r"+rt+" = (tmp>>>16)&0xff; break;");
883 p("case 2: r"+rt+" = (tmp>>> 8)&0xff; break;");
884 p("case 3: r"+rt+" = (tmp>>> 0)&0xff; break;");
890 p("addr=r" + rs +"+"+signedImmediate + ";");
891 memRead("addr&~3","tmp");
892 p("switch(addr&2) {");
894 p("case 0: r"+rt+" = (tmp>>>16)&0xffff; break;");
895 p("case 2: r"+rt+" = (tmp>>> 0)&0xffff; break;");
901 p("addr=r" + rs +"+"+signedImmediate + ";");
902 memRead("addr&~3","tmp");
903 p("switch(addr&3) {");
905 p("case 0: r"+rt+" = (r"+rt+"&0xffffff00)|(tmp>>>24); break;");
906 p("case 1: r"+rt+" = (r"+rt+"&0xffff0000)|(tmp>>>16); break;");
907 p("case 2: r"+rt+" = (r"+rt+"&0xff000000)|(tmp>>> 8); break;");
908 p("case 3: r"+rt+" = (r"+rt+"&0x00000000)|(tmp>>> 0); break;");
915 p("addr=r" + rs +"+"+signedImmediate + ";");
916 memRead("addr&~3","tmp");
917 p("switch(addr&3) {");
919 p("case 0: tmp = (tmp&0x00ffffff) | ((r"+rt+"&0xff)<<24); break;");
920 p("case 1: tmp = (tmp&0xff00ffff) | ((r"+rt+"&0xff)<<16); break;");
921 p("case 2: tmp = (tmp&0xffff00ff) | ((r"+rt+"&0xff)<< 8); break;");
922 p("case 3: tmp = (tmp&0xffffff00) | ((r"+rt+"&0xff)<< 0); break;");
925 memWrite("addr&~3","tmp");
930 p("addr=r" + rs +"+"+signedImmediate + ";");
931 memRead("addr&~3","tmp");
932 p("switch(addr&2) {");
934 p("case 0: tmp = (tmp&0x0000ffff) | ((r"+rt+"&0xffff)<<16); break;");
935 p("case 2: tmp = (tmp&0xffff0000) | ((r"+rt+"&0xffff)<< 0); break;");
938 memWrite("addr&~3","tmp");
943 p("addr=r" + rs +"+"+signedImmediate + ";");
944 memRead("addr&~3","tmp");
945 p("switch(addr&3) {");
947 p("case 0: tmp=(tmp&0x00000000)|(r"+rt+">>> 0); break;");
948 p("case 1: tmp=(tmp&0xff000000)|(r"+rt+">>> 8); break;");
949 p("case 2: tmp=(tmp&0xffff0000)|(r"+rt+">>>16); break;");
950 p("case 3: tmp=(tmp&0xffffff00)|(r"+rt+">>>24); break;");
953 memWrite("addr&~3","tmp");
957 memWrite("r"+rs+"+"+signedImmediate,"r" + rt);
961 p("addr=r" + rs +"+"+signedImmediate + ";");
962 memRead("addr&~3","tmp");
963 p("switch(addr&3) {");
965 p("case 0: tmp=(tmp&0x00ffffff)|(r"+rt+"<<24); break;");
966 p("case 1: tmp=(tmp&0x0000ffff)|(r"+rt+"<<16); break;");
967 p("case 2: tmp=(tmp&0x000000ff)|(r"+rt+"<< 8); break;");
968 p("case 3: tmp=(tmp&0x00000000)|(r"+rt+"<< 0); break;");
971 memWrite("addr&~3","tmp");
975 memRead("r"+rs+"+"+signedImmediate,"f"+rt);
978 memWrite("r"+rs+"+"+signedImmediate,"f"+rt);
981 throw new CompilationException("Invalid Instruction: " + op + " at " + toHex(pc));
985 private static void memWrite(String addr, String target) {
987 p("writePages[("+addr+")>>>"+Runtime.PAGE_SHIFT+"][(("+addr+")>>>2)&"+toHex(Runtime.PAGE_WORDS-1)+"] = " + target + ";");
989 p("memWrite(" + addr + "," + target + ");");
993 private static void memRead(String addr, String target) {
995 p(target + " = readPages[("+addr+")>>>"+Runtime.PAGE_SHIFT+"][(("+addr+")>>>2)&"+toHex(Runtime.PAGE_WORDS-1)+"];");
997 p(target + " = memRead(" + addr + ");");
1000 private static String getFloat(int r) { return "(Float.intBitsToFloat(f"+r+"))"; }
1001 private static String getDouble(int r) {
1002 return "(Double.longBitsToDouble(((f"+(r+1)+"&0xffffffffL) << 32) | (f"+r+"&0xffffffffL)))";
1004 private static String setFloat(int r, String expr) { return "f"+r+"=Float.floatToRawIntBits("+expr+");"; }
1005 private static String setDouble(int r, String expr) {
1006 return "{ long l = Double.doubleToLongBits("+expr+"); "+
1007 "f"+(r+1)+" = (int)(l >>> 32); f"+r+" = (int)l; }";
1010 private final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
1011 private final static String toHex8(int n) {
1012 String s = Long.toString(n & 0xffffffffL, 16);
1013 StringBuffer sb = new StringBuffer("0x");
1014 for(int i=8-s.length();i>0;i--) sb.append('0');
1016 return sb.toString();