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