-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.xwt.mips;
-
-import java.util.*;
-import java.io.*;
-
-// FEATURE: progress indicator
-// FEATURE: emit bytecode rather than .java code (for on-the-fly classloading without javac present in "real" JVMs
-
-public class Compiler implements Registers {
-
- private static StringBuffer runs = new StringBuffer();
- private static StringBuffer inits = new StringBuffer();
-
- private static PrintStream out = System.out;
-
- private static 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; }
- private static final void p() { out.println(); }
- private static final void p(String s) { out.println(indents[indent] + s); }
-
- // FEATURE: This should probably provide some detail about where the excpetion happened (address, line numbers, etc)
- private static class CompilationException extends Exception { public CompilationException(String s) { super(s); } }
-
- // Set this to true to enable fast memory access
- // When this is enabled a Java RuntimeException will be thrown when a page fault occures. When it is disabled
- // a FaultException will be throw which is easier to catch and deal with, however. as the name implies, this is slower
- private static boolean fastMem = true;
-
- // log_2 of the maximum bytes per method
- // NOTE: This value can be much higher without breaking the classfile
- // specs (around 1024) but Hotstop seems to do much better with smaller
- // methods.
- private static int LOG_MAX_BYTES_PER_METHOD = 9;
- private static int MAX_BYTES_PER_METHOD = 512;
-
- // Store frequently used registers in local variables
- // Unfortunately this doesn't seem to speed things up much
- private static String[] freqRegs = { /*"r2", "r29", "r3", "r16", "r5", "r17", "r6", "r18", "r4", "r31", "r19"*/ };
-
- // True to try to determine which case statement are needed and only include them
- private static boolean pruneCases = true;
-
- // True to insert some code in the output to help diagnore compiler problems
- private final static boolean debugCompiler = false;
-
- // True to print various statistics about the compilation
- private final static boolean printStats = true;
-
- public static void main(String[] s) throws Exception {
-
- if (s.length != 2) {
- System.err.println("usage: java " + Compiler.class.getName() + " <classname> <binary.mips>");
- System.exit(1);
- }
-
- String packageName = null;
- String className = s[0];
- if (s[0].indexOf('.') != -1) {
- packageName = s[0].substring(0, s[0].lastIndexOf('.'));
- className = s[0].substring(s[0].lastIndexOf('.') + 1);
- }
-
- ELF elf = new ELF(s[1]);
- if(elf.header.type != ELF.ELFHeader.ET_EXEC) throw new IOException("Binary is not an executable");
- if(elf.header.machine != ELF.ELFHeader.EM_MIPS) throw new IOException("Binary is not for the MIPS I Architecture");
-
- p("// This file was generated by MipsToJava");
- if (packageName != null) p("package " + packageName + ";");
- p("public class " + className + " extends org.xwt.mips.Runtime {");
- p("");
- 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(" int r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0,");
- p(" r8 = 0, r9 = 0, r10 = 0, r11 = 0, r12 = 0, r13 = 0, r14 = 0, r15 = 0,");
- p(" r16 = 0, r17 = 0, r18 = 0, r19 = 0, r20 = 0, r21 = 0, r22 = 0, r23 = 0,");
- p(" r24 = 0, r25 = 0, r26 = 0, r27 = 0, r28 = 0, r29 = 0, r30 = 0, r31 = 0,");
- p(" hi = 0, lo = 0;");
- p(" // FP registers");
- p(" private int f0 = 0, f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0, f6 = 0, f7 = 0,");
- p(" f8 = 0, f9 = 0, f10 = 0, f11 = 0, f12 = 0, f13 = 0, f14 = 0, f15 = 0,");
- p(" f16 = 0, f17 = 0, f18 = 0, f19 = 0, f20 = 0, f21 = 0, f22 = 0, f23 = 0,");
- p(" f24 = 0, f25 = 0, f26 = 0, f27 = 0, f28 = 0, f29 = 0, f30 = 0, f31 = 0;");
- p(" // FP Control Register");
- p(" private int fcsr = 0;");
- p("");
- indent++;
- // These should all be inlind by javac
- p("private final void setFC(boolean b) { fcsr = (fcsr&~0x800000) | (b ? 0x800000 : 0x000000); }");
- p("private final int roundingMode() { return fcsr & 3; /* bits 0-1 */ }");
- indent--;
-
- Set jumpableAddresses = null;
- if(pruneCases) {
- // Find all possible branches
- jumpableAddresses = new HashSet();
-
- jumpableAddresses.add(new Integer(elf.header.entry));
-
- ELF.SHeader text = elf.sectionWithName(".text");
- if(text == null) throw new Error("No .text segment");
- findBranchesInText(text.addr,new DataInputStream(text.getInputStream()),text.size,jumpableAddresses);
-
- findBranchesInSymtab(elf.getSymtab(),jumpableAddresses);
-
- 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;
- if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors"))
- findBranchesInData(new DataInputStream(sheader.getInputStream()),sheader.size,jumpableAddresses,text.addr,text.addr+text.size);
- }
- }
-
- // Generate main body functions
- int highestAddr = 0;
- indent=1;
- 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,jumpableAddresses);
- endMethod(nextEmitTextAddr);
- } 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")) {
- if(sheader.entsize != 0) throw new CompilationException("bss segment has data!");
- emitBSS(sheader.addr,sheader.size);
- } else {
- throw new CompilationException("Unknown segment: " + name);
- }
- }
- indent = 0;
-
- p(" public " + className + "() throws FaultException {");
- if(fastMem) {
- p(" super(false); // don't allow empty pages");
- p(" if(PAGE_SIZE != " + toHex(Runtime.PAGE_SIZE) + ") throw new Error(\"Runtime.PAGE_SIZE mismatch\");");
- } else {
- p(" super(true); // allow empty pages");
- }
- p(" // init data");
- p(" entryPoint = " + toHex(elf.header.entry) + ";");
- p(inits.toString());
- p(" brk = (" + toHex(highestAddr) + "+PAGE_SIZE-1) >>> PAGE_SHIFT;");
- p(" state = INITIALIZED;");
- p(" }");
- p("");
- p();
- p(" public static void main(String[] javaArgs) throws Exception {");
- p(" String[] args = new String[javaArgs.length+1];");
- p(" System.arraycopy(javaArgs,0,args,1,javaArgs.length);");
- p(" args[0] = \"" + className + "\";");
- p(" " + className + " me = new " + className + "();");
- p(" // User data");
- p(" int addr = me.sbrk(PAGE_SIZE);");
- p(" for(int i=0;i<10;i++) {");
- p(" String s = \"User Info item: \" + (i+1) + \"\\0\";");
- p(" byte[] b = s.getBytes(\"US-ASCII\");");
- p(" me.copyout(b,addr,b.length);");
- p(" me.setUserInfo(i,addr);");
- p(" addr += b.length;");
- p(" }");
- p(" // End user data");
- p(" int status = me.run(args);");
- p(" System.err.println(\"Exit status: \" + status);");
- p(" System.exit(status);");
- p(" }");
- p();
- p(" protected void _start(int pc) {");
- p(" // set the stack pointer");
- p(" r26 = STUFF_BASE;");
- p(" r27 = PAGE_SIZE;");
- p(" r29 = INITIAL_SP;");
- p(" // set the \"return address\" from _start to point at the \"magic exit address\" (0xdeadbeef)");
- p(" r31 = 0xdeadbeef;");
- p(" this.pc = pc;");
- p(" }");
-
- p();
- p(" protected void _execute() throws ExecutionException { trampoline(); }");
- p();
- p(" private final void trampoline() throws ExecutionException {");
- p(" boolean finished = false;");
- p(" while(!finished) {");
- p(" switch(this.pc >> " + LOG_MAX_BYTES_PER_METHOD + ") {");
- p(runs.toString());
- p(" default: throw new Error(\"invalid address 0x\" + Long.toString(this.pc&0xffffffffL,16));");
- p(" }");
- p(" }");
- p(" }");
- p("}");
- }
-
- private static int startOfMethod = 0;
- private static int endOfMethod = 0;
-
- private static void startMethod(int addr) {
- addr &= ~(MAX_BYTES_PER_METHOD-1);
- endOfMethod= addr + MAX_BYTES_PER_METHOD;
- String methodName = "run_" + Long.toString(addr & 0xffffffffL, 16);
- runs.append(indents[4] + "case " + toHex(addr>>LOG_MAX_BYTES_PER_METHOD) + ": finished = !" + methodName + "(); break;\n");
- p("private final boolean " + methodName + "() throws ExecutionException { /"+"* " + toHex(addr) + " - " + toHex(endOfMethod) + " *" + "/");
- indent++;
- p("int addr, tmp;");
- for(int i=0;i<freqRegs.length;i++)
- p("int " + freqRegs[i] + " = this." + freqRegs[i] + ";");
- p("for(;;) {");
- indent++;
- p("switch(pc>>2) {");
- indent++;
- startOfMethod = addr;
-
- }
- private static void endMethod() { endMethod(endOfMethod); }
- private static void endMethod(int lastAddr) {
- if(startOfMethod == 0) return;
- // This isn't strictly necessary; its just here to work around unreachable code errors
- p("case " + toHex(lastAddr>>2) + ":");
- indent++;
- p("pc=" + toHex(lastAddr) + ";");
- leaveMethod();
- indent--;
- if(debugCompiler)
- p("default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16) + \" (got here from 0x\" + Long.toString(lastPC&0xffffffffL,16)+\")\");");
- else
- p("default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16));");
- indent--;
- p("}"); // end switch
- p("/* NOT REACHED */");
- indent--;
- p("}"); // end for
- indent--;
- p("}"); // end method
- endOfMethod = 0;
- }
-
- private static void branch(int pc, int target) {
- if(debugCompiler)
- p("lastPC = " + toHex(pc) + ";");
- p("pc=" + toHex(target) + ";");
- if((pc>>LOG_MAX_BYTES_PER_METHOD) == (target>>LOG_MAX_BYTES_PER_METHOD))
- p("continue;");
- else
- leaveMethod();
- }
-
- private static void leaveMethod() { leaveMethod(true); }
- private static void leaveMethod(boolean cont) {
- for(int i=0;i<freqRegs.length;i++)
- p("this." + freqRegs[i] + " = " + freqRegs[i] + ";");
- p("return " + (cont?"true":"false") + ";");
- }
-
- private static int nextEmitTextAddr = -1;
- private static void emitText(int addr, DataInputStream dis, int size, Set jumpableAddresses) throws CompilationException,IOException {
- if(addr < nextEmitTextAddr) throw new CompilationException("Out of order sections");
- if((addr&3)!=0 || (size&3)!=0) throw new CompilationException("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>>2) + ":");
- unreachable = false;
- } else if(unreachable) {
- continue;
- } else if(debugCompiler) {
- p("/" + "* pc = " + toHex(addr) + "*" + "/");
- }
- indent++;
- emitInstruction(addr,insn,nextInsn);
- indent--;
- }
- nextEmitTextAddr = addr;
- dis.close();
- }
-
- private static int initDataCount = 0;
- private static void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws CompilationException,IOException {
- if((addr&3)!=0 || (size&3)!=0) throw new CompilationException("Section on weird boundaries");
- int count = size/4;
- String varname = "_data" + (++initDataCount);
- p("private final static int[] " + varname + " = {");
- indent++;
- for(int i=0;i<count;) {
- StringBuffer sb = new StringBuffer();
- for(int j=0;j<8 && i<count;j++,i++) {
- sb.append(toHex8(dis.readInt()));
- if(i!=count-1) sb.append(",");
- }
- p(sb.toString());
- }
- indent--;
- p("};");
- inits.append(indents[2] + "initPages(" + varname + "," + toHex(addr) + "," + (readOnly?"true":"false") + ");\n");
- dis.close();
- }
-
- private static int initBSSCount = 0;
- private static void emitBSS(int addr, int size) throws CompilationException,IOException {
- if((addr&3)!=0 || (size&3)!=0) throw new CompilationException("Section on weird boundaries");
- int count = size/4;
- inits.append(indents[2] + "clearPages(" + toHex(addr) + "," + toHex(count) + ");\n");
- }
-
- private static void findBranchesInSymtab(ELF.Symtab symtab, Set jumps) {
- ELF.Symbol[] symbols = symtab.symbols;
- int n=0;
- for(int i=0;i<symbols.length;i++) {
- ELF.Symbol s = symbols[i];
- if(s.type == ELF.Symbol.STT_FUNC) {
- //System.err.println("Adding symbol: " + s.name + " at " + toHex(s.addr));
- if(jumps.add(new Integer(s.addr))) n++;
- }
- }
- if(printStats) System.err.println("Found " + n + " additional possible branch targets in Symtab");
- }
-
- private static void findBranchesInText(int addr, DataInputStream dis, int size, Set jumps) throws IOException {
- int count = size/4;
- int pc = addr;
- int n=0;
-
- for(int i=0;i<count;i++,pc+=4) {
- int insn = dis.readInt();
- int op = (insn >>> 26) & 0xff;
- int rs = (insn >>> 21) & 0x1f;
- int rt = (insn >>> 16) & 0x1f;
- int signedImmediate = (insn << 16) >> 16;
- int branchTarget = signedImmediate;
- int jumpTarget = (insn & 0x03ffffff);
- int subcode = insn & 0x3f;
-
- switch(op) {
- case 0:
- switch(subcode) {
- case 9: // JALR
- if(jumps.add(new Integer(pc+8))) n++; // return address
- break;
- case 12: // SYSCALL
- if(jumps.add(new Integer(pc+4))) n++;
- break;
- }
- break;
- case 1:
- switch(rt) {
- case 16: // BLTZAL
- case 17: // BGTZAL
- if(jumps.add(new Integer(pc+8))) n++; // return address
- // fall through
- case 0: // BLTZ
- case 1: // BGEZ
- if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
- break;
- }
- break;
- case 3: // JAL
- if(jumps.add(new Integer(pc+8))) n++; // return address
- // fall through
- case 2: // J
- if(jumps.add(new Integer((pc&0xf0000000)|(jumpTarget << 2)))) n++;
- break;
- case 4: // BEQ
- case 5: // BNE
- case 6: // BLEZ
- case 7: // BGTZ
- if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
- break;
- case 17: // FPU Instructions
- switch(rs) {
- case 8: // BC1F, BC1T
- if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
- break;
- }
- break;
- }
- }
- dis.close();
- if(printStats) System.err.println("Found " + n + " additional possible branch targets in Text segment");
- }
-
- private static void findBranchesInData(DataInputStream dis, int size, Set jumps, int textStart, int textEnd) throws IOException {
- int count = size/4;
- int n=0;
- for(int i=0;i<count;i++) {
- int word = dis.readInt();
- if((word&3)==0 && word >= textStart && word < textEnd) {
- if(jumps.add(new Integer(word))) n++;
- }
- }
- dis.close();
- if(n>0 && printStats) System.err.println("Found " + n + " additional possible branch targets in Data segment");
- }
-
- private static boolean unreachable = false;
-
- private static void emitInstruction(int pc, int insn, int nextInsn) throws IOException,CompilationException {
- 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, addr; // 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 *" + "/ ");
-
- switch(op) {
- case 0: {
- switch(subcode) {
- case 0: // SLL
- if(insn == 0)
- p("/* NOOP */");
- else
- 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 + "=" + toHex(pc+8 /*skip this insn and delay slot*/) + ";");
- leaveMethod();
- unreachable = true;
- break;
- case 12: // SYSCALL
- 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(false);
- 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( "hi = (int)((r"+rs+" & 0xffffffffL) % (r"+rt+" & 0xffffffffL)); " +
- "lo = (int)((r"+rs+" & 0xffffffffL) / (r"+rt+" & 0xffffffffL));");
- break;
- case 32: // ADD
- throw new CompilationException("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 CompilationException("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 + "=" + toHex(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 + "=" + toHex(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");
- emitInstruction(-1,nextInsn,-1);
- p("r" + RA + "=" + toHex(pc+8 /*skip this insn and delay slot*/) + ";");
- branch(pc, (pc&0xf0000000)|(jumpTarget << 2));
- unreachable = true;
- break;
- }
- case 4: // BEQ
- if(pc == -1) throw new Error("pc modifying insn in delay slot");
- p("// BEQ");
- 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 CompilationException("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 CompilationException("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 CompilationException("FCR " + fs + " unavailable");
- p( "fcsr = r"+rt+";");
- break;
- case 8: {// BC1F, BC1T
- tmp = (insn>>>16)&1;
- p("//BC1F, BC1T");
- 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))); // FEATURE: just flip the sign bit
- break;
- case 33: // CVT.D.S
- p(setDouble(fd,"(float)"+getFloat(fs)));
- break;
- case 36: // CVT.W.D
- p("// CVT.W.D");
- p("switch(roundingMode()) {");
- 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.D
- p("setFC("+getFloat(fs)+"=="+getFloat(ft)+");"); // FEATURE: just compare the ints, be sure things are normalized
- break;
- case 60: // C.LT.D
- p("setFC("+getFloat(fs)+"<"+getFloat(ft)+");");
- break;
- case 62: // C.LE.D
- p("setFC("+getFloat(fs)+"<="+getFloat(ft)+");");
- break;
- default: throw new CompilationException("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))); // FEATURE: just flip the sign bit
- break;
- case 32: // CVT.S.D
- p(setFloat(fd,"(float)"+getDouble(fs)));
- break;
- case 36: // CVT.W.D
- p("// CVT.W.D");
- p("switch(roundingMode()) {");
- 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("setFC("+getDouble(fs)+"=="+getDouble(ft)+");"); // FEATURE: just compare the ints, be sure things are normalized
- break;
- case 60: // C.LT.D
- p("setFC("+getDouble(fs)+"<"+getDouble(ft)+");");
- break;
- case 62: // C.LE.D
- p("setFC("+getDouble(fs)+"<="+getDouble(ft)+");");
- break;
- default: throw new CompilationException("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("// CVT.D.W");
- p(setDouble(fd,"((double)f"+fs+")"));
- break;
- default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
- }
- break;
- }
- default:
- throw new CompilationException("Invalid Instruction 17/" + rs);
- }
- break;
- }
- case 18: case 19:
- throw new CompilationException("coprocessor 2 and 3 instructions not available");
- case 32: { // LB
- p("addr=r" + rs +"+"+signedImmediate + ";");
- memRead("addr&~3","tmp");
- p("switch(addr&3) {");
- indent++;
- p("case 0: tmp = (tmp>>>24)&0xff; break;");
- p("case 1: tmp = (tmp>>>16)&0xff; break;");
- p("case 2: tmp = (tmp>>> 8)&0xff; break;");
- p("case 3: tmp = (tmp>>> 0)&0xff; break;");
- indent--;
- p("}");
- p("if((tmp&0x80)!=0) tmp |= 0xffffff00; // sign extend");
- p("r"+rt+" = tmp;");
- break;
- }
- case 33: { // LH
- p("addr=r" + rs +"+"+signedImmediate + ";");
- memRead("addr&~3","tmp");
- p("switch(addr&2) {");
- indent++;
- p("case 0: tmp = (tmp>>>16)&0xffff; break;");
- p("case 2: tmp = (tmp>>> 0)&0xffff; break;");
- indent--;
- p("}");
- p("if((tmp&0x8000)!=0) tmp |= 0xffff0000; // sign extend");
- p("r"+rt+" = tmp;");
- break;
- }
- case 34: { // LWL;
- 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
- memRead("r" + rs +"+"+signedImmediate,"r"+rt);
- break;
- case 36: { // LBU
- p("addr=r" + rs +"+"+signedImmediate + ";");
- memRead("addr&~3","tmp");
- p("switch(addr&3) {");
- indent++;
- p("case 0: r"+rt+" = (tmp>>>24)&0xff; break;");
- p("case 1: r"+rt+" = (tmp>>>16)&0xff; break;");
- p("case 2: r"+rt+" = (tmp>>> 8)&0xff; break;");
- p("case 3: r"+rt+" = (tmp>>> 0)&0xff; break;");
- indent--;
- p("}");
- break;
- }
- case 37: { // LHU
- p("addr=r" + rs +"+"+signedImmediate + ";");
- memRead("addr&~3","tmp");
- p("switch(addr&2) {");
- indent++;
- p("case 0: r"+rt+" = (tmp>>>16)&0xffff; break;");
- p("case 2: r"+rt+" = (tmp>>> 0)&0xffff; break;");
- indent--;
- p("}");
- break;
- }
- case 38: { // LWR
- 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
- p("// SB");
- p("addr=r" + rs +"+"+signedImmediate + ";");
- memRead("addr&~3","tmp");
- p("switch(addr&3) {");
- indent++;
- p("case 0: tmp = (tmp&0x00ffffff) | ((r"+rt+"&0xff)<<24); break;");
- p("case 1: tmp = (tmp&0xff00ffff) | ((r"+rt+"&0xff)<<16); break;");
- p("case 2: tmp = (tmp&0xffff00ff) | ((r"+rt+"&0xff)<< 8); break;");
- p("case 3: tmp = (tmp&0xffffff00) | ((r"+rt+"&0xff)<< 0); break;");
- indent--;
- p("}");
- memWrite("addr&~3","tmp");
- break;
- }
- case 41: { // SH
- p("// SH");
- p("addr=r" + rs +"+"+signedImmediate + ";");
- memRead("addr&~3","tmp");
- p("switch(addr&2) {");
- indent++;
- p("case 0: tmp = (tmp&0x0000ffff) | ((r"+rt+"&0xffff)<<16); break;");
- p("case 2: tmp = (tmp&0xffff0000) | ((r"+rt+"&0xffff)<< 0); break;");
- indent--;
- p("}");
- memWrite("addr&~3","tmp");
- break;
- }
- case 42: { // SWL
- p(" // SWL");
- p("addr=r" + rs +"+"+signedImmediate + ";");
- memRead("addr&~3","tmp");
- p("switch(addr&3) {");
- indent++;
- p("case 0: tmp=(tmp&0x00000000)|(r"+rt+">>> 0); break;");
- p("case 1: tmp=(tmp&0xff000000)|(r"+rt+">>> 8); break;");
- p("case 2: tmp=(tmp&0xffff0000)|(r"+rt+">>>16); break;");
- p("case 3: tmp=(tmp&0xffffff00)|(r"+rt+">>>24); break;");
- indent--;
- p("}");
- memWrite("addr&~3","tmp");
- break;
- }
- case 43: // SW
- memWrite("r"+rs+"+"+signedImmediate,"r" + rt);
- break;
- case 46: { // SWR
- p(" // SWR");
- p("addr=r" + rs +"+"+signedImmediate + ";");
- memRead("addr&~3","tmp");
- p("switch(addr&3) {");
- indent++;
- p("case 0: tmp=(tmp&0x00ffffff)|(r"+rt+"<<24); break;");
- p("case 1: tmp=(tmp&0x0000ffff)|(r"+rt+"<<16); break;");
- p("case 2: tmp=(tmp&0x000000ff)|(r"+rt+"<< 8); break;");
- p("case 3: tmp=(tmp&0x00000000)|(r"+rt+"<< 0); break;");
- indent--;
- p("}");
- memWrite("addr&~3","tmp");
- break;
- }
- case 49: // LWC1
- memRead("r"+rs+"+"+signedImmediate,"f"+rt);
- break;
- case 57: // SWC1
- memWrite("r"+rs+"+"+signedImmediate,"f"+rt);
- break;
- default:
- throw new CompilationException("Invalid Instruction: " + op + " at " + toHex(pc));
- }
- }
-
- private static void memWrite(String addr, String target) {
- if(fastMem)
- p("writePages[("+addr+")>>>"+Runtime.PAGE_SHIFT+"][(("+addr+")>>>2)&"+toHex(Runtime.PAGE_WORDS-1)+"] = " + target + ";");
- else
- p("memWrite(" + addr + "," + target + ");");
-
- }
-
- private static void memRead(String addr, String target) {
- if(fastMem)
- p(target + " = readPages[("+addr+")>>>"+Runtime.PAGE_SHIFT+"][(("+addr+")>>>2)&"+toHex(Runtime.PAGE_WORDS-1)+"];");
- else
- p(target + " = memRead(" + 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; }";
- }
-
- private final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
- private final static String toHex8(int n) {
- String s = Long.toString(n & 0xffffffffL, 16);
- StringBuffer sb = new StringBuffer("0x");
- for(int i=8-s.length();i>0;i--) sb.append('0');
- sb.append(s);
- return sb.toString();
- }
-}
-