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 // This MUST be a power of two. If it is not horrible things will happen
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 MAX_INSN_PER_METHOD = 32;
38 private static int MAX_BYTES_PER_METHOD = MAX_INSN_PER_METHOD*4;
39 private static int METHOD_MASK = ~(MAX_BYTES_PER_METHOD-1);
41 // Store frequently used registers in local variables
42 // Unfortunately this doesn't seem to speed things up much
43 private static String[] freqRegs = { /*"r2", "r29", "r3", "r16", "r5", "r17", "r6", "r18", "r4", "r31", "r19"*/ };
45 // True to try to determine which case statement are needed and only include them
46 private static boolean pruneCases = true;
48 // True to insert some code in the output to help diagnore compiler problems
49 private final static boolean debugCompiler = false;
51 // True to print various statistics about the compilation
52 private final static boolean printStats = true;
54 public static void main(String[] s) throws Exception {
57 System.err.println("usage: java " + Compiler.class.getName() + " <classname> <binary.mips>");
61 String packageName = null;
62 String className = s[0];
63 if (s[0].indexOf('.') != -1) {
64 packageName = s[0].substring(0, s[0].lastIndexOf('.'));
65 className = s[0].substring(s[0].lastIndexOf('.') + 1);
68 ELF elf = new ELF(s[1]);
69 if(elf.header.type != ELF.ELFHeader.ET_EXEC) throw new IOException("Binary is not an executable");
70 if(elf.header.machine != ELF.ELFHeader.EM_MIPS) throw new IOException("Binary is not for the MIPS I Architecture");
72 p("// This file was generated by MipsToJava");
73 if (packageName != null) p("package " + packageName + ";");
74 p("public class " + className + " extends org.xwt.mips.Runtime {");
76 p(" // program counter");
77 p(" private int pc = 0;");
79 p(" private int lastPC = 0;");
81 p(" // General Purpose registers");
82 p(" private final static int r0 = 0;");
83 p(" int r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0,");
84 p(" r8 = 0, r9 = 0, r10 = 0, r11 = 0, r12 = 0, r13 = 0, r14 = 0, r15 = 0,");
85 p(" r16 = 0, r17 = 0, r18 = 0, r19 = 0, r20 = 0, r21 = 0, r22 = 0, r23 = 0,");
86 p(" r24 = 0, r25 = 0, r26 = 0, r27 = 0, r28 = 0, r29 = 0, r30 = 0, r31 = 0,");
87 p(" hi = 0, lo = 0;");
88 p(" // FP registers");
89 p(" private int f0 = 0, f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0, f6 = 0, f7 = 0,");
90 p(" f8 = 0, f9 = 0, f10 = 0, f11 = 0, f12 = 0, f13 = 0, f14 = 0, f15 = 0,");
91 p(" f16 = 0, f17 = 0, f18 = 0, f19 = 0, f20 = 0, f21 = 0, f22 = 0, f23 = 0,");
92 p(" f24 = 0, f25 = 0, f26 = 0, f27 = 0, f28 = 0, f29 = 0, f30 = 0, f31 = 0;");
93 p(" // FP Control Register");
94 p(" private int fcsr = 0;");
97 // These should all be inlind by javac
98 p("private final void setFC(boolean b) { fcsr = (fcsr&~0x800000) | (b ? 0x800000 : 0x000000); }");
99 p("private final int roundingMode() { return fcsr & 3; /* bits 0-1 */ }");
102 Set jumpableAddresses = null;
104 // Find all possible branches
105 jumpableAddresses = new HashSet();
107 jumpableAddresses.add(new Integer(elf.header.entry));
109 ELF.SHeader text = elf.sectionWithName(".text");
110 if(text == null) throw new Error("No .text segment");
111 findBranchesInText(text.addr,new DataInputStream(text.getInputStream()),text.size,jumpableAddresses);
113 findBranchesInSymtab(elf.getSymtab(),jumpableAddresses);
115 for(int i=0;i<elf.sheaders.length;i++) {
116 ELF.SHeader sheader = elf.sheaders[i];
117 String name = sheader.name;
118 // if this section doesn't get loaded into our address space don't worry about it
119 if(sheader.addr == 0x0) continue;
120 if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors"))
121 findBranchesInData(new DataInputStream(sheader.getInputStream()),sheader.size,jumpableAddresses,text.addr,text.addr+text.size);
125 // Generate main body functions
128 for(int i=0;i<elf.sheaders.length;i++) {
129 ELF.SHeader sheader = elf.sheaders[i];
130 String name = sheader.name;
131 // if this section doesn't get loaded into our address space don't worry about it
132 if(sheader.addr == 0x0) continue;
134 highestAddr = Math.max(highestAddr, sheader.addr + sheader.size);
136 if(name.equals(".text")) {
137 emitText(sheader.addr, new DataInputStream(sheader.getInputStream()),sheader.size,jumpableAddresses);
138 endMethod(nextEmitTextAddr);
139 } else if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors")) {
140 emitData(sheader.addr, new DataInputStream(sheader.getInputStream()), sheader.size,name.equals(".rodata"));
141 } else if(name.equals(".bss") || name.equals(".sbss")) {
142 if(sheader.entsize != 0) throw new CompilationException("bss segment has data!");
143 emitBSS(sheader.addr,sheader.size);
145 throw new CompilationException("Unknown segment: " + name);
150 p(" public " + className + "() throws FaultException {");
152 p(" super(false); // don't allow empty pages");
153 p(" if(PAGE_SIZE != " + toHex(Runtime.PAGE_SIZE) + ") throw new Error(\"Runtime.PAGE_SIZE mismatch\");");
155 p(" super(true); // allow empty pages");
158 p(" entryPoint = " + toHex(elf.header.entry) + ";");
160 p(" brk = (" + toHex(highestAddr) + "+PAGE_SIZE-1) >>> PAGE_SHIFT;");
161 p(" state = INITIALIZED;");
165 p(" public static void main(String[] javaArgs) throws Exception {");
166 p(" String[] args = new String[javaArgs.length+1];");
167 p(" System.arraycopy(javaArgs,0,args,1,javaArgs.length);");
168 p(" args[0] = \"" + className + "\";");
169 p(" " + className + " me = new " + className + "();");
171 p(" int addr = me.sbrk(PAGE_SIZE);");
172 p(" for(int i=0;i<10;i++) {");
173 p(" String s = \"User Info item: \" + (i+1) + \"\\0\";");
174 p(" byte[] b = s.getBytes(\"US-ASCII\");");
175 p(" me.copyout(b,addr,b.length);");
176 p(" me.setUserInfo(i,addr);");
177 p(" addr += b.length;");
179 p(" // End user data");
180 p(" int status = me.run(args);");
181 p(" System.err.println(\"Exit status: \" + status);");
182 p(" System.exit(status);");
185 p(" protected void _start(int pc) {");
186 p(" // set the stack pointer");
187 p(" r26 = STUFF_BASE;");
188 p(" r27 = PAGE_SIZE;");
189 p(" r29 = INITIAL_SP;");
190 p(" // set the \"return address\" from _start to point at the \"magic exit address\" (0xdeadbeef)");
191 p(" r31 = 0xdeadbeef;");
196 p(" protected void _execute() throws ExecutionException { trampoline(); }");
198 p(" private final void trampoline() throws ExecutionException {");
199 p(" boolean finished = false;");
200 p(" while(!finished) {");
201 p(" switch(this.pc & " + toHex(~(MAX_BYTES_PER_METHOD-1)) + ") {");
203 p(" default: throw new Error(\"invalid address 0x\" + Long.toString(this.pc&0xffffffffL,16));");
210 private static int startOfMethod = 0;
211 private static int endOfMethod = 0;
213 private static void startMethod(int addr) {
214 addr &= ~(MAX_BYTES_PER_METHOD-1);
215 endOfMethod = addr + MAX_BYTES_PER_METHOD;
216 String methodName = "run_" + Long.toString(addr & 0xffffffffL, 16);
217 runs.append(indents[4] + "case " + toHex(addr) + ": finished = !" + methodName + "(); break;\n");
218 p("private final boolean " + methodName + "() throws ExecutionException { /"+"* " + toHex(addr) + " - " + toHex(endOfMethod) + " *" + "/");
221 for(int i=0;i<freqRegs.length;i++)
222 p("int " + freqRegs[i] + " = this." + freqRegs[i] + ";");
227 startOfMethod = addr;
230 private static void endMethod() { endMethod(endOfMethod); }
231 private static void endMethod(int lastAddr) {
232 if(startOfMethod == 0) return;
233 // This isn't strictly necessary; its just here to work around unreachable code errors
234 p("case " + toHex(lastAddr) + ":");
236 p("pc=" + toHex(lastAddr) + ";");
240 p("default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16) + \" (got here from 0x\" + Long.toString(lastPC&0xffffffffL,16)+\")\");");
242 p("default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16));");
244 p("}"); // end switch
245 p("/* NOT REACHED */");
249 p("}"); // end method
253 private static void branch(int pc, int target) {
255 p("lastPC = " + toHex(pc) + ";");
256 p("pc=" + toHex(target) + ";");
257 if((pc&METHOD_MASK) == (target&METHOD_MASK))
263 private static void leaveMethod() { leaveMethod(true); }
264 private static void leaveMethod(boolean cont) {
265 for(int i=0;i<freqRegs.length;i++)
266 p("this." + freqRegs[i] + " = " + freqRegs[i] + ";");
267 p("return " + (cont?"true":"false") + ";");
270 private static int nextEmitTextAddr = -1;
271 private static void emitText(int addr, DataInputStream dis, int size, Set jumpableAddresses) throws CompilationException,IOException {
272 if(addr < nextEmitTextAddr) throw new CompilationException("Out of order sections");
273 if((addr&3)!=0 || (size&3)!=0) throw new CompilationException("Section on weird boundaries");
275 int nextInsn = dis.readInt();
276 if(nextInsn == -1) throw new Error("Actually read -1 at " + toHex(addr));
279 for(int i=0;i<count;i++,addr+=4) {
281 nextInsn = (i == count-1) ? -1 : dis.readInt();
282 if(addr >= endOfMethod) { endMethod(); startMethod(addr); }
283 if(jumpableAddresses==null || addr == startOfMethod || jumpableAddresses.contains(new Integer(addr))) {
284 p("case " + toHex(addr) + ":");
286 } else if(unreachable) {
288 } else if(debugCompiler) {
289 p("/" + "* pc = " + toHex(addr) + "*" + "/");
292 emitInstruction(addr,insn,nextInsn);
295 nextEmitTextAddr = addr;
299 private static int initDataCount = 0;
300 private static void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws CompilationException,IOException {
301 if((addr&3)!=0 || (size&3)!=0) throw new CompilationException("Section on weird boundaries");
303 String varname = "_data" + (++initDataCount);
304 p("private final static int[] " + varname + " = {");
306 for(int i=0;i<count;) {
307 StringBuffer sb = new StringBuffer();
308 for(int j=0;j<8 && i<count;j++,i++) {
309 sb.append(toHex8(dis.readInt()));
310 if(i!=count-1) sb.append(",");
316 inits.append(indents[2] + "initPages(" + varname + "," + toHex(addr) + "," + (readOnly?"true":"false") + ");\n");
320 private static int initBSSCount = 0;
321 private static void emitBSS(int addr, int size) throws CompilationException,IOException {
322 if((addr&3)!=0 || (size&3)!=0) throw new CompilationException("Section on weird boundaries");
324 inits.append(indents[2] + "clearPages(" + toHex(addr) + "," + toHex(count) + ");\n");
327 private static void findBranchesInSymtab(ELF.Symtab symtab, Set jumps) {
328 ELF.Symbol[] symbols = symtab.symbols;
330 for(int i=0;i<symbols.length;i++) {
331 ELF.Symbol s = symbols[i];
332 if(s.type == ELF.Symbol.STT_FUNC) {
333 //System.err.println("Adding symbol: " + s.name + " at " + toHex(s.addr));
334 if(jumps.add(new Integer(s.addr))) n++;
337 if(printStats) System.err.println("Found " + n + " additional possible branch targets in Symtab");
340 private static void findBranchesInText(int addr, DataInputStream dis, int size, Set jumps) throws IOException {
345 for(int i=0;i<count;i++,pc+=4) {
346 int insn = dis.readInt();
347 int op = (insn >>> 26) & 0xff;
348 int rs = (insn >>> 21) & 0x1f;
349 int rt = (insn >>> 16) & 0x1f;
350 int signedImmediate = (insn << 16) >> 16;
351 int branchTarget = signedImmediate;
352 int jumpTarget = (insn & 0x03ffffff);
353 int subcode = insn & 0x3f;
359 if(jumps.add(new Integer(pc+8))) n++; // return address
362 if(jumps.add(new Integer(pc+4))) n++;
370 if(jumps.add(new Integer(pc+8))) n++; // return address
374 if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
379 if(jumps.add(new Integer(pc+8))) n++; // return address
382 if(jumps.add(new Integer((pc&0xf0000000)|(jumpTarget << 2)))) n++;
388 if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
390 case 17: // FPU Instructions
392 case 8: // BC1F, BC1T
393 if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
400 if(printStats) System.err.println("Found " + n + " additional possible branch targets in Text segment");
403 private static void findBranchesInData(DataInputStream dis, int size, Set jumps, int textStart, int textEnd) throws IOException {
406 for(int i=0;i<count;i++) {
407 int word = dis.readInt();
408 if((word&3)==0 && word >= textStart && word < textEnd) {
409 if(jumps.add(new Integer(word))) n++;
413 if(n>0 && printStats) System.err.println("Found " + n + " additional possible branch targets in Data segment");
416 private static boolean unreachable = false;
418 private static void emitInstruction(int pc, int insn, int nextInsn) throws IOException,CompilationException {
419 if(insn == -1) throw new Error("insn is -1");
421 int op = (insn >>> 26) & 0xff; // bits 26-31
422 int rs = (insn >>> 21) & 0x1f; // bits 21-25
423 int rt = (insn >>> 16) & 0x1f; // bits 16-20
424 int ft = (insn >>> 16) & 0x1f;
425 int rd = (insn >>> 11) & 0x1f; // bits 11-15
426 int fs = (insn >>> 11) & 0x1f;
427 int shamt = (insn >>> 6) & 0x1f; // bits 6-10
428 int fd = (insn >>> 6) & 0x1f;
429 int subcode = insn & 0x3f; // bits 0-5
431 int jumpTarget = (insn & 0x03ffffff); // bits 0-25
432 int unsignedImmediate = insn & 0xffff;
433 int signedImmediate = (insn << 16) >> 16;
434 int branchTarget = signedImmediate;
436 int tmp, addr; // temporaries
438 //if(pc%64==0) p("System.err.println(\"Executing: " + toHex(pc) + "\");");
439 //p("/" + "*" + (pc == -1 ? "Delay Slot" : toHex(pc)) + " *" + "/ ");
440 if(pc==-1) p("/" + "* Next insn is delay slot *" + "/ ");
449 p( "r"+rd+" = r"+rt+" << "+shamt+";");
452 p( "r"+rd+" = r"+rt+" >>> "+shamt+";");
455 p( "r"+rd+" = r"+rt+" >> "+shamt+";");
458 p( "r"+rd+" = r"+rt+" << (r"+rs+"&0x1f);");
461 p( "r"+rd+" = r"+rt+" >>> (r"+rs+"&0x1f);");
464 p( "r"+rd+" = r"+rt+" >> (r"+rs+"&0x1f);");
467 if(pc == -1) throw new Error("pc modifying insn in delay slot");
468 emitInstruction(-1,nextInsn,-1);
469 if(debugCompiler) p("lastPC = " + toHex(pc) + ";");
470 p("pc=r" + rs + ";");
475 if(pc == -1) throw new Error("pc modifying insn in delay slot");
476 emitInstruction(-1,nextInsn,-1);
477 if(debugCompiler) p("lastPC = " + toHex(pc) + ";");
478 p("pc=r" + rs + ";");
479 p("r" + RA + "=" + toHex(pc+8 /*skip this insn and delay slot*/) + ";");
484 p( "r"+V0+" = syscall(r"+V0+",r"+A0+",r"+A1+",r"+A2+",r"+A3+");");
485 p("if (state != RUNNING) {");
487 p("pc = " + toHex(pc+4) + ";");
493 p( "throw new ExecutionException(\"Break\");");
508 p( "{ long hilo = (long)(r"+rs+") * ((long)r"+rt+"); " +
509 "hi = (int) (hilo >>> 32); " +
510 "lo = (int) hilo; }");
513 p( "{ long hilo = (r"+rs+" & 0xffffffffL) * (r"+rt+" & 0xffffffffL); " +
514 "hi = (int) (hilo >>> 32); " +
515 "lo = (int) hilo; } ");
518 p( "hi = r"+rs+"%r"+rt+"; lo = r"+rs+"/r"+rt+";");
521 p( "hi = (int)((r"+rs+" & 0xffffffffL) % (r"+rt+" & 0xffffffffL)); " +
522 "lo = (int)((r"+rs+" & 0xffffffffL) / (r"+rt+" & 0xffffffffL));");
525 throw new CompilationException("ADD (add with oveflow trap) not suported");
526 /*This must trap on overflow
527 p( "r"+rd+" = r"+rs+" + r"+rt+";");
530 p( "r"+rd+" = r"+rs+" + r"+rt+";");
533 throw new CompilationException("SUB (add with oveflow trap) not suported");
534 /*This must trap on overflow
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+");");
553 p( "r"+rd+" = r"+rs+" < r"+rt+" ? 1 : 0;");
556 p( "r"+rd+" = ((r"+rs+" & 0xffffffffL) < (r"+rt+" & 0xffffffffL)) ? 1 : 0;");
559 throw new RuntimeException("Illegal instruction 0/" + subcode);
566 if(pc == -1) throw new Error("pc modifying insn in delay slot");
567 p("if(r" + rs + " < 0) {");
569 emitInstruction(-1,nextInsn,-1);
570 branch(pc,pc+branchTarget*4+4);
575 if(pc == -1) throw new Error("pc modifying insn in delay slot");
576 p("if(r" + rs + " >= 0) {");
578 emitInstruction(-1,nextInsn,-1);
579 branch(pc,pc+branchTarget*4+4);
584 if(pc == -1) throw new Error("pc modifying insn in delay slot");
585 p("if(r" + rs + " < 0) {");
587 emitInstruction(-1,nextInsn,-1);
588 p("r" + RA + "=" + toHex(pc+8 /*skip this insn and delay slot*/) + ";");
589 branch(pc,pc+branchTarget*4+4);
594 if(pc == -1) throw new Error("pc modifying insn in delay slot");
595 p("if(r" + rs + " >= 0) {");
597 emitInstruction(-1,nextInsn,-1);
598 p("r" + RA + "=" + toHex(pc+8 /*skip this insn and delay slot*/) + ";");
599 branch(pc,pc+branchTarget*4+4);
604 throw new RuntimeException("Illegal Instruction 1/" + rt);
609 if(pc == -1) throw new Error("pc modifying insn in delay slot");
610 emitInstruction(-1,nextInsn,-1);
611 branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
616 if(pc == -1) throw new Error("pc modifying insn in delay slot");
617 emitInstruction(-1,nextInsn,-1);
618 p("r" + RA + "=" + toHex(pc+8 /*skip this insn and delay slot*/) + ";");
619 branch(pc, (pc&0xf0000000)|(jumpTarget << 2));
624 if(pc == -1) throw new Error("pc modifying insn in delay slot");
626 p("if(r" + rs + " == r" + rt + ") {");
628 emitInstruction(-1,nextInsn,-1);
629 branch(pc,pc+branchTarget*4+4);
634 if(pc == -1) throw new Error("pc modifying insn in delay slot");
635 p("if(r" + rs + " != r" + rt + ") {");
637 emitInstruction(-1,nextInsn,-1);
638 branch(pc,pc+branchTarget*4+4);
643 if(pc == -1) throw new Error("pc modifying insn in delay slot");
644 p("if(r" + rs + " <= 0) {");
646 emitInstruction(-1,nextInsn,-1);
647 branch(pc,pc+branchTarget*4+4);
652 if(pc == -1) throw new Error("pc modifying insn in delay slot");
653 p("if(r" + rs + " > 0) {");
655 emitInstruction(-1,nextInsn,-1);
656 branch(pc,pc+branchTarget*4+4);
661 p( "r"+rt+" = r"+rs+" + "+signedImmediate +";");
664 p( "r"+rt+" = r"+rs+" + "+signedImmediate+";");
667 p( "r"+rt+" = r"+rs+" < "+signedImmediate+" ? 1 : 0;");
670 p( "r"+rt+" = (r"+rs+"&0xffffffffL) < ("+unsignedImmediate+"&0xffffffffL) ? 1 : 0;");
673 p( "r"+rt+" = r"+rs+" & "+unsignedImmediate+";");
676 p( "r"+rt+" = r"+rs+" | "+unsignedImmediate+";");
679 p( "r"+rt+" = r"+rs+" ^ "+unsignedImmediate+";");
682 p( "r"+rt+" = "+unsignedImmediate+" << 16;");
685 throw new CompilationException("TLB/Exception support not implemented");
689 p( "r"+rt+" = f"+rd+";");
692 if(fs != 31) throw new CompilationException("FCR " + fs + " unavailable");
693 p( "r"+rt+" = fcsr;");
696 p( "f"+rd+" = r"+rt+";");
699 if(fs != 31) throw new CompilationException("FCR " + fs + " unavailable");
700 p( "fcsr = r"+rt+";");
702 case 8: {// BC1F, BC1T
705 p("if(((fcsr&0x800000)!=0) == (" + tmp + "!=0)) {");
707 emitInstruction(-1,nextInsn,-1);
708 branch(pc,pc+branchTarget*4+4);
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,getFloat(fs)+"/"+getFloat(ft)));
728 p(setFloat(fd,"Math.abs("+getFloat(fs)+")"));
731 p("f"+fd+" = f"+fs+"; // MOV.S");
734 p(setFloat(fd,"-"+getFloat(fs))); // FEATURE: just flip the sign bit
737 p(setDouble(fd,"(float)"+getFloat(fs)));
741 p("switch(roundingMode()) {");
743 p("case 0: f"+fd+" = (int)Math.floor("+getFloat(fs)+"+0.5); break; // Round to nearest");
744 p("case 1: f"+fd+" = (int)"+getFloat(fs)+"; break; // Round towards zero");
745 p("case 2: f"+fd+" = (int)Math.ceil("+getFloat(fs)+"); break; // Round towards plus infinity");
746 p("case 3: f"+fd+" = (int)Math.floor("+getFloat(fs)+"); break; // Round towards minus infinity");
751 p("setFC("+getFloat(fs)+"=="+getFloat(ft)+");"); // FEATURE: just compare the ints, be sure things are normalized
754 p("setFC("+getFloat(fs)+"<"+getFloat(ft)+");");
757 p("setFC("+getFloat(fs)+"<="+getFloat(ft)+");");
759 default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
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,getDouble(fs)+"/"+getDouble(ft)));
778 p(setDouble(fd,"Math.abs("+getDouble(fs)+")"));
781 p("f"+fd+" = f"+fs+";");
782 p("f"+(fd+1)+" = f"+(fs+1)+";");
785 p(setDouble(fd,"-"+getDouble(fs))); // FEATURE: just flip the sign bit
788 p(setFloat(fd,"(float)"+getDouble(fs)));
792 p("switch(roundingMode()) {");
794 p("case 0: f"+fd+" = (int)Math.floor("+getDouble(fs)+"+0.5); break; // Round to nearest");
795 p("case 1: f"+fd+" = (int)"+getDouble(fs)+"; break; // Round towards zero");
796 p("case 2: f"+fd+" = (int)Math.ceil("+getDouble(fs)+"); break; // Round towards plus infinity");
797 p("case 3: f"+fd+" = (int)Math.floor("+getDouble(fs)+"); break; // Round towards minus infinity");
802 p("setFC("+getDouble(fs)+"=="+getDouble(ft)+");"); // FEATURE: just compare the ints, be sure things are normalized
805 p("setFC("+getDouble(fs)+"<"+getDouble(ft)+");");
808 p("setFC("+getDouble(fs)+"<="+getDouble(ft)+");");
810 default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
814 case 20: { // Integer
818 p(setFloat(fd,"((float)f"+fs+")"));
822 p(setDouble(fd,"((double)f"+fs+")"));
824 default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
829 throw new CompilationException("Invalid Instruction 17/" + rs);
834 throw new CompilationException("coprocessor 2 and 3 instructions not available");
836 p("addr=r" + rs +"+"+signedImmediate + ";");
837 memRead("addr&~3","tmp");
838 p("switch(addr&3) {");
840 p("case 0: tmp = (tmp>>>24)&0xff; break;");
841 p("case 1: tmp = (tmp>>>16)&0xff; break;");
842 p("case 2: tmp = (tmp>>> 8)&0xff; break;");
843 p("case 3: tmp = (tmp>>> 0)&0xff; break;");
846 p("if((tmp&0x80)!=0) tmp |= 0xffffff00; // sign extend");
851 p("addr=r" + rs +"+"+signedImmediate + ";");
852 memRead("addr&~3","tmp");
853 p("switch(addr&2) {");
855 p("case 0: tmp = (tmp>>>16)&0xffff; break;");
856 p("case 2: tmp = (tmp>>> 0)&0xffff; break;");
859 p("if((tmp&0x8000)!=0) tmp |= 0xffff0000; // sign extend");
864 p("addr=r" + rs +"+"+signedImmediate + ";");
865 memRead("addr&~3","tmp");
866 p("switch(addr&3) {");
868 p("case 0: r"+rt+" = (r"+rt+"&0x00000000)|(tmp<< 0); break;");
869 p("case 1: r"+rt+" = (r"+rt+"&0x000000ff)|(tmp<< 8); break;");
870 p("case 2: r"+rt+" = (r"+rt+"&0x0000ffff)|(tmp<<16); break;");
871 p("case 3: r"+rt+" = (r"+rt+"&0x00ffffff)|(tmp<<24); break;");
877 memRead("r" + rs +"+"+signedImmediate,"r"+rt);
880 p("addr=r" + rs +"+"+signedImmediate + ";");
881 memRead("addr&~3","tmp");
882 p("switch(addr&3) {");
884 p("case 0: r"+rt+" = (tmp>>>24)&0xff; break;");
885 p("case 1: r"+rt+" = (tmp>>>16)&0xff; break;");
886 p("case 2: r"+rt+" = (tmp>>> 8)&0xff; break;");
887 p("case 3: r"+rt+" = (tmp>>> 0)&0xff; break;");
893 p("addr=r" + rs +"+"+signedImmediate + ";");
894 memRead("addr&~3","tmp");
895 p("switch(addr&2) {");
897 p("case 0: r"+rt+" = (tmp>>>16)&0xffff; break;");
898 p("case 2: r"+rt+" = (tmp>>> 0)&0xffff; break;");
904 p("addr=r" + rs +"+"+signedImmediate + ";");
905 memRead("addr&~3","tmp");
906 p("switch(addr&3) {");
908 p("case 0: r"+rt+" = (r"+rt+"&0xffffff00)|(tmp>>>24); break;");
909 p("case 1: r"+rt+" = (r"+rt+"&0xffff0000)|(tmp>>>16); break;");
910 p("case 2: r"+rt+" = (r"+rt+"&0xff000000)|(tmp>>> 8); break;");
911 p("case 3: r"+rt+" = (r"+rt+"&0x00000000)|(tmp>>> 0); break;");
918 p("addr=r" + rs +"+"+signedImmediate + ";");
919 memRead("addr&~3","tmp");
920 p("switch(addr&3) {");
922 p("case 0: tmp = (tmp&0x00ffffff) | ((r"+rt+"&0xff)<<24); break;");
923 p("case 1: tmp = (tmp&0xff00ffff) | ((r"+rt+"&0xff)<<16); break;");
924 p("case 2: tmp = (tmp&0xffff00ff) | ((r"+rt+"&0xff)<< 8); break;");
925 p("case 3: tmp = (tmp&0xffffff00) | ((r"+rt+"&0xff)<< 0); break;");
928 memWrite("addr&~3","tmp");
933 p("addr=r" + rs +"+"+signedImmediate + ";");
934 memRead("addr&~3","tmp");
935 p("switch(addr&2) {");
937 p("case 0: tmp = (tmp&0x0000ffff) | ((r"+rt+"&0xffff)<<16); break;");
938 p("case 2: tmp = (tmp&0xffff0000) | ((r"+rt+"&0xffff)<< 0); break;");
941 memWrite("addr&~3","tmp");
946 p("addr=r" + rs +"+"+signedImmediate + ";");
947 memRead("addr&~3","tmp");
948 p("switch(addr&3) {");
950 p("case 0: tmp=(tmp&0x00000000)|(r"+rt+">>> 0); break;");
951 p("case 1: tmp=(tmp&0xff000000)|(r"+rt+">>> 8); break;");
952 p("case 2: tmp=(tmp&0xffff0000)|(r"+rt+">>>16); break;");
953 p("case 3: tmp=(tmp&0xffffff00)|(r"+rt+">>>24); break;");
956 memWrite("addr&~3","tmp");
960 memWrite("r"+rs+"+"+signedImmediate,"r" + rt);
964 p("addr=r" + rs +"+"+signedImmediate + ";");
965 memRead("addr&~3","tmp");
966 p("switch(addr&3) {");
968 p("case 0: tmp=(tmp&0x00ffffff)|(r"+rt+"<<24); break;");
969 p("case 1: tmp=(tmp&0x0000ffff)|(r"+rt+"<<16); break;");
970 p("case 2: tmp=(tmp&0x000000ff)|(r"+rt+"<< 8); break;");
971 p("case 3: tmp=(tmp&0x00000000)|(r"+rt+"<< 0); break;");
974 memWrite("addr&~3","tmp");
978 memRead("r"+rs+"+"+signedImmediate,"f"+rt);
981 memWrite("r"+rs+"+"+signedImmediate,"f"+rt);
984 throw new CompilationException("Invalid Instruction: " + op + " at " + toHex(pc));
988 private static void memWrite(String addr, String target) {
990 p("writePages[("+addr+")>>>"+Runtime.PAGE_SHIFT+"][(("+addr+")>>>2)&"+toHex(Runtime.PAGE_WORDS-1)+"] = " + target + ";");
992 p("memWrite(" + addr + "," + target + ");");
996 private static void memRead(String addr, String target) {
998 p(target + " = readPages[("+addr+")>>>"+Runtime.PAGE_SHIFT+"][(("+addr+")>>>2)&"+toHex(Runtime.PAGE_WORDS-1)+"];");
1000 p(target + " = memRead(" + addr + ");");
1003 private static String getFloat(int r) { return "(Float.intBitsToFloat(f"+r+"))"; }
1004 private static String getDouble(int r) {
1005 return "(Double.longBitsToDouble(((f"+(r+1)+"&0xffffffffL) << 32) | (f"+r+"&0xffffffffL)))";
1007 private static String setFloat(int r, String expr) { return "f"+r+"=Float.floatToRawIntBits("+expr+");"; }
1008 private static String setDouble(int r, String expr) {
1009 return "{ long l = Double.doubleToLongBits("+expr+"); "+
1010 "f"+(r+1)+" = (int)(l >>> 32); f"+r+" = (int)l; }";
1013 private final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
1014 private final static String toHex8(int n) {
1015 String s = Long.toString(n & 0xffffffffL, 16);
1016 StringBuffer sb = new StringBuffer("0x");
1017 for(int i=8-s.length();i>0;i--) sb.append('0');
1019 return sb.toString();