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