1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
5 // Copyright 2003 Brian Alliet
6 // Based on org.xwt.imp.MIPS by Adam Megacz
7 // Portions Copyright 2003 Adam Megacz
9 package org.ibex.nestedvm;
11 import org.ibex.nestedvm.util.*;
14 public class Interpreter extends UnixRuntime implements Cloneable {
16 private int[] registers = new int[32];
19 // Floating Point Registers
20 private int[] fpregs = new int[32];
22 // 23 - conditional bit
24 // 12-17 - cause bits (unimplemented)
25 // 7-11 - enables bits (unimplemented)
26 // 2-6 - flags (unimplemented)
27 // 0-1 - rounding mode (only implemented for fixed point conversions)
32 // The filename if the binary we're running
34 private ELF.Symtab symtab;
36 // Register Operations
37 private final void setFC(boolean b) { fcsr = (fcsr&~0x800000) | (b ? 0x800000 : 0x000000); }
38 private final int roundingMode() { return fcsr & 3; /* bits 0-1 */ }
39 private final double getDouble(int r) {
40 return Double.longBitsToDouble(((fpregs[r+1]&0xffffffffL) << 32) | (fpregs[r]&0xffffffffL));
42 private final void setDouble(int r, double d) {
43 long l = Double.doubleToLongBits(d);
44 fpregs[r+1] = (int)(l >>> 32); fpregs[r] = (int)l;
46 private final float getFloat(int r) { return Float.intBitsToFloat(fpregs[r]); }
47 private final void setFloat(int r, float f) { fpregs[r] = Float.floatToRawIntBits(f); }
49 protected void _execute() throws ExecutionException {
52 } catch(ExecutionException e) {
53 e.setLocation(toHex(pc) + ": " + sourceLine(pc));
58 protected Object clone() throws CloneNotSupportedException {
59 Interpreter r = (Interpreter) super.clone();
60 r.registers = (int[]) registers.clone();
61 r.fpregs = (int[]) fpregs.clone();
66 // the return value is meaningless, its just to catch people typing "return" by accident
67 private final int runSome() throws FaultException,ExecutionException {
68 final int PAGE_WORDS = (1<<pageShift)>>2;
77 insn = readPages[pc>>>pageShift][(pc>>>2)&PAGE_WORDS-1];
78 } catch (RuntimeException e) {
79 if(pc == 0xdeadbeef) throw new Error("fell off cpu: r2: " + r[2]);
83 int op = (insn >>> 26) & 0xff; // bits 26-31
84 int rs = (insn >>> 21) & 0x1f; // bits 21-25
85 int rt = (insn >>> 16) & 0x1f; // bits 16-20
86 int ft = (insn >>> 16) & 0x1f;
87 int rd = (insn >>> 11) & 0x1f; // bits 11-15
88 int fs = (insn >>> 11) & 0x1f;
89 int shamt = (insn >>> 6) & 0x1f; // bits 6-10
90 int fd = (insn >>> 6) & 0x1f;
91 int subcode = insn & 0x3f; // bits 0-5
93 int jumpTarget = (insn & 0x03ffffff); // bits 0-25
94 int unsignedImmediate = insn & 0xffff;
95 int signedImmediate = (insn << 16) >> 16;
96 int branchTarget = signedImmediate;
98 int tmp, addr; // temporaries
107 r[rd] = r[rt] << shamt;
110 r[rd] = r[rt] >>> shamt;
113 r[rd] = r[rt] >> shamt;
116 r[rd] = r[rt] << (r[rs]&0x1f);
119 r[rd] = r[rt] >>> (r[rs]&0x1f);
122 r[rd] = r[rt] >> (r[rs]&0x1f);
125 tmp = r[rs]; pc += 4; nextPC = tmp;
128 tmp = r[rs]; pc += 4; r[rd] = pc+4; nextPC = tmp;
132 r[V0] = syscall(r[V0],r[A0],r[A1],r[A2],r[A3],r[T0],r[T1]);
133 if(state != RUNNING) { this.pc = nextPC; break OUTER; }
136 throw new ExecutionException("Break");
150 long hilo = ((long)r[rs]) * ((long)r[rt]);
151 hi = (int) (hilo >>> 32);
156 long hilo = (r[rs] & 0xffffffffL) * (r[rt] & 0xffffffffL);
157 hi = (int) (hilo >>> 32);
167 hi = (int)((r[rs] & 0xffffffffL) % (r[rt] & 0xffffffffL));
168 lo = (int)((r[rs] & 0xffffffffL) / (r[rt] & 0xffffffffL));
172 throw new ExecutionException("ADD (add with oveflow trap) not suported");
173 /*This must trap on overflow
174 r[rd] = r[rs] + r[rt];
177 r[rd] = r[rs] + r[rt];
180 throw new ExecutionException("SUB (sub with oveflow trap) not suported");
181 /*This must trap on overflow
182 r[rd] = r[rs] - r[rt];
185 r[rd] = r[rs] - r[rt];
188 r[rd] = r[rs] & r[rt];
191 r[rd] = r[rs] | r[rt];
194 r[rd] = r[rs] ^ r[rt];
197 r[rd] = ~(r[rs] | r[rt]);
200 r[rd] = r[rs] < r[rt] ? 1 : 0;
203 r[rd] = ((r[rs] & 0xffffffffL) < (r[rt] & 0xffffffffL)) ? 1 : 0;
206 throw new ExecutionException("Illegal instruction 0/" + subcode);
214 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
220 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
226 pc += 4; r[RA] = pc+4; tmp = pc + branchTarget*4; nextPC = tmp;
232 pc += 4; r[RA] = pc+4; tmp = pc + branchTarget*4; nextPC = tmp;
237 throw new ExecutionException("Illegal Instruction");
242 tmp = (pc&0xf0000000) | (jumpTarget << 2);
247 tmp = (pc&0xf0000000) | (jumpTarget << 2);
248 pc+=4; r[RA] = pc+4; nextPC = tmp;
253 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
259 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
265 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
271 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
276 r[rt] = r[rs] + signedImmediate;
279 r[rt] = r[rs] + signedImmediate;
282 r[rt] = r[rs] < signedImmediate ? 1 : 0;
285 r[rt] = (r[rs]&0xffffffffL) < (signedImmediate&0xffffffffL) ? 1 : 0;
288 r[rt] = r[rs] & unsignedImmediate;
291 r[rt] = r[rs] | unsignedImmediate;
294 r[rt] = r[rs] ^ unsignedImmediate;
297 r[rt] = unsignedImmediate << 16;
300 throw new ExecutionException("TLB/Exception support not implemented");
302 boolean debug = false;
303 String line = debug ? sourceLine(pc) : "";
304 boolean debugon = debug && (line.indexOf("dtoa.c:51") >= 0 || line.indexOf("dtoa.c:52") >= 0 || line.indexOf("test.c") >= 0);
305 if(rs > 8 && debugon)
306 System.out.println(" FP Op: " + op + "/" + rs + "/" + subcode + " " + line);
307 if(roundingMode() != 0 && rs != 6 /*CTC.1*/ && !((rs==16 || rs==17) && subcode == 36 /* CVT.W.Z */))
308 throw new ExecutionException("Non-cvt.w.z operation attempted with roundingMode != round to nearest");
314 if(fs != 31) throw new ExecutionException("FCR " + fs + " unavailable");
321 if(fs != 31) throw new ExecutionException("FCR " + fs + " unavailable");
324 case 8: // BC1F, BC1T
325 if(((fcsr&0x800000)!=0) == (((insn>>>16)&1)!=0)) {
326 pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
333 setFloat(fd,getFloat(fs)+getFloat(ft));
336 setFloat(fd,getFloat(fs)-getFloat(ft));
339 setFloat(fd,getFloat(fs)*getFloat(ft));
342 setFloat(fd,getFloat(fs)/getFloat(ft));
345 setFloat(fd,Math.abs(getFloat(fs)));
351 setFloat(fd,-getFloat(fs));
354 setDouble(fd,getFloat(fs));
357 switch(roundingMode()) {
358 case 0: f[fd] = (int)Math.floor(getFloat(fs)+0.5f); break; // Round to nearest
359 case 1: f[fd] = (int)getFloat(fs); break; // Round towards zero
360 case 2: f[fd] = (int)Math.ceil(getFloat(fs)); break; // Round towards plus infinity
361 case 3: f[fd] = (int)Math.floor(getFloat(fs)); break; // Round towards minus infinity
365 setFC(getFloat(fs) == getFloat(ft));
368 setFC(getFloat(fs) < getFloat(ft));
371 setFC(getFloat(fs) <= getFloat(ft));
373 default: throw new ExecutionException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
380 setDouble(fd,getDouble(fs)+getDouble(ft));
383 if(debugon) System.out.println("f" + fd + " = f" + fs + " (" + getDouble(fs) + ") - f" + ft + " (" + getDouble(ft) + ")");
384 setDouble(fd,getDouble(fs)-getDouble(ft));
387 if(debugon) System.out.println("f" + fd + " = f" + fs + " (" + getDouble(fs) + ") * f" + ft + " (" + getDouble(ft) + ")");
388 setDouble(fd,getDouble(fs)*getDouble(ft));
389 if(debugon) System.out.println("f" + fd + " = " + getDouble(fd));
392 setDouble(fd,getDouble(fs)/getDouble(ft));
395 setDouble(fd,Math.abs(getDouble(fs)));
402 setDouble(fd,-getDouble(fs));
405 setFloat(fd,(float)getDouble(fs));
408 if(debugon) System.out.println("CVT.W.D rm: " + roundingMode() + " f" + fs + ":" + getDouble(fs));
409 switch(roundingMode()) {
410 case 0: f[fd] = (int)Math.floor(getDouble(fs)+0.5); break; // Round to nearest
411 case 1: f[fd] = (int)getDouble(fs); break; // Round towards zero
412 case 2: f[fd] = (int)Math.ceil(getDouble(fs)); break; // Round towards plus infinity
413 case 3: f[fd] = (int)Math.floor(getDouble(fs)); break; // Round towards minus infinity
415 if(debugon) System.out.println("CVT.W.D: f" + fd + ":" + f[fd]);
418 setFC(getDouble(fs) == getDouble(ft));
421 setFC(getDouble(fs) < getDouble(ft));
424 setFC(getDouble(fs) <= getDouble(ft));
426 default: throw new ExecutionException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
430 case 20: { // Integer
438 default: throw new ExecutionException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
443 throw new ExecutionException("Invalid Instruction 17/" + rs);
448 throw new ExecutionException("No coprocessor installed");
450 addr = r[rs] + signedImmediate;
452 tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
453 } catch(RuntimeException e) {
454 tmp = memRead(addr&~3);
457 case 0: tmp = (tmp>>>24)&0xff; break;
458 case 1: tmp = (tmp>>>16)&0xff; break;
459 case 2: tmp = (tmp>>> 8)&0xff; break;
460 case 3: tmp = (tmp>>> 0)&0xff; break;
462 if((tmp&0x80)!=0) tmp |= 0xffffff00; // sign extend
467 addr = r[rs] + signedImmediate;
469 tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
470 } catch(RuntimeException e) {
471 tmp = memRead(addr&~3);
474 case 0: tmp = (tmp>>>16)&0xffff; break;
475 case 2: tmp = (tmp>>> 0)&0xffff; break;
476 default: throw new ReadFaultException(addr);
478 if((tmp&0x8000)!=0) tmp |= 0xffff0000; // sign extend
483 addr = r[rs] + signedImmediate;
485 tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
486 } catch(RuntimeException e) {
487 tmp = memRead(addr&~3);
490 case 0: r[rt] = (r[rt]&0x00000000)|(tmp<< 0); break;
491 case 1: r[rt] = (r[rt]&0x000000ff)|(tmp<< 8); break;
492 case 2: r[rt] = (r[rt]&0x0000ffff)|(tmp<<16); break;
493 case 3: r[rt] = (r[rt]&0x00ffffff)|(tmp<<24); break;
498 addr = r[rs] + signedImmediate;
500 r[rt] = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
501 } catch(RuntimeException e) {
502 r[rt] = memRead(addr);
506 addr = r[rs] + signedImmediate;
508 tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
509 } catch(RuntimeException e) {
513 case 0: r[rt] = (tmp>>>24)&0xff; break;
514 case 1: r[rt] = (tmp>>>16)&0xff; break;
515 case 2: r[rt] = (tmp>>> 8)&0xff; break;
516 case 3: r[rt] = (tmp>>> 0)&0xff; break;
521 addr = r[rs] + signedImmediate;
523 tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
524 } catch(RuntimeException e) {
525 tmp = memRead(addr&~3);
528 case 0: r[rt] = (tmp>>>16)&0xffff; break;
529 case 2: r[rt] = (tmp>>> 0)&0xffff; break;
530 default: throw new ReadFaultException(addr);
535 addr = r[rs] + signedImmediate;
537 tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
538 } catch(RuntimeException e) {
539 tmp = memRead(addr&~3);
542 case 0: r[rt] = (r[rt]&0xffffff00)|(tmp>>>24); break;
543 case 1: r[rt] = (r[rt]&0xffff0000)|(tmp>>>16); break;
544 case 2: r[rt] = (r[rt]&0xff000000)|(tmp>>> 8); break;
545 case 3: r[rt] = (r[rt]&0x00000000)|(tmp>>> 0); break;
550 addr = r[rs] + signedImmediate;
552 tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
553 } catch(RuntimeException e) {
554 tmp = memRead(addr&~3);
557 case 0: tmp = (tmp&0x00ffffff) | ((r[rt]&0xff)<<24); break;
558 case 1: tmp = (tmp&0xff00ffff) | ((r[rt]&0xff)<<16); break;
559 case 2: tmp = (tmp&0xffff00ff) | ((r[rt]&0xff)<< 8); break;
560 case 3: tmp = (tmp&0xffffff00) | ((r[rt]&0xff)<< 0); break;
563 writePages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)] = tmp;
564 } catch(RuntimeException e) {
565 memWrite(addr&~3,tmp);
570 addr = r[rs] + signedImmediate;
572 tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
573 } catch(RuntimeException e) {
574 tmp = memRead(addr&~3);
577 case 0: tmp = (tmp&0x0000ffff) | ((r[rt]&0xffff)<<16); break;
578 case 2: tmp = (tmp&0xffff0000) | ((r[rt]&0xffff)<< 0); break;
579 default: throw new WriteFaultException(addr);
582 writePages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)] = tmp;
583 } catch(RuntimeException e) {
584 memWrite(addr&~3,tmp);
589 addr = r[rs] + signedImmediate;
590 tmp = memRead(addr&~3);
592 case 0: tmp=(tmp&0x00000000)|(r[rt]>>> 0); break;
593 case 1: tmp=(tmp&0xff000000)|(r[rt]>>> 8); break;
594 case 2: tmp=(tmp&0xffff0000)|(r[rt]>>>16); break;
595 case 3: tmp=(tmp&0xffffff00)|(r[rt]>>>24); break;
598 writePages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)] = tmp;
599 } catch(RuntimeException e) {
600 memWrite(addr&~3,tmp);
605 addr = r[rs] + signedImmediate;
607 writePages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)] = r[rt];
608 } catch(RuntimeException e) {
609 memWrite(addr&~3,r[rt]);
613 addr = r[rs] + signedImmediate;
614 tmp = memRead(addr&~3);
616 case 0: tmp=(tmp&0x00ffffff)|(r[rt]<<24); break;
617 case 1: tmp=(tmp&0x0000ffff)|(r[rt]<<16); break;
618 case 2: tmp=(tmp&0x000000ff)|(r[rt]<< 8); break;
619 case 3: tmp=(tmp&0x00000000)|(r[rt]<< 0); break;
621 memWrite(addr&~3,tmp);
624 // Needs to be atomic w/ threads
626 r[rt] = memRead(r[rs] + signedImmediate);
629 f[rt] = memRead(r[rs] + signedImmediate);
631 // Needs to be atomic w/ threads
633 memWrite(r[rs] + signedImmediate,r[rt]);
637 memWrite(r[rs] + signedImmediate,f[rt]);
640 throw new ExecutionException("Invalid Instruction: " + op);
645 } catch(ExecutionException e) {
652 public int lookupSymbol(String name) {
653 ELF.Symbol sym = symtab.getGlobalSymbol(name);
654 return sym == null ? -1 : sym.addr;
658 protected int gp() { return gp; }
660 private ELF.Symbol userInfo;
661 protected int userInfoBae() { return userInfo == null ? 0 : userInfo.addr; }
662 protected int userInfoSize() { return userInfo == null ? 0 : userInfo.size; }
664 private int entryPoint;
665 protected int entryPoint() { return entryPoint; }
667 private int heapStart;
668 protected int heapStart() { return heapStart; }
670 // Image loading function
671 private void loadImage(Seekable data) throws IOException {
672 ELF elf = new ELF(data);
673 symtab = elf.getSymtab();
675 if(elf.header.type != ELF.ET_EXEC) throw new IOException("Binary is not an executable");
676 if(elf.header.machine != ELF.EM_MIPS) throw new IOException("Binary is not for the MIPS I Architecture");
677 if(elf.ident.data != ELF.ELFDATA2MSB) throw new IOException("Binary is not big endian");
679 entryPoint = elf.header.entry;
681 ELF.Symtab symtab = elf.getSymtab();
682 if(symtab == null) throw new IOException("No symtab in binary (did you strip it?)");
683 userInfo = symtab.getGlobalSymbol("user_info");
684 ELF.Symbol gpsym = symtab.getGlobalSymbol("_gp");
686 if(gpsym == null) throw new IOException("NO _gp symbol!");
689 entryPoint = elf.header.entry;
691 ELF.PHeader[] pheaders = elf.pheaders;
693 int pageSize = (1<<pageShift);
694 int pageWords = (1<<pageShift) >> 2;
695 for(int i=0;i<pheaders.length;i++) {
696 ELF.PHeader ph = pheaders[i];
697 if(ph.type != ELF.PT_LOAD) continue;
698 int memsize = ph.memsz;
699 int filesize = ph.filesz;
700 if(memsize == 0) continue;
701 if(memsize < 0) throw new IOException("pheader size too large");
703 if(addr == 0x0) throw new IOException("pheader vaddr == 0x0");
704 brk = max(addr+memsize,brk);
706 for(int j=0;j<memsize+pageSize-1;j+=pageSize) {
707 int page = (j+addr) >>> pageShift;
708 if(readPages[page] == null)
709 readPages[page] = new int[pageWords];
710 if(ph.writable()) writePages[page] = readPages[page];
713 filesize = filesize & ~3;
714 DataInputStream dis = new DataInputStream(ph.getInputStream());
716 readPages[addr >>> pageShift][(addr >>> 2)&(pageWords-1)] = dis.readInt();
719 } while(filesize > 0);
723 heapStart = (brk+pageSize-1)&~(pageSize-1);
726 protected void setCPUState(CPUState state) {
727 for(int i=1;i<32;i++) registers[i] = state.r[i];
728 for(int i=0;i<32;i++) fpregs[i] = state.f[i];
729 hi=state.hi; lo=state.lo; fcsr=state.fcsr;
733 protected void getCPUState(CPUState state) {
734 for(int i=1;i<32;i++) state.r[i] = registers[i];
735 for(int i=0;i<32;i++) state.f[i] = fpregs[i];
736 state.hi=hi; state.lo=lo; state.fcsr=fcsr;
740 public Interpreter(Seekable data) throws IOException {
744 public Interpreter(String filename) throws IOException {
745 this(new Seekable.File(filename,false));
748 public Interpreter(InputStream is) throws IOException { this(new Seekable.InputStream(is)); }
751 // NOTE: This probably requires a jdk > 1.1, however, it is only used for debugging
752 private java.util.HashMap sourceLineCache;
753 public String sourceLine(int pc) {
754 final String addr2line = "mips-unknown-elf-addr2line";
755 String line = (String) (sourceLineCache == null ? null : sourceLineCache.get(new Integer(pc)));
756 if(line != null) return line;
757 if(image==null) return null;
759 Process p = java.lang.Runtime.getRuntime().exec(new String[]{addr2line,"-e",image,toHex(pc)});
760 line = new BufferedReader(new InputStreamReader(p.getInputStream())).readLine();
761 if(line == null) return null;
762 while(line.startsWith("../")) line = line.substring(3);
763 if(sourceLineCache == null) sourceLineCache = new java.util.HashMap();
764 sourceLineCache.put(new Integer(pc),line);
766 } catch(IOException e) {
771 public class DebugShutdownHook implements Runnable {
773 int pc = Interpreter.this.pc;
774 if(getState() == RUNNING)
775 System.err.print("\nCPU Executing " + toHex(pc) + ": " + sourceLine(pc) + "\n");
779 public static void main(String[] argv) throws Exception {
780 String image = argv[0];
781 Interpreter emu = new Interpreter(image);
782 java.lang.Runtime.getRuntime().addShutdownHook(new Thread(emu.new DebugShutdownHook()));
783 int status = emu.run(argv);
784 System.err.println("Exit status: " + status);