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