2003/11/16 08:28:10
[org.ibex.core.git] / src / org / xwt / mips / Interpreter.java
1 // Copyright 2003 Brian Alliet
2 // Based on org.xwt.imp.MIPS by Adam Megacz
3 // Portions Copyright 2003 Adam Megacz
4 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 int hi,lo;
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         int tmp, 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 }