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