From 34bb35ae95b7612c75550722133bd3c95574c161 Mon Sep 17 00:00:00 2001 From: megacz Date: Fri, 30 Jan 2004 07:41:08 +0000 Subject: [PATCH] 2003/11/10 22:14:43 darcs-hash:20040130074108-2ba56-2456ed2f6ab1fce901784191169dcabd64b4a020.gz --- src/org/xwt/mips/Compiler.java | 1032 ++++++++++++++++++++++------------------ src/org/xwt/mips/ELF.java | 1 + 2 files changed, 563 insertions(+), 470 deletions(-) diff --git a/src/org/xwt/mips/Compiler.java b/src/org/xwt/mips/Compiler.java index f47d160..21fe7e5 100644 --- a/src/org/xwt/mips/Compiler.java +++ b/src/org/xwt/mips/Compiler.java @@ -8,9 +8,7 @@ import java.io.*; // FIXME: memory accesses aren't handling sign-extending properly // FIXME: probably have to implement nonaligned access // FIXME: implement malloc() - // FIXME: implement an ELF parser based on RandomAccessFile - // FEATURE: progress indicator // FEATURE: support n32 abi (passes more arguments in registers) // FEATURE: trap on arithmetic overflows @@ -40,16 +38,10 @@ public class Compiler { System.out.println(prefix + "// This file was generated by MipsToJava"); if (packageName != null) System.out.println(prefix + "package " + packageName + ";"); - System.out.println(prefix + "public class " + className + " {"); + System.out.println(prefix + "public class " + className + " extends org.xwt.mips.VM {"); System.out.println(prefix + ""); System.out.println(prefix + " public " + className + "() { }"); System.out.println(prefix + ""); - System.out.println(prefix + " // memory"); - System.out.println(prefix + " public int mem_read[][] = new int[65535][];"); - System.out.println(prefix + ""); - System.out.println(prefix + " // same as mem_read unless a page is write-protected"); - System.out.println(prefix + " public int mem_write[][] = new int[65535][];"); - System.out.println(prefix + ""); System.out.println(prefix + " // program counter"); System.out.println(prefix + " int pc = 0;"); System.out.println(prefix + ""); @@ -67,140 +59,81 @@ public class Compiler { System.out.println(prefix + " r24 = 0, r25 = 0, r26 = 0, r27 = 0, r28 = 0, r29 = 0, r30 = 0, r31 = 0;"); System.out.println(prefix + ""); - dis = new DataInputStream(new FileInputStream(s[1])); - - // read the ELF header - if (dis.readByte() != 0x7f || dis.readByte() != 'E' || dis.readByte() != 'L' || dis.readByte() != 'F') - throw new RuntimeException("input file is not an ELF binary"); - dis.skip(12); - - if (dis.readShort() != 2) - throw new RuntimeException("binary is not a linked executable"); - - if (dis.readShort() != 8) - throw new RuntimeException("binary is not a MIPS R3000 binary"); - - dis.skip(4); - - int entry_point = dis.readInt(); - String entry_point_string = Long.toString(entry_point & 0xffffffffL, 16); - - int ph_offset = dis.readInt(); - int sh_offset = dis.readInt(); - if (ph_offset == 0) throw new RuntimeException("binary is not statically linked"); - dis.skip(4); - dis.skip(2); - - int ph_entry_size = dis.readShort(); - int ph_num_entries = dis.readShort(); - int sh_entry_size = dis.readShort(); - int sh_num_entries = dis.readShort(); - int string_table_section_number = dis.readShort(); - - int skipamount = sh_offset - (4 + 12 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 2 + 2 + 2 + 2 + 2 + 2); - while (skipamount>0) skipamount -= (int)dis.skip(skipamount); - - int[] p_type = new int[sh_num_entries]; - int[] p_ofs = new int[sh_num_entries]; - int[] addr = new int[sh_num_entries]; - int[] p_size = new int[sh_num_entries]; - int[] p_name = new int[sh_num_entries]; - for(int i=0; i 0) seek -= dis.skip(seek); - char[] stringTable = new char[p_size[string_table_section_number]]; - for(int i=0; i> 16, 16); - System.out.println(prefix + " private void initData() {"); - System.out.println(prefix + " r28 = 0x" + Long.toString((addr[i] - Short.MIN_VALUE - 12) & 0xffffffffL, 16) + ";"); - System.out.println(prefix + " mem_read[" + base + "] = mem_write[" + base + "] = new int[65535];"); - for(long k=addr[i] & 0xffffffffL; k<((addr[i] + p_size[i]) & 0xffffffffL); k += 4) - System.out.println(prefix + " mem_write[" + base + "][0x" + Long.toString(k & 0xffff, 16) + "] = 0x" + - Long.toString(dis.readInt() & 0xffffffffL, 16) + ";"); - System.out.println(prefix + " }"); - - } else if (name.equals(".text") /*|| name.equals(".init")*/) { - if (pos > p_ofs[i]) { pos = 0; dis.close(); dis = new DataInputStream(new FileInputStream(s[1])); } - while(pos < p_ofs[i]) pos += dis.skip(p_ofs[i] - pos); - int remaining = p_size[i]; - for(int ofs = addr[i]; ofs < addr[i] + p_size[i];) { - String base = Long.toString(ofs & 0xffffff00L, 16); - int len = Math.min(((ofs + 0x100) & 0xffffff00) - ofs, remaining); - emit(ofs, len, dis); - last_emit = ofs; - remaining -= len; - ofs += len; - } + ELF elf = new ELF(new RandomAccessFile(args[1], "r")); + 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"); + + ELF.PHeader[] pheaders = elf.pheaders; + + int[][] readPages = new int[TOTAL_PAGES][]; + int[][] writePages = new int[TOTAL_PAGES][]; + for(int i=0; i= (brk<> PAGE_SHIFT; + // FIXME: set memsize, serialize readPages/writePages + for(int j=0;j>> 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 { + if (ph.executable()) emit(addr, 1, dis); + readPages[addr >>> PAGE_SHIFT][(addr >>> 2)&(PAGE_WORDS-1)] = dis.readInt(); + addr+=4; + filesize-=4; + } while(filesize > 0); + dis.close(); } } - if (last_emit != -1) { - System.out.println(prefix + " case 0x" + Long.toString((last_emit & 0xffffffffL) + 0x1000, 16) + ": return;"); - System.out.println(prefix + " default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16));"); - System.out.println(prefix + " }"); - System.out.println(prefix + " }"); - last_emit = -1; - } + // cap off the last method + emit(-1, -1, dis); + + System.out.println(prefix + " protected int state = INITIALIZED;"); + System.out.println(prefix + " protected int brk = " + brk + ";"); System.out.println(); - System.out.println(prefix + " public static void main(String[] s) { new " + className + "().main(); }"); + System.out.println(prefix + " public static void main(String[] s) { new " + className + "()._start(entryPoint); }"); System.out.println(); - System.out.println(prefix + " public void main() {"); + System.out.println(prefix + " protected int entryPoint = " + elf.header.entry + ";"); System.out.println(); - System.out.println(prefix + " // allocate the stack"); - System.out.println(prefix + " mem_read[1] = mem_write[1] = new int[65535];"); + System.out.println(prefix + " protected void _start(int pc) {"); System.out.println(); System.out.println(prefix + " // set the stack pointer"); - System.out.println(prefix + " r29 = 0x0001ff00;"); + System.out.println(prefix + " r29 = INITIAL_SP;"); System.out.println(); System.out.println(prefix + " // set the \"return address\" from _start to point at the \"magic exit address\" (0xdeadbeef)"); System.out.println(prefix + " r31 = 0xdeadbeef;"); System.out.println(); System.out.println(prefix + " // read in the .data segment"); - System.out.println(prefix + " initData();"); + System.out.println(prefix + " //initData();"); System.out.println(); - System.out.println(prefix + " trampoline(0x" + entry_point_string + ");"); + System.out.println(prefix + " trampoline(pc);"); System.out.println(); System.out.println(prefix + " }"); - + + System.out.println(); + System.out.println(prefix + " public void execute() throws EmulationException {"); + System.out.println(prefix + " if(state == PAUSED) state = RUNNING;"); + System.out.println(prefix + " if(state != RUNNING)"); + System.out.println(prefix + " throw new IllegalStateException(\"execute() called in inappropriate state\");"); + System.out.println(prefix + " trampoline(this.pc);"); + System.out.println(prefix + " }"); System.out.println(); System.out.println(prefix + " public void trampoline(int pc) {"); System.out.println(prefix + " this.pc = pc;"); @@ -220,11 +153,12 @@ public class Compiler { /** reads numbytes from the stream, emitting case blocks starting at vaddr ofs */ static void emit(int vaddr, int numbytes, DataInputStream dis) throws IOException { - if (last_emit != -1 && ((last_emit & 0xffffff00) != (vaddr & 0xffffff00))) { + if ((vaddr == -1 && numbytes == -1) || (last_emit != -1 && ((last_emit & 0xffffff00) != (vaddr & 0xffffff00)))) { System.out.println(prefix + " case 0x" + Long.toString((last_emit & 0xffffffffL) + 0x1000, 16) + ": return;"); System.out.println(prefix + " default: throw new Error(\"invalid address 0x\" + Long.toString(pc&0xffffffffL,16));"); System.out.println(prefix + " }"); System.out.println(prefix + " }"); + if (vaddr == -1 && numbytes == -1) return; } if (last_emit == -1 || ((last_emit & 0xffffff00) != (vaddr & 0xffffff00))) { System.out.println(""); @@ -254,373 +188,531 @@ public class Compiler { } } - private static void emit_instruction(int ofs, int instruction) throws IOException { - int op = (instruction >>> 26) & 0xff; // bits 26-31 - int rs = (instruction >> 21) & 0x1f; // bits 21-25 - int rt = (instruction >> 16) & 0x1f; // bits 16-20 - int rd = (instruction >> 11) & 0x1f; // bits 11-15 - int shamt = (instruction >> 6) & 0x1f; // bits 6-10 - int subcode = instruction & 0x3f; // bits 0-5 + private static void emit_instruction(int pc, int insn) throws IOException { + 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 - int branch_offset = (((instruction & 0x8000) << 16) | ((instruction & 0x7fff))) * 4; - int jump_target = (instruction & 0x03ffffff) * 4; - int signed_immediate = (int)((short)(instruction & 0xffff)); - int unsigned_immediate = instruction & 0xffff; - - switch(op) { - - case 0: { + switch(op) { + case 0: { + switch(subcode) { + case 0: // SLL + if(insn == 0) break; + emit(pc, "r"+rd+" = r"+rt+" << "+shamt+";"); + break; + case 2: // SRL + emit(pc, "r"+rd+" = r"+rt+" >>> "+shamt+";"); + break; + case 3: // SRA + emit(pc, "r"+rd+" = r"+rt+" >> "+shamt+";"); + break; + // FIXME: Do we need % 32 on the r"+rs+" ? + case 4: // SLLV + emit(pc, "r"+rd+" = r"+rt+" << r"+rs+";"); + break; + case 6: // SRLV + emit(pc, "r"+rd+" = r"+rt+" >>> r"+rs+";"); + break; + case 7: // SRAV + emit(pc, "r"+rd+" = r"+rt+" >> r"+rs+";"); + break; + case 8: // JR + emit(pc, "{ int tmp = r"+rs+"; pc += 4; nextPC = tmp; }"); + continue OUTER; + case 9: // JALR + emit(pc, "{ int tmp = r"+rs+"; pc += 4; r"+rd+" = pc+4; nextPC = tmp; }"); + continue OUTER; + case 12: // SYSCALL + emit(pc, "r"+V0+" = syscall(r"+V0+",r"+A0+",r"+A1+",r"+A2+",r"+A3+"); " + + "if (state != RUNNING) { this.nextPC = nextPC; return; }"); + break; + case 13: // BREAK + emit(pc, "throw new EmulationException(\"Break\")"); + break; + case 16: // MFHI + emit(pc, "r"+rd+" = hi;"); + break; + case 17: // MTHI + emit(pc, "hi = r"+rs+";"); + break; + case 18: // MFLO + emit(pc, "r"+rd+" = lo;"); + break; + case 19: // MTLO + emit(pc, "lo = r"+rs+";"); + break; + case 24: // MULT + emit(pc, "long hilo = (long)(r"+rs+") * ((long)r"+rt+"); " + + "hi = (int) (hilo >>> 32); " + + "lo = (int) hilo;"); + break; + case 25: // MULTU + emit(pc, "long hilo = (r"+rs+" & 0xffffffffL) * (r"+rt+" & 0xffffffffL); " + + "hi = (int) (hilo >>> 32); " + + "lo = (int) hilo;"); + case 26: // DIV + emit(pc, "hi = r"+rs+"%r"+rt+"; lo = r"+rs+"/r"+rt+";"); + break; + case 27: // DIVU + emit(pc, "hi = (int)((r"+rs+" & 0xffffffffL) % (r"+rt+" & 0xffffffffL)); " + + "lo = (int)((r"+rs+" & 0xffffffffL) / (r"+rt+" & 0xffffffffL));"); + break; + case 32: // ADD + emit(pc, "r"+rd+" = r"+rs+" + r"+rt+";"); // FIXME: Trap on overflow + break; + case 33: // ADDU + emit(pc, "r"+rd+" = r"+rs+" + r"+rt+";"); + break; + case 34: // SUB + emit(pc, "r"+rd+" = r"+rs+" - r"+rt+";"); // FIXME: Trap on overflow + break; + case 35: // SUBU + emit(pc, "r"+rd+" = r"+rs+" - r"+rt+";"); + break; + case 36: // AND + emit(pc, "r"+rd+" = r"+rs+" & r"+rt+";"); + break; + case 37: // OR + emit(pc, "r"+rd+" = r"+rs+" | r"+rt+";"); + break; + case 38: // XOR + emit(pc, "r"+rd+" = r"+rs+" ^ r"+rt+";"); + break; + case 39: // NOR + emit(pc, "r"+rd+" = ~(r"+rs+" | r"+rt+");"); + break; + case 42: // SLT + emit(pc, "r"+rd+" = r"+rs+" < r"+rt+" ? 1 : 0;"); + break; + case 43: // SLTU + emit(pc, "r"+rd+" = ((r"+rs+" & 0xffffffffL) < (r"+rt+" & 0xffffffffL)) ? 1 : 0;"); + break; + default: + throw new RuntimeException("Illegal instruction 0/" + subcode); + } + break; + } + case 1: { + switch(rt) { + case 0: // BLTZ + emit(pc, "if (r"+rs+"<0) { pc += 4; int tmp = pc + "+ + branchTarget+"*4; nextPC = tmp; }"); + break; + case 1: // BGEZ + emit(pc, "if (r"+rs+">=0) { pc += 4; int tmp = pc + "+ + branchTarget+"*4; nextPC = tmp; }"); + break; + case 16: // BLTZAL + emit(pc, "if(r"+rs+" < 0) { pc += 4; r"+RA+" = pc+4; int tmp = pc + "+ + branchTarget+"*4; nextPC = tmp; }"); + break; + case 17: // BGEZAL + emit(pc, "if(r"+rs+" >= 0) { pc += 4; r"+RA+" = pc+4; int tmp = pc + "+ + branchTarget+"*4; nextPC = tmp; }"); + break; + default: + throw new RuntimeException("Illegal Instruction"); + } + break; + } + case 2: { // J + emit(pc, "int tmp = (pc&0xf0000000) | ("+jumpTarget+" << 2); pc+=4; nextPC = tmp;"); + break; + } + case 3: { // JAL + emit(pc, "int tmp = (pc&0xf0000000) | ("+jumpTarget+" << 2); pc+=4; r"+RA+ + " = pc+4; nextPC = tmp;"); + break; + } + case 4: // BEQ + emit(pc, "if(r"+rs+" == r"+rt+") { pc += 4; int tmp = pc + "+ + branchTarget+"*4; nextPC = tmp; }"); + break; + case 5: // BNE + emit(pc, "if(r"+rs+" != r"+rt+") { pc += 4; int tmp = pc + "+ + branchTarget+"*4; nextPC = tmp; }"); + break; + case 6: //BLEZ + emit(pc, "if(r"+rs+" <= 0) { pc += 4; int tmp = pc + "+ + branchTarget+"*4; nextPC = tmp; ;"); + break; + case 7: //BGTZ + emit(pc, "if(r"+rs+" > 0) { pc += 4; int tmp = pc + "+branchTarget+"*4; nextPC = tmp; }"); + break; + case 8: // ADDI + emit(pc, "r"+rt+" = r"+rs+" + "+signedImmediate +";"); + break; + case 9: // ADDIU + emit(pc, "r"+rt+" = r"+rs+" + "+signedImmediate+";"); + break; + case 10: // SLTI + emit(pc, "r"+rt+" = r"+rs+" < "+signedImmediate+" ? 1 : 0;"); + break; + case 11: // SLTIU + emit(pc, "r"+rt+" = (r"+rs+"&0xffffffffL) < ("+unsignedImmediate+"&0xffffffffL) ? 1 : 0;"); + break; + case 12: // ANDI + emit(pc, "r"+rt+" = r"+rs+" & "+unsignedImmediate+";"); + break; + case 13: // ORI + emit(pc, "r"+rt+" = r"+rs+" | "+unsignedImmediate+";"); + break; + case 14: // XORI + emit(pc, "r"+rt+" = r"+rs+" ^ "+unsignedImmediate+";"); + break; + case 15: // LUI + emit(pc, "r"+rt+" = "+unsignedImmediate+" << 16;"); + break; + case 16: + throw new RuntimeException("TLB/Exception support not implemented"); + case 17: { // FPU + switch(rs) { + case 0: // MFC.1 + emit(pc, "r"+rt+" = f"+rd); + break; + case 2: // CFC.1 + if(fs != 31) throw new EmulationException("FCR " + fs + " unavailable"); + emit(pc, "r"+rt+" = fcsr;"); + break; + case 4: // MTC.1 + emit(pc, "f"+rd+" = r"+rt+";"); + break; + case 6: // CTC.1 + if(fs != 31) throw new EmulationException("FCR " + fs + " unavailable"); + emit(pc, "fcsr = r"+rt+"; ;") + break; + case 8: // BC1F, BC1T + emit(pc, "if(((fcsr&0x800000)!=0) == (((insn>>>16)&1)!=0)) {"+ + " pc += 4; int tmp = pc + "+branchTarget+"*4; nextPC = tmp; ;")} + break; + case 16: { // Single switch(subcode) { - - case 0: - if (instruction == 0) emit(ofs, " /* NOP */;"); // NOP - else emit(ofs, " r" + rd + " = r" + rt + " << " + shamt + ";"); // SLL - break; - - case 1: throw new Error("opcode 0, subcode 1 is not part of the MIPS I instruction set"); - - case 2: - emit(ofs, " r" + rd + " = r" + rt + " >>> " + shamt + ";"); // SRL - break; - - case 3: - emit(ofs, " r" + rd + " = r" + rt + " >> " + shamt + ";"); // SRA - break; - - case 4: - emit(ofs, " r" + rd + " = r" + rt + " << (r" + rs + " % 32);"); // SLLV - break; - - case 5: throw new Error("opcode 0, subcode 5 is not part of the MIPS I instruction set"); - - case 6: - emit(ofs, " r" + rd + " = r" + rs + " >>> (r" + rt + " % 32);"); // SRLV - break; - - case 7: - emit(ofs, " r" + rd + " = r" + rs + " >> (r" + rt + " % 32);"); // SRAV - break; - - case 8: - _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction); - emit(ofs, " pc = r" + rs + "; return;"); // JR - break; - - case 9: - _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction); - emit(ofs, " r" + rd + " = pc + 8; pc = r" + rs + "; return;"); // JALR - break; - - case 10: throw new Error("opcode 0, subcode 10 is not part of the MIPS I instruction set"); - case 11: throw new Error("opcode 0, subcode 11 is not part of the MIPS I instruction set"); - - case 12: - emit(ofs, " syscall(" + ((instruction & 0x07ffffc0) >> 6) + ");"); // SYSCALL - break; - - case 13: - emit(ofs, " /* BREAKPOINT */"); - break; - - case 14: throw new Error("opcode 0, subcode 14 is not part of the MIPS I instruction set"); - case 15: throw new Error("opcode 0, subcode 15 is not part of the MIPS I instruction set"); - - case 16: - emit(ofs, " r" + rd + " = (int)(hilo >>> 32);"); // MFHI - break; - - case 17: - emit(ofs, " hilo = (hilo & 0x00000000ffffffffL) | ((r" + rs + " & 0xffffffffL) << 32);"); // MTHI - break; - - case 18: - emit(ofs, " r" + rd + " = (int)hilo;"); // MFLO - break; - - case 19: - emit(ofs, " hilo = (hilo & 0xffffffff00000000L) | (r" + rs + " & 0xffffffffL);"); // MTLO - break; - - case 20: throw new Error("opcode 0, subcode 20 is not part of the MIPS I instruction set"); - case 22: throw new Error("opcode 0, subcode 22 is not part of the MIPS I instruction set"); - case 23: throw new Error("opcode 0, subcode 23 is not part of the MIPS I instruction set"); - - case 24: - emit(ofs, " hilo = ((long)r" + rs + ") * ((long)r" + rt + ");"); // MULT - break; - - case 25: - emit(ofs, " hilo = (r" + rs + " & 0xffffffffL) * (r" + rt + " & 0xffffffffL);"); // MULTU - break; - - case 26: - emit(ofs, " hilo = (((r" + rs + " % r" + rt +") & 0xffffffffL) << 32) | ((r" + rs + " / r" + rt +") & 0xffffffffL);"); // DIV - break; - - case 27: - emit(ofs, " hilo = (((r" + rs + " & 0xffffffffL) % (r" + rt +" & 0xffffffffL)) << 32) | " + // DIVU - "((r" + rs + " & 0xffffffffL) / (r" + rt +" & 0xffffffffL));"); - break; - - case 28: throw new Error("opcode 0, subcode 28 is not part of the MIPS I instruction set"); - case 29: throw new Error("opcode 0, subcode 29 is not part of the MIPS I instruction set"); - case 30: throw new Error("opcode 0, subcode 30 is not part of the MIPS I instruction set"); - case 31: throw new Error("opcode 0, subcode 31 is not part of the MIPS I instruction set"); - - case 32: - emit(ofs, " r" + rd + " = r" + rs + " + r" + rt + ";"); // ADD - break; - - case 33: - emit(ofs, " r" + rd + " = (int)(((r" + rs + " & 0xffffffffL) + (r" + rt + " & 0xffffffffL)));"); // ADDU - break; - - case 34: - emit(ofs, " r" + rd + " = r" + rs + " - r" + rt + ";"); // SUB - break; - - case 35: - emit(ofs, " r" + rd + " = (int)(((r" + rs + " & 0xffffffffL) - (r" + rt + " & 0xffffffffL)));"); // SUBU - break; - - case 36: - emit(ofs, " r" + rd + " = r" + rs + " & r" + rt + ";"); // AND - break; - - case 37: - emit(ofs, " r" + rd + " = r" + rs + " | r" + rt + ";"); // OR - break; - - case 38: - emit(ofs, " r" + rd + " = r" + rs + " ^ r" + rt + ";"); // XOR - break; - - case 39: - emit(ofs, " r" + rd + " = ~(r" + rs + " | r" + rt + ");"); // NOR - break; - - case 40: throw new Error("opcode 0, subcode 40 is not part of the MIPS I instruction set"); - case 41: throw new Error("opcode 0, subcode 41 is not part of the MIPS I instruction set"); - - case 42: - emit(ofs, " r" + rd + " = (r" + rs + " < r" + rt + ") ? 1 : 0;"); // SLT - break; - - case 43: - emit(ofs, " r" + rd + " = ((r" + rs + " & 0xffffffffL) < (r" + rt + " & 0xffffffffL)) ? 1 : 0;"); // SLTU - break; - - case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: - case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: - throw new Error("opcode 0, subcode " + subcode + " is not part of the MIPS I instruction set"); - default: - throw new Error("opcode 0, subcode " + subcode + " is not a valid MIPS instruction"); + case 0: // ADD.S + emit(pc, setFloat(fd,getFloat(fs)+"+"+getFloat(ft))); + break; + case 1: // SUB.S + emit(pc, setFloat(fd,getFloat(fs)+"-"+getFloat(ft))); + break; + case 2: // MUL.S + emit(pc, setFloat(fd,getFloat(fs)+"*"+getFloat(ft))); + break; + case 3: // DIV.S + emit(pc, setFloat(fd,getFloat(fs)+"/"+getFloat(ft))); + break; + case 5: // ABS.S + emit(pc, setFloat(fd,Math.abs("+getFloat(fs)+"))); + break; + case 6: // MOV.S + emit(pc, f"+fd+" = f"+fs+"); + break; + case 7: // NEG.S + emit(pc, setFloat(fd,"-1 * ("+getFloat(fs)+")")); // FIXME: just flip the sign bi)t + break; + case 33: // CVT.D.S + emit(pc, setDouble(fd,getFloat(fs))); + break; + case 36: // CVT.W.S + switch(roundingMode()) { + case 0: emit(pc, "f"+fd+" = (int)Math.floor("+getFloat(fs)+"+0.5f;"); break; // Round to nearest + case 1: emit(pc, "f"+fd+" = (int)"+getFloat(fs)+";"); break; // Round towards zero + case 2: emit(pc, "f"+fd+" = (int)Math.ceil("+getFloat(fs)+";"); break; // Round towards plus infinity + case 3: emit(pc, "f"+fd+" = (int)Math.floor("+getFloat(fs)+";"); break; // Round towards minus infinity + } + break; + /* FIXME: not implemented yet + case -50: // C.EQ.S + setFC("+getFloat(fs)+" == "+getFloat(ft)+"); // FIXME: just compare the ints, be sure things are normalized + break; + case 60: // C.LT.S + setFC("+getFloat(fs)+" < "+getFloat(ft)+"); + break; + */ + default: throw new RuntimeException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc)); } break; } - - case 1: { - switch(rt) { - case 0: - _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction); - emit(ofs, " if (r" + rs + " < 0) { pc += " + (branch_offset + 4) + "; return; }; "); // BLTZ - break; - - case 1: - _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction); - emit(ofs, " if (r" + rs + " >= 0) { pc += " + (branch_offset + 4) + "; return; }; "); // BGEZ - break; - - case 16: - _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction); - emit(ofs, " r31 = pc + 4; if (r" + rs + " < 0) { pc += " + (branch_offset + 4) + "; return; }; "); // BLTZAL + case 17: { // Double + switch(subcode) { + case 0: // ADD.D + emit(pc, "setDouble(fd,"+getDouble(fs)+"+"+getDouble(ft)+");"); + break; + case 1: // SUB.D + emit(pc, "setDouble(fd,"+getDouble(fs)+"-"+getDouble(ft)+");"); + break; + case 2: // MUL.D + emit(pc, "setDouble(fd,"+getDouble(fs)+"*"+getDouble(ft)+");"); + break; + case 3: // DIV.D + emit(pc, "setDouble(fd,"+getDouble(fs)+"/"+getDouble(ft)+");"); + break; + case 5: // ABS.D + emit(pc, "setDouble(fd,Math.abs("+getDouble(fs)+"));"); + break; + case 6: // MOV.D + emit(pc, "f"+fd+" = f"+fs+";"); + emit(pc, "f"+fd+1+" = f"+fs+1+";"); + break; + case 7: // NEG.D + emit(pc, "setDouble(fd,-"+getDouble(fs)+");"); // FIXME: just flip the sign bit" + break; + case 32: // CVT.S.D + emit(pc, "setFloat(fd,(float)"+getDouble(fs)+");"); + break; + case 36: // CVT.W.D + switch(roundingMode()) { + case 0: emit(pc, "f"+fd+" = (int)Math.floor("+getDouble(fs)+"+0.5);"); break; // Round to nearest + case 1: emit(pc, "f"+fd+" = (int)"+getDouble(fs)+";"); break; // Round towards zero + case 2: emit(pc, "f"+fd+" = (int)Math.ceil("+getDouble(fs)+");"); break; // Round towards plus infinity + case 3: emit(pc, "f"+fd+" = (int)Math.floor("+getDouble(fs)+");"); break; // Round towards minus infinity + } + break; + /* FIXME not implemented yet + case 50: // C.EQ.D + setFC("+getDouble(fs)+" == "+getDouble(ft)+"); // FIXME: just compare the ints, be sure things are normalized + 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 EmulationException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc)); + } break; - - case 17: - _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction); - emit(ofs, " r31 = pc + 4; if (r" + rs + " >= 0) { pc += " + (branch_offset + 4) + "; return; }; "); // BGEZAL + } + case 20: { // Integer + switch(subcode) { + case 33: // CVT.D.W + emit(pc, "setDouble(fd,(double)f"+fs+");"); + break; + default: throw new EmulationException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc)); + } break; - - default: throw new Error("opcode 1, subcode " + rt + " is not part of the MIPS I instruction set"); } - break; + default: + throw new RuntimeException("Invalid Instruction 17/" + rs); + } + case 18: case 19: + throw new RuntimeException("No coprocessor installed"); + case 32: { // LB + /* FIXME not done yet + emit(pc, "addr = r"+rs+" + "+signedImmediate+";"); + try { + int tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1]; + } catch(RuntimeException e) { + int tmp = memRead(addr&~3); } - - case 2: - _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction); - emit(ofs, " pc &= 0xf0000000; pc |= 0x" + Long.toString(jump_target & 0xffffffffL, 16) + "; return;"); // J - break; - - case 3: - _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction); - emit(ofs, " r31 = pc + 4; pc &= 0xf0000000; pc |= 0x" + Long.toString(jump_target & 0xffffffffL, 16) + "; return;"); // JAL - break; - - case 4: - _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction); - emit(ofs, " if (r" + rs + " == r" + rt + ") { pc += 0x" + Long.toString((branch_offset + 4) & 0xffffffffL, 16) + "; return; }; "); // BEQ - break; - - case 5: - _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction); - emit(ofs, " if (r" + rs + " != r" + rt + ") { pc += 0x" + Long.toString((branch_offset + 4) & 0xffffffffL, 16) + "; return; }; "); // BNE - break; - - case 6: - _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction); - emit(ofs, " if (r" + rs + " <= 0) { pc += 0x" + Long.toString((branch_offset + 4) & 0xffffffffL, 16) + "; return; }; "); // BLEZ - break; - - case 7: - _instruction = dis.readInt(); readnext = false; emit_instruction(ofs, _instruction); - emit(ofs, " if (r" + rs + " > 0) { pc += 0x" + Long.toString((branch_offset + 4) & 0xffffffffL, 16) + "; return; }; "); // BGTZ - break; - - case 8: case 9: - emit(ofs, " r" + rt + " = r" + rs + " + " + signed_immediate + ";"); // ADDI[U] - break; - - case 10: - emit(ofs, " r" + rt + " = (r" + rs + " < " + signed_immediate + ") ? 1 : 0;"); // SLTI - break; - - case 11: - emit(ofs, " r" + rt + " = ((r" + rs + " & 0xffffffffL) < (" + signed_immediate + " & 0xffffffffL)) ? 1 : 0;"); // SLTIU - break; - - case 12: - emit(ofs, " r" + rt + " = r" + rs + " & " + unsigned_immediate + ";"); // ANDI - break; - - case 13: - emit(ofs, " r" + rt + " = r" + rs + " | " + unsigned_immediate + ";"); // ORI - break; - - case 14: - emit(ofs, " r" + rt + " = r" + rs + " ^ " + unsigned_immediate + ";"); // XORI - break; - - case 15: - emit(ofs, " r" + rt + " = " + unsigned_immediate + " << 16;"); // LUI - break; - - case 16: /* throw new Error("coprocessor instructions (opcode 16) are not implemented"); */ - emit(ofs, " throw new Error(\"coprocessor instructions (opcode 16) are not implemented\");"); - break; - case 17: throw new Error("coprocessor instructions (opcode 17) are not implemented"); - case 18: throw new Error("coprocessor instructions (opcode 18) are not implemented"); - - case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: - throw new Error("opcode " + op + " is not part of the MIPS I instruction set @" + Long.toString(ofs & 0xffffffffL, 16)); - - case 32: { - String dest = "(r" + rs + " + " + signed_immediate + ")"; - emit(ofs, " tmp = mem_read[" + dest + ">>>16][" + dest + " & 0xffff]; r" + rt + " = ((tmp & 0x80) << 24) | (tmp & 0x7f);"); // LB - break; + switch(addr&3) { + case 0: int tmp = (tmp>>>24)&0xff; break; + case 1: int tmp = (tmp>>>16)&0xff; break; + case 2: int tmp = (tmp>>> 8)&0xff; break; + case 3: int tmp = (tmp>>> 0)&0xff; break; } - - case 33: { - String dest = "(r" + rs + " + " + signed_immediate + ")"; - emit(ofs, " tmp = mem_read[" + dest + ">>>16][" + dest + " & 0xffff]; r" + rt + " = ((tmp & 0x8000) << 16) | (tmp & 0x7fff);"); // LH - break; + if((tmp&0x80)!=0) tmp |= 0xffffff00; // sign extend + r"+rt+" = tmp; + */ + break; + } + case 33: { // LH + /* FIXME not done yet + addr = r"+rs+" + signedImmediate; + try { + int tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1]; + } catch(RuntimeException e) { + int tmp = memRead(addr&~3); } - - case 34: - emit(ofs, " throw new Error(\"LWL (opcode 34) is not supported; are you sure you used -mstrict-align?\");"); - break; - - case 35: { - String dest = "(r" + rs + " + " + signed_immediate + ")"; - emit(ofs, " r" + rt + " = mem_read[" + dest + ">>>16][" + dest + " & 0xffff];"); // LW - break; + switch(addr&2) { + case 0: int tmp = (tmp>>>16)&0xffff; break; + case 2: int tmp = (tmp>>> 0)&0xffff; break; } - - case 36: { - String dest = "(r" + rs + " + " + signed_immediate + ")"; - emit(ofs, " r" + rt + " = mem_read[" + dest + ">>>16][" + dest + " & 0xffff] & 0xff;"); // LBU - break; + if((tmp&0x8000)!=0) tmp |= 0xffff0000; // sign extend + r"+rt+" = tmp; + break; + */ + } + /* FIXME not done yet + case 34: { // LWL; + addr = r"+rs+" + signedImmediate; + try { + int tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1]; + } catch(RuntimeException e) { + int tmp = memRead(addr&~3); } - - case 37: { - String dest = "(r" + rs + " + " + signed_immediate + ")"; - emit(ofs, " r" + rt + " = mem_read[" + dest + ">>>16][" + dest + " & 0xffff] & 0xffff;"); // LHU - break; + 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; } - - case 38: - emit(ofs, " throw new Error(\"LWR (opcode 38) is not supported; are you sure you used -mstrict-align?\");"); - break; - - case 39: throw new Error("opcode 39 is not part of the MIPS I instruction set"); - - case 40: { - String dest = "(r" + rs + " + " + signed_immediate + ")"; - emit(ofs, " tmp = mem_read[" + dest + ">>>16][" + dest + " & 0xffff]; " + - "mem_write[" + dest + ">>>16][" + dest + " & 0xffff] = (tmp & 0xffffff00) | (r" + rt + " & 0xff);"); // SB - 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); } - - case 41: { - String dest = "(r" + rs + " + " + signed_immediate + ")"; - emit(ofs, " tmp = mem_read[" + dest + ">>>16][" + dest + " & 0xffff]; " + - "mem_write[" + dest + ">>>16][" + dest + " & 0xffff] = (tmp & 0xffff0000) | (r" + rt + " & 0xffff);"); // SH - break; + break; + case 36: { // LBU + addr = r"+rs+" + signedImmediate; + try { + int tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1]; + } catch(RuntimeException e) { + int tmp = memRead(addr); } - - case 42: - emit(ofs, " throw new Error(\"SWL (opcode 42) is not supported; are you sure you used -mstrict-align?\");"); - break; - - case 43: { - String dest = "(r" + rs + " + " + signed_immediate + ")"; - emit(ofs, " mem_write[" + dest + ">>>16][" + dest + " & 0xffff] = r" + rt + ";"); // SW - break; + 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; } - - case 44: throw new Error("opcode 44 is not part of the MIPS I instruction set"); - case 45: throw new Error("opcode 45 is not part of the MIPS I instruction set"); - - case 46: - emit(ofs, " throw new Error(\"SWR (opcode 46) is not supported; are you sure you used -mstrict-align?\");"); - break; - - case 47: throw new Error("opcode 47 is not part of the MIPS I instruction set"); - case 48: throw new Error("opcode 48 is not part of the MIPS I instruction set"); - - case 49: - emit(ofs, " throw new Error(\"floating point operations (opcode 49) are not yet supported\");"); - break; - - case 50: - emit(ofs, " throw new Error(\"floating point operations (opcode 50) are not yet supported\");"); - break; - - case 51: case 52: case 53: case 54: case 55: case 56: - throw new Error("opcode " + op + " is not part of the MIPS I instruction set"); - - case 57: - emit(ofs, " throw new Error(\"floating point operations (opcode 57) are not yet supported\");"); - break; - - case 58: - emit(ofs, " throw new Error(\"floating point operations (opcode 58) are not yet supported\");"); - break; - - case 60: case 61: case 62: case 63: - throw new Error("opcode " + op + " is not part of the MIPS I instruction set"); - - default: - throw new Error("unknown opcode " + op); + break; + } + case 37: { // LHU + addr = r"+rs+" + signedImmediate; + try { + int tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1]; + } catch(RuntimeException e) { + int 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 { + int tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1]; + } catch(RuntimeException e) { + int 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 { + int tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1]; + } catch(RuntimeException e) { + int tmp = memRead(addr&~3); + } + switch(addr&3) { + case 0: int tmp = (tmp&0x00ffffff) | ((r"+rt+"&0xff)<<24); break; + case 1: int tmp = (tmp&0xff00ffff) | ((r"+rt+"&0xff)<<16); break; + case 2: int tmp = (tmp&0xffff00ff) | ((r"+rt+"&0xff)<< 8); break; + case 3: int 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 { + int tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&PAGE_WORDS-1]; + } catch(RuntimeException e) { + int tmp = memRead(addr&~3); + } + switch(addr&2) { + case 0: int tmp = (tmp&0x0000ffff) | ((r"+rt+"&0xffff)<<16); break; + case 2: int 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; + int 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; + int 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; + } + case 49: // LWC1 + f"+rt+" = memRead(r"+rs+" + signedImmediate); + break; + case 57: // SWC1 + memWrite(r"+rs+" + signedImmediate,f"+rt+"); + break; + default: + throw new EmulationException("Invalid Instruction: " + op); + */ + } + } + static String prefix = ""; static void emit(int vaddr, String s) { if (s.indexOf("r0 = ") != -1) s = " /* NOP */"; if (!s.trim().endsWith("return;") && s.indexOf("throw") == -1) s += " pc = 0x" + Long.toString((vaddr + 4) & 0xffffffffL,16) + ";"; System.out.println(s); } + + static String getFloat(int r) { return "Float.intBitsToFloat(f"+r+")"; } + static String getDouble(int r) { + return "Double.longBitsToDouble(((f"+r+"&0xffffffffL) << 32) | (f"+r+"&0xffffffffL));"; + } + static String setFloat(int r, String expr) { return "f"+r+" = Float.floatToRawIntBits("+expr+");" } + static String setDouble(int r, String expr) { + return "{ long l = Double.doubleToLongBits("+expr+"); "+ + "f"+(r+1)+" = (int)(l >>> 32); f"+(r)+" = (int)l; }"; + } } diff --git a/src/org/xwt/mips/ELF.java b/src/org/xwt/mips/ELF.java index 8f2c771..91dd79d 100644 --- a/src/org/xwt/mips/ELF.java +++ b/src/org/xwt/mips/ELF.java @@ -101,6 +101,7 @@ class ELF { } public boolean writable() { return (flags & PF_W) != 0; } + public boolean executable() { return (flags & PF_X) != 0; } public InputStream getInputStream() throws IOException { return new BufferedInputStream(new SectionInputStream( -- 1.7.10.4