org.xwt.mips -> org.ibex.nestedvm
[nestedvm.git] / src / org / xwt / mips / JavaSourceCompiler.java
diff --git a/src/org/xwt/mips/JavaSourceCompiler.java b/src/org/xwt/mips/JavaSourceCompiler.java
deleted file mode 100644 (file)
index 85295e6..0000000
+++ /dev/null
@@ -1,936 +0,0 @@
-package org.xwt.mips;
-
-import java.util.*;
-import java.io.*;
-import org.xwt.mips.util.SeekableData;
-
-public class JavaSourceCompiler extends Compiler {
-    /** Stores the "case r XXX: ... run_YYYY();" blocks generated by the emitText method/ */
-    private StringBuffer runs = new StringBuffer();
-    /** Stores the "initData" and "cleadData" calls generated by the emitData and emitBSS methods */
-    private StringBuffer inits = new StringBuffer();
-    /** Stores lines to go in the class scope */
-    private StringBuffer classLevel = new StringBuffer();
-    
-    /** The stream to write the compiled output to */
-    private PrintWriter out;
-
-    /** Prints a blank line to the output stream */
-    private void p() { out.println(); }
-    /** prints the given string (indented by <i>indent</i>*4 spaces) to the output stream */ 
-    private void p(String s) { out.println(indents[indent] + s); }
-    private void pblock(StringBuffer sb) { out.print(sb.toString()); }
-    
-    /** Used by the p() method to add indentation */
-    private int indent;
-    
-    private static String indents[] = new String[16];
-    static { String s=""; for(int i=0;i<indents.length;i++,s=s+"    ") indents[i] = s; }
-    
-    public JavaSourceCompiler(SeekableData binary, String className, Writer w)  throws IOException {
-        super(binary,className);
-        out = new PrintWriter(w);
-    }
-    
-    protected void _go() throws Exn, IOException {
-        String packageName;
-        String className;
-        if (fullClassName.indexOf('.') != -1) {
-            packageName = fullClassName.substring(0, fullClassName.lastIndexOf('.'));
-            className = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
-        } else {
-            className = fullClassName;
-            packageName = null;
-        }
-        
-        p("/* This file was generated from " + source + " by Mips2Java on " + dateTime() + " */");
-        if (packageName != null) p("package " + packageName + ";");
-        if(runtimeStats) p("import java.util.*;");
-        p();
-        p("public class " + className + " extends " + runtimeClass + " {");
-        indent++;
-        
-        p("/* program counter */");
-        p("private int pc = 0;");
-        if(debugCompiler)
-            p("private int lastPC = 0;");
-        p();
-        p("/* General Purpose registers */");
-        p("private final static int r0 = 0;");
-        p("private int      r1,  r2,  r3,  r4,  r5,  r6,  r7,");
-        p("            r8,  r9,  r10, r11, r12, r13, r14, r15,");
-        p("            r16, r17, r18, r19, r20, r21, r22, r23,");
-        p("            r24, r25, r26, r27, r28, r29, r30, r31,");
-        p("            hi = 0, lo = 0;");
-        p("/* FP registers */");
-        p("private int f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,");
-        p("            f8,  f9,  f10, f11, f12, f13, f14, f15,");
-        p("            f16, f17, f18, f19, f20, f21, f22, f23,");
-        p("            f24, f25, f26, f27, f28, f29, f30, f31;");
-        p("/* FP Control Register */");
-        p("private int fcsr = 0;");
-        p();
-        
-        if(onePage) p("private final int[] page = readPages[0];");
-                
-        // Generate main body functions (run_XXXX() blocks, _data[] arrays, etc) 
-        int highestAddr = 0;
-        
-        for(int i=0;i<elf.sheaders.length;i++) {
-            ELF.SHeader sheader = elf.sheaders[i];
-            String name = sheader.name;
-            // if this section doesn't get loaded into our address space don't worry about it
-            if(sheader.addr == 0x0) continue;
-            
-            highestAddr = Math.max(highestAddr, sheader.addr + sheader.size);
-            
-            if(name.equals(".text"))
-                emitText(sheader.addr, new DataInputStream(sheader.getInputStream()),sheader.size);
-            else if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors"))
-                emitData(sheader.addr, new DataInputStream(sheader.getInputStream()), sheader.size,name.equals(".rodata")); 
-            else if(name.equals(".bss") || name.equals(".sbss"))                
-                emitBSS(sheader.addr,sheader.size);
-            else
-                throw new Exn("Unknown segment: " + name);
-        }
-        p();
-        
-        pblock(classLevel);
-        p();
-        
-        // Trampoline (dispatch calls to the appropriate run_XXX() methods
-        p("private final void trampoline() throws ExecutionException {");
-        indent++;
-        p("while(state == RUNNING) {");
-        indent++;
-        p("switch(pc>>>" + methodShift+ ") {");
-        //p("switch(pc&" + toHex(methodMask) + ") {");
-        indent++;
-        pblock(runs);
-        p("default: throw new ExecutionException(\"invalid address 0x\" + Long.toString(this.pc&0xffffffffL,16) + \": r2: \" + r2);");
-        indent--; p("}");
-        indent--; p("}");
-        indent--; p("}");
-        p();
-        
-        // Constructor
-        p("public " + className + "() {");
-        indent++;
-        p("super(" + pageSize + "," + totalPages + "," + (fastMem?"false":"true") + ");");
-        p("entryPoint = " + toHex(elf.header.entry) + ";");
-        if(userInfo != null) {
-            p("userInfoBase=" + toHex(userInfo.addr) + ";");
-            p("userInfoSize=" + userInfo.size + ";");
-        }
-        p("gp = " + toHex(gp.addr) + ";");
-        if(onePage)
-            p("brkAddr = " + toHex((highestAddr+4095)&~4095) + ";");
-        else
-            p("brkAddr = " + toHex((highestAddr+pageSize-1)&~(pageSize-1)) + ";");
-        pblock(inits);
-        p("state = INITIALIZED;");
-        indent--;
-        p("}");
-        p();
-        
-        // main() function
-        p("public static void main(String[] args) throws Exception {");
-        indent++;
-        p("" + className + " me = new " + className + "();");
-        p("int status = me.run(\"" + fullClassName + "\",args);");
-        if(runtimeStats) p("me.printStats();");
-        p("System.exit(status);");
-        indent--;
-        p("}");
-        p();
-        
-        // Runtime abstract methods
-        p("protected void _execute() throws ExecutionException { trampoline(); }");
-        p();
-        
-        p("protected void setCPUState(CPUState state) {");
-        indent++;
-        for(int i=1;i<32;i++) p("r" + i + "=state.r[" + i + "];");
-        for(int i=0;i<32;i++) p("f" + i + "=state.f[" + i + "];");
-        p("hi=state.hi; lo=state.lo; fcsr=state.fcsr;");
-        p("pc=state.pc;");
-        indent--;
-        p("}");
-        p("protected CPUState getCPUState() {");
-        indent++;
-        p("CPUState state = new CPUState();");
-        for(int i=1;i<32;i++) p("state.r[" + i + "]=r" + i+ ";");
-        for(int i=0;i<32;i++) p("state.f[" + i + "]=f" + i +";");
-        p("state.hi=hi; state.lo=lo; state.fcsr=fcsr;");
-        p("state.pc=pc;");
-        p("return state;");
-        indent--;
-        p("}");
-        p();
-        
-        if(supportCall) {
-            p("private static final " + hashClass + " symbols = new " + hashClass + "();");
-            p("static {");
-            indent++;
-            ELF.Symbol[] symbols = elf.getSymtab().symbols;
-            for(int i=0;i<symbols.length;i++) {
-                ELF.Symbol s = symbols[i];
-                if(s.type == ELF.Symbol.STT_FUNC && s.binding == ELF.Symbol.STB_GLOBAL && (s.name.equals("_call_helper") || !s.name.startsWith("_")))
-                    p("symbols.put(\"" + s.name + "\",new Integer(" + toHex(s.addr) + "));");
-            }
-            indent--;
-            p("}");
-            p("public int lookupSymbol(String symbol) { Integer i = (Integer) symbols.get(symbol); return i==null ? -1 : i.intValue(); }");
-            p();
-        }
-        
-        // Runtime stats
-        if(runtimeStats) {
-            p("private HashMap counters = new HashMap();");
-            p("private void inc(String k) { Long i = (Long)counters.get(k); counters.put(k,new Long(i==null ? 1 : i.longValue() + 1)); }");
-            p("private void printStats() {");
-            p(" Iterator i = new TreeSet(counters.keySet()).iterator();");
-            p(" while(i.hasNext()) { Object o = i.next(); System.err.println(\"\" + o + \": \" + counters.get(o)); }");
-            p("}");
-            p();
-        }
-        
-        indent--;
-        p("}");
-    }
-    
-    private int startOfMethod = 0;
-    private int endOfMethod = 0;
-    
-    private void startMethod(int addr) {
-        addr &= ~(maxBytesPerMethod-1);
-        startOfMethod = addr;
-        endOfMethod = addr + maxBytesPerMethod;
-        String methodName = "run_" + Long.toString(addr & 0xffffffffL, 16);
-        runs.append(indents[4] + "case " + toHex(addr>>>methodShift) + ": " + methodName + "(); break; \n");
-        //runs.append(indents[4] + "case " + toHex(addr&methodMask) + ": " + methodName + "(); break; \n");
-        
-        p("private final void " + methodName + "() throws ExecutionException { /"+"* " + toHex(addr) + " - " + toHex(endOfMethod) + " *" + "/");
-        indent++;
-        p("int addr, tmp;");
-        p("for(;;) {");
-        indent++;
-        p("switch(pc) {");
-        indent++;
-    }
-    
-    private void endMethod() { endMethod(endOfMethod); }
-    private void endMethod(int lastAddr) {
-        if(startOfMethod == 0) return;
-        // FEATURE: We should be able to use if(!unreachable) here (i think)
-        // This isn't strictly necessary; its just here to work around unreachable code errors
-        p("case " + toHex(lastAddr) + ":");
-        indent++;
-        p("pc=" + constant(lastAddr) + ";");
-        leaveMethod();
-        indent--;
-        if(debugCompiler)
-            p("default: throw new ExecutionException(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16)  + \" (got here from 0x\" + Long.toString(lastPC&0xffffffffL,16)+\")\");");
-        else
-            p("default: throw new ExecutionException(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16));");
-        indent--;
-        p("}"); // end switch
-        p("/* NOT REACHED */");
-        indent--;
-        p("}"); // end for
-        indent--;
-        p("}"); // end method
-        endOfMethod = startOfMethod = 0;
-    }
-    
-    private HashMap relativeAddrs = new HashMap();  
-    private String constant(int target) {
-        if(target >= 4096 && lessConstants) {
-            int n = target & ~1023;
-            String var = "N_" + toHex8(n);
-            if(relativeAddrs.get(new Integer(n)) == null) {
-                relativeAddrs.put(new Integer(n),Boolean.TRUE);
-                classLevel.append(indents[1] + "private static int " + var + " = " + toHex(n) + ";\n");
-            }
-            return "(" + var + " + " + toHex(target - n) + ")";
-        } else {
-            return toHex(target);
-        }
-    }
-    
-    private void branch(int pc, int target) {
-        if(debugCompiler) p("lastPC = " + toHex(pc) + ";");
-        p("pc=" + constant(target) + ";");
-        if(target == 0)
-            p("throw new ExecutionException(\"Branch to addr 0x0\");");
-        else if((pc&methodMask) == (target&methodMask))
-            p("continue;");
-        else if(assumeTailCalls)
-            p("run_" +  Long.toString((target&methodMask)&0xffffffffL, 16) + "(); return;");
-        else
-            leaveMethod();
-    }
-    
-    private void leaveMethod() {
-        p("return;");
-    }
-    
-    private boolean textDone;
-    private void emitText(int addr, DataInputStream dis, int size) throws Exn,IOException {
-        if(textDone) throw new Exn("Multiple text segments");
-        textDone = true;
-        
-        if((addr&3)!=0 || (size&3)!=0) throw new Exn("Section on weird boundaries");
-        int count = size/4;
-        int nextInsn = dis.readInt();
-        if(nextInsn == -1) throw new Error("Actually read -1 at " + toHex(addr));
-        int insn;
-        
-        for(int i=0;i<count;i++,addr+=4) {
-            insn = nextInsn;
-            nextInsn = (i == count-1) ? -1 : dis.readInt();
-            if(addr >= endOfMethod) { endMethod(); startMethod(addr); }
-            if(jumpableAddresses==null || addr == startOfMethod || jumpableAddresses.contains(new Integer(addr))) {
-                p("case " + toHex(addr) + ":");
-                unreachable = false;
-            } else if(unreachable) {
-                continue;
-            } else if(debugCompiler) {
-                p("/" + "* pc = " + toHex(addr) + "*" + "/");
-            }
-            indent++;
-            emitInstruction(addr,insn,nextInsn);
-            indent--;
-        }
-        endMethod(addr);
-        p();
-        dis.close();
-    }
-    
-    private int initDataCount = 0;
-    private void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws Exn,IOException {
-        if((addr&3)!=0 || (size&3)!=0) throw new Exn("Data section on weird boundaries");
-        int last = addr + size;
-        while(addr < last) {
-            int segSize = Math.min(size,28000); // must be a multiple of 56
-            StringBuffer sb = new StringBuffer();
-            for(int i=0;i<segSize;i+=7) {
-                long l = 0;
-                for(int j=0;j<7;j++) {
-                    l <<= 8;
-                    byte b = (i+j < size) ? dis.readByte() : 1;
-                    l |= (b & 0xffL);
-                }
-                for(int j=0;j<8;j++) {
-                    char c = (char) ((l>>>(7*(7-j)))&0x7f);
-                    if(c=='\n') sb.append("\\n"); 
-                    else if(c=='\r') sb.append("\\r");
-                    else if(c=='\\') sb.append("\\\\");
-                    else if(c=='"') sb.append("\\\"");
-                    else if(c >= 32 && c <= 126) sb.append(c);
-                    else sb.append("\\" +  toOctal3(c));
-                }
-            }
-            String varname =  "_data" + (++initDataCount);
-            p("private static final int[] " + varname + " = decodeData(\"" + sb.toString() + "\"," + toHex(segSize/4) + ");");
-            inits.append(indents[2] + "initPages(" + varname +"," + toHex(addr) + "," + (readOnly?"true":"false") + ");\n");
-            addr += segSize;
-            size -= segSize;
-        }
-        dis.close();
-    }
-
-    private void emitBSS(int addr, int size) throws Exn {
-        if((addr&3)!=0) throw new Exn("BSS section on weird boundaries");
-        size = (size+3)&~3;
-        int count = size/4;
-        inits.append(indents[2] + "clearPages(" + toHex(addr) + "," + toHex(count) + ");\n");
-    }
-
-    // True if the current code path is unreachable (any instruction with a case statement is reachable)
-    private boolean unreachable = false;
-    
-    private void emitInstruction(int pc, int insn, int nextInsn) throws IOException,Exn {
-        if(insn == -1) throw new Error("insn is -1");
-        
-        int op = (insn >>> 26) & 0xff;                 // bits 26-31
-        int rs = (insn >>> 21) & 0x1f;                 // bits 21-25
-        int rt = (insn >>> 16) & 0x1f;                 // bits 16-20 
-        int ft = (insn >>> 16) & 0x1f;
-        int rd = (insn >>> 11) & 0x1f;                 // bits 11-15
-        int fs = (insn >>> 11) & 0x1f;
-        int shamt = (insn >>> 6) & 0x1f;               // bits 6-10
-        int fd = (insn >>> 6) & 0x1f;
-        int subcode = insn & 0x3f;                     // bits 0-5  
-
-        int jumpTarget = (insn & 0x03ffffff);          // bits 0-25
-        int unsignedImmediate = insn & 0xffff;
-        int signedImmediate = (insn << 16) >> 16;
-        int branchTarget = signedImmediate;
-
-        int tmp; // temporaries
-        
-        //if(pc%64==0) p("System.err.println(\"Executing: " + toHex(pc) + "\");");
-        //p("/" + "*" + (pc == -1 ? "Delay Slot"  : toHex(pc)) + " *" + "/ ");
-        if(pc==-1) p("/" + "* Next insn is delay slot *" + "/ ");
-        
-        if(runtimeStats && op != 0) p("inc(\"opcode: " + op + "\");");
-        switch(op) {
-            case 0: {
-                if(runtimeStats && insn != 0) p("inc(\"opcode: 0/" + subcode + "\");");
-                switch(subcode) {
-                    case 0: // SLL
-                        if(insn != 0) 
-                            p( "r"+rd+" = r"+rt+" << "+shamt+";");
-                        break;
-                    case 2: // SRL
-                        p( "r"+rd+" = r"+rt+" >>> "+shamt+";");
-                        break;
-                    case 3: // SRA
-                        p( "r"+rd+" = r"+rt+" >> "+shamt+";");
-                        break;
-                    case 4: // SLLV
-                        p( "r"+rd+" = r"+rt+" << (r"+rs+"&0x1f);");
-                        break;
-                    case 6: // SRLV
-                        p( "r"+rd+" = r"+rt+" >>> (r"+rs+"&0x1f);");
-                        break;
-                    case 7: // SRAV
-                        p( "r"+rd+" = r"+rt+" >> (r"+rs+"&0x1f);");
-                        break;
-                    case 8: // JR
-                        if(pc == -1) throw new Error("pc modifying insn in delay slot");
-                        emitInstruction(-1,nextInsn,-1);
-                        if(debugCompiler) p("lastPC = " + toHex(pc) + ";");
-                        p("pc=r" + rs + ";");
-                        leaveMethod();
-                        unreachable = true;
-                        break;
-                    case 9: // JALR
-                        if(pc == -1) throw new Error("pc modifying insn in delay slot");
-                        emitInstruction(-1,nextInsn,-1);
-                        if(debugCompiler) p("lastPC = " + toHex(pc) + ";");
-                        p("pc=r" + rs + ";");
-                        p("r" + RA + "=" + constant(pc+8 /*skip this insn and delay slot*/) + ";");
-                        leaveMethod();
-                        unreachable = true;
-                        break;
-                    case 12: // SYSCALL
-                        p("pc = " + toHex(pc) + ";");
-                        p( "r"+V0+" = syscall(r"+V0+",r"+A0+",r"+A1+",r"+A2+",r"+A3+");");
-                        p("if (state != RUNNING) {");
-                            indent++;
-                            p("pc = " + toHex(pc+4) + ";");
-                            leaveMethod();
-                            indent--;
-                        p("}");
-                        break;
-                    case 13: // BREAK
-                        p( "throw new ExecutionException(\"Break\");");
-                        break;
-                    case 16: // MFHI
-                        p( "r"+rd+" = hi;");
-                        break;
-                    case 17: // MTHI
-                        p( "hi = r"+rs+";");
-                        break;
-                    case 18: // MFLO
-                        p( "r"+rd+" = lo;");
-                        break;
-                    case 19: // MTLO
-                        p( "lo = r"+rs+";");
-                        break;
-                    case 24: // MULT
-                        p( "{ long hilo = (long)(r"+rs+") * ((long)r"+rt+"); " +
-                             "hi = (int) (hilo >>> 32); " +
-                             "lo = (int) hilo; }");
-                        break;
-                    case 25: // MULTU
-                        p( "{ long hilo = (r"+rs+" & 0xffffffffL) * (r"+rt+" & 0xffffffffL); " +
-                             "hi = (int) (hilo >>> 32); " +
-                             "lo = (int) hilo; } ");
-                        break;
-                    case 26: // DIV
-                        p( "hi = r"+rs+"%r"+rt+"; lo = r"+rs+"/r"+rt+";");
-                        break;
-                    case 27: // DIVU
-                        p("if(r"+rt+"!=0) {");
-                        p( "hi = (int)((r"+rs+" & 0xffffffffL) % (r"+rt+" & 0xffffffffL)); " +
-                             "lo = (int)((r"+rs+" & 0xffffffffL) / (r"+rt+" & 0xffffffffL));");
-                        p("}");
-                        break;
-                    case 32: // ADD
-                         throw new Exn("ADD (add with oveflow trap) not suported");
-                        /*This must trap on overflow
-                        p( "r"+rd+" = r"+rs+" + r"+rt+";");
-                        break;*/
-                    case 33: // ADDU
-                        p( "r"+rd+" = r"+rs+" + r"+rt+";");
-                        break;
-                    case 34: // SUB
-                         throw new Exn("SUB (add with oveflow trap) not suported");
-                        /*This must trap on overflow
-                        p( "r"+rd+" = r"+rs+" - r"+rt+";");
-                        break;*/
-                    case 35: // SUBU
-                        p( "r"+rd+" = r"+rs+" - r"+rt+";");
-                        break;
-                    case 36: // AND
-                        p( "r"+rd+" = r"+rs+" & r"+rt+";");
-                        break;
-                    case 37: // OR
-                        p( "r"+rd+" = r"+rs+" | r"+rt+";");
-                        break;
-                    case 38: // XOR
-                        p( "r"+rd+" = r"+rs+" ^ r"+rt+";");
-                        break;
-                    case 39: // NOR
-                        p( "r"+rd+" = ~(r"+rs+" | r"+rt+");");
-                        break;
-                    case 42: // SLT
-                        p( "r"+rd+" = r"+rs+" < r"+rt+" ? 1 : 0;");
-                        break;
-                    case 43: // SLTU
-                        p( "r"+rd+" = ((r"+rs+" & 0xffffffffL) < (r"+rt+" & 0xffffffffL)) ? 1 : 0;");
-                        break;
-                    default:
-                        throw new RuntimeException("Illegal instruction 0/" + subcode);
-                }
-                break;
-            }
-            case 1: {
-                switch(rt) {
-                    case 0: // BLTZ
-                        if(pc == -1) throw new Error("pc modifying insn in delay slot");
-                        p("if(r" + rs + " < 0) {");
-                            indent++;
-                            emitInstruction(-1,nextInsn,-1);
-                            branch(pc,pc+branchTarget*4+4);
-                            indent--;
-                        p("}");
-                        break;
-                    case 1: // BGEZ
-                        if(pc == -1) throw new Error("pc modifying insn in delay slot");
-                        p("if(r" + rs + " >= 0) {");
-                            indent++;
-                            emitInstruction(-1,nextInsn,-1);
-                            branch(pc,pc+branchTarget*4+4);
-                            indent--;
-                        p("}");
-                        break;
-                    case 16: // BLTZAL
-                        if(pc == -1) throw new Error("pc modifying insn in delay slot");
-                        p("if(r" + rs + " < 0) {");
-                            indent++;
-                            emitInstruction(-1,nextInsn,-1);
-                            p("r" + RA + "=" + constant(pc+8 /*skip this insn and delay slot*/) + ";");
-                            branch(pc,pc+branchTarget*4+4);
-                            indent--;
-                        p("}");
-                        break;
-                    case 17: // BGEZAL
-                        if(pc == -1) throw new Error("pc modifying insn in delay slot");
-                        p("if(r" + rs + " >= 0) {");
-                            indent++;
-                            emitInstruction(-1,nextInsn,-1);
-                            p("r" + RA + "=" + constant(pc+8 /*skip this insn and delay slot*/) + ";");
-                            branch(pc,pc+branchTarget*4+4);
-                            indent--;
-                        p("}");
-                        break;
-                    default:
-                        throw new RuntimeException("Illegal Instruction 1/" + rt);
-                }
-                break;
-            }
-            case 2: { // J
-                if(pc == -1) throw new Error("pc modifying insn in delay slot");
-                emitInstruction(-1,nextInsn,-1);
-                branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
-                unreachable = true;
-                break;
-            }
-            case 3: { // JAL
-                if(pc == -1) throw new Error("pc modifying insn in delay slot");
-                int target = (pc&0xf0000000)|(jumpTarget << 2);
-                emitInstruction(-1,nextInsn,-1);
-                if(optimizedMemcpy && (target == memcpy || target == memset)) {
-                    if(target == memcpy)
-                        p("memcpy(r4,r5,r6);");
-                    else if(target == memset)
-                        p("memset(r4,r5,r6);");
-                    p("r2 = r4;");
-                    branch(pc,pc+8);
-                } else {
-                    p("r" + RA + "=" + constant(pc+8 /*skip this insn and delay slot*/) + ";");
-                    branch(pc, target);
-                }
-                unreachable = true;
-                break;
-            }
-            case 4: // BEQ
-                if(pc == -1) throw new Error("pc modifying insn in delay slot");
-                p("if(r" + rs + " == r" + rt + ") {");
-                    indent++;
-                    emitInstruction(-1,nextInsn,-1);
-                    branch(pc,pc+branchTarget*4+4);
-                    indent--;
-                p("}");
-                break;
-            case 5: // BNE       
-                if(pc == -1) throw new Error("pc modifying insn in delay slot");
-                p("if(r" + rs + " != r" + rt + ") {");
-                    indent++;
-                    emitInstruction(-1,nextInsn,-1);
-                    branch(pc,pc+branchTarget*4+4);
-                    indent--;
-                p("}");
-                break;
-            case 6: //BLEZ
-                if(pc == -1) throw new Error("pc modifying insn in delay slot");
-                p("if(r" + rs + " <= 0) {");
-                    indent++;
-                    emitInstruction(-1,nextInsn,-1);
-                    branch(pc,pc+branchTarget*4+4);
-                    indent--;
-                p("}");
-                break;
-            case 7: //BGTZ
-                if(pc == -1) throw new Error("pc modifying insn in delay slot");
-                p("if(r" + rs + " > 0) {");
-                    indent++;
-                    emitInstruction(-1,nextInsn,-1);
-                    branch(pc,pc+branchTarget*4+4);
-                    indent--;
-                p("}");
-                break;
-            case 8: // ADDI
-                p( "r"+rt+" = r"+rs+" + "+signedImmediate +";");
-                break;
-            case 9: // ADDIU
-                p( "r"+rt+" = r"+rs+" + "+signedImmediate+";");
-                break;
-            case 10: // SLTI
-                p( "r"+rt+" = r"+rs+" < "+signedImmediate+" ? 1 : 0;");
-                break;
-            case 11: // SLTIU
-                p( "r"+rt+" = (r"+rs+"&0xffffffffL) < ("+unsignedImmediate+"&0xffffffffL) ? 1 : 0;");
-                break;
-            case 12: // ANDI
-                p( "r"+rt+" = r"+rs+" & "+unsignedImmediate+";");
-                break;
-            case 13: // ORI
-                p( "r"+rt+" = r"+rs+" | "+unsignedImmediate+";");
-                break;
-            case 14: // XORI
-                p( "r"+rt+" = r"+rs+" ^ "+unsignedImmediate+";");
-                break;
-            case 15: // LUI
-                p( "r"+rt+" = "+unsignedImmediate+" << 16;");
-                break;
-            case 16:
-                throw new Exn("TLB/Exception support not implemented");
-            case 17: { // FPU
-                switch(rs) {
-                    case 0: // MFC.1
-                        p( "r"+rt+" = f"+rd+";");
-                        break;
-                    case 2: // CFC.1
-                        if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
-                        p( "r"+rt+" = fcsr;");
-                        break;
-                    case 4: // MTC.1
-                        p( "f"+rd+" = r"+rt+";");
-                        break;
-                    case 6: // CTC.1
-                        if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
-                        p( "fcsr = r"+rt+";");
-                        break;
-                    case 8: {// BC1F, BC1T
-                        tmp = (insn>>>16)&1;
-                        p("if(((fcsr&0x800000)!=0) == (" + tmp + "!=0)) {");
-                            indent++;
-                            emitInstruction(-1,nextInsn,-1);
-                            branch(pc,pc+branchTarget*4+4);
-                            indent--;
-                        p("}");
-                        break;
-                    }
-                    case 16: {  // Single 
-                        switch(subcode) {
-                            case 0: // ADD.S
-                                p(setFloat(fd,getFloat(fs)+"+"+getFloat(ft)));
-                                break;
-                            case 1: // SUB.S
-                                p(setFloat(fd,getFloat(fs)+"-"+getFloat(ft)));
-                                break;
-                            case 2: // MUL.S
-                                p(setFloat(fd,getFloat(fs)+"*"+getFloat(ft)));
-                                break;
-                            case 3: // DIV.S
-                                p(setFloat(fd,getFloat(fs)+"/"+getFloat(ft)));
-                                break;
-                            case 5: // ABS.S
-                                p(setFloat(fd,"Math.abs("+getFloat(fs)+")"));
-                                break;
-                            case 6: // MOV.S
-                                p("f"+fd+" = f"+fs+"; // MOV.S");
-                                break;
-                            case 7: // NEG.S
-                                p(setFloat(fd,"-"+getFloat(fs)));
-                                break;
-                            case 33: // CVT.D.S
-                                p(setDouble(fd,"(float)"+getFloat(fs)));
-                                break;
-                            case 36: // CVT.W.D
-                                p("switch(fcsr & 3) {");
-                                    indent++;
-                                    p("case 0: f"+fd+" = (int)Math.floor("+getFloat(fs)+"+0.5); break; // Round to nearest");
-                                    p("case 1: f"+fd+" = (int)"+getFloat(fs)+"; break; // Round towards zero");
-                                    p("case 2: f"+fd+" = (int)Math.ceil("+getFloat(fs)+"); break; // Round towards plus infinity");
-                                    p("case 3: f"+fd+" = (int)Math.floor("+getFloat(fs)+"); break; // Round towards minus infinity");
-                                    indent--;
-                                p("}");
-                                break;
-                            case 50: // C.EQ.S
-                                p("fcsr = (fcsr&~0x800000) | (("+getFloat(fs)+"=="+getFloat(ft)+") ? 0x800000 : 0x000000);");
-                                break;
-                            case 60: // C.LT.S
-                                p("fcsr = (fcsr&~0x800000) | (("+getFloat(fs)+"<"+getFloat(ft)+") ? 0x800000 : 0x000000);");
-                                break;
-                            case 62: // C.LE.S
-                                p("fcsr = (fcsr&~0x800000) | (("+getFloat(fs)+"<="+getFloat(ft)+") ? 0x800000 : 0x000000);");
-                                break;                                
-                            default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
-                        }
-                        break;
-                    }
-                    case 17: { // Double
-                        switch(subcode) {
-                            case 0: // ADD.D
-                                p(setDouble(fd,getDouble(fs)+"+"+getDouble(ft)));
-                                break;
-                            case 1: // SUB.D
-                                p(setDouble(fd,getDouble(fs)+"-"+getDouble(ft)));
-                                break;
-                            case 2: // MUL.D
-                                p(setDouble(fd,getDouble(fs)+"*"+getDouble(ft)));
-                                break;
-                            case 3: // DIV.D
-                                p(setDouble(fd,getDouble(fs)+"/"+getDouble(ft)));
-                                break;
-                            case 5: // ABS.D
-                                p(setDouble(fd,"Math.abs("+getDouble(fs)+")"));
-                                break;
-                            case 6: // MOV.D
-                                p("f"+fd+" = f"+fs+";");
-                                p("f"+(fd+1)+" = f"+(fs+1)+";");
-                                break;
-                            case 7: // NEG.D
-                                p(setDouble(fd,"-"+getDouble(fs)));
-                                break;
-                            case 32: // CVT.S.D
-                                p(setFloat(fd,"(float)"+getDouble(fs)));
-                                break;
-                            case 36: // CVT.W.D
-                                p("switch(fcsr & 3) {");
-                                    indent++;
-                                    p("case 0: f"+fd+" = (int)Math.floor("+getDouble(fs)+"+0.5); break; // Round to nearest");
-                                    p("case 1: f"+fd+" = (int)"+getDouble(fs)+"; break; // Round towards zero");
-                                    p("case 2: f"+fd+" = (int)Math.ceil("+getDouble(fs)+"); break; // Round towards plus infinity");
-                                    p("case 3: f"+fd+" = (int)Math.floor("+getDouble(fs)+"); break; // Round towards minus infinity");
-                                    indent--;
-                                p("}");
-                                break;
-                            case 50: // C.EQ.D
-                                p("fcsr = (fcsr&~0x800000) | (("+getDouble(fs)+"=="+getDouble(ft)+") ? 0x800000 : 0x000000);");                                
-                                break;
-                            case 60: // C.LT.D
-                                p("fcsr = (fcsr&~0x800000) | (("+getDouble(fs)+"<"+getDouble(ft)+") ? 0x800000 : 0x000000);");                                
-                                break;
-                            case 62: // C.LE.D
-                                p("fcsr = (fcsr&~0x800000) | (("+getDouble(fs)+"<="+getDouble(ft)+") ? 0x800000 : 0x000000);");                                
-                                break;                                
-                            default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
-                        }
-                        break;
-                    }
-                    case 20: { // Integer
-                        switch(subcode) {
-                            case 32: // CVT.S.W
-                                p(" // CVS.S.W");
-                                p(setFloat(fd,"((float)f"+fs+")"));
-                                break;
-                            case 33: // CVT.D.W
-                                p(setDouble(fd,"((double)f"+fs+")"));
-                                break;
-                            default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
-                        }
-                        break; 
-                    }
-                    default:
-                        throw new Exn("Invalid Instruction 17/" + rs);
-                }
-                break;
-            }
-            case 18: case 19:
-                throw new Exn("coprocessor 2 and 3 instructions not available");
-            case 32: { // LB
-                if(runtimeStats) p("inc(\"LB\");");
-                p("addr=r" + rs +"+"+signedImmediate + ";");
-                memRead("addr","tmp");
-                p("tmp = (tmp>>>(((~addr)&3)<<3)) & 0xff;");
-                p("if((tmp&0x80)!=0) tmp |= 0xffffff00; /* sign extend */");
-                p("r"+rt+" = tmp;");
-                break; 
-            }
-            case 33: { // LH
-                if(runtimeStats) p("inc(\"LH\");");
-                p("addr=r" + rs +"+"+signedImmediate + ";");
-                memRead("addr","tmp");
-                p("tmp = (tmp>>>(((~addr)&2)<<3)) & 0xffff;");
-                p("if((tmp&0x8000)!=0) tmp |= 0xffff0000; /* sign extend */");
-                p("r"+rt+" = tmp;");
-                break; 
-            }
-            case 34: { // LWL;
-                p("addr=r" + rs +"+"+signedImmediate + ";");
-                memRead("addr","tmp");
-                p("r" + rt + " = (r"+rt+"&(0x00ffffff>>>(((~addr)&3)<<3)))|(tmp<<((addr&3)<<3));");
-                break;
-                /*p("addr=r" + rs +"+"+signedImmediate + ";");
-                memRead("addr&~3","tmp");
-                p("switch(addr&3) {");
-                indent++;
-                p("case 0: r"+rt+" = (r"+rt+"&0x00000000)|(tmp<< 0); break;");
-                p("case 1: r"+rt+" = (r"+rt+"&0x000000ff)|(tmp<< 8); break;");
-                p("case 2: r"+rt+" = (r"+rt+"&0x0000ffff)|(tmp<<16); break;");
-                p("case 3: r"+rt+" = (r"+rt+"&0x00ffffff)|(tmp<<24); break;");
-                indent--;
-                p("}");
-                break;*/
-            }
-            case 35: // LW
-                if(runtimeStats) p("inc(\"LW\");");
-                memRead("r" + rs +"+"+signedImmediate,"r"+rt);
-                break;
-            case 36: { // LBU
-                p("addr=r" + rs +"+"+signedImmediate + ";");
-                memRead("addr","tmp");
-                p("tmp = (tmp>>>(((~addr)&3)<<3)) & 0xff;");
-                p("r"+rt+" = tmp;");
-                break; 
-            }
-            case 37: { // LHU
-                p("addr=r" + rs +"+"+signedImmediate + ";");
-                memRead("addr","tmp");
-                p("tmp = (tmp>>>(((~addr)&2)<<3)) & 0xffff;");
-                p("r"+rt+" = tmp;");
-                break; 
-            }
-            case 38: { // LWR
-                p("addr=r" + rs +"+"+signedImmediate + ";");
-                memRead("addr","tmp");
-                p("r" + rt + " = (r"+rt+"&(0xffffff00<<((addr&3)<<3)))|(tmp>>>(((~addr)&3)<<3));");
-                break;
-                
-                /*p("addr=r" + rs +"+"+signedImmediate + ";");
-                memRead("addr&~3","tmp");
-                p("switch(addr&3) {");
-                indent++;
-                p("case 0: r"+rt+" = (r"+rt+"&0xffffff00)|(tmp>>>24); break;");
-                p("case 1: r"+rt+" = (r"+rt+"&0xffff0000)|(tmp>>>16); break;");
-                p("case 2: r"+rt+" = (r"+rt+"&0xff000000)|(tmp>>> 8); break;");
-                p("case 3: r"+rt+" = (r"+rt+"&0x00000000)|(tmp>>> 0); break;");
-                indent--;
-                p("}");
-                break;*/
-                
-            }
-            case 40: { // SB
-                if(runtimeStats) p("inc(\"SB\");");
-                p("addr=r" + rs +"+"+signedImmediate + ";");
-                memRead("addr","tmp");
-                p("tmp = (tmp&~(0xff000000>>>((addr&3)<<3)))|((r"+rt+"&0xff)<<(((~addr)&3)<<3));");
-                memWrite("addr","tmp");
-                break;
-            }
-            case 41: { // SH
-                if(runtimeStats) p("inc(\"SH\");");
-                p("addr=r" + rs +"+"+signedImmediate + ";");
-                memRead("addr","tmp");
-                p("tmp = (tmp&(0xffff<<((addr&2)<<3)))|((r" + rt + "&0xffff)<<(((~addr)&2)<<3));");
-                memWrite("addr","tmp");
-                break;
-            }
-            case 42: { // SWL
-                p(" // SWL");
-                p("addr=r" + rs +"+"+signedImmediate + ";");
-                memRead("addr","tmp");
-                p("tmp = (tmp&(0xffffff00<<(((~addr)&3)<<3)))|(r"+rt+">>>((addr&3)<<3));");
-                memWrite("addr","tmp");
-                break;
-            }
-            case 43: // SW
-                if(runtimeStats) p("inc(\"SW\");");
-                memWrite("r"+rs+"+"+signedImmediate,"r" + rt);
-                break;
-            case 46: { // SWR
-                p(" // SWR");
-                p("addr=r" + rs +"+"+signedImmediate + ";");
-                memRead("addr","tmp");
-                p("tmp = (tmp&(0x00ffffff>>>((addr&3)<<3)))|(r"+rt+"<<(((~addr)&3)<<3));");
-                memWrite("addr","tmp");
-                break;
-            }
-            // FEATURE: Need to be atomic if threads
-            case 48: // LWC0/LL
-                memRead("r"+rs+"+"+signedImmediate,"r"+rt);
-                break;
-            case 49: // LWC1
-                memRead("r"+rs+"+"+signedImmediate,"f"+rt);
-                break;
-            // FEATURE: Needs to be atomic if threads
-            case 56: // SWC1/SC
-                memWrite("r"+rs+"+"+signedImmediate,"r"+rt);
-                p("r" + rt + "=1;");
-                break;
-            case 57: // SWC1
-                memWrite("r"+rs+"+"+signedImmediate,"f"+rt);
-                break;
-            default:
-                throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc));
-        }
-    }
-    
-    // Helper functions for emitText
-    // NOTE: memWrite and memRead MUST discard the last two bits of addr
-    private void memWrite(String addr, String target) {
-        if(nullPointerCheck) p("nullPointerCheck(" + addr + ");");
-        if(onePage)
-            p("page[(" + addr + ")>>>2] = " + target + ";");
-        else if(fastMem)
-            p("writePages[("+addr+")>>>"+pageShift+"][(("+addr+")>>>2)&"+toHex((pageSize>>2)-1)+"] = " + target + ";");
-        else
-            p("unsafeMemWrite(" + addr + "," + target + ");");
-    }
-    private void memRead(String addr, String target) {
-        if(nullPointerCheck) p("nullPointerCheck(" + addr + ");");
-        if(onePage)
-            p(target + "= page[(" + addr + ")>>>2];");
-        else if(fastMem)
-            p(target  + " = readPages[("+addr+")>>>"+pageShift+"][(("+addr+")>>>2)&"+toHex((pageSize>>2)-1)+"];");
-        else
-            p(target + " = unsafeMemRead(" + addr + ");");
-    }
-    private static String getFloat(int r) { return "(Float.intBitsToFloat(f"+r+"))"; }
-    private static String getDouble(int r) {
-        return "(Double.longBitsToDouble(((f"+(r+1)+"&0xffffffffL) << 32) | (f"+r+"&0xffffffffL)))";
-    }
-    private static String setFloat(int r, String expr) { return "f"+r+"=Float.floatToRawIntBits("+expr+");"; }
-    private static String setDouble(int r, String expr) {
-        return "{ long l = Double.doubleToLongBits("+expr+"); "+
-            "f"+(r+1)+" = (int)(l >>> 32); f"+r+" = (int)l; }";
-    }
-}
-    
\ No newline at end of file