5 import org.xwt.mips.util.SeekableData;
7 public class JavaSourceCompiler extends Compiler {
8 /** Stores the "case r XXX: ... run_YYYY();" blocks generated by the emitText method/ */
9 private StringBuffer runs = new StringBuffer();
10 /** Stores the "initData" and "cleadData" calls generated by the emitData and emitBSS methods */
11 private StringBuffer inits = new StringBuffer();
12 /** Stores lines to go in the class scope */
13 private StringBuffer classLevel = new StringBuffer();
15 /** The stream to write the compiled output to */
16 private PrintWriter out;
18 /** Prints a blank line to the output stream */
19 private void p() { out.println(); }
20 /** prints the given string (indented by <i>indent</i>*4 spaces) to the output stream */
21 private void p(String s) { out.println(indents[indent] + s); }
22 private void pblock(StringBuffer sb) { out.print(sb.toString()); }
24 /** Used by the p() method to add indentation */
27 private static String indents[] = new String[16];
28 static { String s=""; for(int i=0;i<indents.length;i++,s=s+" ") indents[i] = s; }
30 public JavaSourceCompiler(SeekableData binary, String className, Writer w) throws IOException {
31 super(binary,className);
32 out = new PrintWriter(w);
35 protected void _go() throws Exn, IOException {
38 if (fullClassName.indexOf('.') != -1) {
39 packageName = fullClassName.substring(0, fullClassName.lastIndexOf('.'));
40 className = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
42 className = fullClassName;
46 p("/* This file was generated from " + source + " by Mips2Java on " + dateTime() + " */");
47 if (packageName != null) p("package " + packageName + ";");
48 if(runtimeStats) p("import java.util.*;");
50 p("public class " + className + " extends " + runtimeClass + " {");
53 p("/* program counter */");
54 p("private int pc = 0;");
56 p("private int lastPC = 0;");
58 p("/* General Purpose registers */");
59 p("private final static int r0 = 0;");
60 p("private int r1, r2, r3, r4, r5, r6, r7,");
61 p(" r8, r9, r10, r11, r12, r13, r14, r15,");
62 p(" r16, r17, r18, r19, r20, r21, r22, r23,");
63 p(" r24, r25, r26, r27, r28, r29, r30, r31,");
64 p(" hi = 0, lo = 0;");
65 p("/* FP registers */");
66 p("private int f0, f1, f2, f3, f4, f5, f6, f7,");
67 p(" f8, f9, f10, f11, f12, f13, f14, f15,");
68 p(" f16, f17, f18, f19, f20, f21, f22, f23,");
69 p(" f24, f25, f26, f27, f28, f29, f30, f31;");
70 p("/* FP Control Register */");
71 p("private int fcsr = 0;");
74 if(onePage) p("private final int[] page = readPages[0];");
76 // Generate main body functions (run_XXXX() blocks, _data[] arrays, etc)
79 for(int i=0;i<elf.sheaders.length;i++) {
80 ELF.SHeader sheader = elf.sheaders[i];
81 String name = sheader.name;
82 // if this section doesn't get loaded into our address space don't worry about it
83 if(sheader.addr == 0x0) continue;
85 highestAddr = Math.max(highestAddr, sheader.addr + sheader.size);
87 if(name.equals(".text"))
88 emitText(sheader.addr, new DataInputStream(sheader.getInputStream()),sheader.size);
89 else if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors"))
90 emitData(sheader.addr, new DataInputStream(sheader.getInputStream()), sheader.size,name.equals(".rodata"));
91 else if(name.equals(".bss") || name.equals(".sbss"))
92 emitBSS(sheader.addr,sheader.size);
94 throw new Exn("Unknown segment: " + name);
101 // Trampoline (dispatch calls to the appropriate run_XXX() methods
102 p("private final void trampoline() throws ExecutionException {");
104 p("while(state == RUNNING) {");
106 p("switch(pc>>>" + methodShift+ ") {");
107 //p("switch(pc&" + toHex(methodMask) + ") {");
110 p("default: throw new ExecutionException(\"invalid address 0x\" + Long.toString(this.pc&0xffffffffL,16) + \": r2: \" + r2);");
117 p("public " + className + "() {");
119 p("super(" + pageSize + "," + totalPages + "," + (fastMem?"false":"true") + ");");
120 p("entryPoint = " + toHex(elf.header.entry) + ";");
121 if(userInfo != null) {
122 p("userInfoBase=" + toHex(userInfo.addr) + ";");
123 p("userInfoSize=" + userInfo.size + ";");
125 p("gp = " + toHex(gp.addr) + ";");
127 p("brkAddr = " + toHex((highestAddr+4095)&~4095) + ";");
129 p("brkAddr = " + toHex((highestAddr+pageSize-1)&~(pageSize-1)) + ";");
131 p("state = INITIALIZED;");
137 p("public static void main(String[] args) throws Exception {");
139 p("" + className + " me = new " + className + "();");
140 p("int status = me.run(\"" + fullClassName + "\",args);");
141 if(runtimeStats) p("me.printStats();");
142 p("System.exit(status);");
147 // Runtime abstract methods
148 p("protected void _execute() throws ExecutionException { trampoline(); }");
151 p("protected void setCPUState(CPUState state) {");
153 for(int i=1;i<32;i++) p("r" + i + "=state.r[" + i + "];");
154 for(int i=0;i<32;i++) p("f" + i + "=state.f[" + i + "];");
155 p("hi=state.hi; lo=state.lo; fcsr=state.fcsr;");
159 p("protected CPUState getCPUState() {");
161 p("CPUState state = new CPUState();");
162 for(int i=1;i<32;i++) p("state.r[" + i + "]=r" + i+ ";");
163 for(int i=0;i<32;i++) p("state.f[" + i + "]=f" + i +";");
164 p("state.hi=hi; state.lo=lo; state.fcsr=fcsr;");
172 p("private static final " + hashClass + " symbols = new " + hashClass + "();");
175 ELF.Symbol[] symbols = elf.getSymtab().symbols;
176 for(int i=0;i<symbols.length;i++) {
177 ELF.Symbol s = symbols[i];
178 if(s.type == ELF.Symbol.STT_FUNC && s.binding == ELF.Symbol.STB_GLOBAL && (s.name.equals("_call_helper") || !s.name.startsWith("_")))
179 p("symbols.put(\"" + s.name + "\",new Integer(" + toHex(s.addr) + "));");
183 p("public int lookupSymbol(String symbol) { Integer i = (Integer) symbols.get(symbol); return i==null ? -1 : i.intValue(); }");
189 p("private HashMap counters = new HashMap();");
190 p("private void inc(String k) { Long i = (Long)counters.get(k); counters.put(k,new Long(i==null ? 1 : i.longValue() + 1)); }");
191 p("private void printStats() {");
192 p(" Iterator i = new TreeSet(counters.keySet()).iterator();");
193 p(" while(i.hasNext()) { Object o = i.next(); System.err.println(\"\" + o + \": \" + counters.get(o)); }");
202 private int startOfMethod = 0;
203 private int endOfMethod = 0;
205 private void startMethod(int addr) {
206 addr &= ~(maxBytesPerMethod-1);
207 startOfMethod = addr;
208 endOfMethod = addr + maxBytesPerMethod;
209 String methodName = "run_" + Long.toString(addr & 0xffffffffL, 16);
210 runs.append(indents[4] + "case " + toHex(addr>>>methodShift) + ": " + methodName + "(); break; \n");
211 //runs.append(indents[4] + "case " + toHex(addr&methodMask) + ": " + methodName + "(); break; \n");
213 p("private final void " + methodName + "() throws ExecutionException { /"+"* " + toHex(addr) + " - " + toHex(endOfMethod) + " *" + "/");
222 private void endMethod() { endMethod(endOfMethod); }
223 private void endMethod(int lastAddr) {
224 if(startOfMethod == 0) return;
225 // FEATURE: We should be able to use if(!unreachable) here (i think)
226 // This isn't strictly necessary; its just here to work around unreachable code errors
227 p("case " + toHex(lastAddr) + ":");
229 p("pc=" + constant(lastAddr) + ";");
233 p("default: throw new ExecutionException(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16) + \" (got here from 0x\" + Long.toString(lastPC&0xffffffffL,16)+\")\");");
235 p("default: throw new ExecutionException(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16));");
237 p("}"); // end switch
238 p("/* NOT REACHED */");
242 p("}"); // end method
243 endOfMethod = startOfMethod = 0;
246 private HashMap relativeAddrs = new HashMap();
247 private String constant(int target) {
248 if(target >= 4096 && lessConstants) {
249 int n = target & ~1023;
250 String var = "N_" + toHex8(n);
251 if(relativeAddrs.get(new Integer(n)) == null) {
252 relativeAddrs.put(new Integer(n),Boolean.TRUE);
253 classLevel.append(indents[1] + "private static int " + var + " = " + toHex(n) + ";\n");
255 return "(" + var + " + " + toHex(target - n) + ")";
257 return toHex(target);
261 private void branch(int pc, int target) {
262 if(debugCompiler) p("lastPC = " + toHex(pc) + ";");
263 p("pc=" + constant(target) + ";");
265 p("throw new ExecutionException(\"Branch to addr 0x0\");");
266 else if((pc&methodMask) == (target&methodMask))
268 else if(assumeTailCalls)
269 p("run_" + Long.toString((target&methodMask)&0xffffffffL, 16) + "(); return;");
274 private void leaveMethod() {
278 private boolean textDone;
279 private void emitText(int addr, DataInputStream dis, int size) throws Exn,IOException {
280 if(textDone) throw new Exn("Multiple text segments");
283 if((addr&3)!=0 || (size&3)!=0) throw new Exn("Section on weird boundaries");
285 int nextInsn = dis.readInt();
286 if(nextInsn == -1) throw new Error("Actually read -1 at " + toHex(addr));
289 for(int i=0;i<count;i++,addr+=4) {
291 nextInsn = (i == count-1) ? -1 : dis.readInt();
292 if(addr >= endOfMethod) { endMethod(); startMethod(addr); }
293 if(jumpableAddresses==null || addr == startOfMethod || jumpableAddresses.contains(new Integer(addr))) {
294 p("case " + toHex(addr) + ":");
296 } else if(unreachable) {
298 } else if(debugCompiler) {
299 p("/" + "* pc = " + toHex(addr) + "*" + "/");
302 emitInstruction(addr,insn,nextInsn);
310 private int initDataCount = 0;
311 private void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws Exn,IOException {
312 if((addr&3)!=0 || (size&3)!=0) throw new Exn("Data section on weird boundaries");
313 int last = addr + size;
315 int segSize = Math.min(size,28000); // must be a multiple of 56
316 StringBuffer sb = new StringBuffer();
317 for(int i=0;i<segSize;i+=7) {
319 for(int j=0;j<7;j++) {
321 byte b = (i+j < size) ? dis.readByte() : 1;
324 for(int j=0;j<8;j++) {
325 char c = (char) ((l>>>(7*(7-j)))&0x7f);
326 if(c=='\n') sb.append("\\n");
327 else if(c=='\r') sb.append("\\r");
328 else if(c=='\\') sb.append("\\\\");
329 else if(c=='"') sb.append("\\\"");
330 else if(c >= 32 && c <= 126) sb.append(c);
331 else sb.append("\\" + toOctal3(c));
334 String varname = "_data" + (++initDataCount);
335 p("private static final int[] " + varname + " = decodeData(\"" + sb.toString() + "\"," + toHex(segSize/4) + ");");
336 inits.append(indents[2] + "initPages(" + varname +"," + toHex(addr) + "," + (readOnly?"true":"false") + ");\n");
343 private void emitBSS(int addr, int size) throws Exn {
344 if((addr&3)!=0) throw new Exn("BSS section on weird boundaries");
347 inits.append(indents[2] + "clearPages(" + toHex(addr) + "," + toHex(count) + ");\n");
350 // True if the current code path is unreachable (any instruction with a case statement is reachable)
351 private boolean unreachable = false;
353 private void emitInstruction(int pc, int insn, int nextInsn) throws IOException,Exn {
354 if(insn == -1) throw new Error("insn is -1");
356 int op = (insn >>> 26) & 0xff; // bits 26-31
357 int rs = (insn >>> 21) & 0x1f; // bits 21-25
358 int rt = (insn >>> 16) & 0x1f; // bits 16-20
359 int ft = (insn >>> 16) & 0x1f;
360 int rd = (insn >>> 11) & 0x1f; // bits 11-15
361 int fs = (insn >>> 11) & 0x1f;
362 int shamt = (insn >>> 6) & 0x1f; // bits 6-10
363 int fd = (insn >>> 6) & 0x1f;
364 int subcode = insn & 0x3f; // bits 0-5
366 int jumpTarget = (insn & 0x03ffffff); // bits 0-25
367 int unsignedImmediate = insn & 0xffff;
368 int signedImmediate = (insn << 16) >> 16;
369 int branchTarget = signedImmediate;
371 int tmp; // temporaries
373 //if(pc%64==0) p("System.err.println(\"Executing: " + toHex(pc) + "\");");
374 //p("/" + "*" + (pc == -1 ? "Delay Slot" : toHex(pc)) + " *" + "/ ");
375 if(pc==-1) p("/" + "* Next insn is delay slot *" + "/ ");
377 if(runtimeStats && op != 0) p("inc(\"opcode: " + op + "\");");
380 if(runtimeStats && insn != 0) p("inc(\"opcode: 0/" + subcode + "\");");
384 p( "r"+rd+" = r"+rt+" << "+shamt+";");
387 p( "r"+rd+" = r"+rt+" >>> "+shamt+";");
390 p( "r"+rd+" = r"+rt+" >> "+shamt+";");
393 p( "r"+rd+" = r"+rt+" << (r"+rs+"&0x1f);");
396 p( "r"+rd+" = r"+rt+" >>> (r"+rs+"&0x1f);");
399 p( "r"+rd+" = r"+rt+" >> (r"+rs+"&0x1f);");
402 if(pc == -1) throw new Error("pc modifying insn in delay slot");
403 emitInstruction(-1,nextInsn,-1);
404 if(debugCompiler) p("lastPC = " + toHex(pc) + ";");
405 p("pc=r" + rs + ";");
410 if(pc == -1) throw new Error("pc modifying insn in delay slot");
411 emitInstruction(-1,nextInsn,-1);
412 if(debugCompiler) p("lastPC = " + toHex(pc) + ";");
413 p("pc=r" + rs + ";");
414 p("r" + RA + "=" + constant(pc+8 /*skip this insn and delay slot*/) + ";");
419 p("pc = " + toHex(pc) + ";");
420 p( "r"+V0+" = syscall(r"+V0+",r"+A0+",r"+A1+",r"+A2+",r"+A3+");");
421 p("if (state != RUNNING) {");
423 p("pc = " + toHex(pc+4) + ";");
429 p( "throw new ExecutionException(\"Break\");");
444 p( "{ long hilo = (long)(r"+rs+") * ((long)r"+rt+"); " +
445 "hi = (int) (hilo >>> 32); " +
446 "lo = (int) hilo; }");
449 p( "{ long hilo = (r"+rs+" & 0xffffffffL) * (r"+rt+" & 0xffffffffL); " +
450 "hi = (int) (hilo >>> 32); " +
451 "lo = (int) hilo; } ");
454 p( "hi = r"+rs+"%r"+rt+"; lo = r"+rs+"/r"+rt+";");
457 p("if(r"+rt+"!=0) {");
458 p( "hi = (int)((r"+rs+" & 0xffffffffL) % (r"+rt+" & 0xffffffffL)); " +
459 "lo = (int)((r"+rs+" & 0xffffffffL) / (r"+rt+" & 0xffffffffL));");
463 throw new Exn("ADD (add with oveflow trap) not suported");
464 /*This must trap on overflow
465 p( "r"+rd+" = r"+rs+" + r"+rt+";");
468 p( "r"+rd+" = r"+rs+" + r"+rt+";");
471 throw new Exn("SUB (add with oveflow trap) not suported");
472 /*This must trap on overflow
473 p( "r"+rd+" = r"+rs+" - r"+rt+";");
476 p( "r"+rd+" = r"+rs+" - r"+rt+";");
479 p( "r"+rd+" = r"+rs+" & r"+rt+";");
482 p( "r"+rd+" = r"+rs+" | r"+rt+";");
485 p( "r"+rd+" = r"+rs+" ^ r"+rt+";");
488 p( "r"+rd+" = ~(r"+rs+" | r"+rt+");");
491 p( "r"+rd+" = r"+rs+" < r"+rt+" ? 1 : 0;");
494 p( "r"+rd+" = ((r"+rs+" & 0xffffffffL) < (r"+rt+" & 0xffffffffL)) ? 1 : 0;");
497 throw new RuntimeException("Illegal instruction 0/" + subcode);
504 if(pc == -1) throw new Error("pc modifying insn in delay slot");
505 p("if(r" + rs + " < 0) {");
507 emitInstruction(-1,nextInsn,-1);
508 branch(pc,pc+branchTarget*4+4);
513 if(pc == -1) throw new Error("pc modifying insn in delay slot");
514 p("if(r" + rs + " >= 0) {");
516 emitInstruction(-1,nextInsn,-1);
517 branch(pc,pc+branchTarget*4+4);
522 if(pc == -1) throw new Error("pc modifying insn in delay slot");
523 p("if(r" + rs + " < 0) {");
525 emitInstruction(-1,nextInsn,-1);
526 p("r" + RA + "=" + constant(pc+8 /*skip this insn and delay slot*/) + ";");
527 branch(pc,pc+branchTarget*4+4);
532 if(pc == -1) throw new Error("pc modifying insn in delay slot");
533 p("if(r" + rs + " >= 0) {");
535 emitInstruction(-1,nextInsn,-1);
536 p("r" + RA + "=" + constant(pc+8 /*skip this insn and delay slot*/) + ";");
537 branch(pc,pc+branchTarget*4+4);
542 throw new RuntimeException("Illegal Instruction 1/" + rt);
547 if(pc == -1) throw new Error("pc modifying insn in delay slot");
548 emitInstruction(-1,nextInsn,-1);
549 branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
554 if(pc == -1) throw new Error("pc modifying insn in delay slot");
555 int target = (pc&0xf0000000)|(jumpTarget << 2);
556 emitInstruction(-1,nextInsn,-1);
557 if(optimizedMemcpy && (target == memcpy || target == memset)) {
559 p("memcpy(r4,r5,r6);");
560 else if(target == memset)
561 p("memset(r4,r5,r6);");
565 p("r" + RA + "=" + constant(pc+8 /*skip this insn and delay slot*/) + ";");
572 if(pc == -1) throw new Error("pc modifying insn in delay slot");
573 p("if(r" + rs + " == r" + rt + ") {");
575 emitInstruction(-1,nextInsn,-1);
576 branch(pc,pc+branchTarget*4+4);
581 if(pc == -1) throw new Error("pc modifying insn in delay slot");
582 p("if(r" + rs + " != r" + rt + ") {");
584 emitInstruction(-1,nextInsn,-1);
585 branch(pc,pc+branchTarget*4+4);
590 if(pc == -1) throw new Error("pc modifying insn in delay slot");
591 p("if(r" + rs + " <= 0) {");
593 emitInstruction(-1,nextInsn,-1);
594 branch(pc,pc+branchTarget*4+4);
599 if(pc == -1) throw new Error("pc modifying insn in delay slot");
600 p("if(r" + rs + " > 0) {");
602 emitInstruction(-1,nextInsn,-1);
603 branch(pc,pc+branchTarget*4+4);
608 p( "r"+rt+" = r"+rs+" + "+signedImmediate +";");
611 p( "r"+rt+" = r"+rs+" + "+signedImmediate+";");
614 p( "r"+rt+" = r"+rs+" < "+signedImmediate+" ? 1 : 0;");
617 p( "r"+rt+" = (r"+rs+"&0xffffffffL) < ("+unsignedImmediate+"&0xffffffffL) ? 1 : 0;");
620 p( "r"+rt+" = r"+rs+" & "+unsignedImmediate+";");
623 p( "r"+rt+" = r"+rs+" | "+unsignedImmediate+";");
626 p( "r"+rt+" = r"+rs+" ^ "+unsignedImmediate+";");
629 p( "r"+rt+" = "+unsignedImmediate+" << 16;");
632 throw new Exn("TLB/Exception support not implemented");
636 p( "r"+rt+" = f"+rd+";");
639 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
640 p( "r"+rt+" = fcsr;");
643 p( "f"+rd+" = r"+rt+";");
646 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
647 p( "fcsr = r"+rt+";");
649 case 8: {// BC1F, BC1T
651 p("if(((fcsr&0x800000)!=0) == (" + tmp + "!=0)) {");
653 emitInstruction(-1,nextInsn,-1);
654 branch(pc,pc+branchTarget*4+4);
662 p(setFloat(fd,getFloat(fs)+"+"+getFloat(ft)));
665 p(setFloat(fd,getFloat(fs)+"-"+getFloat(ft)));
668 p(setFloat(fd,getFloat(fs)+"*"+getFloat(ft)));
671 p(setFloat(fd,getFloat(fs)+"/"+getFloat(ft)));
674 p(setFloat(fd,"Math.abs("+getFloat(fs)+")"));
677 p("f"+fd+" = f"+fs+"; // MOV.S");
680 p(setFloat(fd,"-"+getFloat(fs)));
683 p(setDouble(fd,"(float)"+getFloat(fs)));
686 p("switch(fcsr & 3) {");
688 p("case 0: f"+fd+" = (int)Math.floor("+getFloat(fs)+"+0.5); break; // Round to nearest");
689 p("case 1: f"+fd+" = (int)"+getFloat(fs)+"; break; // Round towards zero");
690 p("case 2: f"+fd+" = (int)Math.ceil("+getFloat(fs)+"); break; // Round towards plus infinity");
691 p("case 3: f"+fd+" = (int)Math.floor("+getFloat(fs)+"); break; // Round towards minus infinity");
696 p("fcsr = (fcsr&~0x800000) | (("+getFloat(fs)+"=="+getFloat(ft)+") ? 0x800000 : 0x000000);");
699 p("fcsr = (fcsr&~0x800000) | (("+getFloat(fs)+"<"+getFloat(ft)+") ? 0x800000 : 0x000000);");
702 p("fcsr = (fcsr&~0x800000) | (("+getFloat(fs)+"<="+getFloat(ft)+") ? 0x800000 : 0x000000);");
704 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
711 p(setDouble(fd,getDouble(fs)+"+"+getDouble(ft)));
714 p(setDouble(fd,getDouble(fs)+"-"+getDouble(ft)));
717 p(setDouble(fd,getDouble(fs)+"*"+getDouble(ft)));
720 p(setDouble(fd,getDouble(fs)+"/"+getDouble(ft)));
723 p(setDouble(fd,"Math.abs("+getDouble(fs)+")"));
726 p("f"+fd+" = f"+fs+";");
727 p("f"+(fd+1)+" = f"+(fs+1)+";");
730 p(setDouble(fd,"-"+getDouble(fs)));
733 p(setFloat(fd,"(float)"+getDouble(fs)));
736 p("switch(fcsr & 3) {");
738 p("case 0: f"+fd+" = (int)Math.floor("+getDouble(fs)+"+0.5); break; // Round to nearest");
739 p("case 1: f"+fd+" = (int)"+getDouble(fs)+"; break; // Round towards zero");
740 p("case 2: f"+fd+" = (int)Math.ceil("+getDouble(fs)+"); break; // Round towards plus infinity");
741 p("case 3: f"+fd+" = (int)Math.floor("+getDouble(fs)+"); break; // Round towards minus infinity");
746 p("fcsr = (fcsr&~0x800000) | (("+getDouble(fs)+"=="+getDouble(ft)+") ? 0x800000 : 0x000000);");
749 p("fcsr = (fcsr&~0x800000) | (("+getDouble(fs)+"<"+getDouble(ft)+") ? 0x800000 : 0x000000);");
752 p("fcsr = (fcsr&~0x800000) | (("+getDouble(fs)+"<="+getDouble(ft)+") ? 0x800000 : 0x000000);");
754 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
758 case 20: { // Integer
762 p(setFloat(fd,"((float)f"+fs+")"));
765 p(setDouble(fd,"((double)f"+fs+")"));
767 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
772 throw new Exn("Invalid Instruction 17/" + rs);
777 throw new Exn("coprocessor 2 and 3 instructions not available");
779 if(runtimeStats) p("inc(\"LB\");");
780 p("addr=r" + rs +"+"+signedImmediate + ";");
781 memRead("addr","tmp");
782 p("tmp = (tmp>>>(((~addr)&3)<<3)) & 0xff;");
783 p("if((tmp&0x80)!=0) tmp |= 0xffffff00; /* sign extend */");
788 if(runtimeStats) p("inc(\"LH\");");
789 p("addr=r" + rs +"+"+signedImmediate + ";");
790 memRead("addr","tmp");
791 p("tmp = (tmp>>>(((~addr)&2)<<3)) & 0xffff;");
792 p("if((tmp&0x8000)!=0) tmp |= 0xffff0000; /* sign extend */");
797 p("addr=r" + rs +"+"+signedImmediate + ";");
798 memRead("addr","tmp");
799 p("r" + rt + " = (r"+rt+"&(0x00ffffff>>>(((~addr)&3)<<3)))|(tmp<<((addr&3)<<3));");
801 /*p("addr=r" + rs +"+"+signedImmediate + ";");
802 memRead("addr&~3","tmp");
803 p("switch(addr&3) {");
805 p("case 0: r"+rt+" = (r"+rt+"&0x00000000)|(tmp<< 0); break;");
806 p("case 1: r"+rt+" = (r"+rt+"&0x000000ff)|(tmp<< 8); break;");
807 p("case 2: r"+rt+" = (r"+rt+"&0x0000ffff)|(tmp<<16); break;");
808 p("case 3: r"+rt+" = (r"+rt+"&0x00ffffff)|(tmp<<24); break;");
814 if(runtimeStats) p("inc(\"LW\");");
815 memRead("r" + rs +"+"+signedImmediate,"r"+rt);
818 p("addr=r" + rs +"+"+signedImmediate + ";");
819 memRead("addr","tmp");
820 p("tmp = (tmp>>>(((~addr)&3)<<3)) & 0xff;");
825 p("addr=r" + rs +"+"+signedImmediate + ";");
826 memRead("addr","tmp");
827 p("tmp = (tmp>>>(((~addr)&2)<<3)) & 0xffff;");
832 p("addr=r" + rs +"+"+signedImmediate + ";");
833 memRead("addr","tmp");
834 p("r" + rt + " = (r"+rt+"&(0xffffff00<<((addr&3)<<3)))|(tmp>>>(((~addr)&3)<<3));");
837 /*p("addr=r" + rs +"+"+signedImmediate + ";");
838 memRead("addr&~3","tmp");
839 p("switch(addr&3) {");
841 p("case 0: r"+rt+" = (r"+rt+"&0xffffff00)|(tmp>>>24); break;");
842 p("case 1: r"+rt+" = (r"+rt+"&0xffff0000)|(tmp>>>16); break;");
843 p("case 2: r"+rt+" = (r"+rt+"&0xff000000)|(tmp>>> 8); break;");
844 p("case 3: r"+rt+" = (r"+rt+"&0x00000000)|(tmp>>> 0); break;");
851 if(runtimeStats) p("inc(\"SB\");");
852 p("addr=r" + rs +"+"+signedImmediate + ";");
853 memRead("addr","tmp");
854 p("tmp = (tmp&~(0xff000000>>>((addr&3)<<3)))|((r"+rt+"&0xff)<<(((~addr)&3)<<3));");
855 memWrite("addr","tmp");
859 if(runtimeStats) p("inc(\"SH\");");
860 p("addr=r" + rs +"+"+signedImmediate + ";");
861 memRead("addr","tmp");
862 p("tmp = (tmp&(0xffff<<((addr&2)<<3)))|((r" + rt + "&0xffff)<<(((~addr)&2)<<3));");
863 memWrite("addr","tmp");
868 p("addr=r" + rs +"+"+signedImmediate + ";");
869 memRead("addr","tmp");
870 p("tmp = (tmp&(0xffffff00<<(((~addr)&3)<<3)))|(r"+rt+">>>((addr&3)<<3));");
871 memWrite("addr","tmp");
875 if(runtimeStats) p("inc(\"SW\");");
876 memWrite("r"+rs+"+"+signedImmediate,"r" + rt);
880 p("addr=r" + rs +"+"+signedImmediate + ";");
881 memRead("addr","tmp");
882 p("tmp = (tmp&(0x00ffffff>>>((addr&3)<<3)))|(r"+rt+"<<(((~addr)&3)<<3));");
883 memWrite("addr","tmp");
886 // FEATURE: Need to be atomic if threads
888 memRead("r"+rs+"+"+signedImmediate,"r"+rt);
891 memRead("r"+rs+"+"+signedImmediate,"f"+rt);
893 // FEATURE: Needs to be atomic if threads
895 memWrite("r"+rs+"+"+signedImmediate,"r"+rt);
899 memWrite("r"+rs+"+"+signedImmediate,"f"+rt);
902 throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc));
906 // Helper functions for emitText
907 // NOTE: memWrite and memRead MUST discard the last two bits of addr
908 private void memWrite(String addr, String target) {
909 if(nullPointerCheck) p("nullPointerCheck(" + addr + ");");
911 p("page[(" + addr + ")>>>2] = " + target + ";");
913 p("writePages[("+addr+")>>>"+pageShift+"][(("+addr+")>>>2)&"+toHex((pageSize>>2)-1)+"] = " + target + ";");
915 p("unsafeMemWrite(" + addr + "," + target + ");");
917 private void memRead(String addr, String target) {
918 if(nullPointerCheck) p("nullPointerCheck(" + addr + ");");
920 p(target + "= page[(" + addr + ")>>>2];");
922 p(target + " = readPages[("+addr+")>>>"+pageShift+"][(("+addr+")>>>2)&"+toHex((pageSize>>2)-1)+"];");
924 p(target + " = unsafeMemRead(" + addr + ");");
926 private static String getFloat(int r) { return "(Float.intBitsToFloat(f"+r+"))"; }
927 private static String getDouble(int r) {
928 return "(Double.longBitsToDouble(((f"+(r+1)+"&0xffffffffL) << 32) | (f"+r+"&0xffffffffL)))";
930 private static String setFloat(int r, String expr) { return "f"+r+"=Float.floatToRawIntBits("+expr+");"; }
931 private static String setDouble(int r, String expr) {
932 return "{ long l = Double.doubleToLongBits("+expr+"); "+
933 "f"+(r+1)+" = (int)(l >>> 32); f"+r+" = (int)l; }";