2003/11/10 22:14:43
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:41:08 +0000 (07:41 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:41:08 +0000 (07:41 +0000)
darcs-hash:20040130074108-2ba56-2456ed2f6ab1fce901784191169dcabd64b4a020.gz

src/org/xwt/mips/Compiler.java
src/org/xwt/mips/ELF.java

index f47d160..21fe7e5 100644 (file)
@@ -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<sh_num_entries; i++) {
-            p_name[i] = dis.readInt();
-            p_type[i] = dis.readInt();
-            dis.skip(4);
-            addr[i] = dis.readInt();
-            p_ofs[i] = dis.readInt();
-            p_size[i] = dis.readInt();
-            dis.skip(sh_entry_size - 4 * 6);
-        }
-
-        dis.close();
-        dis = new DataInputStream(new FileInputStream(s[1]));
-
-        int seek = p_ofs[string_table_section_number];
-        while (seek > 0) seek -= dis.skip(seek);
-        char[] stringTable = new char[p_size[string_table_section_number]];
-        for(int i=0; i<p_size[string_table_section_number]; i++)
-            stringTable[i] = (char)dis.readByte();
-
-        dis.close();
-        dis = new DataInputStream(new FileInputStream(s[1]));
-
-        int pos = 0;
-        for(int i=0; i<sh_num_entries; i++) {
-
-            String name = "";
-            for(int j=p_name[i]; j<stringTable.length && stringTable[j] != 0; j++) name += stringTable[j];
-            System.out.println();
-            System.out.println(prefix + "// section \"" + name +
-                               "\" #" + i + "; file offset 0x" + Long.toString(p_ofs[i] & 0xffffffffL, 16) +
-                               ", vma 0x" + Long.toString(addr[i] & 0xffffffffL, 16) + 
-                               ", size 0x" + Long.toString(p_size[i] & 0xffffffff, 16));
-
-            if (name.equals(".sdata")) {
-        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;
-        }
-                pos = 0; dis.close(); dis = new DataInputStream(new FileInputStream(s[1]));
-                while(pos < p_ofs[i]) pos += dis.skip(p_ofs[i] - pos);
-                String base = "0x" + Long.toString((addr[i] & 0xffff0000L) >> 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<STACK_PAGES; i++)
+            readPages[TOTAL_PAGES-1-i] = writePages[TOTAL_PAGES-1-i] = emptyPage;
+
+        // FIXME: what is this?
+        int brk = 0;
+        for(int i=0;i<pheaders.length;i++) {
+            ELF.PHeader ph = pheaders[i];
+            if(ph.type != ELF.PHeader.PT_LOAD) continue;
+            int memsize = ph.memsz;
+            int filesize = ph.filesz;
+            if(memsize == 0) continue;
+            if(memsize < 0) throw new IOException("pheader size too large");
+            int addr = ph.vaddr;
+            if(addr == 0x0) throw new IOException("pheader vaddr == 0x0");
+            if(addr+memsize >= (brk<<PAGE_SHIFT)) brk = (addr+memsize+PAGE_SIZE-1) >> PAGE_SHIFT;
+            // FIXME: set memsize, serialize readPages/writePages
+            for(int j=0;j<memsize+PAGE_SIZE-1;j+=PAGE_SIZE) {
+                int page = (j+addr) >>> 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 <tt>numbytes</tt> from the stream, emitting <tt>case</tt> blocks starting at vaddr <tt>ofs</tt> */
     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; }";
+    }
 }
 
index 8f2c771..91dd79d 100644 (file)
@@ -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(