X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FInterpreter.java;fp=src%2Forg%2Fibex%2Fnestedvm%2FInterpreter.java;h=cd82365e172eb44a5f6d4645c8ac92fea4ea1883;hp=0000000000000000000000000000000000000000;hb=c2b2704764af1ade923ba8f15d517b87f9d16189;hpb=90f1aff73ed698ab5992fbd7eb53c1ba7329b1a5 diff --git a/src/org/ibex/nestedvm/Interpreter.java b/src/org/ibex/nestedvm/Interpreter.java new file mode 100644 index 0000000..cd82365 --- /dev/null +++ b/src/org/ibex/nestedvm/Interpreter.java @@ -0,0 +1,757 @@ +// Copyright 2003 Brian Alliet +// Based on org.xwt.imp.MIPS by Adam Megacz +// Portions Copyright 2003 Adam Megacz + +package org.ibex.nestedvm; + +import org.ibex.nestedvm.util.*; +import java.io.*; + +public class Interpreter extends UnixRuntime { + // Registers + private int[] registers = new int[32]; + private int hi,lo; + + // Floating Point Registers + private int[] fpregs = new int[32]; + // 24-31 - unused + // 23 - conditional bit + // 18-22 - unused + // 12-17 - cause bits (unimplemented) + // 7-11 - enables bits (unimplemented) + // 2-6 - flags (unimplemented) + // 0-1 - rounding mode (only implemented for fixed point conversions) + private int fcsr; + + private int pc; + + // The filename if the binary we're running + public String image; + private ELF.Symtab symtab; + + // Register Operations + private final void setFC(boolean b) { fcsr = (fcsr&~0x800000) | (b ? 0x800000 : 0x000000); } + private final int roundingMode() { return fcsr & 3; /* bits 0-1 */ } + private final double getDouble(int r) { + return Double.longBitsToDouble(((fpregs[r+1]&0xffffffffL) << 32) | (fpregs[r]&0xffffffffL)); + } + private final void setDouble(int r, double d) { + long l = Double.doubleToLongBits(d); + fpregs[r+1] = (int)(l >>> 32); fpregs[r] = (int)l; + } + private final float getFloat(int r) { return Float.intBitsToFloat(fpregs[r]); } + private final void setFloat(int r, float f) { fpregs[r] = Float.floatToRawIntBits(f); } + + protected void _execute() throws ExecutionException { + try { + runSome(); + } catch(ExecutionException e) { + e.setLocation(toHex(pc) + ": " + sourceLine(pc)); + throw e; + } + } + + // Main interpretor + // the return value is meaningless, its just to catch people typing "return" by accident + private final int runSome() throws FaultException,ExecutionException { + int[] r = registers; + int[] f = fpregs; + int pc = this.pc; + int nextPC = pc + 4; + try { + OUTER: for(;;) { + int insn; + try { + insn = readPages[pc>>>PAGE_SHIFT][(pc>>>2)&PAGE_WORDS-1]; + } catch (RuntimeException e) { + insn = memRead(pc); + } + + int op = (insn >>> 26) & 0xff; // bits 26-31 + int rs = (insn >>> 21) & 0x1f; // bits 21-25 + int rt = (insn >>> 16) & 0x1f; // bits 16-20 + int ft = (insn >>> 16) & 0x1f; + int rd = (insn >>> 11) & 0x1f; // bits 11-15 + int fs = (insn >>> 11) & 0x1f; + int shamt = (insn >>> 6) & 0x1f; // bits 6-10 + int fd = (insn >>> 6) & 0x1f; + int subcode = insn & 0x3f; // bits 0-5 + + int jumpTarget = (insn & 0x03ffffff); // bits 0-25 + int unsignedImmediate = insn & 0xffff; + int signedImmediate = (insn << 16) >> 16; + int branchTarget = signedImmediate; + + int tmp, addr; // temporaries + + r[ZERO] = 0; + + switch(op) { + case 0: { + switch(subcode) { + case 0: // SLL + if(insn == 0) break; + r[rd] = r[rt] << shamt; + break; + case 2: // SRL + r[rd] = r[rt] >>> shamt; + break; + case 3: // SRA + r[rd] = r[rt] >> shamt; + break; + case 4: // SLLV + r[rd] = r[rt] << (r[rs]&0x1f); + break; + case 6: // SRLV + r[rd] = r[rt] >>> (r[rs]&0x1f); + break; + case 7: // SRAV + r[rd] = r[rt] >> (r[rs]&0x1f); + break; + case 8: // JR + tmp = r[rs]; pc += 4; nextPC = tmp; + continue OUTER; + case 9: // JALR + tmp = r[rs]; pc += 4; r[rd] = pc+4; nextPC = tmp; + continue OUTER; + case 12: // SYSCALL + this.pc = pc; + r[V0] = syscall(r[V0],r[A0],r[A1],r[A2],r[A3]); + if(state != RUNNING) { this.pc = nextPC; break OUTER; } + break; + case 13: // BREAK + throw new ExecutionException("Break"); + case 16: // MFHI + r[rd] = hi; + break; + case 17: // MTHI + hi = r[rs]; + break; + case 18: // MFLO + r[rd] = lo; + break; + case 19: // MTLO + lo = r[rs]; + break; + case 24: { // MULT + long hilo = (long)(r[rs]) * ((long)r[rt]); + hi = (int) (hilo >>> 32); + lo = (int) hilo; + break; + } + case 25: { // MULTU + long hilo = (r[rs] & 0xffffffffL) * (r[rt] & 0xffffffffL); + hi = (int) (hilo >>> 32); + lo = (int) hilo; + break; + } + case 26: // DIV + hi = r[rs]%r[rt]; + lo = r[rs]/r[rt]; + break; + case 27: // DIVU + if(rt != 0) { + hi = (int)((r[rs] & 0xffffffffL) % (r[rt] & 0xffffffffL)); + lo = (int)((r[rs] & 0xffffffffL) / (r[rt] & 0xffffffffL)); + } + break; + case 32: // ADD + throw new ExecutionException("ADD (add with oveflow trap) not suported"); + /*This must trap on overflow + r[rd] = r[rs] + r[rt]; + break;*/ + case 33: // ADDU + r[rd] = r[rs] + r[rt]; + break; + case 34: // SUB + throw new ExecutionException("SUB (sub with oveflow trap) not suported"); + /*This must trap on overflow + r[rd] = r[rs] - r[rt]; + break;*/ + case 35: // SUBU + r[rd] = r[rs] - r[rt]; + break; + case 36: // AND + r[rd] = r[rs] & r[rt]; + break; + case 37: // OR + r[rd] = r[rs] | r[rt]; + break; + case 38: // XOR + r[rd] = r[rs] ^ r[rt]; + break; + case 39: // NOR + r[rd] = ~(r[rs] | r[rt]); + break; + case 42: // SLT + r[rd] = r[rs] < r[rt] ? 1 : 0; + break; + case 43: // SLTU + r[rd] = ((r[rs] & 0xffffffffL) < (r[rt] & 0xffffffffL)) ? 1 : 0; + break; + default: + throw new ExecutionException("Illegal instruction 0/" + subcode); + } + break; + } + case 1: { + switch(rt) { + case 0: // BLTZ + if(r[rs] < 0) { + pc += 4; tmp = pc + branchTarget*4; nextPC = tmp; + continue OUTER; + } + break; + case 1: // BGEZ + if(r[rs] >= 0) { + pc += 4; tmp = pc + branchTarget*4; nextPC = tmp; + continue OUTER; + } + break; + case 16: // BLTZAL + if(r[rs] < 0) { + pc += 4; r[RA] = pc+4; tmp = pc + branchTarget*4; nextPC = tmp; + continue OUTER; + } + break; + case 17: // BGEZAL + if(r[rs] >= 0) { + pc += 4; r[RA] = pc+4; tmp = pc + branchTarget*4; nextPC = tmp; + continue OUTER; + } + break; + default: + throw new ExecutionException("Illegal Instruction"); + } + break; + } + case 2: { // J + tmp = (pc&0xf0000000) | (jumpTarget << 2); + pc+=4; nextPC = tmp; + continue OUTER; + } + case 3: { // JAL + tmp = (pc&0xf0000000) | (jumpTarget << 2); + pc+=4; r[RA] = pc+4; nextPC = tmp; + continue OUTER; + } + case 4: // BEQ + if(r[rs] == r[rt]) { + pc += 4; tmp = pc + branchTarget*4; nextPC = tmp; + continue OUTER; + } + break; + case 5: // BNE + if(r[rs] != r[rt]) { + pc += 4; tmp = pc + branchTarget*4; nextPC = tmp; + continue OUTER; + } + break; + case 6: //BLEZ + if(r[rs] <= 0) { + pc += 4; tmp = pc + branchTarget*4; nextPC = tmp; + continue OUTER; + } + break; + case 7: //BGTZ + if(r[rs] > 0) { + pc += 4; tmp = pc + branchTarget*4; nextPC = tmp; + continue OUTER; + } + break; + case 8: // ADDI + r[rt] = r[rs] + signedImmediate; + break; + case 9: // ADDIU + r[rt] = r[rs] + signedImmediate; + break; + case 10: // SLTI + r[rt] = r[rs] < signedImmediate ? 1 : 0; + break; + case 11: // SLTIU + r[rt] = (r[rs]&0xffffffffL) < (unsignedImmediate&0xffffffffL) ? 1 : 0; + break; + case 12: // ANDI + r[rt] = r[rs] & unsignedImmediate; + break; + case 13: // ORI + r[rt] = r[rs] | unsignedImmediate; + break; + case 14: // XORI + r[rt] = r[rs] ^ unsignedImmediate; + break; + case 15: // LUI + r[rt] = unsignedImmediate << 16; + break; + case 16: + throw new ExecutionException("TLB/Exception support not implemented"); + case 17: { // FPU + boolean debug = false; + String line = debug ? sourceLine(pc) : ""; + boolean debugon = debug && (line.indexOf("dtoa.c:51") >= 0 || line.indexOf("dtoa.c:52") >= 0 || line.indexOf("test.c") >= 0); + if(rs > 8 && debugon) + System.out.println(" FP Op: " + op + "/" + rs + "/" + subcode + " " + line); + if(roundingMode() != 0 && rs != 6 /*CTC.1*/ && !((rs==16 || rs==17) && subcode == 36 /* CVT.W.Z */)) + throw new ExecutionException("Non-cvt.w.z operation attempted with roundingMode != round to nearest"); + switch(rs) { + case 0: // MFC.1 + r[rt] = f[rd]; + break; + case 2: // CFC.1 + if(fs != 31) throw new ExecutionException("FCR " + fs + " unavailable"); + r[rt] = fcsr; + break; + case 4: // MTC.1 + f[rd] = r[rt]; + break; + case 6: // CTC.1 + if(fs != 31) throw new ExecutionException("FCR " + fs + " unavailable"); + fcsr = r[rt]; + break; + case 8: // BC1F, BC1T + if(((fcsr&0x800000)!=0) == (((insn>>>16)&1)!=0)) { + pc += 4; tmp = pc + branchTarget*4; nextPC = tmp; + continue OUTER; + } + break; + case 16: { // Single + switch(subcode) { + case 0: // ADD.S + setFloat(fd,getFloat(fs)+getFloat(ft)); + break; + case 1: // SUB.S + setFloat(fd,getFloat(fs)-getFloat(ft)); + break; + case 2: // MUL.S + setFloat(fd,getFloat(fs)*getFloat(ft)); + break; + case 3: // DIV.S + setFloat(fd,getFloat(fs)/getFloat(ft)); + break; + case 5: // ABS.S + setFloat(fd,Math.abs(getFloat(fs))); + break; + case 6: // MOV.S + f[fd] = f[fs]; + break; + case 7: // NEG.S + setFloat(fd,-getFloat(fs)); + break; + case 33: // CVT.D.S + setDouble(fd,getFloat(fs)); + break; + case 36: // CVT.W.S + switch(roundingMode()) { + case 0: f[fd] = (int)Math.floor(getFloat(fs)+0.5f); break; // Round to nearest + case 1: f[fd] = (int)getFloat(fs); break; // Round towards zero + case 2: f[fd] = (int)Math.ceil(getFloat(fs)); break; // Round towards plus infinity + case 3: f[fd] = (int)Math.floor(getFloat(fs)); break; // Round towards minus infinity + } + break; + case 50: // C.EQ.S + setFC(getFloat(fs) == getFloat(ft)); + break; + case 60: // C.LT.S + setFC(getFloat(fs) < getFloat(ft)); + break; + default: throw new ExecutionException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc)); + } + break; + } + case 17: { // Double + switch(subcode) { + case 0: // ADD.D + setDouble(fd,getDouble(fs)+getDouble(ft)); + break; + case 1: // SUB.D + if(debugon) System.out.println("f" + fd + " = f" + fs + " (" + getDouble(fs) + ") - f" + ft + " (" + getDouble(ft) + ")"); + setDouble(fd,getDouble(fs)-getDouble(ft)); + break; + case 2: // MUL.D + if(debugon) System.out.println("f" + fd + " = f" + fs + " (" + getDouble(fs) + ") * f" + ft + " (" + getDouble(ft) + ")"); + setDouble(fd,getDouble(fs)*getDouble(ft)); + if(debugon) System.out.println("f" + fd + " = " + getDouble(fd)); + break; + case 3: // DIV.D + setDouble(fd,getDouble(fs)/getDouble(ft)); + break; + case 5: // ABS.D + setDouble(fd,Math.abs(getDouble(fs))); + break; + case 6: // MOV.D + f[fd] = f[fs]; + f[fd+1] = f[fs+1]; + break; + case 7: // NEG.D + setDouble(fd,-getDouble(fs)); + break; + case 32: // CVT.S.D + setFloat(fd,(float)getDouble(fs)); + break; + case 36: // CVT.W.D + if(debugon) System.out.println("CVT.W.D rm: " + roundingMode() + " f" + fs + ":" + getDouble(fs)); + switch(roundingMode()) { + case 0: f[fd] = (int)Math.floor(getDouble(fs)+0.5); break; // Round to nearest + case 1: f[fd] = (int)getDouble(fs); break; // Round towards zero + case 2: f[fd] = (int)Math.ceil(getDouble(fs)); break; // Round towards plus infinity + case 3: f[fd] = (int)Math.floor(getDouble(fs)); break; // Round towards minus infinity + } + if(debugon) System.out.println("CVT.W.D: f" + fd + ":" + f[fd]); + break; + case 50: // C.EQ.D + setFC(getDouble(fs) == getDouble(ft)); + break; + case 60: // C.LT.D + setFC(getDouble(fs) < getDouble(ft)); + break; + case 62: // C.LE.D + setFC(getDouble(fs) <= getDouble(ft)); + break; + default: throw new ExecutionException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc)); + } + break; + } + case 20: { // Integer + switch(subcode) { + case 33: // CVT.D.W + setDouble(fd,f[fs]); + break; + default: throw new ExecutionException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc)); + } + break; + } + default: + throw new ExecutionException("Invalid Instruction 17/" + rs); + } + break; + } + case 18: case 19: + throw new ExecutionException("No coprocessor installed"); + case 32: { // LB + addr = r[rs] + signedImmediate; + try { + tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + } catch(RuntimeException e) { + tmp = memRead(addr&~3); + } + switch(addr&3) { + case 0: tmp = (tmp>>>24)&0xff; break; + case 1: tmp = (tmp>>>16)&0xff; break; + case 2: tmp = (tmp>>> 8)&0xff; break; + case 3: tmp = (tmp>>> 0)&0xff; break; + } + if((tmp&0x80)!=0) tmp |= 0xffffff00; // sign extend + r[rt] = tmp; + break; + } + case 33: { // LH + addr = r[rs] + signedImmediate; + try { + tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + } catch(RuntimeException e) { + tmp = memRead(addr&~3); + } + switch(addr&2) { + case 0: tmp = (tmp>>>16)&0xffff; break; + case 2: tmp = (tmp>>> 0)&0xffff; break; + } + if((tmp&0x8000)!=0) tmp |= 0xffff0000; // sign extend + r[rt] = tmp; + break; + } + case 34: { // LWL; + addr = r[rs] + signedImmediate; + try { + tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + } catch(RuntimeException e) { + tmp = memRead(addr&~3); + } + switch(addr&3) { + case 0: r[rt] = (r[rt]&0x00000000)|(tmp<< 0); break; + case 1: r[rt] = (r[rt]&0x000000ff)|(tmp<< 8); break; + case 2: r[rt] = (r[rt]&0x0000ffff)|(tmp<<16); break; + case 3: r[rt] = (r[rt]&0x00ffffff)|(tmp<<24); break; + } + break; + } + case 35: // LW + addr = r[rs] + signedImmediate; + try { + r[rt] = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + } catch(RuntimeException e) { + r[rt] = memRead(addr); + } + break; + case 36: { // LBU + addr = r[rs] + signedImmediate; + try { + tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + } catch(RuntimeException e) { + tmp = memRead(addr); + } + switch(addr&3) { + case 0: r[rt] = (tmp>>>24)&0xff; break; + case 1: r[rt] = (tmp>>>16)&0xff; break; + case 2: r[rt] = (tmp>>> 8)&0xff; break; + case 3: r[rt] = (tmp>>> 0)&0xff; break; + } + break; + } + case 37: { // LHU + addr = r[rs] + signedImmediate; + try { + tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + } catch(RuntimeException e) { + tmp = memRead(addr&~3); + } + switch(addr&2) { + case 0: r[rt] = (tmp>>>16)&0xffff; break; + case 2: r[rt] = (tmp>>> 0)&0xffff; break; + } + break; + } + case 38: { // LWR + addr = r[rs] + signedImmediate; + try { + tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + } catch(RuntimeException e) { + tmp = memRead(addr&~3); + } + switch(addr&3) { + case 0: r[rt] = (r[rt]&0xffffff00)|(tmp>>>24); break; + case 1: r[rt] = (r[rt]&0xffff0000)|(tmp>>>16); break; + case 2: r[rt] = (r[rt]&0xff000000)|(tmp>>> 8); break; + case 3: r[rt] = (r[rt]&0x00000000)|(tmp>>> 0); break; + } + break; + } + case 40: { // SB + addr = r[rs] + signedImmediate; + try { + tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + } catch(RuntimeException e) { + tmp = memRead(addr&~3); + } + switch(addr&3) { + case 0: tmp = (tmp&0x00ffffff) | ((r[rt]&0xff)<<24); break; + case 1: tmp = (tmp&0xff00ffff) | ((r[rt]&0xff)<<16); break; + case 2: tmp = (tmp&0xffff00ff) | ((r[rt]&0xff)<< 8); break; + case 3: tmp = (tmp&0xffffff00) | ((r[rt]&0xff)<< 0); break; + } + try { + writePages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)] = tmp; + } catch(RuntimeException e) { + memWrite(addr&~3,tmp); + } + break; + } + case 41: { // SH + addr = r[rs] + signedImmediate; + try { + tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + } catch(RuntimeException e) { + tmp = memRead(addr&~3); + } + switch(addr&2) { + case 0: tmp = (tmp&0x0000ffff) | ((r[rt]&0xffff)<<16); break; + case 2: tmp = (tmp&0xffff0000) | ((r[rt]&0xffff)<< 0); break; + } + try { + writePages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)] = tmp; + } catch(RuntimeException e) { + memWrite(addr&~3,tmp); + } + break; + } + case 42: { // SWL + addr = r[rs] + signedImmediate; + tmp = memRead(addr&~3); + switch(addr&3) { + case 0: tmp=(tmp&0x00000000)|(r[rt]>>> 0); break; + case 1: tmp=(tmp&0xff000000)|(r[rt]>>> 8); break; + case 2: tmp=(tmp&0xffff0000)|(r[rt]>>>16); break; + case 3: tmp=(tmp&0xffffff00)|(r[rt]>>>24); break; + } + try { + writePages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)] = tmp; + } catch(RuntimeException e) { + memWrite(addr&~3,tmp); + } + break; + } + case 43: // SW + addr = r[rs] + signedImmediate; + try { + writePages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)] = r[rt]; + } catch(RuntimeException e) { + memWrite(addr&~3,r[rt]); + } + break; + case 46: { // SWR + addr = r[rs] + signedImmediate; + tmp = memRead(addr&~3); + switch(addr&3) { + case 0: tmp=(tmp&0x00ffffff)|(r[rt]<<24); break; + case 1: tmp=(tmp&0x0000ffff)|(r[rt]<<16); break; + case 2: tmp=(tmp&0x000000ff)|(r[rt]<< 8); break; + case 3: tmp=(tmp&0x00000000)|(r[rt]<< 0); break; + } + memWrite(addr&~3,tmp); + break; + } + // FEATURE: Needs to be atomic w/ threads + case 48: // LWC0/LL + r[rt] = memRead(r[rs] + signedImmediate); + break; + case 49: // LWC1 + f[rt] = memRead(r[rs] + signedImmediate); + break; + // FEATURE: Needs to be atomic w/ threads + case 56: + memWrite(r[rs] + signedImmediate,r[rt]); + r[rt] = 1; + break; + case 57: // SWC1 + memWrite(r[rs] + signedImmediate,f[rt]); + break; + default: + throw new ExecutionException("Invalid Instruction: " + op); + } + pc = nextPC; + nextPC = pc + 4; + } // for(;;) + } catch(ExecutionException e) { + this.pc = pc; + throw e; + } + return 0; + } + + public int lookupSymbol(String name) { + ELF.Symbol sym = symtab.getGlobalSymbol(name); + return sym == null ? -1 : sym.addr; + } + + // Image loading function + private void loadImage(Seekable data) throws IOException { + if(state != UNINITIALIZED) throw new IllegalStateException("loadImage called on initialized runtime"); + + ELF elf = new ELF(data); + symtab = elf.getSymtab(); + + if(elf.header.type != ELF.ELFHeader.ET_EXEC) throw new IOException("Binary is not an executable"); + if(elf.header.machine != ELF.ELFHeader.EM_MIPS) throw new IOException("Binary is not for the MIPS I Architecture"); + if(elf.ident.data != ELF.ELFIdent.ELFDATA2MSB) throw new IOException("Binary is not big endian"); + + entryPoint = elf.header.entry; + + ELF.Symtab symtab = elf.getSymtab(); + if(symtab == null) throw new IOException("No symtab in binary (did you strip it?)"); + ELF.Symbol userInfo = symtab.getGlobalSymbol("user_info"); + ELF.Symbol gpsym = symtab.getGlobalSymbol("_gp"); + + if(gpsym == null) throw new IOException("NO _gp symbol!"); + gp = gpsym.addr; + + if(userInfo != null) { + userInfoBase = userInfo.addr; + userInfoSize = userInfo.size; + } + + ELF.PHeader[] pheaders = elf.pheaders; + int brk = 0; + for(int i=0;i>> PAGE_SHIFT; + if(readPages[page] == null) + readPages[page] = new int[PAGE_WORDS]; + if(ph.writable()) writePages[page] = readPages[page]; + } + if(filesize != 0) { + filesize = filesize & ~3; + DataInputStream dis = new DataInputStream(ph.getInputStream()); + do { + readPages[addr >>> PAGE_SHIFT][(addr >>> 2)&(PAGE_WORDS-1)] = dis.readInt(); + addr+=4; + filesize-=4; + } while(filesize > 0); + dis.close(); + } + } + brkAddr = (brk+PAGE_SIZE-1)&~(PAGE_SIZE-1); + state = INITIALIZED; + } + + protected void setCPUState(CPUState state) { + for(int i=1;i<32;i++) registers[i] = state.r[i]; + for(int i=0;i<32;i++) fpregs[i] = state.f[i]; + hi=state.hi; lo=state.lo; fcsr=state.fcsr; + pc=state.pc; + } + + protected CPUState getCPUState() { + CPUState state = new CPUState(); + for(int i=1;i<32;i++) state.r[i] = registers[i]; + for(int i=0;i<32;i++) state.f[i] = fpregs[i]; + state.hi=hi; state.lo=lo; state.fcsr=fcsr; + state.pc=pc; + return state; + } + + // This is package private for fork() which does all kinds of ugly things behind the scenes + Interpreter() { super(4096,65536,true); } + public Interpreter(Seekable data) throws IOException { this(); loadImage(data); } + public Interpreter(String filename) throws IOException { + this(new Seekable.File(filename,false)); + image = filename; + } + public Interpreter(InputStream is) throws IOException { this(new Seekable.InputStream(is)); } + + // Debug functions + // NOTE: This probably requires a jdk > 1.1, however, it is only used for debugging + private java.util.HashMap sourceLineCache; + public String sourceLine(int pc) { + final String addr2line = "mips-unknown-elf-addr2line"; + String line = (String) (sourceLineCache == null ? null : sourceLineCache.get(new Integer(pc))); + if(line != null) return line; + if(image==null) return null; + try { + Process p = java.lang.Runtime.getRuntime().exec(new String[]{addr2line,"-e",image,toHex(pc)}); + line = new BufferedReader(new InputStreamReader(p.getInputStream())).readLine(); + if(line == null) return null; + while(line.startsWith("../")) line = line.substring(3); + if(sourceLineCache == null) sourceLineCache = new java.util.HashMap(); + sourceLineCache.put(new Integer(pc),line); + return line; + } catch(IOException e) { + return null; + } + } + + public class DebugShutdownHook implements Runnable { + public void run() { + int pc = Interpreter.this.pc; + if(getState() == RUNNING) + System.err.print("\nCPU Executing " + toHex(pc) + ": " + sourceLine(pc) + "\n"); + } + } + + public static void main(String[] argv) throws Exception { + String image = argv[0]; + Interpreter emu = new Interpreter(image); + java.lang.Runtime.getRuntime().addShutdownHook(new Thread(emu.new DebugShutdownHook())); + int status = emu.run(argv); + System.err.println("Exit status: " + status); + System.exit(status); + } +}