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