get rid of useless main() func
[nestedvm.git] / src / org / xwt / mips / Interpreter.java
1 // Copyright 2003 Brian Alliet
2 // Based on org.xwt.imp.MIPS by Adam Megacz
3 // Portions Copyright 2003 Adam Megacz
4
5 package org.xwt.mips;
6
7 import org.xwt.mips.util.*;
8 import java.io.*;
9
10 public class Interpreter extends UnixRuntime {
11     // Registers
12     private int[] registers = new int[32];
13     private int hi,lo;
14     
15     // Floating Point Registers
16     private int[] fpregs = new int[32];
17     // 24-31 - unused
18     // 23 - conditional bit
19     // 18-22 - unused
20     // 12-17 - cause bits (unimplemented)
21     // 7-11  - enables bits (unimplemented)
22     // 2-6   - flags (unimplemented)
23     // 0-1   - rounding mode (only implemented for fixed point conversions)
24     private int fcsr;
25     
26     private int pc;
27     
28     // The filename if the binary we're running
29     public String image;
30     private ELF.Symtab symtab;
31     
32     // Register Operations
33     private final void setFC(boolean b) { fcsr = (fcsr&~0x800000) | (b ? 0x800000 : 0x000000); }
34     private final int roundingMode() { return fcsr & 3; /* bits 0-1 */ }
35     private final double getDouble(int r) {
36         return Double.longBitsToDouble(((fpregs[r+1]&0xffffffffL) << 32) | (fpregs[r]&0xffffffffL));
37     }
38     private final void setDouble(int r, double d) {
39         long l = Double.doubleToLongBits(d);
40         fpregs[r+1] = (int)(l >>> 32); fpregs[r] = (int)l;
41     }
42     private final float getFloat(int r) { return Float.intBitsToFloat(fpregs[r]); }
43     private final void setFloat(int r, float f) { fpregs[r] = Float.floatToRawIntBits(f); }
44     
45     protected void _execute() throws ExecutionException {
46         try {
47             runSome();
48         } catch(ExecutionException e) {
49             e.setLocation(toHex(pc) + ": " + sourceLine(pc));
50             throw e;
51         }
52     }
53     
54     // Main interpretor
55     // the return value is meaningless, its just to catch people typing "return" by accident
56     private final int runSome() throws FaultException,ExecutionException {
57         int[] r = registers;
58         int[] f = fpregs;
59         int pc = this.pc;
60         int nextPC = pc + 4;
61     try {
62     OUTER: for(;;) {
63         int insn;
64         try {
65             insn = readPages[pc>>>PAGE_SHIFT][(pc>>>2)&PAGE_WORDS-1];
66         } catch (RuntimeException e) {
67             insn = memRead(pc);
68         }
69
70         int op = (insn >>> 26) & 0xff;                 // bits 26-31
71         int rs = (insn >>> 21) & 0x1f;                 // bits 21-25
72         int rt = (insn >>> 16) & 0x1f;                 // bits 16-20 
73         int ft = (insn >>> 16) & 0x1f;
74         int rd = (insn >>> 11) & 0x1f;                 // bits 11-15
75         int fs = (insn >>> 11) & 0x1f;
76         int shamt = (insn >>> 6) & 0x1f;               // bits 6-10
77         int fd = (insn >>> 6) & 0x1f;
78         int subcode = insn & 0x3f;                     // bits 0-5  
79
80         int jumpTarget = (insn & 0x03ffffff);          // bits 0-25
81         int unsignedImmediate = insn & 0xffff;
82         int signedImmediate = (insn << 16) >> 16;
83         int branchTarget = signedImmediate;
84
85         int tmp, addr; // temporaries
86         
87         r[ZERO] = 0;
88     
89         switch(op) {
90             case 0: {
91                 switch(subcode) {
92                     case 0: // SLL
93                         if(insn == 0) break;
94                         r[rd] = r[rt] << shamt;
95                         break;
96                     case 2: // SRL
97                         r[rd] = r[rt] >>> shamt;
98                         break;
99                     case 3: // SRA
100                         r[rd] = r[rt] >> shamt;
101                         break;
102                     case 4: // SLLV
103                         r[rd] = r[rt] << (r[rs]&0x1f);
104                         break;
105                     case 6: // SRLV
106                         r[rd] = r[rt] >>> (r[rs]&0x1f);
107                         break;
108                     case 7: // SRAV
109                         r[rd] = r[rt] >> (r[rs]&0x1f);
110                         break;
111                     case 8: // JR
112                         tmp = r[rs]; pc += 4; nextPC = tmp;
113                         continue OUTER;
114                     case 9: // JALR
115                         tmp = r[rs]; pc += 4; r[rd] = pc+4; nextPC = tmp;
116                         continue OUTER;
117                     case 12: // SYSCALL
118                         this.pc = pc;
119                         r[V0] = syscall(r[V0],r[A0],r[A1],r[A2],r[A3]);
120                         if(state != RUNNING) { this.pc = nextPC; break OUTER; }
121                         break;
122                     case 13: // BREAK
123                         throw new ExecutionException("Break");
124                     case 16: // MFHI
125                         r[rd] = hi;
126                         break;
127                     case 17: // MTHI
128                         hi = r[rs];
129                         break;
130                     case 18: // MFLO
131                         r[rd] = lo;
132                         break;
133                     case 19: // MTLO
134                         lo = r[rs];
135                         break;
136                     case 24: { // MULT
137                         long hilo = (long)(r[rs]) * ((long)r[rt]);
138                         hi = (int) (hilo >>> 32);
139                         lo = (int) hilo;
140                         break;
141                     }
142                     case 25: { // MULTU
143                         long hilo = (r[rs] & 0xffffffffL) * (r[rt] & 0xffffffffL);
144                         hi = (int) (hilo >>> 32);
145                         lo = (int) hilo;
146                         break;
147                     }
148                     case 26: // DIV
149                         hi = r[rs]%r[rt];
150                         lo = r[rs]/r[rt];
151                         break;
152                     case 27: // DIVU
153                         if(rt != 0) {
154                             hi = (int)((r[rs] & 0xffffffffL) % (r[rt] & 0xffffffffL));
155                             lo = (int)((r[rs] & 0xffffffffL) / (r[rt] & 0xffffffffL));
156                         }
157                         break;
158                     case 32: // ADD
159                         throw new ExecutionException("ADD (add with oveflow trap) not suported");
160                         /*This must trap on overflow
161                         r[rd] = r[rs] + r[rt];
162                         break;*/
163                     case 33: // ADDU
164                         r[rd] = r[rs] + r[rt];
165                         break;
166                     case 34: // SUB
167                         throw new ExecutionException("SUB (sub with oveflow trap) not suported");
168                         /*This must trap on overflow
169                         r[rd] = r[rs] - r[rt];
170                         break;*/
171                     case 35: // SUBU
172                         r[rd] = r[rs] - r[rt];
173                         break;
174                     case 36: // AND
175                         r[rd] = r[rs] & r[rt];
176                         break;
177                     case 37: // OR
178                         r[rd] = r[rs] | r[rt];
179                         break;
180                     case 38: // XOR
181                         r[rd] = r[rs] ^ r[rt];
182                         break;
183                     case 39: // NOR
184                         r[rd] = ~(r[rs] | r[rt]);
185                         break;
186                     case 42: // SLT
187                         r[rd] = r[rs] < r[rt] ? 1 : 0;
188                         break;
189                     case 43: // SLTU
190                         r[rd] = ((r[rs] & 0xffffffffL) < (r[rt] & 0xffffffffL)) ? 1 : 0;
191                         break;
192                     default:
193                         throw new ExecutionException("Illegal instruction 0/" + subcode);
194                 }
195                 break;
196             }
197             case 1: {
198                 switch(rt) {
199                     case 0: // BLTZ
200                         if(r[rs] < 0) {
201                             pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;                   
202                             continue OUTER;
203                         }
204                         break;
205                     case 1: // BGEZ
206                         if(r[rs] >= 0) {
207                             pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
208                             continue OUTER;
209                         }
210                         break;
211                     case 16: // BLTZAL
212                         if(r[rs] < 0) {
213                             pc += 4; r[RA] = pc+4; tmp = pc + branchTarget*4; nextPC = tmp;
214                             continue OUTER;
215                         }
216                         break;
217                     case 17: // BGEZAL
218                         if(r[rs] >= 0) {
219                             pc += 4; r[RA] = pc+4; tmp = pc + branchTarget*4; nextPC = tmp;  
220                             continue OUTER;
221                         }
222                         break;
223                     default:
224                         throw new ExecutionException("Illegal Instruction");
225                 }
226                 break;
227             }
228             case 2: { // J
229                 tmp = (pc&0xf0000000) | (jumpTarget << 2);
230                 pc+=4; nextPC = tmp;
231                 continue OUTER;
232             }
233             case 3: { // JAL
234                 tmp = (pc&0xf0000000) | (jumpTarget << 2);
235                 pc+=4; r[RA] = pc+4; nextPC = tmp;
236                 continue OUTER;
237             }
238             case 4: // BEQ
239                 if(r[rs] == r[rt]) {
240                     pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
241                     continue OUTER;
242                 }
243                 break;
244             case 5: // BNE                
245                 if(r[rs] != r[rt]) {
246                     pc += 4; tmp = pc + branchTarget*4; nextPC = tmp; 
247                     continue OUTER;
248                 }
249                 break;
250             case 6: //BLEZ
251                 if(r[rs] <= 0) {
252                     pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
253                     continue OUTER;
254                 }
255                 break;
256             case 7: //BGTZ
257                 if(r[rs] > 0) {
258                     pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
259                     continue OUTER;
260                 }
261                 break;
262             case 8: // ADDI
263                 r[rt] = r[rs] + signedImmediate;
264                 break;
265             case 9: // ADDIU
266                 r[rt] = r[rs] + signedImmediate;
267                 break;
268             case 10: // SLTI
269                 r[rt] = r[rs] < signedImmediate ? 1 : 0;
270                 break;
271             case 11: // SLTIU
272                 r[rt] = (r[rs]&0xffffffffL) < (unsignedImmediate&0xffffffffL) ? 1 : 0;
273                 break;
274             case 12: // ANDI
275                 r[rt] = r[rs] & unsignedImmediate;
276                 break;
277             case 13: // ORI
278                 r[rt] = r[rs] | unsignedImmediate;
279                 break;
280             case 14: // XORI
281                 r[rt] = r[rs] ^ unsignedImmediate;
282                 break;
283             case 15: // LUI
284                 r[rt] = unsignedImmediate << 16;
285                 break;
286             case 16:
287                 throw new ExecutionException("TLB/Exception support not implemented");
288             case 17: { // FPU
289                 boolean debug = false;
290                 String line = debug ? sourceLine(pc) : "";
291                 boolean debugon = debug && (line.indexOf("dtoa.c:51") >= 0 || line.indexOf("dtoa.c:52") >= 0 || line.indexOf("test.c") >= 0);
292                 if(rs > 8 && debugon)
293                     System.out.println("               FP Op: " + op + "/" + rs + "/" + subcode + " " + line);
294                 if(roundingMode() != 0 && rs != 6 /*CTC.1*/ && !((rs==16 || rs==17) && subcode == 36 /* CVT.W.Z */))
295                     throw new ExecutionException("Non-cvt.w.z operation attempted with roundingMode != round to nearest");
296                 switch(rs) {
297                     case 0: // MFC.1
298                         r[rt] = f[rd];
299                         break;
300                     case 2: // CFC.1
301                         if(fs != 31) throw new ExecutionException("FCR " + fs + " unavailable");
302                         r[rt] = fcsr;
303                         break;
304                     case 4: // MTC.1
305                         f[rd] = r[rt];
306                         break;
307                     case 6: // CTC.1
308                         if(fs != 31) throw new ExecutionException("FCR " + fs + " unavailable");
309                         fcsr = r[rt];   
310                         break;
311                     case 8: // BC1F, BC1T
312                         if(((fcsr&0x800000)!=0) == (((insn>>>16)&1)!=0)) {
313                             pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
314                             continue OUTER;
315                         }
316                         break;
317                     case 16: {  // Single
318                         switch(subcode) {
319                             case 0: // ADD.S
320                                 setFloat(fd,getFloat(fs)+getFloat(ft));
321                                 break;
322                             case 1: // SUB.S
323                                 setFloat(fd,getFloat(fs)-getFloat(ft));
324                                 break;
325                             case 2: // MUL.S
326                                 setFloat(fd,getFloat(fs)*getFloat(ft));
327                                 break;
328                             case 3: // DIV.S
329                                 setFloat(fd,getFloat(fs)/getFloat(ft));
330                                 break;
331                             case 5: // ABS.S
332                                 setFloat(fd,Math.abs(getFloat(fs)));
333                                 break;
334                             case 6: // MOV.S
335                                 f[fd] = f[fs];
336                                 break;
337                             case 7: // NEG.S
338                                 setFloat(fd,-getFloat(fs));
339                                 break;
340                             case 33: // CVT.D.S
341                                 setDouble(fd,getFloat(fs));
342                                 break;
343                             case 36: // CVT.W.S
344                                 switch(roundingMode()) {
345                                     case 0: f[fd] = (int)Math.floor(getFloat(fs)+0.5f); break; // Round to nearest
346                                     case 1: f[fd] = (int)getFloat(fs); break; // Round towards zero
347                                     case 2: f[fd] = (int)Math.ceil(getFloat(fs)); break; // Round towards plus infinity
348                                     case 3: f[fd] = (int)Math.floor(getFloat(fs)); break; // Round towards minus infinity
349                                 }
350                                 break;
351                             case 50: // C.EQ.S
352                                 setFC(getFloat(fs) == getFloat(ft));
353                                 break;
354                             case 60: // C.LT.S
355                                 setFC(getFloat(fs) < getFloat(ft));
356                                 break;
357                             default: throw new ExecutionException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
358                         }
359                         break;
360                     }
361                     case 17: { // Double
362                         switch(subcode) {
363                             case 0: // ADD.D
364                                 setDouble(fd,getDouble(fs)+getDouble(ft));
365                                 break;
366                             case 1: // SUB.D
367                                 if(debugon) System.out.println("f" + fd + " = f" + fs + " (" + getDouble(fs) + ") - f" + ft + " (" + getDouble(ft) + ")");
368                                 setDouble(fd,getDouble(fs)-getDouble(ft));
369                                 break;
370                             case 2: // MUL.D
371                                 if(debugon) System.out.println("f" + fd + " = f" + fs + " (" + getDouble(fs) + ") * f" + ft + " (" + getDouble(ft) + ")");
372                                 setDouble(fd,getDouble(fs)*getDouble(ft));
373                                 if(debugon) System.out.println("f" + fd + " = " + getDouble(fd));
374                                 break;
375                             case 3: // DIV.D
376                                 setDouble(fd,getDouble(fs)/getDouble(ft));
377                                 break;
378                             case 5: // ABS.D
379                                 setDouble(fd,Math.abs(getDouble(fs)));
380                                 break;
381                             case 6: // MOV.D
382                                 f[fd] = f[fs];
383                                 f[fd+1] = f[fs+1];
384                                 break;
385                             case 7: // NEG.D
386                                 setDouble(fd,-getDouble(fs));
387                                 break;
388                             case 32: // CVT.S.D
389                                 setFloat(fd,(float)getDouble(fs));
390                                 break;
391                             case 36: // CVT.W.D
392                                 if(debugon) System.out.println("CVT.W.D rm: " + roundingMode() + " f" + fs + ":" + getDouble(fs));
393                                 switch(roundingMode()) {
394                                     case 0: f[fd] = (int)Math.floor(getDouble(fs)+0.5); break; // Round to nearest
395                                     case 1: f[fd] = (int)getDouble(fs); break; // Round towards zero
396                                     case 2: f[fd] = (int)Math.ceil(getDouble(fs)); break; // Round towards plus infinity
397                                     case 3: f[fd] = (int)Math.floor(getDouble(fs)); break; // Round towards minus infinity
398                                 }
399                                 if(debugon) System.out.println("CVT.W.D: f" + fd + ":" + f[fd]);
400                                 break;
401                             case 50: // C.EQ.D
402                                 setFC(getDouble(fs) == getDouble(ft));
403                                 break;
404                             case 60: // C.LT.D
405                                 setFC(getDouble(fs) < getDouble(ft));
406                                 break;
407                             case 62: // C.LE.D
408                                 setFC(getDouble(fs) <= getDouble(ft));
409                                 break;                                
410                             default: throw new ExecutionException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
411                         }
412                         break;
413                     }
414                     case 20: { // Integer
415                         switch(subcode) {
416                             case 33: // CVT.D.W
417                                 setDouble(fd,f[fs]);
418                                 break;
419                             default: throw new ExecutionException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
420                         }
421                         break;
422                     }
423                     default:
424                         throw new ExecutionException("Invalid Instruction 17/" + rs);
425                 }
426                 break;
427             }
428             case 18: case 19:
429                 throw new ExecutionException("No coprocessor installed");
430             case 32: { // LB
431                 addr = r[rs] + signedImmediate;
432                 try {
433                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)];
434                 } catch(RuntimeException e) {
435                     tmp = memRead(addr&~3);
436                 }
437                 switch(addr&3) {
438                     case 0: tmp = (tmp>>>24)&0xff; break;
439                     case 1: tmp = (tmp>>>16)&0xff; break;
440                     case 2: tmp = (tmp>>> 8)&0xff; break;
441                     case 3: tmp = (tmp>>> 0)&0xff; break;
442                 }
443                 if((tmp&0x80)!=0) tmp |= 0xffffff00; // sign extend
444                 r[rt] = tmp;
445                 break;
446             }
447             case 33: { // LH
448                 addr = r[rs] + signedImmediate;
449                 try {
450                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)];
451                 } catch(RuntimeException e) {
452                     tmp = memRead(addr&~3);
453                 }
454                 switch(addr&2) {
455                     case 0: tmp = (tmp>>>16)&0xffff; break;
456                     case 2: tmp = (tmp>>> 0)&0xffff; break;
457                 }
458                 if((tmp&0x8000)!=0) tmp |= 0xffff0000; // sign extend
459                 r[rt] = tmp;
460                 break;              
461             }
462             case 34: { // LWL;
463                 addr = r[rs] + signedImmediate;
464                 try {
465                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)];
466                 } catch(RuntimeException e) {
467                     tmp = memRead(addr&~3);
468                 }
469                 switch(addr&3) {
470                     case 0: r[rt] = (r[rt]&0x00000000)|(tmp<< 0); break;
471                     case 1: r[rt] = (r[rt]&0x000000ff)|(tmp<< 8); break;
472                     case 2: r[rt] = (r[rt]&0x0000ffff)|(tmp<<16); break;
473                     case 3: r[rt] = (r[rt]&0x00ffffff)|(tmp<<24); break;
474                 }
475                 break;
476             }
477             case 35: // LW
478                 addr = r[rs] + signedImmediate;
479                 try {
480                     r[rt] = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)];
481                 } catch(RuntimeException e) {
482                     r[rt] = memRead(addr);
483                 }
484                 break;
485             case 36: { // LBU
486                 addr = r[rs] + signedImmediate;
487                 try {
488                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)];
489                 } catch(RuntimeException e) {
490                     tmp = memRead(addr);
491                 }
492                 switch(addr&3) {
493                     case 0: r[rt] = (tmp>>>24)&0xff; break;
494                     case 1: r[rt] = (tmp>>>16)&0xff; break;
495                     case 2: r[rt] = (tmp>>> 8)&0xff; break;
496                     case 3: r[rt] = (tmp>>> 0)&0xff; break;
497                 }
498                 break;
499             }
500             case 37: { // LHU
501                 addr = r[rs] + signedImmediate;
502                 try {
503                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)];
504                 } catch(RuntimeException e) {
505                     tmp = memRead(addr&~3);
506                 }
507                 switch(addr&2) {
508                     case 0: r[rt] = (tmp>>>16)&0xffff; break;
509                     case 2: r[rt] = (tmp>>> 0)&0xffff; break;
510                 }
511                 break;
512             }
513             case 38: { // LWR
514                 addr = r[rs] + signedImmediate;
515                 try {
516                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)];
517                 } catch(RuntimeException e) {
518                     tmp = memRead(addr&~3);
519                 }
520                 switch(addr&3) {
521                     case 0: r[rt] = (r[rt]&0xffffff00)|(tmp>>>24); break;
522                     case 1: r[rt] = (r[rt]&0xffff0000)|(tmp>>>16); break;
523                     case 2: r[rt] = (r[rt]&0xff000000)|(tmp>>> 8); break;
524                     case 3: r[rt] = (r[rt]&0x00000000)|(tmp>>> 0); break;
525                 }
526                 break;
527             }
528             case 40: { // SB
529                 addr = r[rs] + signedImmediate;
530                 try {
531                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)];
532                 } catch(RuntimeException e) {
533                     tmp = memRead(addr&~3);
534                 }
535                 switch(addr&3) {
536                     case 0: tmp = (tmp&0x00ffffff) | ((r[rt]&0xff)<<24); break;
537                     case 1: tmp = (tmp&0xff00ffff) | ((r[rt]&0xff)<<16); break;
538                     case 2: tmp = (tmp&0xffff00ff) | ((r[rt]&0xff)<< 8); break;
539                     case 3: tmp = (tmp&0xffffff00) | ((r[rt]&0xff)<< 0); break;
540                 }
541                 try {
542                     writePages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)] = tmp;
543                 } catch(RuntimeException e) {
544                     memWrite(addr&~3,tmp);
545                 }
546                 break;
547             }
548             case 41: { // SH
549                 addr = r[rs] + signedImmediate;
550                 try {
551                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)];
552                 } catch(RuntimeException e) {
553                     tmp = memRead(addr&~3);
554                 }
555                 switch(addr&2) {
556                     case 0: tmp = (tmp&0x0000ffff) | ((r[rt]&0xffff)<<16); break;
557                     case 2: tmp = (tmp&0xffff0000) | ((r[rt]&0xffff)<< 0); break;
558                 }
559                 try {
560                     writePages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)] = tmp;
561                 } catch(RuntimeException e) {
562                     memWrite(addr&~3,tmp);
563                 }
564                 break;
565             }
566             case 42: { // SWL
567                 addr = r[rs] + signedImmediate;
568                 tmp = memRead(addr&~3);
569                 switch(addr&3) {
570                     case 0: tmp=(tmp&0x00000000)|(r[rt]>>> 0); break;
571                     case 1: tmp=(tmp&0xff000000)|(r[rt]>>> 8); break;
572                     case 2: tmp=(tmp&0xffff0000)|(r[rt]>>>16); break;
573                     case 3: tmp=(tmp&0xffffff00)|(r[rt]>>>24); break;
574                 }
575                 try {
576                     writePages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)] = tmp;
577                 } catch(RuntimeException e) {
578                     memWrite(addr&~3,tmp);
579                 }
580                 break;
581             }
582             case 43: // SW
583                 addr = r[rs] + signedImmediate;
584                 try {
585                     writePages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)] = r[rt];
586                 } catch(RuntimeException e) {
587                     memWrite(addr&~3,r[rt]);
588                 }
589                 break;
590             case 46: { // SWR
591                 addr = r[rs] + signedImmediate;
592                 tmp = memRead(addr&~3);
593                 switch(addr&3) {
594                     case 0: tmp=(tmp&0x00ffffff)|(r[rt]<<24); break;
595                     case 1: tmp=(tmp&0x0000ffff)|(r[rt]<<16); break;
596                     case 2: tmp=(tmp&0x000000ff)|(r[rt]<< 8); break;
597                     case 3: tmp=(tmp&0x00000000)|(r[rt]<< 0); break;
598                 }
599                 memWrite(addr&~3,tmp);
600                 break;
601             }
602             // FEATURE: Needs to be atomic w/ threads
603             case 48: // LWC0/LL
604                 r[rt] = memRead(r[rs] + signedImmediate);
605                 break;
606             case 49: // LWC1
607                 f[rt] = memRead(r[rs] + signedImmediate);
608                 break;
609             // FEATURE: Needs to be atomic w/ threads
610             case 56:
611                 memWrite(r[rs] + signedImmediate,r[rt]);
612                 r[rt] = 1;
613                 break;
614             case 57: // SWC1
615                 memWrite(r[rs] + signedImmediate,f[rt]);
616                 break;
617             default:
618                 throw new ExecutionException("Invalid Instruction: " + op);
619         }
620         pc = nextPC;
621         nextPC = pc + 4;
622     } // for(;;)
623     } catch(ExecutionException e) {
624         this.pc = pc;
625         throw e;
626     }
627         return 0;
628     }
629     
630     public int lookupSymbol(String name) {
631         ELF.Symbol sym = symtab.getGlobalSymbol(name);
632         return sym == null ? -1 : sym.addr;
633     }
634     
635     // Image loading function
636     private void loadImage(SeekableData data) throws IOException {
637         if(state != UNINITIALIZED) throw new IllegalStateException("loadImage called on initialized runtime");
638         
639         ELF elf = new ELF(data);
640         symtab = elf.getSymtab();
641         
642         if(elf.header.type != ELF.ELFHeader.ET_EXEC) throw new IOException("Binary is not an executable");
643         if(elf.header.machine != ELF.ELFHeader.EM_MIPS) throw new IOException("Binary is not for the MIPS I Architecture");
644         if(elf.ident.data != ELF.ELFIdent.ELFDATA2MSB) throw new IOException("Binary is not big endian");
645         
646         entryPoint = elf.header.entry;
647         
648         ELF.Symtab symtab = elf.getSymtab();
649         if(symtab == null) throw new IOException("No symtab in binary (did you strip it?)");
650         ELF.Symbol userInfo = symtab.getGlobalSymbol("user_info");
651         ELF.Symbol gpsym = symtab.getGlobalSymbol("_gp");
652         
653         if(gpsym == null) throw new IOException("NO _gp symbol!");
654         gp = gpsym.addr;
655         
656         if(userInfo != null) {
657             userInfoBase = userInfo.addr;
658             userInfoSize = userInfo.size;
659         }
660         
661         ELF.PHeader[] pheaders = elf.pheaders;
662         int brk = 0;
663         for(int i=0;i<pheaders.length;i++) {
664             ELF.PHeader ph = pheaders[i];
665             if(ph.type != ELF.PHeader.PT_LOAD) continue;
666             int memsize = ph.memsz;
667             int filesize = ph.filesz;
668             if(memsize == 0) continue;
669             if(memsize < 0) throw new IOException("pheader size too large");
670             int addr = ph.vaddr;
671             if(addr == 0x0) throw new IOException("pheader vaddr == 0x0");
672             brk = max(addr+memsize,brk);
673             
674             for(int j=0;j<memsize+PAGE_SIZE-1;j+=PAGE_SIZE) {
675                 int page = (j+addr) >>> PAGE_SHIFT;
676                 if(readPages[page] == null)
677                     readPages[page] = new int[PAGE_WORDS];
678                 if(ph.writable()) writePages[page] = readPages[page];
679             }
680             if(filesize != 0) {
681                 filesize = filesize & ~3;
682                 DataInputStream dis = new DataInputStream(ph.getInputStream());
683                 do {
684                     readPages[addr >>> PAGE_SHIFT][(addr >>> 2)&(PAGE_WORDS-1)] = dis.readInt();
685                     addr+=4;
686                     filesize-=4;
687                 } while(filesize > 0);
688                 dis.close();
689             }
690         }
691         brkAddr = (brk+PAGE_SIZE-1)&~(PAGE_SIZE-1);
692         state = INITIALIZED;
693     }
694     
695     protected void setCPUState(CPUState state) {
696         for(int i=1;i<32;i++) registers[i] = state.r[i];
697         for(int i=0;i<32;i++) fpregs[i] = state.f[i];
698         hi=state.hi; lo=state.lo; fcsr=state.fcsr;
699         pc=state.pc;
700     }
701     
702     protected CPUState getCPUState() {
703         CPUState state = new CPUState();
704         for(int i=1;i<32;i++) state.r[i] = registers[i];
705         for(int i=0;i<32;i++) state.f[i] = fpregs[i];
706         state.hi=hi; state.lo=lo; state.fcsr=fcsr;
707         state.pc=pc;
708         return state;
709     }
710     
711     // This is package private for fork() which does all kinds of ugly things behind the scenes
712     Interpreter() { super(4096,65536,true); }
713     public Interpreter(SeekableData data) throws IOException { this(); loadImage(data); }
714     public Interpreter(String filename) throws IOException {
715         this(new SeekableFile(filename,false));
716         image = filename;
717     }
718     public Interpreter(InputStream is) throws IOException { this(new SeekableInputStream(is)); }
719     
720     // Debug functions
721     // NOTE: This probably requires a jdk > 1.1, however, it is only used for debugging
722     private java.util.HashMap sourceLineCache;
723     public String sourceLine(int pc) {
724         final String addr2line = "mips-unknown-elf-addr2line";
725         String line = (String) (sourceLineCache == null ? null : sourceLineCache.get(new Integer(pc)));
726         if(line != null) return line;
727         if(image==null) return null;
728         try {
729             Process p = java.lang.Runtime.getRuntime().exec(new String[]{addr2line,"-e",image,toHex(pc)});
730             line = new BufferedReader(new InputStreamReader(p.getInputStream())).readLine();
731             if(line == null) return null;
732             while(line.startsWith("../")) line = line.substring(3);
733             if(sourceLineCache == null) sourceLineCache = new java.util.HashMap();
734             sourceLineCache.put(new Integer(pc),line);
735             return line;
736         } catch(IOException e) {
737             return null;
738         }
739     }
740     
741     public class DebugShutdownHook implements Runnable {
742         public void run() {
743             int pc = Interpreter.this.pc;
744             if(getState() == RUNNING)
745                 System.err.print("\nCPU Executing " + toHex(pc) + ": " + sourceLine(pc) + "\n");
746         }
747     }
748
749     public static void main(String[] argv) throws Exception {
750         String image = argv[0];
751         Interpreter emu = new Interpreter(image);
752         java.lang.Runtime.getRuntime().addShutdownHook(new Thread(emu.new DebugShutdownHook()));
753         int status = emu.run(argv);
754         System.err.println("Exit status: " + status);
755         System.exit(status);
756     }
757 }