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 + ");");
pblock(inits);
indent--;
p("}");
p();
p("protected int entryPoint() { return " + toHex(elf.header.entry) + "; }");
p("protected int heapStart() { return " + toHex(highestAddr) + "; }");
p("protected int gp() { return " + toHex(gp.addr) + "; }");
if(userInfo != null) {
p("protected int userInfoBase() { return " + toHex(userInfo.addr) + "; }");
p("protected int userInfoSize() { return " + toHex(userInfo.size) + "; }");
}
// 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 void getCPUState(CPUState state) {");
indent++;
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;");
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);
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) < ("+signedImmediate+"&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;
}
// 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;
// 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; }";
}
}