2003/09/18 08:10:36
[org.ibex.core.git] / src / org / xwt / mips / Interpreter.java
1 // Copyright 2003 Adam Megacz
2 // Author Brian Alliet
3 // Based on org.xwt.imp.MIPS by Adam Megacz
4
5 package org.xwt.imp;
6
7 import java.io.*;
8
9 public class MIPSInterpreter extends MIPSEmu {
10
11     // Registers
12     private int[] registers = new int[32];
13     private int hi,lo;
14     
15     // Floating Point Registers
16     private int[] fpregs = new int[32];
17
18     // 24-31 - unused
19     // 23    - conditional bit
20     // 18-22 - unused
21     // 12-17 - cause bits (unimplemented)
22     // 7-11  - enables bits (unimplemented)
23     // 2-6   - flags (unimplemented)
24     // 0-1   - rounding mode (only implemented for fixed point conversions)
25     private int fcsr;
26     
27     private int nextPC;
28     
29     // The filename if the binary we're running
30     private String image;
31     
32     // Register Operations
33     private final void setFC(boolean b) { fcsr = (fcsr&~0x800000) | (b ? 0x800000 : 0x000000); }
34     private final int roundingMode() { return fcsr & 3; /* bits 0-1 */ }
35     private final double getDouble(int r) {
36         return Double.longBitsToDouble(((fpregs[r+1]&0xffffffffL) << 32) | (fpregs[r]&0xffffffffL));
37     }
38     private final void setDouble(int r, double d) {
39         long l = Double.doubleToLongBits(d);
40         fpregs[r+1] = (int)(l >>> 32); fpregs[r] = (int)l;
41     }
42     private final float getFloat(int r) { return Float.intBitsToFloat(fpregs[r]); }
43     private final void setFloat(int r, float f) { fpregs[r] = Float.floatToRawIntBits(f); }
44     
45     // Main run loop
46     public void execute() throws EmulationException {
47         int[] r = registers;
48         if(state == PAUSED) state = RUNNING;
49         if(state != RUNNING) throw new IllegalStateException("execute() called in inappropriate state");
50         runSome(nextPC);
51     }
52     
53     // Main interpretor (also used for compilation)
54     // the return value is meaningless, its just to catch people typing "return" by accident
55     private int runSome(int pc) throws FaultException,EmulationException {
56         int[] r = registers;
57         int[] f = fpregs;
58         int nextPC = pc + 4;
59     try {
60     OUTER: for(;;) {
61         int insn;
62         try {
63             insn = readPages[pc>>>PAGE_SHIFT][(pc>>>2)&PAGE_WORDS-1];
64         } catch (RuntimeException e) {
65             insn = memRead(pc);
66         }
67
68         int op = (insn >>> 26) & 0xff;                 // bits 26-31
69         int rs = (insn >>> 21) & 0x1f;                 // bits 21-25
70         int rt = (insn >>> 16) & 0x1f;                 // bits 16-20 
71         int ft = (insn >>> 16) & 0x1f;
72         int rd = (insn >>> 11) & 0x1f;                 // bits 11-15
73         int fs = (insn >>> 11) & 0x1f;
74         int shamt = (insn >>> 6) & 0x1f;               // bits 6-10
75         int fd = (insn >>> 6) & 0x1f;
76         int subcode = insn & 0x3f;                     // bits 0-5  
77
78         int jumpTarget = (insn & 0x03ffffff);          // bits 0-25
79         int unsignedImmediate = insn & 0xffff;
80         int signedImmediate = (insn << 16) >> 16;
81         int branchTarget = signedImmediate;
82
83         int tmp, addr; // temporaries
84         
85         r[ZERO] = 0;
86     
87         switch(op) {
88             case 0: {
89                 switch(subcode) {
90                     case 0: // SLL
91                         if(insn == 0) break;
92                         r[rd] = r[rt] << shamt;
93                         break;
94                     case 2: // SRL
95                         r[rd] = r[rt] >>> shamt;
96                         break;
97                     case 3: // SRA
98                         r[rd] = r[rt] >> shamt;
99                         break;
100                     // FIXME: Do we need % 32 on the r[rs] ?
101                     case 4: // SLLV
102                         r[rd] = r[rt] << r[rs];
103                         break;
104                     case 6: // SRLV
105                         r[rd] = r[rt] >>> r[rs];
106                         break;
107                     case 7: // SRAV
108                         r[rd] = r[rt] >> r[rs];
109                         break;
110                     case 8: // JR
111                         tmp = r[rs]; pc += 4; nextPC = tmp;
112                         continue OUTER;
113                     case 9: // JALR
114                         tmp = r[rs]; pc += 4; r[rd] = pc+4; nextPC = tmp;
115                         continue OUTER;
116                     case 12: // SYSCALL
117                         r[V0] = syscall(r[V0],r[A0],r[A1],r[A2],r[A3]);
118                         if(state != RUNNING) {
119                             this.nextPC = nextPC;
120                             break OUTER;
121                         }
122                         break;
123                     case 13: // BREAK
124                         throw new EmulationException("Break");
125                     case 16: // MFHI
126                         r[rd] = hi;
127                         break;
128                     case 17: // MTHI
129                         hi = r[rs];
130                         break;
131                     case 18: // MFLO
132                         r[rd] = lo;
133                         break;
134                     case 19: // MTLO
135                         lo = r[rs];
136                         break;
137                     case 24: { // MULT
138                         long hilo = (long)(r[rs]) * ((long)r[rt]);
139                         hi = (int) (hilo >>> 32);
140                         lo = (int) hilo;
141                         break;
142                     }
143                     case 25: { // MULTU
144                         long hilo = (r[rs] & 0xffffffffL) * (r[rt] & 0xffffffffL);
145                         hi = (int) (hilo >>> 32);
146                         lo = (int) hilo;
147                         break;
148                     }
149                     case 26: // DIV
150                         hi = r[rs]%r[rt];
151                         lo = r[rs]/r[rt];
152                         break;
153                     case 27: // DIVU
154                         hi = (int)((r[rs] & 0xffffffffL) % (r[rt] & 0xffffffffL));
155                         lo = (int)((r[rs] & 0xffffffffL) / (r[rt] & 0xffffffffL));
156                         break;
157                     case 32: // ADD
158                         r[rd] = r[rs] + r[rt]; // FIXME: Trap on overflow
159                         break;
160                     case 33: // ADDU
161                         r[rd] = r[rs] + r[rt];
162                         break;
163                     case 34: // SUB
164                         r[rd] = r[rs] - r[rt]; // FIXME: Trap on overflow
165                         break;
166                     case 35: // SUBU
167                         r[rd] = r[rs] - r[rt];
168                         break;
169                     case 36: // AND
170                         r[rd] = r[rs] & r[rt];
171                         break;
172                     case 37: // OR
173                         r[rd] = r[rs] | r[rt];
174                         break;
175                     case 38: // XOR
176                         r[rd] = r[rs] ^ r[rt];
177                         break;
178                     case 39: // NOR
179                         r[rd] = ~(r[rs] | r[rt]);
180                         break;
181                     case 42: // SLT
182                         r[rd] = r[rs] < r[rt] ? 1 : 0;
183                         break;
184                     case 43: // SLTU
185                         r[rd] = ((r[rs] & 0xffffffffL) < (r[rt] & 0xffffffffL)) ? 1 : 0;
186                         break;
187                     default:
188                         throw new EmulationException("Illegal instruction 0/" + subcode);
189                 }
190                 break;
191             }
192             case 1: {
193                 switch(rt) {
194                     case 0: // BLTZ
195                         if(r[rs] < 0) {
196                             pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;                   
197                             continue OUTER;
198                         }
199                         break;
200                     case 1: // BGEZ
201                         if(r[rs] >= 0) {
202                             pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
203                             continue OUTER;
204                         }
205                         break;
206                     case 16: // BLTZAL
207                         if(r[rs] < 0) {
208                             pc += 4; r[RA] = pc+4; tmp = pc + branchTarget*4; nextPC = tmp;
209                             continue OUTER;
210                         }
211                         break;
212                     case 17: // BGEZAL
213                         if(r[rs] >= 0) {
214                             pc += 4; r[RA] = pc+4; tmp = pc + branchTarget*4; nextPC = tmp;  
215                             continue OUTER;
216                         }
217                         break;
218                     default:
219                         throw new EmulationException("Illegal Instruction");
220                 }
221                 break;
222             }
223             case 2: { // J
224                 tmp = (pc&0xf0000000) | (jumpTarget << 2);
225                 pc+=4; nextPC = tmp;
226                 continue OUTER;
227             }
228             case 3: { // JAL
229                 tmp = (pc&0xf0000000) | (jumpTarget << 2);
230                 pc+=4; r[RA] = pc+4; nextPC = tmp;
231                 continue OUTER;
232             }
233             case 4: // BEQ
234                 if(r[rs] == r[rt]) {
235                     pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
236                     continue OUTER;
237                 }
238                 break;
239             case 5: // BNE                
240                 if(r[rs] != r[rt]) {
241                     pc += 4; tmp = pc + branchTarget*4; nextPC = tmp; 
242                     continue OUTER;
243                 }
244                 break;
245             case 6: //BLEZ
246                 if(r[rs] <= 0) {
247                     pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
248                     continue OUTER;
249                 }
250                 break;
251             case 7: //BGTZ
252                 if(r[rs] > 0) {
253                     pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
254                     continue OUTER;
255                 }
256                 break;
257             case 8: // ADDI
258                 r[rt] = r[rs] + signedImmediate;
259                 break;
260             case 9: // ADDIU
261                 r[rt] = r[rs] + signedImmediate;
262                 break;
263             case 10: // SLTI
264                 r[rt] = r[rs] < signedImmediate ? 1 : 0;
265                 break;
266             case 11: // SLTIU
267                 r[rt] = (r[rs]&0xffffffffL) < (unsignedImmediate&0xffffffffL) ? 1 : 0;
268                 break;
269             case 12: // ANDI
270                 r[rt] = r[rs] & unsignedImmediate;
271                 break;
272             case 13: // ORI
273                 r[rt] = r[rs] | unsignedImmediate;
274                 break;
275             case 14: // XORI
276                 r[rt] = r[rs] ^ unsignedImmediate;
277                 break;
278             case 15: // LUI
279                 r[rt] = unsignedImmediate << 16;
280                 break;
281             case 16:
282                 throw new EmulationException("TLB/Exception support not implemented");
283             case 17: { // FPU
284                 boolean debug = false;
285                 String line = debug ? sourceLine(pc) : "";
286                 boolean debugon = debug && (line.indexOf("dtoa.c:51") >= 0 || line.indexOf("dtoa.c:52") >= 0 || line.indexOf("test.c") >= 0);
287                 if(rs > 8 && debugon)
288                     System.out.println("               FP Op: " + op + "/" + rs + "/" + subcode + " " + line);
289                 // FIXME: This could probably be removed. I don't think gcc will ever generate code that does this
290                 if(roundingMode() != 0 && rs != 6 /*CTC.1*/ && !((rs==16 || rs==17) && subcode == 36 /* CVT.W.Z */))
291                     throw new EmulationException("Non-cvt.w.z operation attempted with roundingMode != round to nearest");
292                 switch(rs) {
293                     case 0: // MFC.1
294                         r[rt] = f[rd];
295                         break;
296                     case 2: // CFC.1
297                         if(fs != 31) throw new EmulationException("FCR " + fs + " unavailable");
298                         r[rt] = fcsr;
299                         break;
300                     case 4: // MTC.1
301                         f[rd] = r[rt];
302                         break;
303                     case 6: // CTC.1
304                         if(fs != 31) throw new EmulationException("FCR " + fs + " unavailable");
305                         fcsr = r[rt];   
306                         break;
307                     case 8: // BC1F, BC1T
308                         if(((fcsr&0x800000)!=0) == (((insn>>>16)&1)!=0)) {
309                             pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
310                             continue OUTER;
311                         }
312                         break;
313                     case 16: {  // Single
314                         switch(subcode) {
315                             case 0: // ADD.S
316                                 setFloat(fd,getFloat(fs)+getFloat(ft));
317                                 break;
318                             case 1: // SUB.S
319                                 setFloat(fd,getFloat(fs)-getFloat(ft));
320                                 break;
321                             case 2: // MUL.S
322                                 setFloat(fd,getFloat(fs)*getFloat(ft));
323                                 break;
324                             case 3: // DIV.S
325                                 setFloat(fd,getFloat(fs)/getFloat(ft));
326                                 break;
327                             case 5: // ABS.S
328                                 setFloat(fd,Math.abs(getFloat(fs)));
329                                 break;
330                             case 6: // MOV.S
331                                 f[fd] = f[fs];
332                                 break;
333                             case 7: // NEG.S
334                                 setFloat(fd,-getFloat(fs)); // FIXME: just flip the sign bit
335                                 break;
336                             case 33: // CVT.D.S
337                                 setDouble(fd,getFloat(fs));
338                                 break;
339                             case 36: // CVT.W.S
340                                 switch(roundingMode()) {
341                                     case 0: f[fd] = (int)Math.floor(getFloat(fs)+0.5f); break; // Round to nearest
342                                     case 1: f[fd] = (int)getFloat(fs); break; // Round towards zero
343                                     case 2: f[fd] = (int)Math.ceil(getFloat(fs)); break; // Round towards plus infinity
344                                     case 3: f[fd] = (int)Math.floor(getFloat(fs)); break; // Round towards minus infinity
345                                 }
346                                 break;
347                             case -50: // C.EQ.S
348                                 setFC(getFloat(fs) == getFloat(ft)); // FIXME: just compare the ints, be sure things are normalized
349                                 break;
350                             case 60: // C.LT.S
351                                 setFC(getFloat(fs) < getFloat(ft));
352                                 break;
353                             default: throw new EmulationException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
354                         }
355                         break;
356                     }
357                     case 17: { // Double
358                         switch(subcode) {
359                             case 0: // ADD.D
360                                 setDouble(fd,getDouble(fs)+getDouble(ft));
361                                 break;
362                             case 1: // SUB.D
363                                 if(debugon) System.out.println("f" + fd + " = f" + fs + " (" + getDouble(fs) + ") - f" + ft + " (" + getDouble(ft) + ")");
364                                 setDouble(fd,getDouble(fs)-getDouble(ft));
365                                 break;
366                             case 2: // MUL.D
367                                 if(debugon) System.out.println("f" + fd + " = f" + fs + " (" + getDouble(fs) + ") * f" + ft + " (" + getDouble(ft) + ")");
368                                 setDouble(fd,getDouble(fs)*getDouble(ft));
369                                 if(debugon) System.out.println("f" + fd + " = " + getDouble(fd));
370                                 break;
371                             case 3: // DIV.D
372                                 setDouble(fd,getDouble(fs)/getDouble(ft));
373                                 break;
374                             case 5: // ABS.D
375                                 setDouble(fd,Math.abs(getDouble(fs)));
376                                 break;
377                             case 6: // MOV.D
378                                 f[fd] = f[fs];
379                                 f[fd+1] = f[fs+1];
380                                 break;
381                             case 7: // NEG.D
382                                 setDouble(fd,-getDouble(fs)); // FIXME: just flip the sign bit
383                                 break;
384                             case 32: // CVT.S.D
385                                 setFloat(fd,(float)getDouble(fs));
386                                 break;
387                             case 36: // CVT.W.D
388                                 if(debugon) System.out.println("CVT.W.D rm: " + roundingMode() + " f" + fs + ":" + getDouble(fs));
389                                 switch(roundingMode()) {
390                                     case 0: f[fd] = (int)Math.floor(getDouble(fs)+0.5); break; // Round to nearest
391                                     case 1: f[fd] = (int)getDouble(fs); break; // Round towards zero
392                                     case 2: f[fd] = (int)Math.ceil(getDouble(fs)); break; // Round towards plus infinity
393                                     case 3: f[fd] = (int)Math.floor(getDouble(fs)); break; // Round towards minus infinity
394                                 }
395                                 if(debugon) System.out.println("CVT.W.D: f" + fd + ":" + f[fd]);
396                                 break;
397                             case 50: // C.EQ.D
398                                 setFC(getDouble(fs) == getDouble(ft)); // FIXME: just compare the ints, be sure things are normalized
399                                 break;
400                             case 60: // C.LT.D
401                                 setFC(getDouble(fs) < getDouble(ft));
402                                 break;
403                             case 62: // C.LE.D
404                                 setFC(getDouble(fs) <= getDouble(ft));
405                                 break;                                
406                             default: throw new EmulationException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
407                         }
408                         break;
409                     }
410                     case 20: { // Integer
411                         switch(subcode) {
412                             case 33: // CVT.D.W
413                                 setDouble(fd,(double)f[fs]);
414                                 break;
415                             default: throw new EmulationException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
416                         }
417                         break;
418                     }
419                     default:
420                         throw new EmulationException("Invalid Instruction 17/" + rs);
421                 }
422                 break;
423             }
424             case 18: case 19:
425                 throw new EmulationException("No coprocessor installed");
426             case 32: { // LB
427                 addr = r[rs] + signedImmediate;
428                 try {
429                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
430                 } catch(RuntimeException e) {
431                     tmp = memRead(addr&~3);
432                 }
433                 switch(addr&3) {
434                     case 0: tmp = (tmp>>>24)&0xff; break;
435                     case 1: tmp = (tmp>>>16)&0xff; break;
436                     case 2: tmp = (tmp>>> 8)&0xff; break;
437                     case 3: tmp = (tmp>>> 0)&0xff; break;
438                 }
439                 if((tmp&0x80)!=0) tmp |= 0xffffff00; // sign extend
440                 r[rt] = tmp;
441                 break;
442             }
443             case 33: { // LH
444                 addr = r[rs] + signedImmediate;
445                 try {
446                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
447                 } catch(RuntimeException e) {
448                     tmp = memRead(addr&~3);
449                 }
450                 switch(addr&2) {
451                     case 0: tmp = (tmp>>>16)&0xffff; break;
452                     case 2: tmp = (tmp>>> 0)&0xffff; break;
453                 }
454                 if((tmp&0x8000)!=0) tmp |= 0xffff0000; // sign extend
455                 r[rt] = tmp;
456                 break;              
457             }
458             case 34: { // LWL;
459                 addr = r[rs] + signedImmediate;
460                 try {
461                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
462                 } catch(RuntimeException e) {
463                     tmp = memRead(addr&~3);
464                 }
465                 switch(addr&3) {
466                     case 0: r[rt] = (r[rt]&0x00000000)|(tmp<< 0); break;
467                     case 1: r[rt] = (r[rt]&0x000000ff)|(tmp<< 8); break;
468                     case 2: r[rt] = (r[rt]&0x0000ffff)|(tmp<<16); break;
469                     case 3: r[rt] = (r[rt]&0x00ffffff)|(tmp<<24); break;
470                 }
471                 break;
472             }
473             case 35: // LW
474                 addr = r[rs] + signedImmediate;
475                 try {
476                     r[rt] = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
477                 } catch(RuntimeException e) {
478                     r[rt] = memRead(addr);
479                 }
480                 break;
481             case 36: { // LBU
482                 addr = r[rs] + signedImmediate;
483                 try {
484                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
485                 } catch(RuntimeException e) {
486                     tmp = memRead(addr);
487                 }
488                 switch(addr&3) {
489                     case 0: r[rt] = (tmp>>>24)&0xff; break;
490                     case 1: r[rt] = (tmp>>>16)&0xff; break;
491                     case 2: r[rt] = (tmp>>> 8)&0xff; break;
492                     case 3: r[rt] = (tmp>>> 0)&0xff; break;
493                 }
494                 break;
495             }
496             case 37: { // LHU
497                 addr = r[rs] + signedImmediate;
498                 try {
499                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
500                 } catch(RuntimeException e) {
501                     tmp = memRead(addr&~3);
502                 }
503                 switch(addr&2) {
504                     case 0: r[rt] = (tmp>>>16)&0xffff; break;
505                     case 2: r[rt] = (tmp>>> 0)&0xffff; break;
506                 }
507                 break;
508             }
509             case 38: { // LWR
510                 addr = r[rs] + signedImmediate;
511                 try {
512                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
513                 } catch(RuntimeException e) {
514                     tmp = memRead(addr&~3);
515                 }
516                 switch(addr&3) {
517                     case 0: r[rt] = (r[rt]&0xffffff00)|(tmp>>>24); break;
518                     case 1: r[rt] = (r[rt]&0xffff0000)|(tmp>>>16); break;
519                     case 2: r[rt] = (r[rt]&0xff000000)|(tmp>>> 8); break;
520                     case 3: r[rt] = (r[rt]&0x00000000)|(tmp>>> 0); break;
521                 }
522                 break;
523             }
524             case 40: { // SB
525                 addr = r[rs] + signedImmediate;
526                 try {
527                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
528                 } catch(RuntimeException e) {
529                     tmp = memRead(addr&~3);
530                 }
531                 switch(addr&3) {
532                     case 0: tmp = (tmp&0x00ffffff) | ((r[rt]&0xff)<<24); break;
533                     case 1: tmp = (tmp&0xff00ffff) | ((r[rt]&0xff)<<16); break;
534                     case 2: tmp = (tmp&0xffff00ff) | ((r[rt]&0xff)<< 8); break;
535                     case 3: tmp = (tmp&0xffffff00) | ((r[rt]&0xff)<< 0); break;
536                 }
537                 try {
538                     writePages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1] = tmp;
539                 } catch(RuntimeException e) {
540                     memWrite(addr&~3,tmp);
541                 }
542                 break;
543             }
544             case 41: { // SH
545                 addr = r[rs] + signedImmediate;
546                 try {
547                     tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1];
548                 } catch(RuntimeException e) {
549                     tmp = memRead(addr&~3);
550                 }
551                 switch(addr&2) {
552                     case 0: tmp = (tmp&0x0000ffff) | ((r[rt]&0xffff)<<16); break;
553                     case 2: tmp = (tmp&0xffff0000) | ((r[rt]&0xffff)<< 0); break;
554                 }
555                 try {
556                     writePages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1] = tmp;
557                 } catch(RuntimeException e) {
558                     memWrite(addr&~3,tmp);
559                 }
560                 break;
561             }
562             case 42: { // SWL
563                 addr = r[rs] + signedImmediate;
564                 tmp = memRead(addr&~3);
565                 switch(addr&3) {
566                     case 0: tmp=(tmp&0x00000000)|(r[rt]>>> 0); break;
567                     case 1: tmp=(tmp&0xff000000)|(r[rt]>>> 8); break;
568                     case 2: tmp=(tmp&0xffff0000)|(r[rt]>>>16); break;
569                     case 3: tmp=(tmp&0xffffff00)|(r[rt]>>>24); break;
570                 }
571                 try {
572                     writePages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1] = tmp;
573                 } catch(RuntimeException e) {
574                     memWrite(addr&~3,tmp);
575                 }
576                 break;
577             }
578             case 43: // SW
579                 addr = r[rs] + signedImmediate;
580                 try {
581                     writePages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1] = r[rt];
582                 } catch(RuntimeException e) {
583                     memWrite(addr&~3,r[rt]);
584                 }
585                 break;
586             case 46: { // SWR
587                 addr = r[rs] + signedImmediate;
588                 tmp = memRead(addr&~3);
589                 switch(addr&3) {
590                     case 0: tmp=(tmp&0x00ffffff)|(r[rt]<<24); break;
591                     case 1: tmp=(tmp&0x0000ffff)|(r[rt]<<16); break;
592                     case 2: tmp=(tmp&0x000000ff)|(r[rt]<< 8); break;
593                     case 3: tmp=(tmp&0x00000000)|(r[rt]<< 0); break;
594                 }
595                 memWrite(addr&~3,tmp);
596                 break;
597             }
598             case 49: // LWC1
599                 f[rt] = memRead(r[rs] + signedImmediate);
600                 break;
601             case 57: // SWC1
602                 memWrite(r[rs] + signedImmediate,f[rt]);
603                 break;
604             default:
605                 throw new EmulationException("Invalid Instruction: " + op);
606         }
607         pc = nextPC;
608         nextPC = pc + 4;
609     } // for(;;)
610     } catch(EmulationException e) {
611         this.nextPC = pc;
612         throw e;
613     }
614         return 0;
615     }
616     
617     // Image loading function
618     void loadImage(String file) throws IOException {
619         ELF elf = new ELF(file);
620         if(elf.header.type != ELF.ELFHeader.ET_EXEC)
621             throw new IOException("Binary is not an executable");
622         if(elf.header.machine != ELF.ELFHeader.EM_MIPS)
623             throw new IOException("Binary is not for the MIPS I Architecture");
624         entryPoint = elf.header.entry;
625         ELF.PHeader[] pheaders = elf.pheaders;
626         brk = 0;
627         for(int i=0;i<pheaders.length;i++) {
628             ELF.PHeader ph = pheaders[i];
629             if(ph.type != ELF.PHeader.PT_LOAD) continue;
630             int memsize = ph.memsz;
631             int filesize = ph.filesz;
632             if(memsize == 0) continue;
633             if(memsize < 0) throw new IOException("pheader size too large");
634             int addr = ph.vaddr;
635             if(addr == 0x0) throw new IOException("pheader vaddr == 0x0");
636             if(addr+memsize >= (brk<<PAGE_SHIFT)) brk = (addr+memsize+PAGE_SIZE-1) >> PAGE_SHIFT;
637             
638             for(int j=0;j<memsize+PAGE_SIZE-1;j+=PAGE_SIZE) {
639                 int page = (j+addr) >>> PAGE_SHIFT;
640                 if(readPages[page] == null)
641                     readPages[page] = new int[PAGE_WORDS];
642                 if(ph.writable()) writePages[page] = readPages[page];
643             }
644             if(filesize != 0) {
645                 filesize = filesize & ~3;
646                 DataInputStream dis = new DataInputStream(ph.getInputStream());
647                 do {
648                     readPages[addr >>> PAGE_SHIFT][(addr >>> 2)&(PAGE_WORDS-1)] = dis.readInt();
649                     addr+=4;
650                     filesize-=4;
651                 } while(filesize > 0);
652                 dis.close();
653             }
654         }
655         image = file;
656         state = INITIALIZED;
657     }
658     
659     protected void _start(int pc) {
660         registers[SP] = INITIAL_SP;
661         registers[RA] = 0xdeadbeef;
662         nextPC = pc;
663     }
664     public MIPSInterpreter() { }
665     public MIPSInterpreter(String image) throws IOException { loadImage(image); }
666     
667     // Debug functions
668     // NOTE: This probably requires a jdk > 1.1, however, it is only used for debugging
669     public String sourceLine(int pc) {
670         final String addr2line = "mips-unknown-elf-addr2line";
671         String line;
672         if(image==null) return null;
673         try {
674             Process p = Runtime.getRuntime().exec(new String[]{addr2line,"-e",image,toHex(pc)});
675             line = new BufferedReader(new InputStreamReader(p.getInputStream())).readLine();
676             if(line == null) return null;
677             while(line.startsWith("../")) line = line.substring(3);
678             return line;
679         } catch(IOException e) {
680             return null;
681         }
682     }
683     
684     public class DebugShutdownHook implements Runnable {
685         public void run() {
686             int pc = nextPC;
687             if(getState() == RUNNING)
688                 System.err.print("\nCPU Executing " + toHex(pc) + ": " + sourceLine(pc) + "\n");
689         }
690     }
691
692     public static void main(String[] argv) throws Exception {
693         String image = argv[0];
694         MIPSInterpreter emu = new MIPSInterpreter();
695         emu.loadImage(image);
696         Runtime.getRuntime().addShutdownHook(new Thread(emu.new DebugShutdownHook()));
697         // User data
698         int addr = emu.sbrk(PAGE_SIZE);
699         for(int i=0;i<10;i++) {
700             String s = "User Info item: " + (i+1) + "\0";
701             byte[] b = s.getBytes("US-ASCII");
702             emu.copyout(b,addr,b.length);
703             emu.setUserInfo(i,addr);
704             addr += b.length;
705         }
706         // End user data
707         int status = emu.run(argv);
708         System.err.println("Exit status: " + status);
709         System.exit(status);
710     }
711 }
712
713 abstract class MIPSEmu implements Syscalls, Errno {
714     // Register Names
715     protected final static int ZERO = 0; // Immutable, hardwired to 0
716     protected final static int AT = 1;  // Reserved for assembler
717     protected final static int K0 = 26; // Reserved for kernel 
718     protected final static int K1 = 27; // Reserved for kernel 
719     protected final static int GP = 28; // Global pointer (the middle of .sdata/.sbss)
720     protected final static int SP = 29; // Stack pointer
721     protected final static int FP = 30; // Frame Pointer
722     protected final static int RA = 31; // Return Address
723     
724     // Return values (caller saved)
725     protected final static int V0 = 2;
726     protected final static int V1 = 3;
727     // Argument Registers (caller saved)
728     protected final static int A0 = 4; 
729     protected final static int A1 = 5;
730     protected final static int A2 = 6;
731     protected final static int A3 = 7;
732     // Temporaries (caller saved)
733     protected final static int T0 = 8;
734     protected final static int T1 = 9;
735     protected final static int T2 = 10;
736     protected final static int T3 = 11;
737     protected final static int T4 = 12;
738     protected final static int T5 = 13;
739     protected final static int T6 = 14;
740     protected final static int T7 = 15;
741     protected final static int T8 = 24;
742     protected final static int T9 = 25;
743     // Saved (callee saved)
744     protected final static int S0 = 16;
745     protected final static int S1 = 17;
746     protected final static int S2 = 18;
747     protected final static int S3 = 19;
748     protected final static int S4 = 20;
749     protected final static int S5 = 21;
750     protected final static int S6 = 22;
751     protected final static int S7 = 23;
752
753     // Page Constants
754     // Page Size: 4k
755     // Total Pages: 64k
756     // Maxiumum Addressable memory 256mb
757     // 1mb of stack space
758     protected final static int PAGE_SIZE = 4096;
759     protected final static int PAGE_WORDS = (int)(PAGE_SIZE >>> 2);
760     protected final static int PAGE_SHIFT = 12;
761     protected final static int STACK_PAGES = 256;
762     // NOTE: If you change TOTAL_PAGES crt0.c needs to be updated to reflect the
763     // new location of INITIAL_SP
764     protected final static int TOTAL_PAGES = 65536;
765     protected final static int BRK_LIMIT = 32768;
766     // Top page is always empty
767     // next page down contains command line arguments
768     protected final static int ARGS_ADDR = (TOTAL_PAGES-2)*PAGE_SIZE;
769     // next page down contains _user_info data
770     protected final static int USER_INFO_ADDR = (TOTAL_PAGES-3)*PAGE_SIZE;
771     // next page down is the start of the stack
772     protected final static int INITIAL_SP = (TOTAL_PAGES-3)*PAGE_SIZE;
773     // magic page that signified an allocated but empty (untouched) page
774     private final static int[] emptyPage = new int[0];
775     
776     // Main memory
777     protected final int[][] readPages;
778     protected final int[][] writePages;
779     
780     // Brk
781     protected int brk; // PAGE not address
782         
783     // Entry point - what start() sets pc to
784     protected int entryPoint;
785     
786     // State constants
787     public final static int UNINITIALIZED = 0;
788     public final static int INITIALIZED = 1;
789     public final static int RUNNING = 2;
790     public final static int PAUSED = 3;
791     public final static int DONE = 4;
792     
793     // State
794     protected int state = UNINITIALIZED;
795     public final int getState() { return state; }
796     protected int exitStatus;
797     
798     // File descriptors
799     private final static int OPEN_MAX = 256;
800     private FileDescriptor[] fds;
801     
802     // Temporary buffer for read/write operations
803     private byte[] _byteBuf = null;
804     private final static int MAX_CHUNK = 4*1024*1024-8;
805     
806     // Abstract methods
807     // This should start executing at pc
808     public abstract void execute() throws EmulationException;
809     // This should initialize the cpu registers to point to the entry point
810     protected abstract void _start(int pc);
811    
812     public static final int PID = 1;
813     
814     public MIPSEmu() {
815         readPages = new int[TOTAL_PAGES][];
816         writePages = new int[TOTAL_PAGES][];
817         for(int i=0;i<STACK_PAGES;i++)
818             readPages[TOTAL_PAGES-1-i] = writePages[TOTAL_PAGES-1-i] = emptyPage;
819     }
820     
821     public void copyin(int addr, byte[] a, int length) throws ReadFaultException {
822         int n=0;
823         if((addr&3)!=0) {
824             int word = memRead(addr&~3);
825              switch(addr&3) {
826                 case 1: a[n++] = (byte)((word>>>16)&0xff); if(length-n==0) break;
827                 case 2: a[n++] = (byte)((word>>> 8)&0xff); if(length-n==0) break;
828                 case 3: a[n++] = (byte)((word>>> 0)&0xff); if(length-n==0) break;
829             }
830             addr = (addr&~3)+4;
831         }
832         while(length-n > 3) {
833             int start = (addr&(PAGE_SIZE-1))>>2;
834             int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2);
835             int[] page = readPages[addr >>> PAGE_SHIFT];
836             if(page == null) throw new ReadFaultException(addr);
837             if(page == emptyPage) { addr+=(end-start); n+=(end-start); continue; }
838             for(int i=start;i<end;i++,addr+=4) {
839                 int word = page[i];
840                 a[n++] = (byte)((word>>>24)&0xff); a[n++] = (byte)((word>>>16)&0xff);
841                 a[n++] = (byte)((word>>> 8)&0xff); a[n++] = (byte)((word>>> 0)&0xff);
842             }
843         }
844         if(length-n > 0) {
845             int word = memRead(addr);
846             if(length-n >= 1) a[n] = (byte)((word>>>24)&0xff);
847             if(length-n >= 2) a[n+1] = (byte)((word>>>16)&0xff);
848             if(length-n >= 3) a[n+2] = (byte)((word>>> 8)&0xff);
849         }
850     }
851     
852     public void copyout(byte[] a, int addr, int length) throws FaultException {
853         int n=0;
854         if((addr&3)!=0) {
855             int word = memRead(addr&~3);
856              switch(addr&3) {
857                 case 1: word = (word&0xff00ffff)|((a[n]&0xff)<<16); n++; if(length-n==0) break;
858                 case 2: word = (word&0xffff00ff)|((a[n]&0xff)<< 8); n++; if(length-n==0) break;
859                 case 3: word = (word&0xffffff00)|((a[n]&0xff)<< 0); n++; if(length-n==0) break;
860             }
861             memWrite(addr&~3,word);
862             addr = (addr&~3)+4;
863         }
864         
865         while(length-n > 3) {
866             int start = (addr&(PAGE_SIZE-1))>>2;
867             int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2);
868             int[] page = writePages[addr >>> PAGE_SHIFT];
869             if(page == null) throw new WriteFaultException(addr);
870             if(page == emptyPage) { memWrite(addr,0); page = writePages[addr >>> PAGE_SHIFT]; }
871             for(int i=start;i<end;i++,addr+=4) {
872                 int word = ((a[n+0]&0xff)<<24)|((a[n+1]&0xff)<<16)|((a[n+2]&0xff)<<8)|((a[n+3]&0xff)<<0); n+=4;
873                 page[i] = word;
874             }
875         }
876         if(length-n > 0) {
877             int word = memRead(addr);
878             word = (word&0x00ffffff)|((a[n]&0xff)<<24);
879             if(length-n > 1) { word = (word&0xff00ffff)|((a[n+1]&0xff)<<16); }
880             if(length-n > 2) { word = (word&0xffff00ff)|((a[n+2]&0xff)<< 8); }
881             memWrite(addr,word);
882         }
883     }
884     
885     protected final int memRead(int addr) throws ReadFaultException  {
886         if((addr & 3) != 0) throw new ReadFaultException(addr);
887         int page = addr >>> PAGE_SHIFT;
888         int entry = (addr >>> 2) & (PAGE_WORDS-1);
889         try {
890             return readPages[page][entry];
891         } catch(ArrayIndexOutOfBoundsException e) {
892             if(page < 0) throw e; // should never happen
893             if(page > readPages.length) throw new ReadFaultException(addr);
894             if(readPages[page] != emptyPage) throw e; // should never happen
895             initPage(page);
896             return 0;
897         } catch(NullPointerException e) {
898             throw new ReadFaultException(addr);
899         }
900     }
901     
902     protected final void memWrite(int addr, int value) throws WriteFaultException  {
903         if((addr & 3) != 0) throw new WriteFaultException(addr);
904         int page = addr >>> PAGE_SHIFT;
905         int entry = (addr>>>2)&(PAGE_WORDS-1);
906         try {
907             writePages[page][entry] = value;
908         } catch(ArrayIndexOutOfBoundsException e) {
909             if(page < 0) throw e;// should never happen
910             if(page > writePages.length) throw new WriteFaultException(addr);
911             if(readPages[page] != emptyPage) throw e; // should never happen
912             initPage(page);
913             writePages[page][entry] = value;
914         } catch(NullPointerException e) {
915             throw new WriteFaultException(addr);
916         }
917     }
918     
919     protected void initPage(int page) { writePages[page] = readPages[page] = new int[PAGE_WORDS]; }
920     
921     public final int exitStatus() {
922         if(state != DONE) throw new IllegalStateException("exitStatus() called in an inappropriate state");
923         return exitStatus;
924     }
925      
926     public final int run(String[] args) throws EmulationException {
927         start(args);
928         for(;;) {
929             execute();
930             if(state != PAUSED) break;
931             System.err.println("WARNING: Pause requested while executing run()");
932             try { Thread.sleep(500); } catch(InterruptedException e) { }
933         }
934         if(state != DONE) throw new IllegalStateException("run() ended up in an inappropriate state");
935         return exitStatus();
936     }
937     
938     private void addArgs(String[] args) throws EmulationException {
939         if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("addArgs() called in inappropriate state");
940         int count = args.length;
941         byte[] nullTerminator = new byte[1];
942         int total = 4; /* null last table entry  */
943         for(int i=0;i<count;i++) total += args[i].length() + 1/*null terminator*/ + 4/*table entry*/;
944         if(total > PAGE_SIZE) throw new EmulationException("Arguments too large");
945         int start = ARGS_ADDR;
946         int addr = start + (count+1)*4;
947         int[] table = new int[count+1];
948         for(int i=0;i<count;i++) {
949             byte[] a;
950             try { a = args[i].getBytes("US-ASCII"); } catch(UnsupportedEncodingException e){ throw  new Error(e.getMessage()); }
951             table[i] = addr;
952
953                 copyout(a,addr,a.length);
954                 addr += a.length;
955                 copyout(nullTerminator,addr,1);
956                 addr += 1;
957
958         }
959         addr=start;
960         for(int i=0;i<count;i++) {
961             memWrite(addr,table[i]);
962             addr += 4;
963         }
964     }
965     
966     public void setUserInfo(int index, int word) throws EmulationException {
967         if(index < 0 ||  index >= 1024) throw new EmulationException("setUserInfo called with index >= 1024");
968         memWrite(USER_INFO_ADDR+index*4,word);
969     }
970     
971     public int getUserInfo(int index) throws EmulationException {
972         if(index < 0 ||  index >= 1024) throw new EmulationException("getUserInfo called with index >= 1024");
973         return memRead(USER_INFO_ADDR+index*4);
974     }
975     
976     public final void start(String[] args) throws EmulationException {
977         if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("start() called in inappropriate state");
978         _start(entryPoint);
979         addArgs(args);
980         fds = new FileDescriptor[OPEN_MAX];
981         fds[0] = new InputStreamFD(System.in)   { public boolean isatty() { return true; } };
982         fds[1] = new OutputStreamFD(System.out) { public boolean isatty() { return true; } };
983         fds[2] = new OutputStreamFD(System.err) { public boolean isatty() { return true; } };
984         state = PAUSED;
985     }
986     
987         
988     // Syscalls
989     private int write(int fdn, int addr, int count) {
990         int n = 0;
991         int r;
992         FileDescriptor fd;
993         count = Math.min(count,MAX_CHUNK);
994         try {
995             fd = fds[fdn];
996             if(fd == null || !fd.writable()) return -EBADFD;
997         } catch(ArrayIndexOutOfBoundsException e) {
998             return -EBADFD;
999         }
1000         try {
1001             byte[] buf = byteBuf(count);
1002             copyin(addr,buf,count);
1003             return fd.write(buf,0,count);
1004         } catch(FaultException e) {
1005             System.err.println(e);
1006             return -EFAULT;
1007         } catch(IOException e) {
1008             System.err.println(e);
1009             return -EIO;
1010         }
1011     }
1012
1013     private int read(int fdn, int addr, int count) {
1014         FileDescriptor fd;
1015         count = Math.min(count,MAX_CHUNK);
1016         try {
1017             fd = fds[fdn];
1018             if(fd == null || !fd.readable()) return -EBADFD;
1019         } catch(ArrayIndexOutOfBoundsException e) {
1020             return -EBADFD;
1021         }
1022         try {
1023             byte[] buf = byteBuf(count);
1024             int n = fd.read(buf,0,count);
1025             copyout(buf,addr,n);
1026             return n;
1027         } catch(FaultException e) {
1028             System.err.println(e);
1029             return -EFAULT;
1030         } catch(IOException e) {
1031             System.err.println(e);
1032             return -EIO;
1033         }
1034     }
1035     
1036     private int close(int fdn) {
1037         FileDescriptor fd;
1038         try {
1039             fd = fds[fdn];
1040             if(fd == null) return -EBADFD;
1041         } catch(ArrayIndexOutOfBoundsException e) {
1042             return -EBADFD;
1043         }
1044         fds[fdn] = null;
1045         fd.close();
1046         return 0;
1047     }
1048     
1049     private int stat(FileInfo fi, int addr) {
1050         int size = fi.size();
1051         try {
1052             memWrite(addr+0,0); // st_dev (top 16), // st_ino (bottom 16)
1053             memWrite(addr+4,(fi.type() & 0xf000)|0644); // st_mode
1054             memWrite(addr+8,1); // st_nlink (top 16) // st_uid (bottom 16)
1055             memWrite(addr+12,0); // st_gid (top 16) // st_rdev (bottom 16)
1056             memWrite(addr+16,size); // st_size
1057             memWrite(addr+20,0); // st_atime
1058             // memWrite(addr+24,0) // st_spare1
1059             memWrite(addr+28,(int)(fi.modTime()/1000)); // st_mtime
1060             // memWrite(addr+32,0) // st_spare2
1061             memWrite(addr+36,0); // st_atime
1062             // memWrite(addr+40,0) // st_spare3
1063             memWrite(addr+44,512); // st_bklsize;
1064             memWrite(addr+48,(size+511)&(~511)); // st_blocks
1065             // memWrite(addr+52,0) // st_spare4[0]
1066             // memWrite(addr+56,0) // st_spare4[1]
1067         } catch(FaultException e) {
1068             System.err.println(e);
1069             return -EFAULT;
1070         }
1071         return 0;
1072     }
1073     
1074     private int fstat(int fdn, int addr) {
1075         FileDescriptor fd;
1076         try {
1077             fd = fds[fdn];
1078             if(fd == null) return -EBADFD;
1079         } catch(ArrayIndexOutOfBoundsException e) {
1080             return -EBADFD;
1081         }
1082         return stat(fd.fileInfo(),addr);
1083     }
1084     
1085     public int sbrk(int incr) {
1086         if(incr==0) return brk<<PAGE_SHIFT;
1087         int oldBrk = brk;
1088         int newBrk = oldBrk + ((incr+PAGE_SIZE-1)>>PAGE_SHIFT);
1089         if(newBrk >= BRK_LIMIT) {
1090             System.err.println("Hit BRK_LIMIT");
1091             return -ENOMEM;
1092         }
1093         for(int i=oldBrk;i<newBrk+256;i++)
1094             readPages[i] = writePages[i] = emptyPage;
1095         brk = newBrk;
1096         return oldBrk<<PAGE_SHIFT;
1097     }
1098         
1099     private int open(int addr, int flags, int mode) {
1100         final int O_RDONLY = 0;
1101         final int O_WRONLY = 1;
1102         final int O_RDWR = 2;
1103         final int O_APPEND = 0x0008;
1104         final int O_CREAT = 0x0200;
1105         final int O_NONBLOCK = 0x4000;
1106         final int O_EXCL = 0x0800;
1107         
1108         if((flags & O_APPEND) != 0) {
1109             System.err.println("WARNING: O_APPEND not supported");
1110             return -EOPNOTSUPP;
1111         }
1112         if((flags & O_NONBLOCK) != 0) {
1113             System.err.println("WARNING: O_NONBLOCK not supported");
1114             return -EOPNOTSUPP;
1115         }
1116         
1117         try {
1118             int fdn=-1;
1119             File f = new File(cstring(addr));
1120             System.err.println("Opening: " + f);
1121             if((flags & O_EXCL) != 0 && (flags & O_CREAT) != 0)
1122                 if(!f.createNewFile()) return -EEXIST;
1123             if(f.exists()) {
1124                 if(f.length() >= Integer.MAX_VALUE) return -EOPNOTSUPP;
1125             } else {
1126                 if((flags & O_CREAT) == 0) return -ENOENT;
1127             }
1128             for(int i=0;i<OPEN_MAX;i++) if(fds[i] == null) { fdn = i; break; }
1129             if(fdn==-1) return -ENFILE;
1130             fds[fdn] = new RegularFileDescriptor(f,flags&3);
1131             return fdn;
1132         } catch(FaultException e) {
1133             return -EFAULT;
1134         } catch(FileNotFoundException e) { 
1135             if(e.getMessage().indexOf("Permission denied") >= 0) return -EACCES;
1136             return -ENOENT;
1137         } catch(IOException e) {
1138             return -EIO;
1139         }
1140     }
1141     
1142     private int seek(int fdn, int offset, int whence) {
1143         FileDescriptor fd;
1144         try {
1145             fd = fds[fdn];
1146             if(fd == null || !fd.readable()) return -EBADFD;
1147         } catch(ArrayIndexOutOfBoundsException e) {
1148             return -EBADFD;
1149         }
1150         try {
1151             return fd.seek(offset,whence);
1152         } catch(IOException e) {
1153             System.err.println(e);
1154             return -EPIPE;
1155         }
1156     }
1157     
1158     // This will only be called by raise() to invoke the default handler
1159     // We don't have to worry about actually delivering the signal
1160     private int kill(int pid, int signal) {
1161         if(pid != PID) return -ESRCH;
1162         if(signal < 0 || signal >= 32) return -EINVAL;
1163         switch(signal) {
1164             case 0: return 0;
1165             case 17: // SIGSTOP
1166             case 18: // SIGTSTP
1167             case 21: // SIGTTIN
1168             case 22: // SIGTTOU
1169                 state = PAUSED;
1170                 break;
1171             case 19: // SIGCONT
1172             case 20: // SIGCHLD
1173             case 23: // SIGIO
1174             case 28: // SIGWINCH
1175                 break;
1176             default: {
1177                 String msg = "Terminating on signal: " + signal + "\n";
1178                 exitStatus = 1;
1179                 state = DONE;
1180                 if(fds[2]==null) {
1181                     System.out.print(msg);
1182                 } else {
1183                     byte[] b = msg.getBytes();
1184                     try {
1185                         fds[2].write(b,0,b.length);
1186                     } catch(IOException e) { }
1187                 }
1188             }
1189         }
1190         return 0;
1191     }
1192     
1193     private int getpid() { return PID; }
1194     
1195     protected int syscall(int syscall, int a, int b, int c, int d) {
1196         switch(syscall) {
1197             case SYS_null: return 0;
1198             case SYS_exit: exitStatus = a; state = DONE; return 0;
1199             case SYS_pause: state = PAUSED; return 0;
1200             case SYS_write: return write(a,b,c);
1201             case SYS_fstat: return fstat(a,b);
1202             case SYS_sbrk: return sbrk(a);
1203             case SYS_open: return open(a,b,c);
1204             case SYS_close: return close(a);
1205             case SYS_read: return read(a,b,c);
1206             case SYS_seek: return seek(a,b,c);
1207             case SYS_kill: return kill(a,b);
1208             case SYS_getpid: return getpid();
1209             default:
1210                 System.err.println("Attempted to use unknown syscall: " + syscall);
1211                 return -ENOSYS;
1212         }
1213     }
1214     
1215     // Helper function to read a cstring from main memory
1216     private String cstring(int addr) throws ReadFaultException {
1217         StringBuffer sb = new StringBuffer();
1218         for(;;) {
1219             int word = memRead(addr&~3);
1220             switch(addr&3) {
1221                 case 0: if(((word>>>24)&0xff)==0) return sb.toString(); sb.append((char)((word>>>24)&0xff)); addr++;
1222                 case 1: if(((word>>>16)&0xff)==0) return sb.toString(); sb.append((char)((word>>>16)&0xff)); addr++;
1223                 case 2: if(((word>>> 8)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 8)&0xff)); addr++;
1224                 case 3: if(((word>>> 0)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 0)&0xff)); addr++;
1225             }
1226         }
1227     }
1228      
1229     // Exceptions
1230     public static class ReadFaultException extends FaultException {
1231         public ReadFaultException(int addr) { super(addr); }
1232     }
1233     public static class WriteFaultException extends FaultException {
1234         public WriteFaultException(int addr) { super(addr); }
1235     }
1236     public static abstract class FaultException extends EmulationException {
1237         private int addr;
1238         public FaultException(int addr) { this.addr = addr; }
1239         public String getMessage() { return "fault at: " + toHex(addr); }
1240     }
1241     public static class EmulationException extends Exception {
1242         public EmulationException() { }
1243         public EmulationException(String s) { super(s); }
1244     }
1245     
1246     // FileInfo classes - used by stat(2)
1247     static class FileInfo {
1248         public static final int S_IFIFO = 0010000;
1249         public static final int S_FCHR =  0020000;
1250         public static final int S_IFDIR = 0040000;
1251         public static final int S_IFREG = 0100000;
1252         
1253         public int size() { return 0; }
1254         public int type() { return S_IFIFO; }
1255         public long modTime() { return 0; }
1256     }
1257         
1258     public static class FileFileInfo extends FileInfo {
1259         public File f;
1260         public FileFileInfo(File f) { this.f = f; }
1261         public int size() { return (int)f.length(); }
1262         public int type() { return f.isDirectory() ? S_IFDIR : S_IFREG; }
1263         public long modTime() { return f.lastModified(); }
1264     }
1265
1266     // File descriptor classes
1267     public static abstract class FileDescriptor {
1268         public boolean readable() { return false; }
1269         public boolean writable() { return false; }
1270         
1271         private static final FileInfo nullFi = new FileInfo();
1272         private FileInfo fi;
1273         public FileInfo fileInfo() { return fi; }
1274         
1275         FileDescriptor() { this(null); }
1276         FileDescriptor(FileInfo fi) { this.fi = fi==null ? nullFi : fi; }
1277         
1278         public int read(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); }
1279         public int write(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); }
1280         
1281         public int seek(int n, int whence)  throws IOException  { return -ESPIPE; }
1282         public boolean isatty() { return false; }
1283         
1284         void close() { }
1285     }
1286     
1287     public static class RegularFileDescriptor extends FileDescriptor {
1288         private int mode;
1289         private RandomAccessFile raf;
1290         public boolean readable() { return mode != 1; }
1291         public boolean writable() { return mode != 0; }
1292         
1293         RegularFileDescriptor(File f,int m) throws IOException {
1294             super(new FileFileInfo(f));
1295             String mode = m == 0 ? "r" : "rw";
1296             this.mode = m;
1297             raf = new RandomAccessFile(f,mode);
1298             if(raf.length() >= Integer.MAX_VALUE) throw new IOException("File too large");
1299         }
1300         
1301         public int seek(int n, int whence) throws IOException {
1302             final int SEEK_SET = 0;
1303             final int SEEK_CUR = 1;
1304             final int SEEK_END = 2;
1305             
1306             switch(whence) {
1307                 case SEEK_SET: break;
1308                 case SEEK_CUR: n = (int)(raf.getFilePointer()+n); break;
1309                 case SEEK_END: n = (int)(raf.length()+n); break;
1310                 default: return -EINVAL;
1311             }
1312             raf.seek(n);
1313             return n;
1314         }
1315         
1316         public int write(byte[] a, int off, int length) throws IOException { raf.write(a,off,length); return length; }
1317         public int read(byte[] a, int off, int length) throws IOException { int n = raf.read(a,off,length); return n < 0 ? 0 : n; }
1318         
1319         void close() { try { raf.close(); } catch(Exception e) { } }
1320     }
1321     
1322     public class OutputStreamFD extends FileDescriptor {
1323         private OutputStream os;
1324         public boolean writable() { return true; }
1325         public OutputStreamFD(OutputStream os) { this.os = os; }
1326         public int write(byte[] a, int off, int length) throws IOException { os.write(a,off,length); return length; }
1327     }
1328     
1329     public class InputStreamFD extends FileDescriptor {
1330         private InputStream is;
1331         public boolean readable() { return true; }
1332         public InputStreamFD(InputStream is) { this.is = is; }
1333         public int read(byte[] a, int off, int length) throws IOException { int n = is.read(a,off,length); return n < 0 ? 0 : n; }
1334     }
1335     
1336     // Utility functions
1337     private byte[] byteBuf(int size) {
1338         if(_byteBuf==null) _byteBuf = new byte[size];
1339         else if(_byteBuf.length < size)
1340             _byteBuf = new byte[min(max(_byteBuf.length*2,size),MAX_CHUNK+8)];
1341         return _byteBuf;
1342     }
1343     protected final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
1344     protected final static int min(int a, int b) { return a < b ? a : b; }
1345     protected final static int max(int a, int b) { return a > b ? a : b; }
1346 }
1347
1348 class ELF {
1349     private MyRandomAccessFile fd;
1350     
1351     public ELFHeader header;
1352     public PHeader[] pheaders;
1353     public SHeader[] sheaders;
1354     
1355     private boolean sectionReaderActive;
1356     
1357     public class ELFHeader {
1358         byte klass;
1359         byte data;
1360         byte osabi;
1361         byte abiversion;
1362         
1363         public static final short ET_EXEC = 2;
1364         public short type;
1365         public static final short EM_MIPS = 8;
1366         public short machine;
1367         public int version;
1368         public int entry;
1369         public int phoff;
1370         public int shoff;
1371         public int flags;
1372         public short ehsize;
1373         public short phentsize;
1374         public short phnum;
1375         public short shentsize;
1376         public short shnum;
1377         public short shstrndx;
1378
1379         private static final int ELF_MAGIC = 0x7f454c46; // '\177', 'E', 'L', 'F'
1380         ELFHeader() throws IOException {
1381             if(fd.readInt() != ELF_MAGIC) throw new ELFException("Bad Magic (is: " );
1382             klass = fd.readByte();
1383             data = fd.readByte();
1384             fd.skipFully(1); // version
1385             osabi = fd.readByte();
1386             abiversion = fd.readByte();
1387             fd.skipFully(7);
1388             type = fd.readShort();
1389             machine = fd.readShort();
1390             version = fd.readInt();
1391             entry = fd.readInt();
1392             phoff = fd.readInt();
1393             shoff = fd.readInt();
1394             flags = fd.readInt();
1395             ehsize = fd.readShort();
1396             phentsize = fd.readShort();
1397             phnum = fd.readShort();
1398             shentsize = fd.readShort();
1399             shnum = fd.readShort();
1400             shstrndx = fd.readShort();
1401         }
1402     }
1403     
1404     public class PHeader {
1405         public int type;
1406         public int offset;
1407         public int vaddr;
1408         public int paddr;
1409         public int filesz;
1410         public int memsz;
1411         public int flags;
1412         public int align;
1413         
1414         public static final int PF_X = 0x1;
1415         public static final int PF_W = 0x2;
1416         public static final int PF_R = 0x4;
1417         
1418         public static final int PT_LOAD = 1;
1419         
1420         PHeader() throws IOException {
1421             type = fd.readInt();
1422             offset = fd.readInt();
1423             vaddr = fd.readInt();
1424             paddr = fd.readInt();
1425             filesz = fd.readInt();
1426             memsz = fd.readInt();
1427             flags = fd.readInt();
1428             align = fd.readInt();
1429             if(filesz > memsz) throw new ELFException("ELF inconsistency: filesz > memsz");
1430         }
1431         
1432         public boolean writable() { return (flags & PF_W) != 0; }
1433         
1434         public InputStream getInputStream() throws IOException {
1435             return new BufferedInputStream(new SectionInputStream(
1436                 offset,offset+filesz));
1437         }
1438     }
1439     
1440     public class SHeader {
1441         int nameidx;
1442         public String name;
1443         public int type;
1444         public int flags;
1445         public int addr;
1446         public int offset;
1447         public int size;
1448         public int link;
1449         public int info;
1450         public int addralign;
1451         public int entsize;
1452         
1453         public static final int T_NOBITS = 8;
1454         
1455         SHeader() throws IOException {
1456             nameidx = fd.readInt();
1457             type = fd.readInt();
1458             flags = fd.readInt();
1459             addr = fd.readInt();
1460             offset = fd.readInt();
1461             size = fd.readInt();
1462             link = fd.readInt();
1463             info = fd.readInt();
1464             addralign = fd.readInt();
1465             entsize = fd.readInt();
1466         }
1467         
1468         public InputStream getInputStream() throws IOException {
1469             return new BufferedInputStream(new SectionInputStream(
1470                 offset, type == T_NOBITS ? 0 : offset+size));
1471         }
1472     }
1473     
1474     public ELF(String file) throws IOException, ELFException {
1475         fd = new MyRandomAccessFile(file,"r");
1476         header = new ELFHeader();
1477         pheaders = new PHeader[header.phnum];
1478         for(int i=0;i<header.phnum;i++) {
1479             fd.seek(header.phoff+i*header.phentsize);
1480             pheaders[i] = new PHeader();
1481         }
1482         sheaders = new SHeader[header.shnum];
1483         for(int i=0;i<header.shnum;i++) {
1484             fd.seek(header.shoff+i*header.shentsize);
1485             sheaders[i] = new SHeader();
1486         }
1487         if(header.shstrndx < 0 || header.shstrndx >= header.shnum) throw new ELFException("Bad shstrndx");
1488         fd.seek(sheaders[header.shstrndx].offset);
1489         byte[] a = new byte[sheaders[header.shstrndx].size];
1490         fd.readFully(a);
1491         for(int i=0;i<header.shnum;i++) {
1492             SHeader s = sheaders[i];
1493             StringBuffer sb = new StringBuffer();
1494                for(int off = s.nameidx;off < a.length && a[off] != 0; off++) sb.append((char)a[off]);
1495             s.name = sb.toString();
1496         }            
1497     }
1498         
1499     public SHeader sectionWithName(String name) {
1500         for(int i=0;i<sheaders.length;i++)
1501             if(sheaders[i].name.equals(name))
1502                 return sheaders[i];
1503         return null;
1504     }
1505     
1506     public class ELFException extends IOException { ELFException(String s) { super(s); } }
1507     
1508     private class MyRandomAccessFile extends RandomAccessFile  {
1509         MyRandomAccessFile(String f,String m) throws IOException { super(f,m); }
1510         public void skipFully(int n) throws IOException {
1511             while(n>0) n-= skipBytes(n);
1512         }
1513     }
1514
1515     private class SectionInputStream extends InputStream {
1516         private int pos;
1517         private int maxpos;
1518         SectionInputStream(int start, int end) throws IOException {
1519             if(sectionReaderActive)
1520                 throw new IOException("Section reader already active");
1521             sectionReaderActive = true;
1522             pos = start;
1523             fd.seek(pos);
1524             maxpos = end;
1525         }
1526         
1527         private int bytesLeft() { return maxpos - pos; }
1528         public int read() throws IOException { if(bytesLeft()==0) return -1; int b = fd.read(); if(b >= 0) pos++; return b; }
1529         public int read(byte[] b, int off, int len) throws IOException {
1530             int n = fd.read(b,off,Math.min(len,bytesLeft())); if(n > 0) pos += n; return n;
1531         }
1532         public void close() { sectionReaderActive = false; }
1533     }
1534     
1535     private static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
1536     
1537     public static void main(String[] args) throws IOException {
1538         ELF elf = new ELF(args[0]);
1539         System.out.println("Type: " + toHex(elf.header.type));
1540         System.out.println("Machine: " + toHex(elf.header.machine));
1541         for(int i=0;i<elf.pheaders.length;i++) {
1542             ELF.PHeader ph = elf.pheaders[i];
1543             System.out.println("PHeader " + toHex(i));
1544             System.out.println("\tOffset: " + ph.offset);
1545             System.out.println("\tVaddr: " + toHex(ph.vaddr));
1546             System.out.println("\tFile Size: " + ph.filesz);
1547             System.out.println("\tMem Size: " + ph.memsz);
1548         }
1549         for(int i=0;i<elf.sheaders.length;i++) {
1550             ELF.SHeader sh = elf.sheaders[i];
1551             System.out.println("SHeader " + toHex(i));
1552             System.out.println("\tName: " + sh.name);
1553             System.out.println("\tOffset: " + sh.offset);
1554             System.out.println("\tAddr: " + toHex(sh.addr));
1555             System.out.println("\tSize: " + sh.size);
1556             System.out.println("\tType: " + toHex(sh.type));
1557         }
1558     }
1559 }
1560 interface Errno {
1561     public static final int EPERM = 1;
1562     public static final int ENOENT = 2;
1563     public static final int ESRCH = 3;
1564     public static final int EINTR = 4;
1565     public static final int EIO = 5;
1566     public static final int ENXIO = 6;
1567     public static final int ENOEXEC = 8;
1568     public static final int EBADF = 9;
1569     public static final int ECHILD = 10;
1570     public static final int EAGAIN = 11;
1571     public static final int ENOMEM = 12;
1572     public static final int EACCES = 13;
1573     public static final int EFAULT = 14;
1574     public static final int ENOTBLK = 15;
1575     public static final int EBUSY = 16;
1576     public static final int EEXIST = 17;
1577     public static final int EXDEV = 18;
1578     public static final int ENODEV = 19;
1579     public static final int ENOTDIR = 20;
1580     public static final int EISDIR = 21;
1581     public static final int EINVAL = 22;
1582     public static final int ENFILE = 23;
1583     public static final int EMFILE = 24;
1584     public static final int ENOTTY = 25;
1585     public static final int ETXTBSY = 26;
1586     public static final int EFBIG = 27;
1587     public static final int ENOSPC = 28;
1588     public static final int ESPIPE = 29;
1589     public static final int EROFS = 30;
1590     public static final int EMLINK = 31;
1591     public static final int EPIPE = 32;
1592     public static final int EDOM = 33;
1593     public static final int ERANGE = 34;
1594     public static final int ENOMSG = 35;
1595     public static final int EIDRM = 36;
1596     public static final int ECHRNG = 37;
1597     public static final int ELNRNG = 41;
1598     public static final int EUNATCH = 42;
1599     public static final int ENOCSI = 43;
1600     public static final int EDEADLK = 45;
1601     public static final int ENOLCK = 46;
1602     public static final int EBADE = 50;
1603     public static final int EBADR = 51;
1604     public static final int EXFULL = 52;
1605     public static final int ENOANO = 53;
1606     public static final int EBADRQC = 54;
1607     public static final int EBADSLT = 55;
1608     public static final int EDEADLOCK = 56;
1609     public static final int EBFONT = 57;
1610     public static final int ENOSTR = 60;
1611     public static final int ENODATA = 61;
1612     public static final int ETIME = 62;
1613     public static final int ENOSR = 63;
1614     public static final int ENONET = 64;
1615     public static final int ENOPKG = 65;
1616     public static final int EREMOTE = 66;
1617     public static final int ENOLINK = 67;
1618     public static final int EADV = 68;
1619     public static final int ESRMNT = 69;
1620     public static final int ECOMM = 70;
1621     public static final int EPROTO = 71;
1622     public static final int EMULTIHOP = 74;
1623     public static final int ELBIN = 75;
1624     public static final int EDOTDOT = 76;
1625     public static final int EBADMSG = 77;
1626     public static final int EFTYPE = 79;
1627     public static final int ENOTUNIQ = 80;
1628     public static final int EBADFD = 81;
1629     public static final int EREMCHG = 82;
1630     public static final int ELIBACC = 83;
1631     public static final int ELIBBAD = 84;
1632     public static final int ELIBSCN = 85;
1633     public static final int ELIBMAX = 86;
1634     public static final int ELIBEXEC = 87;
1635     public static final int ENOSYS = 88;
1636     public static final int ENMFILE = 89;
1637     public static final int ENOTEMPTY = 90;
1638     public static final int ENAMETOOLONG = 91;
1639     public static final int ELOOP = 92;
1640     public static final int EOPNOTSUPP = 95;
1641     public static final int EPFNOSUPPORT = 96;
1642     public static final int ECONNRESET = 104;
1643     public static final int ENOBUFS = 105;
1644     public static final int EAFNOSUPPORT = 106;
1645     public static final int EPROTOTYPE = 107;
1646     public static final int ENOTSOCK = 108;
1647     public static final int ENOPROTOOPT = 109;
1648     public static final int ESHUTDOWN = 110;
1649     public static final int ECONNREFUSED = 111;
1650     public static final int EADDRINUSE = 112;
1651     public static final int ECONNABORTED = 113;
1652     public static final int ENETUNREACH = 114;
1653     public static final int ENETDOWN = 115;
1654     public static final int ETIMEDOUT = 116;
1655     public static final int EHOSTDOWN = 117;
1656     public static final int EHOSTUNREACH = 118;
1657     public static final int EINPROGRESS = 119;
1658     public static final int EALREADY = 120;
1659     public static final int EDESTADDRREQ = 121;
1660     public static final int EMSGSIZE = 122;
1661     public static final int EPROTONOSUPPORT = 123;
1662     public static final int ESOCKTNOSUPPORT = 124;
1663     public static final int EADDRNOTAVAIL = 125;
1664     public static final int ENETRESET = 126;
1665     public static final int EISCONN = 127;
1666     public static final int ENOTCONN = 128;
1667     public static final int ETOOMANYREFS = 129;
1668     public static final int EPROCLIM = 130;
1669     public static final int EUSERS = 131;
1670     public static final int EDQUOT = 132;
1671     public static final int ESTALE = 133;
1672     public static final int ENOTSUP = 134;
1673     public static final int ENOMEDIUM = 135;
1674     public static final int ENOSHARE = 136;
1675     public static final int ECASECLASH = 137;
1676     public static final int EILSEQ = 138;
1677     public static final int EOVERFLOW = 139;
1678     public static final int __ELASTERROR = 2000;
1679 }
1680 interface Syscalls {
1681     public static final int SYS_null = 0;
1682     public static final int SYS_exit = 1;
1683     public static final int SYS_pause = 2;
1684     public static final int SYS_open = 3;
1685     public static final int SYS_close = 4;
1686     public static final int SYS_read = 5;
1687     public static final int SYS_write = 6;
1688     public static final int SYS_sbrk = 7;
1689     public static final int SYS_fstat = 8;
1690     public static final int SYS_isatty = 9;
1691     public static final int SYS_seek = 10;
1692     public static final int SYS_kill = 11;
1693     public static final int SYS_getpid = 12;
1694 }