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