1
2 package org.xwt.mips;
3
4 import java.util.*;
5 import java.io.*;
6
7
8
9
10 public class Compiler implements Registers {
11
12 private static StringBuffer runs = new StringBuffer();
13 private static StringBuffer inits = new StringBuffer();
14
15 private static PrintStream out = System.out;
16
17 private static int indent;
18 private static String indents[] = new String[16];
19 static { String s=""; for(int i=0;i<indents.length;i++,s=s+" ") indents[i] = s; }
20 private static final void p() { out.println(); }
21 private static final void p(String s) { out.println(indents[indent] + s); }
22
23
24 private static class CompilationException extends Exception { public CompilationException(String s) { super(s); } }
25
26
27
28
29 private static boolean fastMem = true;
30
31
32
33
34
35 private static int LOG_MAX_BYTES_PER_METHOD = 9;
36 private static int MAX_BYTES_PER_METHOD = 512;
37
38
39
40 private static String[] freqRegs = { };
41
42
43 private static boolean pruneCases = true;
44
45
46 private final static boolean debugCompiler = false;
47
48
49 private final static boolean printStats = true;
50
51 public static void main(String[] s) throws Exception {
52
53 if (s.length != 2) {
54 System.err.println("usage: java " + Compiler.class.getName() + " <classname> <binary.mips>");
55 System.exit(1);
56 }
57
58 String packageName = null;
59 String className = s[0];
60 if (s[0].indexOf('.') != -1) {
61 packageName = s[0].substring(0, s[0].lastIndexOf('.'));
62 className = s[0].substring(s[0].lastIndexOf('.') + 1);
63 }
64
65 ELF elf = new ELF(s[1]);
66 if(elf.header.type != ELF.ELFHeader.ET_EXEC) throw new IOException("Binary is not an executable");
67 if(elf.header.machine != ELF.ELFHeader.EM_MIPS) throw new IOException("Binary is not for the MIPS I Architecture");
68
69 p("// This file was generated by MipsToJava");
70 if (packageName != null) p("package " + packageName + ";");
71 p("public class " + className + " extends org.xwt.mips.Runtime {");
72 p("");
73 p(" // program counter");
74 p(" private int pc = 0;");
75 if(debugCompiler)
76 p(" private int lastPC = 0;");
77 p("");
78 p(" // General Purpose registers");
79 p(" private final static int r0 = 0;");
80 p(" int r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0,");
81 p(" r8 = 0, r9 = 0, r10 = 0, r11 = 0, r12 = 0, r13 = 0, r14 = 0, r15 = 0,");
82 p(" r16 = 0, r17 = 0, r18 = 0, r19 = 0, r20 = 0, r21 = 0, r22 = 0, r23 = 0,");
83 p(" r24 = 0, r25 = 0, r26 = 0, r27 = 0, r28 = 0, r29 = 0, r30 = 0, r31 = 0,");
84 p(" hi = 0, lo = 0;");
85 p(" // FP registers");
86 p(" private int f0 = 0, f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0, f6 = 0, f7 = 0,");
87 p(" f8 = 0, f9 = 0, f10 = 0, f11 = 0, f12 = 0, f13 = 0, f14 = 0, f15 = 0,");
88 p(" f16 = 0, f17 = 0, f18 = 0, f19 = 0, f20 = 0, f21 = 0, f22 = 0, f23 = 0,");
89 p(" f24 = 0, f25 = 0, f26 = 0, f27 = 0, f28 = 0, f29 = 0, f30 = 0, f31 = 0;");
90 p(" // FP Control Register");
91 p(" private int fcsr = 0;");
92 p("");
93 indent++;
94
95 p("private final void setFC(boolean b) { fcsr = (fcsr&~0x800000) | (b ? 0x800000 : 0x000000); }");
96 p("private final int roundingMode() { return fcsr & 3; /* bits 0-1 */ }");
97 indent--;
98
99 Set jumpableAddresses = null;
100 if(pruneCases) {
101
102 jumpableAddresses = new HashSet();
103
104 jumpableAddresses.add(new Integer(elf.header.entry));
105
106 ELF.SHeader text = elf.sectionWithName(".text");
107 if(text == null) throw new Error("No .text segment");
108 findBranchesInText(text.addr,new DataInputStream(text.getInputStream()),text.size,jumpableAddresses);
109
110 findBranchesInSymtab(elf.getSymtab(),jumpableAddresses);
111
112 for(int i=0;i<elf.sheaders.length;i++) {
113 ELF.SHeader sheader = elf.sheaders[i];
114 String name = sheader.name;
115
116 if(sheader.addr == 0x0) continue;
117 if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors"))
118 findBranchesInData(new DataInputStream(sheader.getInputStream()),sheader.size,jumpableAddresses,text.addr,text.addr+text.size);
119 }
120 }
121
122
123 int highestAddr = 0;
124 indent=1;
125 for(int i=0;i<elf.sheaders.length;i++) {
126 ELF.SHeader sheader = elf.sheaders[i];
127 String name = sheader.name;
128
129 if(sheader.addr == 0x0) continue;
130
131 highestAddr = Math.max(highestAddr, sheader.addr + sheader.size);
132
133 if(name.equals(".text")) {
134 emitText(sheader.addr, new DataInputStream(sheader.getInputStream()),sheader.size,jumpableAddresses);
135 endMethod(nextEmitTextAddr);
136 } else if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors")) {
137 emitData(sheader.addr, new DataInputStream(sheader.getInputStream()), sheader.size,name.equals(".rodata"));
138 } else if(name.equals(".bss") || name.equals(".sbss")) {
139 if(sheader.entsize != 0) throw new CompilationException("bss segment has data!");
140 emitBSS(sheader.addr,sheader.size);
141 } else {
142 throw new CompilationException("Unknown segment: " + name);
143 }
144 }
145 indent = 0;
146
147 p(" public " + className + "() throws FaultException {");
148 if(fastMem) {
149 p(" super(false); // don't allow empty pages");
150 p(" if(PAGE_SIZE != " + toHex(Runtime.PAGE_SIZE) + ") throw new Error(\"Runtime.PAGE_SIZE mismatch\");");
151 } else {
152 p(" super(true); // allow empty pages");
153 }
154 p(" // init data");
155 p(" entryPoint = " + toHex(elf.header.entry) + ";");
156 p(inits.toString());
157 p(" brk = (" + toHex(highestAddr) + "+PAGE_SIZE-1) >>> PAGE_SHIFT;");
158 p(" state = INITIALIZED;");
159 p(" }");
160 p("");
161 p();
162 p(" public static void main(String[] javaArgs) throws Exception {");
163 p(" String[] args = new String[javaArgs.length+1];");
164 p(" System.arraycopy(javaArgs,0,args,1,javaArgs.length);");
165 p(" args[0] = \"" + className + "\";");
166 p(" " + className + " me = new " + className + "();");
167 p(" // User data");
168 p(" int addr = me.sbrk(PAGE_SIZE);");
169 p(" for(int i=0;i<10;i++) {");
170 p(" String s = \"User Info item: \" + (i+1) + \"\\0\";");
171 p(" byte[] b = s.getBytes(\"US-ASCII\");");
172 p(" me.copyout(b,addr,b.length);");
173 p(" me.setUserInfo(i,addr);");
174 p(" addr += b.length;");
175 p(" }");
176 p(" // End user data");
177 p(" int status = me.run(args);");
178 p(" System.err.println(\"Exit status: \" + status);");
179 p(" System.exit(status);");
180 p(" }");
181 p();
182 p(" protected void _start(int pc) {");
183 p(" // set the stack pointer");
184 p(" r26 = STUFF_BASE;");
185 p(" r27 = PAGE_SIZE;");
186 p(" r29 = INITIAL_SP;");
187 p(" // set the \"return address\" from _start to point at the \"magic exit address\" (0xdeadbeef)");
188 p(" r31 = 0xdeadbeef;");
189 p(" this.pc = pc;");
190 p(" }");
191
192 p();
193 p(" protected void _execute() throws ExecutionException { trampoline(); }");
194 p();
195 p(" private final void trampoline() throws ExecutionException {");
196 p(" boolean finished = false;");
197 p(" while(!finished) {");
198 p(" switch(this.pc >> " + LOG_MAX_BYTES_PER_METHOD + ") {");
199 p(runs.toString());
200 p(" default: throw new Error(\"invalid address 0x\" + Long.toString(this.pc&0xffffffffL,16));");
201 p(" }");
202 p(" }");
203 p(" }");
204 p("}");
205 }
206
207 private static int startOfMethod = 0;
208 private static int endOfMethod = 0;
209
210 private static void startMethod(int addr) {
211 addr &= ~(MAX_BYTES_PER_METHOD-1);
212 endOfMethod= addr + MAX_BYTES_PER_METHOD;
213 String methodName = "run_" + Long.toString(addr & 0xffffffffL, 16);
214 runs.append(indents[4] + "case " + toHex(addr>>LOG_MAX_BYTES_PER_METHOD) + ": finished = !" + methodName + "(); break;\n");
215 p("private final boolean " + methodName + "() throws ExecutionException { /"+"* " + toHex(addr) + " - " + toHex(endOfMethod) + " *" + "/");
216 indent++;
217 p("int addr, tmp;");
218 for(int i=0;i<freqRegs.length;i++)
219 p("int " + freqRegs[i] + " = this." + freqRegs[i] + ";");
220 p("for(;;) {");
221 indent++;
222 p("switch(pc>>2) {");
223 indent++;
224 startOfMethod = addr;
225
226 }
227 private static void endMethod() { endMethod(endOfMethod); }
228 private static void endMethod(int lastAddr) {
229 if(startOfMethod == 0) return;
230
231 p("case " + toHex(lastAddr>>2) + ":");
232 indent++;
233 p("pc=" + toHex(lastAddr) + ";");
234 leaveMethod();
235 indent--;
236 if(debugCompiler)
237 p("default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16) + \" (got here from 0x\" + Long.toString(lastPC&0xffffffffL,16)+\")\");");
238 else
239 p("default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16));");
240 indent--;
241 p("}");
242 p("/* NOT REACHED */");
243 indent--;
244 p("}");
245 indent--;
246 p("}");
247 endOfMethod = 0;
248 }
249
250 private static void branch(int pc, int target) {
251 if(debugCompiler)
252 p("lastPC = " + toHex(pc) + ";");
253 p("pc=" + toHex(target) + ";");
254 if((pc>>LOG_MAX_BYTES_PER_METHOD) == (target>>LOG_MAX_BYTES_PER_METHOD))
255 p("continue;");
256 else
257 leaveMethod();
258 }
259
260 private static void leaveMethod() { leaveMethod(true); }
261 private static void leaveMethod(boolean cont) {
262 for(int i=0;i<freqRegs.length;i++)
263 p("this." + freqRegs[i] + " = " + freqRegs[i] + ";");
264 p("return " + (cont?"true":"false") + ";");
265 }
266
267 private static int nextEmitTextAddr = -1;
268 private static void emitText(int addr, DataInputStream dis, int size, Set jumpableAddresses) throws CompilationException,IOException {
269 if(addr < nextEmitTextAddr) throw new CompilationException("Out of order sections");
270 if((addr&3)!=0 || (size&3)!=0) throw new CompilationException("Section on weird boundaries");
271 int count = size/4;
272 int nextInsn = dis.readInt();
273 if(nextInsn == -1) throw new Error("Actually read -1 at " + toHex(addr));
274 int insn;
275
276 for(int i=0;i<count;i++,addr+=4) {
277 insn = nextInsn;
278 nextInsn = (i == count-1) ? -1 : dis.readInt();
279 if(addr >= endOfMethod) { endMethod(); startMethod(addr); }
280 if(jumpableAddresses==null || addr == startOfMethod || jumpableAddresses.contains(new Integer(addr))) {
281 p("case " + toHex(addr>>2) + ":");
282 unreachable = false;
283 } else if(unreachable) {
284 continue;
285 } else if(debugCompiler) {
286 p("/" + "* pc = " + toHex(addr) + "*" + "/");
287 }
288 indent++;
289 emitInstruction(addr,insn,nextInsn);
290 indent--;
291 }
292 nextEmitTextAddr = addr;
293 dis.close();
294 }
295
296 private static int initDataCount = 0;
297 private static void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws CompilationException,IOException {
298 if((addr&3)!=0 || (size&3)!=0) throw new CompilationException("Section on weird boundaries");
299 int count = size/4;
300 String varname = "_data" + (++initDataCount);
301 p("private final static int[] " + varname + " = {");
302 indent++;
303 for(int i=0;i<count;) {
304 StringBuffer sb = new StringBuffer();
305 for(int j=0;j<8 && i<count;j++,i++) {
306 sb.append(toHex8(dis.readInt()));
307 if(i!=count-1) sb.append(",");
308 }
309 p(sb.toString());
310 }
311 indent--;
312 p("};");
313 inits.append(indents[2] + "initPages(" + varname + "," + toHex(addr) + "," + (readOnly?"true":"false") + ");\n");
314 dis.close();
315 }
316
317 private static int initBSSCount = 0;
318 private static void emitBSS(int addr, int size) throws CompilationException,IOException {
319 if((addr&3)!=0 || (size&3)!=0) throw new CompilationException("Section on weird boundaries");
320 int count = size/4;
321 inits.append(indents[2] + "clearPages(" + toHex(addr) + "," + toHex(count) + ");\n");
322 }
323
324 private static void findBranchesInSymtab(ELF.Symtab symtab, Set jumps) {
325 ELF.Symbol[] symbols = symtab.symbols;
326 int n=0;
327 for(int i=0;i<symbols.length;i++) {
328 ELF.Symbol s = symbols[i];
329 if(s.type == ELF.Symbol.STT_FUNC) {
330
331 if(jumps.add(new Integer(s.addr))) n++;
332 }
333 }
334 if(printStats) System.err.println("Found " + n + " additional possible branch targets in Symtab");
335 }
336
337 private static void findBranchesInText(int addr, DataInputStream dis, int size, Set jumps) throws IOException {
338 int count = size/4;
339 int pc = addr;
340 int n=0;
341
342 for(int i=0;i<count;i++,pc+=4) {
343 int insn = dis.readInt();
344 int op = (insn >>> 26) & 0xff;
345 int rs = (insn >>> 21) & 0x1f;
346 int rt = (insn >>> 16) & 0x1f;
347 int signedImmediate = (insn << 16) >> 16;
348 int branchTarget = signedImmediate;
349 int jumpTarget = (insn & 0x03ffffff);
350 int subcode = insn & 0x3f;
351
352 switch(op) {
353 case 0:
354 switch(subcode) {
355 case 9:
356 if(jumps.add(new Integer(pc+8))) n++;
357 break;
358 case 12:
359 if(jumps.add(new Integer(pc+4))) n++;
360 break;
361 }
362 break;
363 case 1:
364 switch(rt) {
365 case 16:
366 case 17:
367 if(jumps.add(new Integer(pc+8))) n++;
368
369 case 0:
370 case 1:
371 if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
372 break;
373 }
374 break;
375 case 3:
376 if(jumps.add(new Integer(pc+8))) n++;
377
378 case 2:
379 if(jumps.add(new Integer((pc&0xf0000000)|(jumpTarget << 2)))) n++;
380 break;
381 case 4:
382 case 5:
383 case 6:
384 case 7:
385 if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
386 break;
387 case 17:
388 switch(rs) {
389 case 8:
390 if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
391 break;
392 }
393 break;
394 }
395 }
396 dis.close();
397 if(printStats) System.err.println("Found " + n + " additional possible branch targets in Text segment");
398 }
399
400 private static void findBranchesInData(DataInputStream dis, int size, Set jumps, int textStart, int textEnd) throws IOException {
401 int count = size/4;
402 int n=0;
403 for(int i=0;i<count;i++) {
404 int word = dis.readInt();
405 if((word&3)==0 && word >= textStart && word < textEnd) {
406 if(jumps.add(new Integer(word))) n++;
407 }
408 }
409 dis.close();
410 if(n>0 && printStats) System.err.println("Found " + n + " additional possible branch targets in Data segment");
411 }
412
413 private static boolean unreachable = false;
414
415 private static void emitInstruction(int pc, int insn, int nextInsn) throws IOException,CompilationException {
416 if(insn == -1) throw new Error("insn is -1");
417
418 int op = (insn >>> 26) & 0xff;
419 int rs = (insn >>> 21) & 0x1f;
420 int rt = (insn >>> 16) & 0x1f;
421 int ft = (insn >>> 16) & 0x1f;
422 int rd = (insn >>> 11) & 0x1f;
423 int fs = (insn >>> 11) & 0x1f;
424 int shamt = (insn >>> 6) & 0x1f;
425 int fd = (insn >>> 6) & 0x1f;
426 int subcode = insn & 0x3f;
427
428 int jumpTarget = (insn & 0x03ffffff);
429 int unsignedImmediate = insn & 0xffff;
430 int signedImmediate = (insn << 16) >> 16;
431 int branchTarget = signedImmediate;
432
433 intintp, addr;
434
435
436
437 if(pc==-1) p("/" + "* Next insn is delay slot *" + "/ ");
438
439 switch(op) {
440 case 0: {
441 switch(subcode) {
442 case 0:
443 if(insn == 0)
444 p("/* NOOP */");
445 else
446 p( "r"+rd+" = r"+rt+" << "+shamt+";");
447 break;
448 case 2:
449 p( "r"+rd+" = r"+rt+" >>> "+shamt+";");
450 break;
451 case 3:
452 p( "r"+rd+" = r"+rt+" >> "+shamt+";");
453 break;
454 case 4:
455 p( "r"+rd+" = r"+rt+" << (r"+rs+"&0x1f);");
456 break;
457 case 6:
458 p( "r"+rd+" = r"+rt+" >>> (r"+rs+"&0x1f);");
459 break;
460 case 7:
461 p( "r"+rd+" = r"+rt+" >> (r"+rs+"&0x1f);");
462 break;
463 case 8:
464 if(pc == -1) throw new Error("pc modifying insn in delay slot");
465 emitInstruction(-1,nextInsn,-1);
466 if(debugCompiler) p("lastPC = " + toHex(pc) + ";");
467 p("pc=r" + rs + ";");
468 leaveMethod();
469 unreachable = true;
470 break;
471 case 9:
472 if(pc == -1) throw new Error("pc modifying insn in delay slot");
473 emitInstruction(-1,nextInsn,-1);
474 if(debugCompiler) p("lastPC = " + toHex(pc) + ";");
475 p("pc=r" + rs + ";");
476 p("r" + RA + "=" + toHex(pc+8 ) + ";");
477 leaveMethod();
478 unreachable = true;
479 break;
480 case 12:
481 p( "r"+V0+" = syscall(r"+V0+",r"+A0+",r"+A1+",r"+A2+",r"+A3+");");
482 p("if (state != RUNNING) {");
483 indent++;
484 p("pc = " + toHex(pc+4) + ";");
485 leaveMethod(false);
486 indent--;
487 p("}");
488 break;
489 case 13:
490 p( "throw new ExecutionException(\"Break\");");
491 break;
492 case 16:
493 p( "r"+rd+" = hi;");
494 break;
495 case 17:
496 p( "hi = r"+rs+";");
497 break;
498 case 18:
499 p( "r"+rd+" = lo;");
500 break;
501 case 19:
502 p( "lo = r"+rs+";");
503 break;
504 case 24:
505 p( "{ long hilo = (long)(r"+rs+") * ((long)r"+rt+"); " +
506 "hi = (int) (hilo >>> 32); " +
507 "lo = (int) hilo; }");
508 break;
509 case 25:
510 p( "{ long hilo = (r"+rs+" & 0xffffffffL) * (r"+rt+" & 0xffffffffL); " +
511 "hi = (int) (hilo >>> 32); " +
512 "lo = (int) hilo; } ");
513 break;
514 case 26:
515 p( "hi = r"+rs+"%r"+rt+"; lo = r"+rs+"/r"+rt+";");
516 break;
517 case 27:
518 p( "hi = (int)((r"+rs+" & 0xffffffffL) % (r"+rt+" & 0xffffffffL)); " +
519 "lo = (int)((r"+rs+" & 0xffffffffL) / (r"+rt+" & 0xffffffffL));");
520 break;
521 case 32:
522 throw new CompilationException("ADD (add with oveflow trap) not suported");
523
526 case 33:
527 p( "r"+rd+" = r"+rs+" + r"+rt+";");
528 break;
529 case 34:
530 throw new CompilationException("SUB (add with oveflow trap) not suported");
531
534 case 35:
535 p( "r"+rd+" = r"+rs+" - r"+rt+";");
536 break;
537 case 36:
538 p( "r"+rd+" = r"+rs+" & r"+rt+";");
539 break;
540 case 37:
541 p( "r"+rd+" = r"+rs+" | r"+rt+";");
542 break;
543 case 38:
544 p( "r"+rd+" = r"+rs+" ^ r"+rt+";");
545 break;
546 case 39:
547 p( "r"+rd+" = ~(r"+rs+" | r"+rt+");");
548 break;
549 case 42:
550 p( "r"+rd+" = r"+rs+" < r"+rt+" ? 1 : 0;");
551 break;
552 case 43:
553 p( "r"+rd+" = ((r"+rs+" & 0xffffffffL) < (r"+rt+" & 0xffffffffL)) ? 1 : 0;");
554 break;
555 default:
556 throw new RuntimeException("Illegal instruction 0/" + subcode);
557 }
558 break;
559 }
560 case 1: {
561 switch(rt) {
562 case 0:
563 if(pc == -1) throw new Error("pc modifying insn in delay slot");
564 p("if(r" + rs + " < 0) {");
565 indent++;
566 emitInstruction(-1,nextInsn,-1);
567 branch(pc,pc+branchTarget*4+4);
568 indent--;
569 p("}");
570 break;
571 case 1:
572 if(pc == -1) throw new Error("pc modifying insn in delay slot");
573 p("if(r" + rs + " >= 0) {");
574 indent++;
575 emitInstruction(-1,nextInsn,-1);
576 branch(pc,pc+branchTarget*4+4);
577 indent--;
578 p("}");
579 break;
580 case 16:
581 if(pc == -1) throw new Error("pc modifying insn in delay slot");
582 p("if(r" + rs + " < 0) {");
583 indent++;
584 emitInstruction(-1,nextInsn,-1);
585 p("r" + RA + "=" + toHex(pc+8 ) + ";");
586 branch(pc,pc+branchTarget*4+4);
587 indent--;
588 p("}");
589 break;
590 case 17:
591 if(pc == -1) throw new Error("pc modifying insn in delay slot");
592 p("if(r" + rs + " >= 0) {");
593 indent++;
594 emitInstruction(-1,nextInsn,-1);
595 p("r" + RA + "=" + toHex(pc+8 ) + ";");
596 branch(pc,pc+branchTarget*4+4);
597 indent--;
598 p("}");
599 break;
600 default:
601 throw new RuntimeException("Illegal Instruction 1/" + rt);
602 }
603 break;
604 }
605 case 2: {
606 if(pc == -1) throw new Error("pc modifying insn in delay slot");
607 emitInstruction(-1,nextInsn,-1);
608 branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
609 unreachable = true;
610 break;
611 }
612 case 3: {
613 if(pc == -1) throw new Error("pc modifying insn in delay slot");
614 emitInstruction(-1,nextInsn,-1);
615 p("r" + RA + "=" + toHex(pc+8 ) + ";");
616 branch(pc, (pc&0xf0000000)|(jumpTarget << 2));
617 unreachable = true;
618 break;
619 }
620 case 4:
621 if(pc == -1) throw new Error("pc modifying insn in delay slot");
622 p("// BEQ");
623 p("if(r" + rs + " == r" + rt + ") {");
624 indent++;
625 emitInstruction(-1,nextInsn,-1);
626 branch(pc,pc+branchTarget*4+4);
627 indent--;
628 p("}");
629 break;
630 case 5:
631 if(pc == -1) throw new Error("pc modifying insn in delay slot");
632 p("if(r" + rs + " != r" + rt + ") {");
633 indent++;
634 emitInstruction(-1,nextInsn,-1);
635 branch(pc,pc+branchTarget*4+4);
636 indent--;
637 p("}");
638 break;
639 case 6:
640 if(pc == -1) throw new Error("pc modifying insn in delay slot");
641 p("if(r" + rs + " <= 0) {");
642 indent++;
643 emitInstruction(-1,nextInsn,-1);
644 branch(pc,pc+branchTarget*4+4);
645 indent--;
646 p("}");
647 break;
648 case 7:
649 if(pc == -1) throw new Error("pc modifying insn in delay slot");
650 p("if(r" + rs + " > 0) {");
651 indent++;
652 emitInstruction(-1,nextInsn,-1);
653 branch(pc,pc+branchTarget*4+4);
654 indent--;
655 p("}");
656 break;
657 case 8:
658 p( "r"+rt+" = r"+rs+" + "+signedImmediate +";");
659 break;
660 case 9:
661 p( "r"+rt+" = r"+rs+" + "+signedImmediate+";");
662 break;
663 case 10:
664 p( "r"+rt+" = r"+rs+" < "+signedImmediate+" ? 1 : 0;");
665 break;
666 case 11:
667 p( "r"+rt+" = (r"+rs+"&0xffffffffL) < ("+unsignedImmediate+"&0xffffffffL) ? 1 : 0;");
668 break;
669 case 12:
670 p( "r"+rt+" = r"+rs+" & "+unsignedImmediate+";");
671 break;
672 case 13:
673 p( "r"+rt+" = r"+rs+" | "+unsignedImmediate+";");
674 break;
675 case 14:
676 p( "r"+rt+" = r"+rs+" ^ "+unsignedImmediate+";");
677 break;
678 case 15:
679 p( "r"+rt+" = "+unsignedImmediate+" << 16;");
680 break;
681 case 16:
682 throw new CompilationException("TLB/Exception support not implemented");
683 case 17: {
684 switch(rs) {
685 case 0:
686 p( "r"+rt+" = f"+rd+";");
687 break;
688 case 2:
689 if(fs != 31) throw new CompilationException("FCR " + fs + " unavailable");
690 p( "r"+rt+" = fcsr;");
691 break;
692 case 4:
693 p( "f"+rd+" = r"+rt+";");
694 break;
695 case 6:
696 if(fs != 31) throw new CompilationException("FCR " + fs + " unavailable");
697 p( "fcsr = r"+rt+";");
698 break;
699 case 8: {
700 tmp = (insn>>>16)&1;
701 p("//BC1F, BC1T");
702 p("if(((fcsr&0x800000)!=0) == (" + tmp + "!=0)) {");
703 indent++;
704 emitInstruction(-1,nextInsn,-1);
705 branch(pc,pc+branchTarget*4+4);
706 indent--;
707 p("}");
708 break;
709 }
710 case 16: {
711 switch(subcode) {
712 case 0:
713 p(setFloat(fd,getFloat(fs)+"+"+getFloat(ft)));
714 break;
715 case 1:
716 p(setFloat(fd,getFloat(fs)+"-"+getFloat(ft)));
717 break;
718 case 2:
719 p(setFloat(fd,getFloat(fs)+"*"+getFloat(ft)));
720 break;
721 case 3:
722 p(setFloat(fd,getFloat(fs)+"/"+getFloat(ft)));
723 break;
724 case 5:
725 p(setFloat(fd,"Math.abs("+getFloat(fs)+")"));
726 break;
727 case 6:
728 p("f"+fd+" = f"+fs+"; // MOV.S");
729 break;
730 case 7:
731 p(setFloat(fd,"-"+getFloat(fs)));
732 break;
733 case 33:
734 p(setDouble(fd,"(float)"+getFloat(fs)));
735 break;
736 case 36:
737 p("// CVT.W.D");
738 p("switch(roundingMode()) {");
739 indent++;
740 p("case 0: f"+fd+" = (int)Math.floor("+getFloat(fs)+"+0.5); break; // Round to nearest");
741 p("case 1: f"+fd+" = (int)"+getFloat(fs)+"; break; // Round towards zero");
742 p("case 2: f"+fd+" = (int)Math.ceil("+getFloat(fs)+"); break; // Round towards plus infinity");
743 p("case 3: f"+fd+" = (int)Math.floor("+getFloat(fs)+"); break; // Round towards minus infinity");
744 indent--;
745 p("}");
746 break;
747 case 50:
748 p("setFC("+getFloat(fs)+"=="+getFloat(ft)+");");
749 break;
750 case 60:
751 p("setFC("+getFloat(fs)+"<"+getFloat(ft)+");");
752 break;
753 case 62:
754 p("setFC("+getFloat(fs)+"<="+getFloat(ft)+");");
755 break;
756 default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
757 }
758 break;
759 }
760 case 17: {
761 switch(subcode) {
762 case 0:
763 p(setDouble(fd,getDouble(fs)+"+"+getDouble(ft)));
764 break;
765 case 1:
766 p(setDouble(fd,getDouble(fs)+"-"+getDouble(ft)));
767 break;
768 case 2:
769 p(setDouble(fd,getDouble(fs)+"*"+getDouble(ft)));
770 break;
771 case 3:
772 p(setDouble(fd,getDouble(fs)+"/"+getDouble(ft)));
773 break;
774 case 5:
775 p(setDouble(fd,"Math.abs("+getDouble(fs)+")"));
776 break;
777 case 6:
778 p("f"+fd+" = f"+fs+";");
779 p("f"+(fd+1)+" = f"+(fs+1)+";");
780 break;
781 case 7:
782 p(setDouble(fd,"-"+getDouble(fs)));
783 break;
784 case 32:
785 p(setFloat(fd,"(float)"+getDouble(fs)));
786 break;
787 case 36:
788 p("// CVT.W.D");
789 p("switch(roundingMode()) {");
790 indent++;
791 p("case 0: f"+fd+" = (int)Math.floor("+getDouble(fs)+"+0.5); break; // Round to nearest");
792 p("case 1: f"+fd+" = (int)"+getDouble(fs)+"; break; // Round towards zero");
793 p("case 2: f"+fd+" = (int)Math.ceil("+getDouble(fs)+"); break; // Round towards plus infinity");
794 p("case 3: f"+fd+" = (int)Math.floor("+getDouble(fs)+"); break; // Round towards minus infinity");
795 indent--;
796 p("}");
797 break;
798 case 50:
799 p("setFC("+getDouble(fs)+"=="+getDouble(ft)+");");
800 break;
801 case 60:
802 p("setFC("+getDouble(fs)+"<"+getDouble(ft)+");");
803 break;
804 case 62:
805 p("setFC("+getDouble(fs)+"<="+getDouble(ft)+");");
806 break;
807 default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
808 }
809 break;
810 }
811 case 20: {
812 switch(subcode) {
813 case 32:
814 p(" // CVS.S.W");
815 p(setFloat(fd,"((float)f"+fs+")"));
816 break;
817 case 33:
818 p("// CVT.D.W");
819 p(setDouble(fd,"((double)f"+fs+")"));
820 break;
821 default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
822 }
823 break;
824 }
825 default:
826 throw new CompilationException("Invalid Instruction 17/" + rs);
827 }
828 break;
829 }
830 case 18: case 19:
831 throw new CompilationException("coprocessor 2 and 3 instructions not available");
832 case 32: {
833 p("addr=r" + rs +"+"+signedImmediate + ";");
834 memRead("addr&~3","tmp");
835 p("switch(addr&3) {");
836 indent++;
837 p("case 0: tmp = (tmp>>>24)&0xff; break;");
838 p("case 1: tmp = (tmp>>>16)&0xff; break;");
839 p("case 2: tmp = (tmp>>> 8)&0xff; break;");
840 p("case 3: tmp = (tmp>>> 0)&0xff; break;");
841 indent--;
842 p("}");
843 p("if((tmp&0x80)!=0) tmp |= 0xffffff00; // sign extend");
844 p("r"+rt+" = tmp;");
845 break;
846 }
847 case 33: {
848 p("addr=r" + rs +"+"+signedImmediate + ";");
849 memRead("addr&~3","tmp");
850 p("switch(addr&2) {");
851 indent++;
852 p("case 0: tmp = (tmp>>>16)&0xffff; break;");
853 p("case 2: tmp = (tmp>>> 0)&0xffff; break;");
854 indent--;
855 p("}");
856 p("if((tmp&0x8000)!=0) tmp |= 0xffff0000; // sign extend");
857 p("r"+rt+" = tmp;");
858 break;
859 }
860 case 34: {
861 p("addr=r" + rs +"+"+signedImmediate + ";");
862 memRead("addr&~3","tmp");
863 p("switch(addr&3) {");
864 indent++;
865 p("case 0: r"+rt+" = (r"+rt+"&0x00000000)|(tmp<< 0); break;");
866 p("case 1: r"+rt+" = (r"+rt+"&0x000000ff)|(tmp<< 8); break;");
867 p("case 2: r"+rt+" = (r"+rt+"&0x0000ffff)|(tmp<<16); break;");
868 p("case 3: r"+rt+" = (r"+rt+"&0x00ffffff)|(tmp<<24); break;");
869 indent--;
870 p("}");
871 break;
872 }
873 case 35:
874 memRead("r" + rs +"+"+signedImmediate,"r"+rt);
875 break;
876 case 36: {
877 p("addr=r" + rs +"+"+signedImmediate + ";");
878 memRead("addr&~3","tmp");
879 p("switch(addr&3) {");
880 indent++;
881 p("case 0: r"+rt+" = (tmp>>>24)&0xff; break;");
882 p("case 1: r"+rt+" = (tmp>>>16)&0xff; break;");
883 p("case 2: r"+rt+" = (tmp>>> 8)&0xff; break;");
884 p("case 3: r"+rt+" = (tmp>>> 0)&0xff; break;");
885 indent--;
886 p("}");
887 break;
888 }
889 case 37: {
890 p("addr=r" + rs +"+"+signedImmediate + ";");
891 memRead("addr&~3","tmp");
892 p("switch(addr&2) {");
893 indent++;
894 p("case 0: r"+rt+" = (tmp>>>16)&0xffff; break;");
895 p("case 2: r"+rt+" = (tmp>>> 0)&0xffff; break;");
896 indent--;
897 p("}");
898 break;
899 }
900 case 38: {
901 p("addr=r" + rs +"+"+signedImmediate + ";");
902 memRead("addr&~3","tmp");
903 p("switch(addr&3) {");
904 indent++;
905 p("case 0: r"+rt+" = (r"+rt+"&0xffffff00)|(tmp>>>24); break;");
906 p("case 1: r"+rt+" = (r"+rt+"&0xffff0000)|(tmp>>>16); break;");
907 p("case 2: r"+rt+" = (r"+rt+"&0xff000000)|(tmp>>> 8); break;");
908 p("case 3: r"+rt+" = (r"+rt+"&0x00000000)|(tmp>>> 0); break;");
909 indent--;
910 p("}");
911 break;
912 }
913 case 40: {
914 p("// SB");
915 p("addr=r" + rs +"+"+signedImmediate + ";");
916 memRead("addr&~3","tmp");
917 p("switch(addr&3) {");
918 indent++;
919 p("case 0: tmp = (tmp&0x00ffffff) | ((r"+rt+"&0xff)<<24); break;");
920 p("case 1: tmp = (tmp&0xff00ffff) | ((r"+rt+"&0xff)<<16); break;");
921 p("case 2: tmp = (tmp&0xffff00ff) | ((r"+rt+"&0xff)<< 8); break;");
922 p("case 3: tmp = (tmp&0xffffff00) | ((r"+rt+"&0xff)<< 0); break;");
923 indent--;
924 p("}");
925 memWrite("addr&~3","tmp");
926 break;
927 }
928 case 41: {
929 p("// SH");
930 p("addr=r" + rs +"+"+signedImmediate + ";");
931 memRead("addr&~3","tmp");
932 p("switch(addr&2) {");
933 indent++;
934 p("case 0: tmp = (tmp&0x0000ffff) | ((r"+rt+"&0xffff)<<16); break;");
935 p("case 2: tmp = (tmp&0xffff0000) | ((r"+rt+"&0xffff)<< 0); break;");
936 indent--;
937 p("}");
938 memWrite("addr&~3","tmp");
939 break;
940 }
941 case 42: {
942 p(" // SWL");
943 p("addr=r" + rs +"+"+signedImmediate + ";");
944 memRead("addr&~3","tmp");
945 p("switch(addr&3) {");
946 indent++;
947 p("case 0: tmp=(tmp&0x00000000)|(r"+rt+">>> 0); break;");
948 p("case 1: tmp=(tmp&0xff000000)|(r"+rt+">>> 8); break;");
949 p("case 2: tmp=(tmp&0xffff0000)|(r"+rt+">>>16); break;");
950 p("case 3: tmp=(tmp&0xffffff00)|(r"+rt+">>>24); break;");
951 indent--;
952 p("}");
953 memWrite("addr&~3","tmp");
954 break;
955 }
956 case 43:
957 memWrite("r"+rs+"+"+signedImmediate,"r" + rt);
958 break;
959 case 46: {
960 p(" // SWR");
961 p("addr=r" + rs +"+"+signedImmediate + ";");
962 memRead("addr&~3","tmp");
963 p("switch(addr&3) {");
964 indent++;
965 p("case 0: tmp=(tmp&0x00ffffff)|(r"+rt+"<<24); break;");
966 p("case 1: tmp=(tmp&0x0000ffff)|(r"+rt+"<<16); break;");
967 p("case 2: tmp=(tmp&0x000000ff)|(r"+rt+"<< 8); break;");
968 p("case 3: tmp=(tmp&0x00000000)|(r"+rt+"<< 0); break;");
969 indent--;
970 p("}");
971 memWrite("addr&~3","tmp");
972 break;
973 }
974 case 49:
975 memRead("r"+rs+"+"+signedImmediate,"f"+rt);
976 break;
977 case 57:
978 memWrite("r"+rs+"+"+signedImmediate,"f"+rt);
979 break;
980 default:
981 throw new CompilationException("Invalid Instruction: " + op + " at " + toHex(pc));
982 }
983 }
984
985 private static void memWrite(String addr, String target) {
986 if(fastMem)
987 p("writePages[("+addr+")>>>"+Runtime.PAGE_SHIFT+"][(("+addr+")>>>2)&"+toHex(Runtime.PAGE_WORDS-1)+"] = " + target + ";");
988 else
989 p("memWrite(" + addr + "," + target + ");");
990
991 }
992
993 private static void memRead(String addr, String target) {
994 if(fastMem)
995 p(target + " = readPages[("+addr+")>>>"+Runtime.PAGE_SHIFT+"][(("+addr+")>>>2)&"+toHex(Runtime.PAGE_WORDS-1)+"];");
996 else
997 p(target + " = memRead(" + addr + ");");
998 }
999
1000 private static String getFloat(int r) { return "(Float.intBitsToFloat(f"+r+"))"; }
1001 private static String getDouble(int r) {
1002 return "(Double.longBitsToDouble(((f"+(r+1)+"&0xffffffffL) << 32) | (f"+r+"&0xffffffffL)))";
1003 }
1004 private static String setFloat(int r, String expr) { return "f"+r+"=Float.floatToRawIntBits("+expr+");"; }
1005 private static String setDouble(int r, String expr) {
1006 return "{ long l = Double.doubleToLongBits("+expr+"); "+
1007 "f"+(r+1)+" = (int)(l >>> 32); f"+r+" = (int)l; }";
1008 }
1009
1010 private final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
1011 private final static String toHex8(int n) {
1012 String s = Long.toString(n & 0xffffffffL, 16);
1013 StringBuffer sb = new StringBuffer("0x");
1014 for(int i=8-s.length();i>0;i--) sb.append('0');
1015 sb.append(s);
1016 return sb.toString();
1017 }
1018 }
1019
1020