X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FJavaSourceCompiler.java;fp=src%2Forg%2Fibex%2Fnestedvm%2FJavaSourceCompiler.java;h=d71bee87e7d163f093c9cc9a365d2cf33b207f66;hp=0000000000000000000000000000000000000000;hb=c2b2704764af1ade923ba8f15d517b87f9d16189;hpb=90f1aff73ed698ab5992fbd7eb53c1ba7329b1a5 diff --git a/src/org/ibex/nestedvm/JavaSourceCompiler.java b/src/org/ibex/nestedvm/JavaSourceCompiler.java new file mode 100644 index 0000000..d71bee8 --- /dev/null +++ b/src/org/ibex/nestedvm/JavaSourceCompiler.java @@ -0,0 +1,936 @@ +package org.ibex.nestedvm; + +import java.util.*; +import java.io.*; +import org.ibex.nestedvm.util.*; + +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 indent*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>>" + 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>>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= 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>>(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