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