-
- 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 2: { // J
+ if(pc == -1) throw new Error("pc modifying insn in delay slot");
+ emitInstruction(-1,nextInsn,-1);
+ branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
+ unreachable = true;
+ break;
+ }
+ case 3: { // JAL
+ if(pc == -1) throw new Error("pc modifying insn in delay slot");
+ emitInstruction(-1,nextInsn,-1);
+ p("r" + RA + "=" + toHex(pc+8 /*skip this insn and delay slot*/) + ";");
+ branch(pc, (pc&0xf0000000)|(jumpTarget << 2));
+ unreachable = true;
+ break;
+ }
+ case 4: // BEQ
+ if(pc == -1) throw new Error("pc modifying insn in delay slot");
+ p("// BEQ");
+ p("if(r" + rs + " == r" + rt + ") {");
+ indent++;
+ emitInstruction(-1,nextInsn,-1);
+ branch(pc,pc+branchTarget*4+4);
+ indent--;
+ p("}");
+ break;
+ case 5: // BNE
+ if(pc == -1) throw new Error("pc modifying insn in delay slot");
+ p("if(r" + rs + " != r" + rt + ") {");
+ indent++;
+ emitInstruction(-1,nextInsn,-1);
+ branch(pc,pc+branchTarget*4+4);
+ indent--;
+ p("}");
+ break;
+ case 6: //BLEZ
+ if(pc == -1) throw new Error("pc modifying insn in delay slot");
+ p("if(r" + rs + " <= 0) {");
+ indent++;
+ emitInstruction(-1,nextInsn,-1);
+ branch(pc,pc+branchTarget*4+4);
+ indent--;
+ p("}");
+ break;
+ case 7: //BGTZ
+ if(pc == -1) throw new Error("pc modifying insn in delay slot");
+ p("if(r" + rs + " > 0) {");
+ indent++;
+ emitInstruction(-1,nextInsn,-1);
+ branch(pc,pc+branchTarget*4+4);
+ indent--;
+ p("}");
+ break;
+ case 8: // ADDI
+ p( "r"+rt+" = r"+rs+" + "+signedImmediate +";");
+ break;
+ case 9: // ADDIU
+ p( "r"+rt+" = r"+rs+" + "+signedImmediate+";");
+ break;
+ case 10: // SLTI
+ p( "r"+rt+" = r"+rs+" < "+signedImmediate+" ? 1 : 0;");
+ break;
+ case 11: // SLTIU
+ p( "r"+rt+" = (r"+rs+"&0xffffffffL) < ("+unsignedImmediate+"&0xffffffffL) ? 1 : 0;");
+ break;
+ case 12: // ANDI
+ p( "r"+rt+" = r"+rs+" & "+unsignedImmediate+";");
+ break;
+ case 13: // ORI
+ p( "r"+rt+" = r"+rs+" | "+unsignedImmediate+";");
+ break;
+ case 14: // XORI
+ p( "r"+rt+" = r"+rs+" ^ "+unsignedImmediate+";");
+ break;
+ case 15: // LUI
+ p( "r"+rt+" = "+unsignedImmediate+" << 16;");
+ break;
+ case 16:
+ throw new CompilationException("TLB/Exception support not implemented");
+ case 17: { // FPU
+ switch(rs) {
+ case 0: // MFC.1
+ p( "r"+rt+" = f"+rd+";");
+ break;
+ case 2: // CFC.1
+ if(fs != 31) throw new CompilationException("FCR " + fs + " unavailable");
+ p( "r"+rt+" = fcsr;");
+ break;
+ case 4: // MTC.1
+ p( "f"+rd+" = r"+rt+";");
+ break;
+ case 6: // CTC.1
+ if(fs != 31) throw new CompilationException("FCR " + fs + " unavailable");
+ p( "fcsr = r"+rt+";");
+ break;
+ case 8: {// BC1F, BC1T
+ tmp = (insn>>>16)&1;
+ p("//BC1F, BC1T");
+ p("if(((fcsr&0x800000)!=0) == (" + tmp + "!=0)) {");
+ indent++;
+ emitInstruction(-1,nextInsn,-1);
+ branch(pc,pc+branchTarget*4+4);
+ indent--;
+ p("}");
+ break;
+ }
+ case 16: { // Single
+ switch(subcode) {
+ case 0: // ADD.S
+ p(setFloat(fd,getFloat(fs)+"+"+getFloat(ft)));
+ break;
+ case 1: // SUB.S
+ p(setFloat(fd,getFloat(fs)+"-"+getFloat(ft)));
+ break;
+ case 2: // MUL.S
+ p(setFloat(fd,getFloat(fs)+"*"+getFloat(ft)));
+ break;
+ case 3: // DIV.S
+ p(setFloat(fd,getFloat(fs)+"/"+getFloat(ft)));
+ break;
+ case 5: // ABS.S
+ p(setFloat(fd,"Math.abs("+getFloat(fs)+")"));
+ break;
+ case 6: // MOV.S
+ p("f"+fd+" = f"+fs+"; // MOV.S");
+ break;
+ case 7: // NEG.S
+ p(setFloat(fd,"-"+getFloat(fs))); // FEATURE: just flip the sign bit
+ break;
+ case 33: // CVT.D.S
+ p(setDouble(fd,"(float)"+getFloat(fs)));
+ break;
+ case 36: // CVT.W.D
+ p("// CVT.W.D");
+ p("switch(roundingMode()) {");
+ indent++;
+ p("case 0: f"+fd+" = (int)Math.floor("+getFloat(fs)+"+0.5); break; // Round to nearest");
+ p("case 1: f"+fd+" = (int)"+getFloat(fs)+"; break; // Round towards zero");
+ p("case 2: f"+fd+" = (int)Math.ceil("+getFloat(fs)+"); break; // Round towards plus infinity");
+ p("case 3: f"+fd+" = (int)Math.floor("+getFloat(fs)+"); break; // Round towards minus infinity");
+ indent--;
+ p("}");
+ break;
+ case 50: // C.EQ.D
+ p("setFC("+getFloat(fs)+"=="+getFloat(ft)+");"); // FEATURE: just compare the ints, be sure things are normalized
+ break;
+ case 60: // C.LT.D
+ p("setFC("+getFloat(fs)+"<"+getFloat(ft)+");");
+ break;
+ case 62: // C.LE.D
+ p("setFC("+getFloat(fs)+"<="+getFloat(ft)+");");
+ break;
+ default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
+ }
+ break;
+ }
+ case 17: { // Double
+ switch(subcode) {
+ case 0: // ADD.D
+ p(setDouble(fd,getDouble(fs)+"+"+getDouble(ft)));
+ break;
+ case 1: // SUB.D
+ p(setDouble(fd,getDouble(fs)+"-"+getDouble(ft)));
+ break;
+ case 2: // MUL.D
+ p(setDouble(fd,getDouble(fs)+"*"+getDouble(ft)));
+ break;
+ case 3: // DIV.D
+ p(setDouble(fd,getDouble(fs)+"/"+getDouble(ft)));
+ break;
+ case 5: // ABS.D
+ p(setDouble(fd,"Math.abs("+getDouble(fs)+")"));
+ break;
+ case 6: // MOV.D
+ p("f"+fd+" = f"+fs+";");
+ p("f"+(fd+1)+" = f"+(fs+1)+";");
+ break;
+ case 7: // NEG.D
+ p(setDouble(fd,"-"+getDouble(fs))); // FEATURE: just flip the sign bit
+ break;
+ case 32: // CVT.S.D
+ p(setFloat(fd,"(float)"+getDouble(fs)));
+ break;
+ case 36: // CVT.W.D
+ p("// CVT.W.D");
+ p("switch(roundingMode()) {");
+ indent++;
+ p("case 0: f"+fd+" = (int)Math.floor("+getDouble(fs)+"+0.5); break; // Round to nearest");
+ p("case 1: f"+fd+" = (int)"+getDouble(fs)+"; break; // Round towards zero");
+ p("case 2: f"+fd+" = (int)Math.ceil("+getDouble(fs)+"); break; // Round towards plus infinity");
+ p("case 3: f"+fd+" = (int)Math.floor("+getDouble(fs)+"); break; // Round towards minus infinity");
+ indent--;
+ p("}");
+ break;
+ case 50: // C.EQ.D
+ p("setFC("+getDouble(fs)+"=="+getDouble(ft)+");"); // FEATURE: just compare the ints, be sure things are normalized
+ break;
+ case 60: // C.LT.D
+ p("setFC("+getDouble(fs)+"<"+getDouble(ft)+");");
+ break;
+ case 62: // C.LE.D
+ p("setFC("+getDouble(fs)+"<="+getDouble(ft)+");");
+ break;
+ default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
+ }
+ break;
+ }
+ case 20: { // Integer
+ switch(subcode) {
+ case 32: // CVT.S.W
+ p(" // CVS.S.W");
+ p(setFloat(fd,"((float)f"+fs+")"));
+ break;
+ case 33: // CVT.D.W
+ p("// CVT.D.W");
+ p(setDouble(fd,"((double)f"+fs+")"));
+ break;
+ default: throw new CompilationException("Invalid Instruction 17/" + rs + "/" + subcode);
+ }
+ break;
+ }
+ default:
+ throw new CompilationException("Invalid Instruction 17/" + rs);