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