/* This file is part of jpcsp. Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.Allegrex; import static jpcsp.Allegrex.Common.Instruction.FLAGS_BRANCH_INSTRUCTION; import static jpcsp.Allegrex.Common.Instruction.FLAGS_LINK_INSTRUCTION; import static jpcsp.Allegrex.Common.Instruction.FLAG_CANNOT_BE_SPLIT; import static jpcsp.Allegrex.Common.Instruction.FLAG_COMPILED_PFX; import static jpcsp.Allegrex.Common.Instruction.FLAG_CONSUMES_VFPU_PFXT; import static jpcsp.Allegrex.Common.Instruction.FLAG_ENDS_BLOCK; import static jpcsp.Allegrex.Common.Instruction.FLAG_HAS_DELAY_SLOT; import static jpcsp.Allegrex.Common.Instruction.FLAG_IS_JUMPING; import static jpcsp.Allegrex.Common.Instruction.FLAG_SYSCALL; import static jpcsp.Allegrex.Common.Instruction.FLAG_USE_VFPU_PFXD; import static jpcsp.Allegrex.Common.Instruction.FLAG_USE_VFPU_PFXS; import static jpcsp.Allegrex.Common.Instruction.FLAG_USE_VFPU_PFXT; import static jpcsp.Allegrex.Common.Instruction.FLAG_WRITES_RD; import static jpcsp.Allegrex.Common.Instruction.FLAG_WRITES_RT; import static jpcsp.Allegrex.FpuState.IMPLEMENT_ROUNDING_MODES; import jpcsp.Emulator; import jpcsp.Processor; import jpcsp.Allegrex.Common.Instruction; import jpcsp.Allegrex.VfpuState.Vcr.PfxDst; import jpcsp.Allegrex.VfpuState.Vcr.PfxSrc; import jpcsp.Allegrex.compiler.CodeInstruction; import jpcsp.Allegrex.compiler.Compiler; import jpcsp.Allegrex.compiler.ICompilerContext; import jpcsp.Allegrex.compiler.RuntimeContext; import jpcsp.Allegrex.compiler.SequenceLWCodeInstruction; import jpcsp.Allegrex.compiler.SequenceSWCodeInstruction; import jpcsp.HLE.SyscallHandler; import jpcsp.util.Utilities; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; /** * This file has been auto-generated from Allegrex.isa file. * Changes are now performed directly in this file, * Allegrex.isa is no longer used. * * @author hli, gid15 */ public class Instructions { public static final Instruction NOP = new Instruction(0) { @Override public final String name() { return "NOP"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { return "nop"; } }; public static final Instruction ICACHE_INDEX_INVALIDATE = new Instruction(1) { @Override public final String name() { return "ICACHE INDEX INVALIDATE"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x04, (short)imm16, rs); } }; public static final Instruction ICACHE_INDEX_UNLOCK = new Instruction(2) { @Override public final String name() { return "ICACHE INDEX UNLOCK"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x06, (short)imm16, rs); } }; public static final Instruction ICACHE_HIT_INVALIDATE = new Instruction(3) { @Override public final String name() { return "ICACHE HIT INVALIDATE"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; int addr = processor.cpu.getRegister(rs) + (short) imm16; int size = 64; RuntimeContext.invalidateRange(addr, size); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x08, (short)imm16, rs); } }; public static final Instruction ICACHE_FILL = new Instruction(4) { @Override public final String name() { return "ICACHE FILL"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x0A, (short)imm16, rs); } }; public static final Instruction ICACHE_FILL_WITH_LOCK = new Instruction(5) { @Override public final String name() { return "ICACHE FILL WITH LOCK"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x0B, (short)imm16, rs); } }; public static final Instruction DCACHE_INDEX_WRITEBACK_INVALIDATE = new Instruction(6) { @Override public final String name() { return "DCACHE INDEX WRITEBACK INVALIDATE"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x14, (short)imm16, rs); } }; public static final Instruction DCACHE_INDEX_UNLOCK = new Instruction(7) { @Override public final String name() { return "DCACHE INDEX UNLOCK"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x16, (short)imm16, rs); } }; public static final Instruction DCACHE_CREATE_DIRTY_EXCLUSIVE = new Instruction(8) { @Override public final String name() { return "DCACHE CREATE DIRTY EXCLUSIVE"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x18, (short)imm16, rs); } }; public static final Instruction DCACHE_HIT_INVALIDATE = new Instruction(9) { @Override public final String name() { return "DCACHE HIT INVALIDATE"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x19, (short)imm16, rs); } }; public static final Instruction DCACHE_HIT_WRITEBACK = new Instruction(10) { @Override public final String name() { return "DCACHE HIT WRITEBACK"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x1A, (short)imm16, rs); } }; public static final Instruction DCACHE_HIT_WRITEBACK_INVALIDATE = new Instruction(11) { @Override public final String name() { return "DCACHE HIT WRITEBACK INVALIDATE"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x1B, (short)imm16, rs); } }; public static final Instruction DCACHE_CREATE_DIRTY_EXCLUSIVE_WITH_LOCK = new Instruction(12) { @Override public final String name() { return "DCACHE CREATE DIRTY EXCLUSIVE WITH LOCK"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x1C, (short)imm16, rs); } }; public static final Instruction DCACHE_FILL = new Instruction(13) { @Override public final String name() { return "DCACHE FILL"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x1E, (short)imm16, rs); } }; public static final Instruction DCACHE_FILL_WITH_LOCK = new Instruction(14) { @Override public final String name() { return "DCACHE FILL WITH LOCK"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int imm16 = (insn>>0)&65535; //int rs = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmCODEIMMRS("cache", 0x1F, (short)imm16, rs); } }; public static final Instruction SYSCALL = new Instruction(15, FLAG_SYSCALL) { @Override public final String name() { return "SYSCALL"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm20 = (insn>>6)&1048575; try { SyscallHandler.syscall(imm20); } catch (Exception e) { Emulator.log.error("syscall", e); } } @Override public void compile(ICompilerContext context, int insn) { context.compileSyscall(); } @Override public String disasm(int address, int insn) { int imm20 = (insn>>6)&1048575; return Common.disasmSYSCALL(imm20); } }; public static final Instruction ERET = new Instruction(16) { @Override public final String name() { return "ERET"; } @Override public final String category() { return "MIPS III"; } @Override public void interpret(Processor processor, int insn) { } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { return "eret"; } }; public static final Instruction BREAK = new Instruction(17) { @Override public final String name() { return "BREAK"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm20 = (insn>>6)&1048575; Emulator.log.error(String.format("0x%08X - Allegrex break 0x%05X", processor.cpu.pc, imm20)); // Pause the emulator only if not ignoring invalid memory accesses // (I'm too lazy to introduce a new configuration flag to ignore "break" instructions). if (!Processor.memory.isIgnoreInvalidMemoryAccess()) { Emulator.PauseEmuWithStatus(Emulator.EMU_STATUS_BREAK); } } @Override public void compile(ICompilerContext context, int insn) { context.storePc(); super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm20 = (insn>>6)&1048575; return Common.disasmBREAK(imm20); } }; public static final Instruction SYNC = new Instruction(18) { @Override public final String name() { return "SYNC"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { return "sync"; } }; public static final Instruction HALT = new Instruction(19) { @Override public final String name() { return "HALT"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { Emulator.log.error("Allegrex halt"); Emulator.PauseEmuWithStatus(Emulator.EMU_STATUS_HALT); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { return "halt"; } }; public static final Instruction MFIC = new Instruction(20) { @Override public final String name() { return "MFIC"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int rt = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int rt = (insn>>21)&31; return Common.disasmRT("mfic", rt); } }; public static final Instruction MTIC = new Instruction(21) { @Override public final String name() { return "MTIC"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int rt = (insn>>21)&31; } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int rt = (insn>>21)&31; return Common.disasmRT("mtic", rt); } }; public static final Instruction ADD = new Instruction(22, FLAG_WRITES_RD) { @Override public final String name() { return "ADD"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; // just ignore overflow exception as it is useless processor.cpu.doADDU(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRsRegister0() && context.isRtRegister0()) { context.storeRd(0); } else { context.prepareRdForStore(); if (context.isRsRegister0()) { context.loadRt(); } else { context.loadRs(); if (!context.isRtRegister0()) { context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.IADD); } } context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("add", rd, rs, rt); } }; public static final Instruction ADDU = new Instruction(23, FLAG_WRITES_RD) { @Override public final String name() { return "ADDU"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doADDU(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { ADD.compile(context, insn); } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("addu", rd, rs, rt); } }; public static final Instruction ADDI = new Instruction(24, FLAG_WRITES_RT) { @Override public final String name() { return "ADDI"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; // just ignore overflow exception as it is useless processor.cpu.doADDIU(rt, rs, (short)imm16); } @Override public void compile(ICompilerContext context, int insn) { ADDIU.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTRSIMM("addi", rt, rs, (short)imm16); } }; public static final Instruction ADDIU = new Instruction(25, FLAG_WRITES_RT) { @Override public final String name() { return "ADDIU"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doADDIU(rt, rs, (short)imm16); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { int imm = context.getImm16(true); if (context.isRsRegister0()) { context.storeRt(imm); } else if (imm == 0 && context.getRsRegisterIndex() == context.getRtRegisterIndex()) { // Incrementing a register by 0 is a No-OP: // ADDIU $reg, $reg, 0 } else { context.prepareRtForStore(); context.loadRs(); if (imm != 0) { context.loadImm(imm); context.getMethodVisitor().visitInsn(Opcodes.IADD); } context.storeRt(); } } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTRSIMM("addiu", rt, rs, (short)imm16); } }; public static final Instruction AND = new Instruction(26, FLAG_WRITES_RD) { @Override public final String name() { return "AND"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doAND(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRsRegister0() || context.isRtRegister0()) { context.storeRd(0); } else { context.prepareRdForStore(); context.loadRs(); context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.IAND); context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("and", rd, rs, rt); } }; public static final Instruction ANDI = new Instruction(27, FLAG_WRITES_RT) { @Override public final String name() { return "ANDI"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doANDI(rt, rs, imm16); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { int imm = context.getImm16(false); if (imm == 0 || context.isRsRegister0()) { context.storeRt(0); } else { context.prepareRtForStore(); context.loadRs(); context.loadImm(imm); context.getMethodVisitor().visitInsn(Opcodes.IAND); context.storeRt(); } } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTRSIMM("andi", rt, rs, imm16); } }; public static final Instruction NOR = new Instruction(28, FLAG_WRITES_RD) { @Override public final String name() { return "NOR"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doNOR(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRsRegister0() && context.isRtRegister0()) { // nor $zr, $zr is equivalent to storing -1 context.storeRd(-1); } else { context.prepareRdForStore(); if (context.isRsRegister0()) { context.loadRt(); } else { context.loadRs(); if (!context.isRtRegister0()) { // OR-ing a register with itself is a simple move. if (context.getRsRegisterIndex() != context.getRtRegisterIndex()) { context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.IOR); } } } context.loadImm(-1); context.getMethodVisitor().visitInsn(Opcodes.IXOR); context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("nor", rd, rs, rt); } }; public static final Instruction OR = new Instruction(29, FLAG_WRITES_RD) { @Override public final String name() { return "OR"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doOR(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRsRegister0() && context.isRtRegister0()) { context.storeRd(0); } else { context.prepareRdForStore(); if (context.isRsRegister0()) { context.loadRt(); } else { context.loadRs(); if (!context.isRtRegister0()) { // OR-ing a register with itself is a simple move. if (context.getRsRegisterIndex() != context.getRtRegisterIndex()) { context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.IOR); } } } context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("or", rd, rs, rt); } }; public static final Instruction ORI = new Instruction(30, FLAG_WRITES_RT) { @Override public final String name() { return "ORI"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doORI(rt, rs, imm16); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { int imm = context.getImm16(false); if (context.isRsRegister0()) { context.storeRt(imm); } else if (imm == 0 && context.getRsRegisterIndex() == context.getRtRegisterIndex()) { // Or-ing a register with 0 and himself is a No-OP: // ORI $reg, $reg, 0 } else { context.prepareRtForStore(); context.loadRs(); if (imm != 0) { context.loadImm(imm); context.getMethodVisitor().visitInsn(Opcodes.IOR); } context.storeRt(); } } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTRSIMM("ori", rt, rs, imm16); } }; public static final Instruction XOR = new Instruction(31, FLAG_WRITES_RD) { @Override public final String name() { return "XOR"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doXOR(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRsRegister0() && context.isRtRegister0()) { context.storeRd(0); } else if (context.getRtRegisterIndex() == context.getRsRegisterIndex()) { // XOR-ing a register with himself is equivalent to setting to 0. // XOR $rd, $rs, $rs context.storeRd(0); } else { context.prepareRdForStore(); if (context.isRsRegister0()) { context.loadRt(); } else { context.loadRs(); if (!context.isRtRegister0()) { context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.IXOR); } } context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("xor", rd, rs, rt); } }; public static final Instruction XORI = new Instruction(32, FLAG_WRITES_RT) { @Override public final String name() { return "XORI"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doXORI(rt, rs, imm16); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { int imm = context.getImm16(false); if (context.isRsRegister0()) { context.storeRt(imm); } else if (imm == 0 && context.getRtRegisterIndex() == context.getRsRegisterIndex()) { // XOR-ing a register with 0 and storing the result in the same register is a No-OP. // XORI $reg, $reg, 0 } else { context.prepareRtForStore(); context.loadRs(); if (imm != 0) { context.loadImm(imm); context.getMethodVisitor().visitInsn(Opcodes.IXOR); } context.storeRt(); } } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTRSIMM("xori", rt, rs, imm16); } }; public static final Instruction SLL = new Instruction(33, FLAG_WRITES_RD) { @Override public final String name() { return "SLL"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int sa = (insn>>6)&31; int rd = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doSLL(rd, rt, sa); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRtRegister0()) { context.storeRd(0); } else { context.prepareRdForStore(); context.loadRt(); int sa = context.getSaValue(); if (sa != 0) { context.loadImm(sa); context.getMethodVisitor().visitInsn(Opcodes.ISHL); } context.storeRd(); } } } @Override public String disasm(int address, int insn) { int sa = (insn>>6)&31; int rd = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRDRTSA("sll", rd, rt, sa); } }; public static final Instruction SLLV = new Instruction(34, FLAG_WRITES_RD) { @Override public final String name() { return "SLLV"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSLLV(rd, rt, rs); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRtRegister0()) { context.storeRd(0); } else { context.prepareRdForStore(); context.loadRt(); if (!context.isRsRegister0()) { context.loadRs(); context.loadImm(31); context.getMethodVisitor().visitInsn(Opcodes.IAND); context.getMethodVisitor().visitInsn(Opcodes.ISHL); } context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRTRS("sllv", rd, rt, rs); } }; public static final Instruction SRA = new Instruction(35, FLAG_WRITES_RD) { @Override public final String name() { return "SRA"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int sa = (insn>>6)&31; int rd = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doSRA(rd, rt, sa); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRtRegister0()) { context.storeRd(0); } else { context.prepareRdForStore(); context.loadRt(); int sa = context.getSaValue(); if (sa != 0) { context.loadImm(sa); context.getMethodVisitor().visitInsn(Opcodes.ISHR); } context.storeRd(); } } } @Override public String disasm(int address, int insn) { int sa = (insn>>6)&31; int rd = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRDRTSA("sra", rd, rt, sa); } }; public static final Instruction SRAV = new Instruction(36, FLAG_WRITES_RD) { @Override public final String name() { return "SRAV"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSRAV(rd, rt, rs); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRtRegister0()) { context.storeRd(0); } else { context.prepareRdForStore(); context.loadRt(); if (!context.isRsRegister0()) { context.loadRs(); context.loadImm(31); context.getMethodVisitor().visitInsn(Opcodes.IAND); context.getMethodVisitor().visitInsn(Opcodes.ISHR); } context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRTRS("srav", rd, rt, rs); } }; public static final Instruction SRL = new Instruction(37, FLAG_WRITES_RD) { @Override public final String name() { return "SRL"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int sa = (insn>>6)&31; int rd = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doSRL(rd, rt, sa); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRtRegister0()) { context.storeRd(0); } else { context.prepareRdForStore(); context.loadRt(); int sa = context.getSaValue(); if (sa != 0) { context.loadImm(sa); context.getMethodVisitor().visitInsn(Opcodes.IUSHR); } context.storeRd(); } } } @Override public String disasm(int address, int insn) { int sa = (insn>>6)&31; int rd = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRDRTSA("srl", rd, rt, sa); } }; public static final Instruction SRLV = new Instruction(38, FLAG_WRITES_RD) { @Override public final String name() { return "SRLV"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSRLV(rd, rt, rs); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRtRegister0()) { context.storeRd(0); } else { context.prepareRdForStore(); context.loadRt(); if (!context.isRsRegister0()) { context.loadRs(); context.loadImm(31); context.getMethodVisitor().visitInsn(Opcodes.IAND); context.getMethodVisitor().visitInsn(Opcodes.IUSHR); } context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRTRS("srlv", rd, rt, rs); } }; public static final Instruction ROTR = new Instruction(39, FLAG_WRITES_RD) { @Override public final String name() { return "ROTR"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int sa = (insn>>6)&31; int rd = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doROTR(rd, rt, sa); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRtRegister0()) { context.storeRd(0); } else { context.prepareRdForStore(); context.loadRt(); int sa = context.getSaValue(); if (sa != 0) { // rotateRight(rt, sa) = (rt >>> sa | rt << (32-sa)) context.getMethodVisitor().visitInsn(Opcodes.DUP); context.loadImm(sa); context.getMethodVisitor().visitInsn(Opcodes.IUSHR); context.getMethodVisitor().visitInsn(Opcodes.SWAP); context.loadImm(32 - sa); context.getMethodVisitor().visitInsn(Opcodes.ISHL); context.getMethodVisitor().visitInsn(Opcodes.IOR); } context.storeRd(); } } } @Override public String disasm(int address, int insn) { int sa = (insn>>6)&31; int rd = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRDRTSA("rotr", rd, rt, sa); } }; public static final Instruction ROTRV = new Instruction(40, FLAG_WRITES_RD) { @Override public final String name() { return "ROTRV"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doROTRV(rd, rt, rs); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRtRegister0()) { context.storeRd(0); } else { context.prepareRdForStore(); context.loadRt(); if (!context.isRsRegister0()) { // rotateRight(rt, rs) = (rt >>> rs | rt << -rs) context.loadRs(); context.loadImm(31); context.getMethodVisitor().visitInsn(Opcodes.IAND); context.getMethodVisitor().visitInsn(Opcodes.DUP2); context.getMethodVisitor().visitInsn(Opcodes.IUSHR); context.getMethodVisitor().visitInsn(Opcodes.DUP_X2); context.getMethodVisitor().visitInsn(Opcodes.POP); context.getMethodVisitor().visitInsn(Opcodes.INEG); context.getMethodVisitor().visitInsn(Opcodes.ISHL); context.getMethodVisitor().visitInsn(Opcodes.IOR); } context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRTRS("rotrv", rd, rt, rs); } }; public static final Instruction SLT = new Instruction(41, FLAG_WRITES_RD) { @Override public final String name() { return "SLT"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSLT(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.getRsRegisterIndex() == context.getRtRegisterIndex()) { context.storeRd(0); } else { MethodVisitor mv = context.getMethodVisitor(); Label ifLtLabel = new Label(); Label continueLabel = new Label(); context.prepareRdForStore(); if (context.isRsRegister0()) { // rd = 0 < rt ? 1 : 0 context.loadRt(); mv.visitJumpInsn(Opcodes.IFGT, ifLtLabel); } else if (context.isRtRegister0()) { // rd = rs < 0 ? 1 : 0 context.loadRs(); mv.visitJumpInsn(Opcodes.IFLT, ifLtLabel); } else { // rd = rs < rt ? 1 : 0 context.loadRs(); context.loadRt(); mv.visitJumpInsn(Opcodes.IF_ICMPLT, ifLtLabel); } context.loadImm(0); mv.visitJumpInsn(Opcodes.GOTO, continueLabel); mv.visitLabel(ifLtLabel); context.loadImm(1); mv.visitLabel(continueLabel); context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("slt", rd, rs, rt); } }; public static final Instruction SLTI = new Instruction(42, FLAG_WRITES_RT) { @Override public final String name() { return "SLTI"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSLTI(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { int simm16 = context.getImm16(true); if (context.isRsRegister0()) { context.storeRt(simm16 > 0 ? 1 : 0); } else { MethodVisitor mv = context.getMethodVisitor(); Label ifLtLabel = new Label(); Label continueLabel = new Label(); context.prepareRtForStore(); // rt = rs < simm16 ? 1 : 0 context.loadRs(); if (simm16 == 0) { mv.visitJumpInsn(Opcodes.IFLT, ifLtLabel); } else { context.loadImm(simm16); mv.visitJumpInsn(Opcodes.IF_ICMPLT, ifLtLabel); } context.loadImm(0); mv.visitJumpInsn(Opcodes.GOTO, continueLabel); mv.visitLabel(ifLtLabel); context.loadImm(1); mv.visitLabel(continueLabel); context.storeRt(); } } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTRSIMM("slti", rt, rs, (int)(short)imm16); } }; public static final Instruction SLTU = new Instruction(43, FLAG_WRITES_RD) { @Override public final String name() { return "SLTU"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSLTU(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.getRsRegisterIndex() == context.getRtRegisterIndex()) { // rd = x < x context.storeRd(0); } else if (context.isRtRegister0()) { // rd = rs < 0 context.storeRd(0); } else { MethodVisitor mv = context.getMethodVisitor(); Label ifLtLabel = new Label(); Label continueLabel = new Label(); context.prepareRdForStore(); if (context.isRsRegister0()) { // rd = 0 < rt ? 1 : 0 context.loadRt(); mv.visitJumpInsn(Opcodes.IFNE, ifLtLabel); } else { // rd = rs < rt ? 1 : 0 context.loadRs(); context.convertUnsignedIntToLong(); context.loadRt(); context.convertUnsignedIntToLong(); mv.visitInsn(Opcodes.LCMP); // -1 if rs < rt, 0 if rs == rt, 1 if rs > rt mv.visitJumpInsn(Opcodes.IFLT, ifLtLabel); } context.loadImm(0); mv.visitJumpInsn(Opcodes.GOTO, continueLabel); mv.visitLabel(ifLtLabel); context.loadImm(1); mv.visitLabel(continueLabel); context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("sltu", rd, rs, rt); } }; public static final Instruction SLTIU = new Instruction(44, FLAG_WRITES_RT) { @Override public final String name() { return "SLTIU"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSLTIU(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { int simm16 = context.getImm16(true); if (context.isRsRegister0()) { // rt = 0 < simm16 ? 1 : 0 context.storeRt(0 < simm16 ? 1 : 0); } else if (simm16 == 0) { // rt = rs < 0 context.storeRt(0); } else { MethodVisitor mv = context.getMethodVisitor(); Label ifLtLabel = new Label(); Label continueLabel = new Label(); context.prepareRtForStore(); if (simm16 == 1) { // rt = rs < 1 ? 1 : 0 <=> rt = rs == 0 ? 1 : 0 context.loadRs(); mv.visitJumpInsn(Opcodes.IFEQ, ifLtLabel); } else { // rt = rs < simm16 ? 1 : 0 context.loadRs(); context.convertUnsignedIntToLong(); mv.visitLdcInsn(((long) simm16) & 0xFFFFFFFFL); mv.visitInsn(Opcodes.LCMP); // -1 if rs < rt, 0 if rs == rt, 1 if rs > rt mv.visitJumpInsn(Opcodes.IFLT, ifLtLabel); } context.loadImm(0); mv.visitJumpInsn(Opcodes.GOTO, continueLabel); mv.visitLabel(ifLtLabel); context.loadImm(1); mv.visitLabel(continueLabel); context.storeRt(); } } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTRSIMM("sltiu", rt, rs, (int)(short)imm16); } }; public static final Instruction SUB = new Instruction(45, FLAG_WRITES_RD) { @Override public final String name() { return "SUB"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; // just ignore overflow exception as it is useless processor.cpu.doSUBU(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { // SUB $rd, $rs, $rs <=> li $rd, 0 if (context.getRsRegisterIndex() == context.getRtRegisterIndex()) { context.storeRd(0); } else { context.prepareRdForStore(); if (context.isRsRegister0()) { context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.INEG); } else { context.loadRs(); if (!context.isRtRegister0()) { context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.ISUB); } } context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("sub", rd, rs, rt); } }; public static final Instruction SUBU = new Instruction(46, FLAG_WRITES_RD) { @Override public final String name() { return "SUBU"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSUBU(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { SUB.compile(context, insn); } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("subu", rd, rs, rt); } }; public static final Instruction LUI = new Instruction(47, FLAG_WRITES_RT) { @Override public final String name() { return "LUI"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; processor.cpu.doLUI(rt, imm16); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { int uimm16 = context.getImm16(false); context.storeRt(uimm16 << 16); } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; return Common.disasmRTIMM("lui", rt, imm16); } }; public static final Instruction SEB = new Instruction(48, FLAG_WRITES_RD) { @Override public final String name() { return "SEB"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doSEB(rd, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { context.prepareRdForStore(); context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.I2B); context.storeRd(); } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRDRT("seb", rd, rt); } }; public static final Instruction SEH = new Instruction(49, FLAG_WRITES_RD) { @Override public final String name() { return "SEH"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doSEH(rd, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { context.prepareRdForStore(); context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.I2S); context.storeRd(); } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRDRT("seh", rd, rt); } }; public static final Instruction BITREV = new Instruction(50, FLAG_WRITES_RD) { @Override public final String name() { return "BITREV"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doBITREV(rd, rt); } @Override public void compile(ICompilerContext context, int insn) { context.compileRDRT("doBITREV"); } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRDRT("bitrev", rd, rt); } }; public static final Instruction WSBH = new Instruction(51, FLAG_WRITES_RD) { @Override public final String name() { return "WSBH"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doWSBH(rd, rt); } @Override public void compile(ICompilerContext context, int insn) { context.compileRDRT("doWSBH"); } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRDRT("wsbh", rd, rt); } }; public static final Instruction WSBW = new Instruction(52, FLAG_WRITES_RD) { @Override public final String name() { return "WSBW"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doWSBW(rd, rt); } @Override public void compile(ICompilerContext context, int insn) { context.compileRDRT("doWSBW"); } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRDRT("wsbw", rd, rt); } }; public static final Instruction MOVZ = new Instruction(53, FLAG_WRITES_RD) { @Override public final String name() { return "MOVZ"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doMOVZ(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { context.loadRt(); Label doNotChange = new Label(); context.getMethodVisitor().visitJumpInsn(Opcodes.IFNE, doNotChange); context.prepareRdForStore(); context.loadRs(); context.storeRd(); context.getMethodVisitor().visitLabel(doNotChange); } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("movz", rd, rs, rt); } }; public static final Instruction MOVN = new Instruction(54, FLAG_WRITES_RD) { @Override public final String name() { return "MOVN"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doMOVN(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { context.loadRt(); Label doNotChange = new Label(); context.getMethodVisitor().visitJumpInsn(Opcodes.IFEQ, doNotChange); context.prepareRdForStore(); context.loadRs(); context.storeRd(); context.getMethodVisitor().visitLabel(doNotChange); } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("movn", rd, rs, rt); } }; public static final Instruction MAX = new Instruction(55, FLAG_WRITES_RD) { @Override public final String name() { return "MAX"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doMAX(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { Label continueLabel = new Label(); if (context.getRdRegisterIndex() == context.getRtRegisterIndex()) { // When $rd==$rt: // if ($rs > $rt) { // $rd = $rs // } context.loadRs(); context.loadRt(); context.getMethodVisitor().visitJumpInsn(Opcodes.IF_ICMPLE, continueLabel); context.prepareRdForStore(); context.loadRs(); context.storeRd(); context.getMethodVisitor().visitLabel(continueLabel); } else if (context.getRdRegisterIndex() == context.getRsRegisterIndex()) { // When $rd==$rs: // if ($rs < $rt) { // $rd = $rt // } context.loadRs(); context.loadRt(); context.getMethodVisitor().visitJumpInsn(Opcodes.IF_ICMPGE, continueLabel); context.prepareRdForStore(); context.loadRt(); context.storeRd(); context.getMethodVisitor().visitLabel(continueLabel); } else if (context.getRsRegisterIndex() == context.getRtRegisterIndex()) { // When $rs==$rt: // $rd = $rs context.prepareRdForStore(); context.loadRs(); context.storeRd(); } else { // When $rd!=$rs and $rd!=$rt and $rs!=$rt: // if ($rs > $rt) { // $rd = $rs // } else { // $rd = $rt // } context.prepareRdForStore(); context.loadRs(); context.loadRt(); Label case1Label = new Label(); context.getMethodVisitor().visitJumpInsn(Opcodes.IF_ICMPLE, case1Label); context.loadRs(); context.getMethodVisitor().visitJumpInsn(Opcodes.GOTO, continueLabel); context.getMethodVisitor().visitLabel(case1Label); context.loadRt(); context.getMethodVisitor().visitLabel(continueLabel); context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("max", rd, rs, rt); } }; public static final Instruction MIN = new Instruction(56, FLAG_WRITES_RD) { @Override public final String name() { return "MIN"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doMIN(rd, rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { Label continueLabel = new Label(); if (context.getRdRegisterIndex() == context.getRtRegisterIndex()) { // When $rd==$rt: // if ($rs < $rt) { // $rd = $rs // } context.loadRs(); context.loadRt(); context.getMethodVisitor().visitJumpInsn(Opcodes.IF_ICMPGE, continueLabel); context.prepareRdForStore(); context.loadRs(); context.storeRd(); context.getMethodVisitor().visitLabel(continueLabel); } else if (context.getRdRegisterIndex() == context.getRsRegisterIndex()) { // When $rd==$rs: // if ($rs > $rt) { // $rd = $rt // } context.loadRs(); context.loadRt(); context.getMethodVisitor().visitJumpInsn(Opcodes.IF_ICMPLE, continueLabel); context.prepareRdForStore(); context.loadRt(); context.storeRd(); context.getMethodVisitor().visitLabel(continueLabel); } else if (context.getRsRegisterIndex() == context.getRtRegisterIndex()) { // When $rs==$rt: // $rd = $rs context.prepareRdForStore(); context.loadRs(); context.storeRd(); } else { // When $rd!=$rs and $rd!=$rt and $rs!=$rt: // if ($rs < $rt) { // $rd = $rs // } else { // $rd = $rt // } context.prepareRdForStore(); context.loadRs(); context.loadRt(); Label case1Label = new Label(); context.getMethodVisitor().visitJumpInsn(Opcodes.IF_ICMPGE, case1Label); context.loadRs(); context.getMethodVisitor().visitJumpInsn(Opcodes.GOTO, continueLabel); context.getMethodVisitor().visitLabel(case1Label); context.loadRt(); context.getMethodVisitor().visitLabel(continueLabel); context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRDRSRT("min", rd, rs, rt); } }; public static final Instruction CLZ = new Instruction(57, FLAG_WRITES_RD) { @Override public final String name() { return "CLZ"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rs = (insn>>21)&31; processor.cpu.doCLZ(rd, rs); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRsRegister0()) { context.storeRd(32); } else { context.prepareRdForStore(); context.loadRs(); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Integer.class), "numberOfLeadingZeros", "(I)I"); context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rs = (insn>>21)&31; return Common.disasmRDRS("clz", rd, rs); } }; public static final Instruction CLO = new Instruction(58, FLAG_WRITES_RD) { @Override public final String name() { return "CLO"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rs = (insn>>21)&31; processor.cpu.doCLO(rd, rs); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { if (context.isRsRegister0()) { context.storeRd(0); } else { context.prepareRdForStore(); context.loadRs(); context.loadImm(-1); context.getMethodVisitor().visitInsn(Opcodes.IXOR); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Integer.class), "numberOfLeadingZeros", "(I)I"); context.storeRd(); } } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rs = (insn>>21)&31; return Common.disasmRDRS("clo", rd, rs); } }; public static final Instruction EXT = new Instruction(59, FLAG_WRITES_RT) { @Override public final String name() { return "EXT"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int lsb = (insn>>6)&31; int msb = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doEXT(rt, rs, lsb, msb); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { int lsb = (insn>>6)&31; int msb = (insn>>11)&31; int mask = ~(~0 << (msb + 1)); if (context.isRsRegister0() || mask == 0) { context.storeRt(0); } else { context.prepareRtForStore(); context.loadRs(); if (lsb != 0) { context.loadImm(lsb); context.getMethodVisitor().visitInsn(Opcodes.IUSHR); } if (mask != 0xFFFFFFFF) { context.loadImm(mask); context.getMethodVisitor().visitInsn(Opcodes.IAND); } context.storeRt(); } } } @Override public String disasm(int address, int insn) { int lsb = (insn>>6)&31; int msb = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmEXT(rt, rs, lsb, msb); } }; public static final Instruction INS = new Instruction(60, FLAG_WRITES_RT) { @Override public final String name() { return "INS"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int lsb = (insn>>6)&31; int msb = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doINS(rt, rs, lsb, msb); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { int lsb = (insn>>6)&31; int msb = (insn>>11)&31; int mask = ~(~0 << (msb - lsb + 1)) << lsb; if (mask == 0xFFFFFFFF && context.isRsRegister0()) { context.storeRt(0); } else if (mask != 0) { context.prepareRtForStore(); if (mask == 0xFFFFFFFF) { context.loadRs(); if (lsb != 0) { context.loadImm(lsb); context.getMethodVisitor().visitInsn(Opcodes.ISHL); } } else { context.loadRt(); context.loadImm(~mask); context.getMethodVisitor().visitInsn(Opcodes.IAND); if (!context.isRsRegister0()) { context.loadRs(); if (lsb != 0) { context.loadImm(lsb); context.getMethodVisitor().visitInsn(Opcodes.ISHL); } if (mask != 0xFFFFFFFF) { context.loadImm(mask); context.getMethodVisitor().visitInsn(Opcodes.IAND); } context.getMethodVisitor().visitInsn(Opcodes.IOR); } } context.storeRt(); } } } @Override public String disasm(int address, int insn) { int lsb = (insn>>6)&31; int msb = (insn>>11)&31; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmINS(rt, rs, lsb, msb); } }; public static final Instruction MULT = new Instruction(61) { @Override public final String name() { return "MULT"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doMULT(rs, rt); } @Override public void compile(ICompilerContext context, int insn) { context.prepareHiloForStore(); if (context.isRsRegister0() || context.isRtRegister0()) { context.getMethodVisitor().visitLdcInsn(0L); } else { context.loadRs(); context.getMethodVisitor().visitInsn(Opcodes.I2L); context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.I2L); context.getMethodVisitor().visitInsn(Opcodes.LMUL); } context.storeHilo(); } @Override public String disasm(int address, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRSRT("mult", rs, rt); } }; public static final Instruction MULTU = new Instruction(62) { @Override public final String name() { return "MULTU"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doMULTU(rs, rt); } @Override public void compile(ICompilerContext context, int insn) { context.prepareHiloForStore(); if (context.isRsRegister0() || context.isRtRegister0()) { context.getMethodVisitor().visitLdcInsn(0L); } else { context.loadRs(); context.convertUnsignedIntToLong(); context.loadRt(); context.convertUnsignedIntToLong(); context.getMethodVisitor().visitInsn(Opcodes.LMUL); } context.storeHilo(); } @Override public String disasm(int address, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRSRT("multu", rs, rt); } }; public static final Instruction MADD = new Instruction(63) { @Override public final String name() { return "MADD"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doMADD(rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRsRegister0() && !context.isRtRegister0()) { context.prepareHiloForStore(); context.loadHilo(); context.loadRs(); context.getMethodVisitor().visitInsn(Opcodes.I2L); context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.I2L); context.getMethodVisitor().visitInsn(Opcodes.LMUL); context.getMethodVisitor().visitInsn(Opcodes.LADD); context.storeHilo(); } } @Override public String disasm(int address, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRSRT("madd", rs, rt); } }; public static final Instruction MADDU = new Instruction(64) { @Override public final String name() { return "MADDU"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doMADDU(rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRsRegister0() && !context.isRtRegister0()) { context.prepareHiloForStore(); context.loadHilo(); context.loadRs(); context.convertUnsignedIntToLong(); context.loadRt(); context.convertUnsignedIntToLong(); context.getMethodVisitor().visitInsn(Opcodes.LMUL); context.getMethodVisitor().visitInsn(Opcodes.LADD); context.storeHilo(); } } @Override public String disasm(int address, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRSRT("maddu", rs, rt); } }; public static final Instruction MSUB = new Instruction(65) { @Override public final String name() { return "MSUB"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doMSUB(rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRsRegister0() && !context.isRtRegister0()) { context.prepareHiloForStore(); context.loadHilo(); context.loadRs(); context.getMethodVisitor().visitInsn(Opcodes.I2L); context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.I2L); context.getMethodVisitor().visitInsn(Opcodes.LMUL); context.getMethodVisitor().visitInsn(Opcodes.LSUB); context.storeHilo(); } } @Override public String disasm(int address, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRSRT("msub", rs, rt); } }; public static final Instruction MSUBU = new Instruction(66) { @Override public final String name() { return "MSUBU"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doMSUBU(rs, rt); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRsRegister0() && !context.isRtRegister0()) { context.prepareHiloForStore(); context.loadHilo(); context.loadRs(); context.convertUnsignedIntToLong(); context.loadRt(); context.convertUnsignedIntToLong(); context.getMethodVisitor().visitInsn(Opcodes.LMUL); context.getMethodVisitor().visitInsn(Opcodes.LSUB); context.storeHilo(); } } @Override public String disasm(int address, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRSRT("msubu", rs, rt); } }; public static final Instruction DIV = new Instruction(67) { @Override public final String name() { return "DIV"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doDIV(rs, rt); } @Override public void compile(ICompilerContext context, int insn) { Label divideByZero = new Label(); Label afterInstruction = new Label(); context.loadRt(); context.getMethodVisitor().visitJumpInsn(Opcodes.IFEQ, divideByZero); context.loadRs(); context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.DUP2); context.getMethodVisitor().visitInsn(Opcodes.IREM); context.getMethodVisitor().visitInsn(Opcodes.I2L); context.loadImm(32); context.getMethodVisitor().visitInsn(Opcodes.LSHL); context.getMethodVisitor().visitInsn(Opcodes.DUP2_X2); context.getMethodVisitor().visitInsn(Opcodes.POP2); context.getMethodVisitor().visitInsn(Opcodes.IDIV); context.getMethodVisitor().visitInsn(Opcodes.I2L); context.getMethodVisitor().visitLdcInsn(0x00000000FFFFFFFFL); context.getMethodVisitor().visitInsn(Opcodes.LAND); context.getMethodVisitor().visitInsn(Opcodes.LOR); context.storeHilo(); context.getMethodVisitor().visitJumpInsn(Opcodes.GOTO, afterInstruction); // Division by zero handled by the interpreted instruction context.getMethodVisitor().visitLabel(divideByZero); context.compileInterpreterInstruction(); context.getMethodVisitor().visitLabel(afterInstruction); } @Override public String disasm(int address, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRSRT("div", rs, rt); } }; public static final Instruction DIVU = new Instruction(68) { @Override public final String name() { return "DIVU"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doDIVU(rs, rt); } @Override public void compile(ICompilerContext context, int insn) { Label divideByZero = new Label(); Label afterInstruction = new Label(); context.loadRt(); context.getMethodVisitor().visitJumpInsn(Opcodes.IFEQ, divideByZero); context.loadRs(); context.getMethodVisitor().visitInsn(Opcodes.I2L); context.getMethodVisitor().visitLdcInsn(0x00000000FFFFFFFFL); context.getMethodVisitor().visitInsn(Opcodes.LAND); context.getMethodVisitor().visitInsn(Opcodes.DUP2); context.loadRt(); context.getMethodVisitor().visitInsn(Opcodes.I2L); context.getMethodVisitor().visitLdcInsn(0x00000000FFFFFFFFL); context.getMethodVisitor().visitInsn(Opcodes.LAND); context.getMethodVisitor().visitInsn(Opcodes.DUP2_X2); context.getMethodVisitor().visitInsn(Opcodes.LREM); context.loadImm(32); context.getMethodVisitor().visitInsn(Opcodes.LSHL); context.storeLTmp1(); context.getMethodVisitor().visitInsn(Opcodes.LDIV); context.getMethodVisitor().visitLdcInsn(0x00000000FFFFFFFFL); context.getMethodVisitor().visitInsn(Opcodes.LAND); context.loadLTmp1(); context.getMethodVisitor().visitInsn(Opcodes.LOR); context.storeHilo(); context.getMethodVisitor().visitJumpInsn(Opcodes.GOTO, afterInstruction); // Division by zero handled by the interpreted instruction context.getMethodVisitor().visitLabel(divideByZero); context.compileInterpreterInstruction(); context.getMethodVisitor().visitLabel(afterInstruction); } @Override public String disasm(int address, int insn) { int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRSRT("divu", rs, rt); } }; public static final Instruction MFHI = new Instruction(69, FLAG_WRITES_RD) { @Override public final String name() { return "MFHI"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; processor.cpu.doMFHI(rd); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { context.prepareRdForStore(); context.loadHilo(); context.loadImm(32); context.getMethodVisitor().visitInsn(Opcodes.LUSHR); context.getMethodVisitor().visitInsn(Opcodes.L2I); context.storeRd(); } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; return Common.disasmRD("mfhi", rd); } }; public static final Instruction MFLO = new Instruction(70, FLAG_WRITES_RD) { @Override public final String name() { return "MFLO"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; processor.cpu.doMFLO(rd); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRdRegister0()) { context.prepareRdForStore(); context.loadHilo(); context.getMethodVisitor().visitLdcInsn(0xFFFFFFFFL); context.getMethodVisitor().visitInsn(Opcodes.LAND); context.getMethodVisitor().visitInsn(Opcodes.L2I); context.storeRd(); } } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; return Common.disasmRD("mflo", rd); } }; public static final Instruction MTHI = new Instruction(71) { @Override public final String name() { return "MTHI"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rs = (insn>>21)&31; processor.cpu.doMTHI(rs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int rs = (insn>>21)&31; return Common.disasmRS("mthi", rs); } }; public static final Instruction MTLO = new Instruction(72) { @Override public final String name() { return "MTLO"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rs = (insn>>21)&31; processor.cpu.doMTLO(rs); } @Override public void compile(ICompilerContext context, int insn) { context.loadHilo(); context.getMethodVisitor().visitLdcInsn(0xFFFFFFFF00000000L); context.getMethodVisitor().visitInsn(Opcodes.LAND); if (!context.isRsRegister0()) { context.loadRs(); context.getMethodVisitor().visitInsn(Opcodes.I2L); context.getMethodVisitor().visitLdcInsn(0x00000000FFFFFFFFL); context.getMethodVisitor().visitInsn(Opcodes.LAND); context.getMethodVisitor().visitInsn(Opcodes.LOR); } context.storeHilo(); } @Override public String disasm(int address, int insn) { int rs = (insn>>21)&31; return Common.disasmRS("mtlo", rs); } }; // // BEQ has the flag "FLAG_ENDS_BLOCK" because it can end a block when the // conditional branch can be reduced to an unconditional branch (rt == rs). // "BEQ $xx, $xx, target" // is equivalent to // "B target" // This special case is recognized in the method Compiler.analyse(). // public static final Instruction BEQ = new Instruction(73, FLAGS_BRANCH_INSTRUCTION | FLAG_ENDS_BLOCK) { @Override public final String name() { return "BEQ"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; if (processor.cpu.doBEQ(rs, rt, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRSRTOFFSET("beq", rs, rt, (int)(short)imm16, address); } }; public static final Instruction BEQL = new Instruction(74, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BEQL"; } @Override public final String category() { return "MIPS II"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; if (processor.cpu.doBEQL(rs, rt, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRSRTOFFSET("beql", rs, rt, (int)(short)imm16, address); } }; public static final Instruction BGEZ = new Instruction(75, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BGEZ"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; if (processor.cpu.doBGEZ(rs, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmRSOFFSET("bgez", rs, (int)(short)imm16, address); } }; public static final Instruction BGEZAL = new Instruction(76, FLAGS_LINK_INSTRUCTION | FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BGEZAL"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; if (processor.cpu.doBGEZAL(rs, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmRSOFFSET("bgezal", rs, (int)(short)imm16, address); } }; public static final Instruction BGEZALL = new Instruction(77, FLAGS_LINK_INSTRUCTION | FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BGEZALL"; } @Override public final String category() { return "MIPS II"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; if (processor.cpu.doBGEZALL(rs, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmRSOFFSET("bgezall", rs, (int)(short)imm16, address); } }; public static final Instruction BGEZL = new Instruction(78, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BGEZL"; } @Override public final String category() { return "MIPS II"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; if (processor.cpu.doBGEZL(rs, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmRSOFFSET("bgezl", rs, (int)(short)imm16, address); } }; public static final Instruction BGTZ = new Instruction(79, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BGTZ"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; if (processor.cpu.doBGTZ(rs, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmRSOFFSET("bgtz", rs, (int)(short)imm16, address); } }; public static final Instruction BGTZL = new Instruction(80, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BGTZL"; } @Override public final String category() { return "MIPS II"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; if (processor.cpu.doBGTZL(rs, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmRSOFFSET("bgtzl", rs, (int)(short)imm16, address); } }; public static final Instruction BLEZ = new Instruction(81, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BLEZ"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; if (processor.cpu.doBLEZ(rs, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmRSOFFSET("blez", rs, (int)(short)imm16, address); } }; public static final Instruction BLEZL = new Instruction(82, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BLEZL"; } @Override public final String category() { return "MIPS II"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; if (processor.cpu.doBLEZL(rs, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmRSOFFSET("blezl", rs, (int)(short)imm16, address); } }; public static final Instruction BLTZ = new Instruction(83, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BLTZ"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; if (processor.cpu.doBLTZ(rs, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmRSOFFSET("bltz", rs, (int)(short)imm16, address); } }; public static final Instruction BLTZAL = new Instruction(84, FLAGS_LINK_INSTRUCTION | FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BLTZAL"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; if (processor.cpu.doBLTZAL(rs, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmRSOFFSET("bltzal", rs, (int)(short)imm16, address); } }; public static final Instruction BLTZALL = new Instruction(85, FLAGS_LINK_INSTRUCTION | FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BLTZALL"; } @Override public final String category() { return "MIPS II"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; if (processor.cpu.doBLTZALL(rs, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmRSOFFSET("bltzall", rs, (int)(short)imm16, address); } }; public static final Instruction BLTZL = new Instruction(86, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BLTZL"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; if (processor.cpu.doBLTZL(rs, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rs = (insn>>21)&31; return Common.disasmRSOFFSET("bltzl", rs, (int)(short)imm16, address); } }; public static final Instruction BNE = new Instruction(87, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BNE"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; if (processor.cpu.doBNE(rs, rt, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRSRTOFFSET("bne", rs, rt, (int)(short)imm16, address); } }; public static final Instruction BNEL = new Instruction(88, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BNEL"; } @Override public final String category() { return "MIPS II"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; if (processor.cpu.doBNEL(rs, rt, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRSRTOFFSET("bnel", rs, rt, (int)(short)imm16, address); } }; public static final Instruction J = new Instruction(89, FLAG_HAS_DELAY_SLOT | FLAG_IS_JUMPING | FLAG_CANNOT_BE_SPLIT | FLAG_ENDS_BLOCK) { @Override public final String name() { return "J"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm26 = (insn>>0)&67108863; if (processor.cpu.doJ(imm26)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm26 = (insn>>0)&67108863; return Common.disasmJUMP("j", imm26, address); } }; public static final Instruction JAL = new Instruction(90, FLAGS_LINK_INSTRUCTION | FLAG_IS_JUMPING) { @Override public final String name() { return "JAL"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm26 = (insn>>0)&67108863; if (processor.cpu.doJAL(imm26)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm26 = (insn>>0)&67108863; return Common.disasmJUMP("jal", imm26, address); } }; public static final Instruction JALR = new Instruction(91, FLAG_HAS_DELAY_SLOT) { @Override public final String name() { return "JALR"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rd = (insn>>11)&31; int rs = (insn>>21)&31; if (processor.cpu.doJALR(rd, rs)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int rd = (insn>>11)&31; int rs = (insn>>21)&31; return Common.disasmRDRS("jalr", rd, rs); } }; public static final Instruction JR = new Instruction(92, FLAG_HAS_DELAY_SLOT | FLAG_CANNOT_BE_SPLIT | FLAG_ENDS_BLOCK) { @Override public final String name() { return "JR"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int rs = (insn>>21)&31; if (processor.cpu.doJR(rs)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int rs = (insn>>21)&31; return Common.disasmRS("jr", rs); } }; public static final Instruction BC1F = new Instruction(93, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BC1F"; } @Override public final String category() { return "MIPS I/FPU"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; if (processor.cpu.doBC1F((int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; return Common.disasmOFFSET("bc1f", (int)(short)imm16, address); } }; public static final Instruction BC1T = new Instruction(94, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BC1T"; } @Override public final String category() { return "MIPS I/FPU"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; if (processor.cpu.doBC1T((int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; return Common.disasmOFFSET("bc1t", (int)(short)imm16, address); } }; public static final Instruction BC1FL = new Instruction(95, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BC1FL"; } @Override public final String category() { return "MIPS II/FPU"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; if (processor.cpu.doBC1FL((int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; return Common.disasmOFFSET("bc1fl", (int)(short)imm16, address); } }; public static final Instruction BC1TL = new Instruction(96, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BC1TL"; } @Override public final String category() { return "MIPS II/FPU"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; if (processor.cpu.doBC1TL((int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; return Common.disasmOFFSET("bc1tl", (int)(short)imm16, address); } }; public static final Instruction BVF = new Instruction(97, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BVF"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int imm3 = (insn>>18)&7; if (processor.cpu.doBVF(imm3, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int imm3 = (insn>>18)&7; return Common.disasmVCCOFFSET("bvf", imm3, imm16, address); } }; public static final Instruction BVT = new Instruction(98, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BVT"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int imm3 = (insn>>18)&7; if (processor.cpu.doBVT(imm3, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int imm3 = (insn>>18)&7; return Common.disasmVCCOFFSET("bvt", imm3, imm16, address); } }; public static final Instruction BVFL = new Instruction(99, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BVFL"; } @Override public final String category() { return "MIPS II/VFPU"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int imm3 = (insn>>18)&7; if (processor.cpu.doBVFL(imm3, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int imm3 = (insn>>18)&7; return Common.disasmVCCOFFSET("bvfl", imm3, imm16, address); } }; public static final Instruction BVTL = new Instruction(100, FLAGS_BRANCH_INSTRUCTION) { @Override public final String name() { return "BVTL"; } @Override public final String category() { return "MIPS II/VFPU"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int imm3 = (insn>>18)&7; if (processor.cpu.doBVTL(imm3, (int)(short)imm16)) processor.interpretDelayslot(); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int imm3 = (insn>>18)&7; return Common.disasmVCCOFFSET("bvtl", imm3, imm16, address); } }; public static final Instruction LB = new Instruction(101, FLAG_WRITES_RT) { @Override public final String name() { return "LB"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLB(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { context.prepareRtForStore(); context.memRead8(context.getRsRegisterIndex(), context.getImm16(true)); context.getMethodVisitor().visitInsn(Opcodes.I2B); context.storeRt(); } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("lb", rt, rs, (int)(short)imm16); } }; public static final Instruction LBU = new Instruction(102, FLAG_WRITES_RT) { @Override public final String name() { return "LBU"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLBU(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { context.prepareRtForStore(); context.memRead8(context.getRsRegisterIndex(), context.getImm16(true)); context.storeRt(); } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("lbu", rt, rs, (int)(short)imm16); } }; public static final Instruction LH = new Instruction(103, FLAG_WRITES_RT) { @Override public final String name() { return "LH"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLH(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { context.prepareRtForStore(); context.memRead16(context.getRsRegisterIndex(), context.getImm16(true)); context.getMethodVisitor().visitInsn(Opcodes.I2S); context.storeRt(); } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("lh", rt, rs, (int)(short)imm16); } }; public static final Instruction LHU = new Instruction(104, FLAG_WRITES_RT) { @Override public final String name() { return "LHU"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLHU(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { context.prepareRtForStore(); context.memRead16(context.getRsRegisterIndex(), context.getImm16(true)); context.storeRt(); } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("lhu", rt, rs, (int)(short)imm16); } }; public static final Instruction LW = new Instruction(105, FLAG_WRITES_RT) { @Override public final String name() { return "LW"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLW(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { int rs = context.getRsRegisterIndex(); int simm16 = context.getImm16(true); int countSequence = 1; int[] offsets = null; int[] registers = null; if (!context.getCodeInstruction().isDelaySlot() && context.getRtRegisterIndex() != rs) { int address = context.getCodeInstruction().getAddress() + 4; // Compare LW opcode and rs register final int opcodeMask = 0xFFE00000; for (int i = 1; true; i++, address += 4) { CodeInstruction nextCodeInstruction = context.getCodeInstruction(address); boolean isSequence = false; if (nextCodeInstruction != null && !nextCodeInstruction.isBranchTarget()) { if ((nextCodeInstruction.getOpcode() & opcodeMask) == (insn & opcodeMask)) { if (nextCodeInstruction.getRtRegisterIndex() != rs) { if (offsets == null) { offsets = new int[2]; registers = new int[2]; offsets[0] = simm16; registers[0] = context.getRtRegisterIndex(); } else { offsets = Utilities.extendArray(offsets, 1); registers = Utilities.extendArray(registers, 1); } offsets[i] = nextCodeInstruction.getImm16(true); registers[i] = nextCodeInstruction.getRtRegisterIndex(); isSequence = true; } } } if (!isSequence) { break; } countSequence++; } } if (countSequence > 1 && context.compileLWsequence(rs, offsets, registers)) { if (countSequence > 1) { if (Compiler.log.isDebugEnabled()) { CodeInstruction sequence = new SequenceLWCodeInstruction(rs, offsets, registers); sequence.setAddress(context.getCodeInstruction().getAddress()); Compiler.log.debug(String.format("CodeInstruction.compile %s", sequence)); } // Skip the next lw instructions context.skipInstructions(countSequence - 1, false); } } else { context.prepareRtForStore(); context.memRead32(rs, simm16); context.storeRt(); } } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("lw", rt, rs, (int)(short)imm16); } }; public static final Instruction LWL = new Instruction(106, FLAG_WRITES_RT) { @Override public final String name() { return "LWL"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLWL(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { context.compileRTRSIMM("doLWL", true); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("lwl", rt, rs, (int)(short)imm16); } }; public static final Instruction LWR = new Instruction(107, FLAG_WRITES_RT) { @Override public final String name() { return "LWR"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLWR(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { context.compileRTRSIMM("doLWR", true); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("lwr", rt, rs, (int)(short)imm16); } }; public static final Instruction SB = new Instruction(108) { @Override public final String name() { return "SB"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSB(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { int rs = context.getRsRegisterIndex(); int simm16 = context.getImm16(true); if (context.isRtRegister0()) { context.memWriteZero8(rs, simm16); } else { context.prepareMemWrite8(rs, simm16); context.loadRt(); context.memWrite8(rs, simm16); } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("sb", rt, rs, (int)(short)imm16); } }; public static final Instruction SH = new Instruction(109) { @Override public final String name() { return "SH"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSH(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { int rs = context.getRsRegisterIndex(); int simm16 = context.getImm16(true); context.prepareMemWrite16(rs, simm16); context.loadRt(); context.memWrite16(rs, simm16); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("sh", rt, rs, (int)(short)imm16); } }; public static final Instruction SW = new Instruction(110) { @Override public final String name() { return "SW"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSW(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { int rs = context.getRsRegisterIndex(); int simm16 = context.getImm16(true); int countSequence = 1; int[] offsets = null; int[] registers = null; if (!context.getCodeInstruction().isDelaySlot()) { int address = context.getCodeInstruction().getAddress() + 4; // Compare SW opcode and rs register final int opcodeMask = 0xFFE00000; for (int i = 1; true; i++, address += 4) { CodeInstruction nextCodeInstruction = context.getCodeInstruction(address); boolean isSequence = false; if (nextCodeInstruction != null && !nextCodeInstruction.isBranchTarget()) { if ((nextCodeInstruction.getOpcode() & opcodeMask) == (insn & opcodeMask)) { if (offsets == null) { offsets = new int[2]; registers = new int[2]; offsets[0] = simm16; registers[0] = context.getRtRegisterIndex(); } else { offsets = Utilities.extendArray(offsets, 1); registers = Utilities.extendArray(registers, 1); } offsets[i] = nextCodeInstruction.getImm16(true); registers[i] = nextCodeInstruction.getRtRegisterIndex(); isSequence = true; } } if (!isSequence) { break; } countSequence++; } } if (countSequence > 1 && context.compileSWsequence(rs, offsets, registers)) { if (countSequence > 1) { if (Compiler.log.isDebugEnabled()) { CodeInstruction sequence = new SequenceSWCodeInstruction(rs, offsets, registers); sequence.setAddress(context.getCodeInstruction().getAddress()); Compiler.log.debug(String.format("CodeInstruction.compile %s", sequence)); } // Skip the next sw instructions context.skipInstructions(countSequence - 1, false); } } else { context.prepareMemWrite32(rs, simm16); context.loadRt(); context.memWrite32(rs, simm16); } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("sw", rt, rs, (int)(short)imm16); } }; public static final Instruction SWL = new Instruction(111) { @Override public final String name() { return "SWL"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSWL(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { context.compileRTRSIMM("doSWL", true); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("swl", rt, rs, (int)(short)imm16); } }; public static final Instruction SWR = new Instruction(112) { @Override public final String name() { return "SWR"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSWR(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { context.compileRTRSIMM("doSWR", true); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("swr", rt, rs, (int)(short)imm16); } }; public static final Instruction LL = new Instruction(113) { @Override public final String name() { return "LL"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLL(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { context.compileRTRSIMM("doLL", true); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("ll", rt, rs, (int)(short)imm16); } }; public static final Instruction LWC1 = new Instruction(114) { @Override public final String name() { return "LWC1"; } @Override public final String category() { return "MIPS I/FPU"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int ft = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLWC1(ft, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFtForStore(); context.memRead32(context.getRsRegisterIndex(), context.getImm16(true)); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "intBitsToFloat", "(I)F"); context.storeFt(); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int ft = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmFTIMMRS("lwc1", ft, rs, (int)(short)imm16); } }; public static final Instruction LVS = new Instruction(115) { @Override public final String name() { return "LVS"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int vt2 = (insn>>0)&3; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLVS((vt5|(vt2<<5)), rs, (int)(short)(imm14 << 2)); } @Override public void compile(ICompilerContext context, int insn) { int vt2 = (insn>>0)&3; int vt5 = (insn>>16)&31; int vt = vt5 | (vt2<<5); int simm14 = context.getImm14(true); int rs = context.getRsRegisterIndex(); context.prepareVtForStoreInt(1, vt, 0); context.memRead32(rs, simm14); context.storeVtInt(1, vt, 0); } @Override public String disasm(int address, int insn) { int vt2 = (insn>>0)&3; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmVTIMMRS("lv", 1, (vt5|(vt2<<5)), rs, (int)(short)(imm14 << 2)); } }; public static final Instruction LVLQ = new Instruction(116) { @Override public final String name() { return "LVLQ"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLVLQ((vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmVTIMMRS("lvl", 4, (vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } }; public static final Instruction LVRQ = new Instruction(117) { @Override public final String name() { return "LVRQ"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLVRQ((vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmVTIMMRS("lvr", 4, (vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } }; public static final Instruction LVQ = new Instruction(118) { @Override public final String name() { return "LVQ"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doLVQ((vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } @Override public void compile(ICompilerContext context, int insn) { int vt1 = (insn>>0)&1; int vt5 = (insn>>16)&31; int vt = vt5 | (vt1<<5); int simm14 = context.getImm14(true); int rs = context.getRsRegisterIndex(); final int vsize = 4; int countSequence = 1; int address = context.getCodeInstruction().getAddress(); // Compare LV.Q opcode and vt1 flag final int opcodeMask = 0xFFE00003; for (int i = 1; true; i++) { CodeInstruction nextCodeInstruction = context.getCodeInstruction(address + i * 4); boolean isSequence = false; if (nextCodeInstruction != null) { int nextInsn = nextCodeInstruction.getOpcode(); if (nextCodeInstruction != null && (nextInsn & opcodeMask) == (insn & opcodeMask)) { int nextSimm14 = nextCodeInstruction.getImm14(true); if (nextSimm14 == simm14 + i * 16) { int nextVt5 = (nextInsn >> 16) & 31; if (nextVt5 == vt5 + i) { isSequence = true; } } } } if (!isSequence) { break; } countSequence++; } if (context.compileVFPULoad(context.getRsRegisterIndex(), simm14, vt, countSequence * 4)) { if (countSequence > 1) { if (Compiler.log.isDebugEnabled()) { Compiler.log.debug(String.format("lv.q sequence 0x%08X-0x%08X", address, address + countSequence * 4 - 4)); } // Skip the next lv.q instructions context.skipInstructions(countSequence - 1, false); } } else { for (int n = 0; n < vsize; n++) { context.prepareVtForStoreInt(vsize, vt, n); context.memRead32(rs, simm14 + n * 4); context.storeVtInt(vsize, vt, n); } } } @Override public String disasm(int address, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmVTIMMRS("lv", 4, (vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } }; public static final Instruction SC = new Instruction(119) { @Override public final String name() { return "SC"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSC(rt, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { int rs = context.getRsRegisterIndex(); int simm16 = context.getImm16(true); context.prepareMemWrite32(rs, simm16); context.loadRt(); context.memWrite32(rs, simm16); if (!context.isRtRegister0()) { context.storeRt(1); } } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int rt = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmRTIMMRS("sc", rt, rs, (int)(short)imm16); } }; public static final Instruction SWC1 = new Instruction(120) { @Override public final String name() { return "SWC1"; } @Override public final String category() { return "MIPS I/FPU"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int ft = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSWC1(ft, rs, (int)(short)imm16); } @Override public void compile(ICompilerContext context, int insn) { int rs = context.getRsRegisterIndex(); int simm16 = context.getImm16(true); context.prepareMemWrite32(rs, simm16); context.loadFt(); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "floatToRawIntBits", "(F)I"); context.memWrite32(rs, simm16); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int ft = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmFTIMMRS("swc1", ft, rs, (int)(short)imm16); } }; public static final Instruction SVS = new Instruction(121) { @Override public final String name() { return "SVS"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int vt2 = (insn>>0)&3; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSVS((vt5|(vt2<<5)), rs, (int)(short)(imm14 << 2)); } @Override public void compile(ICompilerContext context, int insn) { int vt2 = (insn>>0)&3; int vt5 = (insn>>16)&31; int vt = vt5 | (vt2<<5); int simm14 = context.getImm14(true); int rs = context.getRsRegisterIndex(); context.prepareMemWrite32(rs, simm14); context.loadVtInt(1, vt, 0); context.memWrite32(rs, simm14); } @Override public String disasm(int address, int insn) { int vt2 = (insn>>0)&3; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmVTIMMRS("sv", 1, (vt5|(vt2<<5)), rs, (int)(short)(imm14 << 2)); } }; public static final Instruction SVLQ = new Instruction(122) { @Override public final String name() { return "SVLQ"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSVLQ((vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmVTIMMRS("svl", 4, (vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } }; public static final Instruction SVRQ = new Instruction(123) { @Override public final String name() { return "SVRQ"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSVRQ((vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmVTIMMRS("svr", 4, (vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } }; public static final Instruction SVQ = new Instruction(124) { @Override public final String name() { return "SVQ"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; processor.cpu.doSVQ((vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } @Override public void compile(ICompilerContext context, int insn) { int vt1 = (insn>>0)&1; int vt5 = (insn>>16)&31; int vt = vt5 | (vt1<<5); int simm14 = context.getImm14(true); int rs = context.getRsRegisterIndex(); int vsize = 4; int countSequence = 1; int address = context.getCodeInstruction().getAddress(); // Compare SV.Q opcode and vt1 flag final int opcodeMask = 0xFFE00001; for (int i = 1; i < 4; i++) { CodeInstruction nextCodeInstruction = context.getCodeInstruction(address + i * 4); boolean isSequence = false; if (nextCodeInstruction != null) { int nextInsn = nextCodeInstruction.getOpcode(); if (nextCodeInstruction != null && (nextInsn & opcodeMask) == (insn & opcodeMask)) { int nextSimm14 = nextCodeInstruction.getImm14(true); if (nextSimm14 == simm14 + i * 16) { int nextVt5 = (nextInsn >> 16) & 31; if (nextVt5 == vt5 + i) { isSequence = true; } } } } if (!isSequence) { break; } countSequence++; } if (context.compileVFPUStore(context.getRsRegisterIndex(), simm14, vt, countSequence * 4)) { if (countSequence > 1) { if (Compiler.log.isDebugEnabled()) { Compiler.log.debug(String.format("sv.q sequence 0x%08X-0x%08X", address, address + countSequence * 4 - 4)); } // Skip the next sv.q instructions context.skipInstructions(countSequence - 1, false); } } else { for (int n = 0; n < vsize; n++) { context.prepareMemWrite32(rs, simm14 + n * 4); context.loadVtInt(vsize, vt, n); context.memWrite32(rs, simm14 + n * 4); } } } @Override public String disasm(int address, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmVTIMMRS("sv", 4, (vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } }; public static final Instruction VWB = new Instruction(125) { @Override public final String name() { return "VWB"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { // Checked using VfpuTest: VWB.Q is equivalent to SV.Q SVQ.interpret(processor, insn); } @Override public void compile(ICompilerContext context, int insn) { SVQ.compile(context, insn); } @Override public String disasm(int address, int insn) { int vt1 = (insn>>0)&1; int imm14 = (insn>>2)&16383; int vt5 = (insn>>16)&31; int rs = (insn>>21)&31; return Common.disasmVTIMMRS("vwb", 4, (vt5|(vt1<<5)), rs, (int)(short)(imm14 << 2)); } }; public static final Instruction ADD_S = new Instruction(126) { @Override public final String name() { return "ADD.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; int ft = (insn>>16)&31; processor.cpu.doADDS(fd, fs, ft); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFdForStore(); context.loadFs(); context.loadFt(); context.getMethodVisitor().visitInsn(Opcodes.FADD); context.storeFd(); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; int ft = (insn>>16)&31; return Common.disasmFDFSFT("add.s", fd, fs, ft); } }; public static final Instruction SUB_S = new Instruction(127) { @Override public final String name() { return "SUB.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; int ft = (insn>>16)&31; processor.cpu.doSUBS(fd, fs, ft); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFdForStore(); context.loadFs(); context.loadFt(); context.getMethodVisitor().visitInsn(Opcodes.FSUB); context.storeFd(); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; int ft = (insn>>16)&31; return Common.disasmFDFSFT("sub.s", fd, fs, ft); } }; public static final Instruction MUL_S = new Instruction(128) { @Override public final String name() { return "MUL.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; int ft = (insn>>16)&31; processor.cpu.doMULS(fd, fs, ft); } @Override public void compile(ICompilerContext context, int insn) { if (IMPLEMENT_ROUNDING_MODES) { context.compileFDFSFT("doMULS"); } else { context.prepareFdForStore(); context.loadFs(); context.loadFt(); context.getMethodVisitor().visitInsn(Opcodes.FMUL); context.storeFd(); } } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; int ft = (insn>>16)&31; return Common.disasmFDFSFT("mul.s", fd, fs, ft); } }; public static final Instruction DIV_S = new Instruction(129) { @Override public final String name() { return "DIV.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; int ft = (insn>>16)&31; processor.cpu.doDIVS(fd, fs, ft); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFdForStore(); context.loadFs(); context.loadFt(); context.getMethodVisitor().visitInsn(Opcodes.FDIV); context.storeFd(); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; int ft = (insn>>16)&31; return Common.disasmFDFSFT("div.s", fd, fs, ft); } }; public static final Instruction SQRT_S = new Instruction(130) { @Override public final String name() { return "SQRT.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; processor.cpu.doSQRTS(fd, fs); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFdForStore(); context.loadFs(); context.getMethodVisitor().visitInsn(Opcodes.F2D); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "sqrt", "(D)D"); context.getMethodVisitor().visitInsn(Opcodes.D2F); context.storeFd(); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; return Common.disasmFDFS("sqrt.s", fd, fs); } }; public static final Instruction ABS_S = new Instruction(131) { @Override public final String name() { return "ABS.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; processor.cpu.doABSS(fd, fs); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFdForStore(); context.loadFs(); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "abs", "(F)F"); context.storeFd(); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; return Common.disasmFDFS("abs.s", fd, fs); } }; public static final Instruction MOV_S = new Instruction(132) { @Override public final String name() { return "MOV.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; processor.cpu.doMOVS(fd, fs); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFdForStore(); context.loadFs(); context.storeFd(); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; return Common.disasmFDFS("mov.s", fd, fs); } }; public static final Instruction NEG_S = new Instruction(133) { @Override public final String name() { return "NEG.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; processor.cpu.doNEGS(fd, fs); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFdForStore(); context.loadFs(); context.getMethodVisitor().visitInsn(Opcodes.FNEG); context.storeFd(); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; return Common.disasmFDFS("neg.s", fd, fs); } }; public static final Instruction ROUND_W_S = new Instruction(134) { @Override public final String name() { return "ROUND.W.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; processor.cpu.doROUNDWS(fd, fs); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFdForStore(); context.loadFs(); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "round", "(F)I"); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "intBitsToFloat", "(I)F"); context.storeFd(); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; return Common.disasmFDFS("round.w.s", fd, fs); } }; public static final Instruction TRUNC_W_S = new Instruction(135) { @Override public final String name() { return "TRUNC.W.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; processor.cpu.doTRUNCWS(fd, fs); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFdForStore(); context.loadFs(); context.getMethodVisitor().visitInsn(Opcodes.F2I); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "intBitsToFloat", "(I)F"); context.storeFd(); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; return Common.disasmFDFS("trunc.w.s", fd, fs); } }; public static final Instruction CEIL_W_S = new Instruction(136) { @Override public final String name() { return "CEIL.W.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; processor.cpu.doCEILWS(fd, fs); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFdForStore(); context.loadFs(); context.getMethodVisitor().visitInsn(Opcodes.F2D); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "ceil", "(D)D"); context.getMethodVisitor().visitInsn(Opcodes.D2I); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "intBitsToFloat", "(I)F"); context.storeFd(); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; return Common.disasmFDFS("ceil.w.s", fd, fs); } }; public static final Instruction FLOOR_W_S = new Instruction(137) { @Override public final String name() { return "FLOOR.W.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; processor.cpu.doFLOORWS(fd, fs); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFdForStore(); context.loadFs(); context.getMethodVisitor().visitInsn(Opcodes.F2D); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "floor", "(D)D"); context.getMethodVisitor().visitInsn(Opcodes.D2I); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "intBitsToFloat", "(I)F"); context.storeFd(); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; return Common.disasmFDFS("floor.w.s", fd, fs); } }; public static final Instruction CVT_S_W = new Instruction(138) { @Override public final String name() { return "CVT.S.W"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; processor.cpu.doCVTSW(fd, fs); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFdForStore(); context.loadFs(); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "floatToRawIntBits", "(F)I"); context.getMethodVisitor().visitInsn(Opcodes.I2F); context.storeFd(); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; return Common.disasmFDFS("cvt.s.w", fd, fs); } }; public static final Instruction CVT_W_S = new Instruction(139) { @Override public final String name() { return "CVT.W.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; processor.cpu.doCVTWS(fd, fs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int fd = (insn>>6)&31; int fs = (insn>>11)&31; return Common.disasmFDFS("cvt.w.s", fd, fs); } }; public static final Instruction C_COND_S = new Instruction(140) { @Override public final String name() { return "C.COND.S"; } @Override public final String category() { return "FPU"; } @Override public void interpret(Processor processor, int insn) { int fcond = (insn>>0)&15; int fs = (insn>>11)&31; int ft = (insn>>16)&31; processor.cpu.doCCONDS(fs, ft, fcond); } @Override public void compile(ICompilerContext context, int insn) { int fcond = (insn >> 0) & 15; Label isNaN = new Label(); Label isNotNaN = new Label(); Label continueLabel = new Label(); Label trueLabel = new Label(); context.prepareFcr31cForStore(); context.loadFt(); context.storeFTmp2(); context.loadFs(); context.getMethodVisitor().visitInsn(Opcodes.DUP); context.storeFTmp1(); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "isNaN", "(F)Z"); context.getMethodVisitor().visitJumpInsn(Opcodes.IFNE, isNaN); context.loadFTmp2(); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "isNaN", "(F)Z"); context.getMethodVisitor().visitJumpInsn(Opcodes.IFEQ, isNotNaN); context.getMethodVisitor().visitLabel(isNaN); context.getMethodVisitor().visitInsn((fcond & 1) != 0 ? Opcodes.ICONST_1 : Opcodes.ICONST_0); context.getMethodVisitor().visitJumpInsn(Opcodes.GOTO, continueLabel); context.getMethodVisitor().visitLabel(isNotNaN); boolean equal = (fcond & 2) != 0; boolean less = (fcond & 4) != 0; if (!equal && !less) { context.getMethodVisitor().visitInsn(Opcodes.ICONST_0); } else { int testOpcode = (equal ? (less ? Opcodes.IFLE : Opcodes.IFEQ) : Opcodes.IFLT); context.loadFTmp1(); context.loadFTmp2(); context.getMethodVisitor().visitInsn(Opcodes.FCMPL); // FCMPG and FCMPL would produce the same result as both values are not NaN context.getMethodVisitor().visitJumpInsn(testOpcode, trueLabel); context.getMethodVisitor().visitInsn(Opcodes.ICONST_0); context.getMethodVisitor().visitJumpInsn(Opcodes.GOTO, continueLabel); context.getMethodVisitor().visitLabel(trueLabel); context.getMethodVisitor().visitInsn(Opcodes.ICONST_1); } context.getMethodVisitor().visitLabel(continueLabel); context.storeFcr31c(); } @Override public String disasm(int address, int insn) { int fcond = (insn>>0)&15; int fs = (insn>>11)&31; int ft = (insn>>16)&31; return Common.disasmCcondS(fcond, fs, ft); } }; public static final Instruction MFC1 = new Instruction(141, FLAG_WRITES_RT) { @Override public final String name() { return "MFC1"; } @Override public final String category() { return "MIPS I/FPU"; } @Override public void interpret(Processor processor, int insn) { int c1dr = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doMFC1(rt, c1dr); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { context.prepareRtForStore(); context.loadFCr(); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "floatToRawIntBits", "(F)I"); context.storeRt(); } } @Override public String disasm(int address, int insn) { int c1dr = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRTFS("mfc1", rt, c1dr); } }; public static final Instruction CFC1 = new Instruction(142) { @Override public final String name() { return "CFC1"; } @Override public final String category() { return "MIPS I/FPU"; } @Override public void interpret(Processor processor, int insn) { int c1cr = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doCFC1(rt, c1cr); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int c1cr = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRTFC("cfc1", rt, c1cr); } }; public static final Instruction MTC1 = new Instruction(143) { @Override public final String name() { return "MTC1"; } @Override public final String category() { return "MIPS I/FPU"; } @Override public void interpret(Processor processor, int insn) { int c1dr = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doMTC1(rt, c1dr); } @Override public void compile(ICompilerContext context, int insn) { context.prepareFCrForStore(); context.loadRt(); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "intBitsToFloat", "(I)F"); context.storeFCr(); } @Override public String disasm(int address, int insn) { int c1dr = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRTFS("mtc1", rt, c1dr); } }; public static final Instruction CTC1 = new Instruction(144) { @Override public final String name() { return "CTC1"; } @Override public final String category() { return "MIPS I/FPU"; } @Override public void interpret(Processor processor, int insn) { int c1cr = (insn>>11)&31; int rt = (insn>>16)&31; processor.cpu.doCTC1(rt, c1cr); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int c1cr = (insn>>11)&31; int rt = (insn>>16)&31; return Common.disasmRTFC("ctc1", rt, c1cr); } }; public static final Instruction MFC0 = new Instruction(145) { @Override public final String name() { return "MFC0"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { //int c0dr = (insn>>11)&31; //int rt = (insn>>16)&31; } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { //int c0dr = (insn>>11)&31; //int rt = (insn>>16)&31; return "Unimplemented MFC0"; } }; public static final Instruction CFC0 = new Instruction(146) { @Override public final String name() { return "CFC0"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int c0cr = (insn>>11)&31; //int rt = (insn>>16)&31; } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { //int c0cr = (insn>>11)&31; //int rt = (insn>>16)&31; return "Unimplemented CFC0"; } }; public static final Instruction MTC0 = new Instruction(147) { @Override public final String name() { return "MTC0"; } @Override public final String category() { return "MIPS I"; } @Override public void interpret(Processor processor, int insn) { //int c0dr = (insn>>11)&31; //int rt = (insn>>16)&31; } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { //int c0dr = (insn>>11)&31; //int rt = (insn>>16)&31; return "Unimplemented MTC0"; } }; public static final Instruction CTC0 = new Instruction(148) { @Override public final String name() { return "CTC0"; } @Override public final String category() { return "ALLEGREX"; } @Override public void interpret(Processor processor, int insn) { //int c0cr = (insn>>11)&31; //int rt = (insn>>16)&31; } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { //int c0cr = (insn>>11)&31; //int rt = (insn>>16)&31; return "Unimplemented CTC0"; } }; public static final Instruction VADD = new Instruction(149, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VADD"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVADD(1 + one + (two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { context.compileVFPUInstr(null, Opcodes.FADD, null); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vadd", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VSUB = new Instruction(150, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VSUB"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVSUB(1 + one + (two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { context.compileVFPUInstr(null, Opcodes.FSUB, null); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vsub", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VSBN = new Instruction(151, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VSBN"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVSBN(1 + one + (two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); if (vsize == 1) { context.startPfxCompiled(); for (int n = 0; n < vsize; n++) { context.prepareVdForStore(n); context.loadVs(n); context.loadVtInt(n); context.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "scalb", "(FI)F"); context.storeVd(n); } context.endPfxCompiled(); } else { // Only VSBN.S is supported context.compileInterpreterInstruction(); } } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vsbn", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VDIV = new Instruction(152, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VDIV"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVDIV(1 + one + (two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { context.compileVFPUInstr(null, Opcodes.FDIV, null); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vdiv", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VMUL = new Instruction(153, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VMUL"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVMUL(1 + one + (two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { context.compileVFPUInstr(null, Opcodes.FMUL, null); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vmul", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VDOT = new Instruction(154, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VDOT"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVDOT(1 + one + (two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); if (vsize > 1) { context.startPfxCompiled(); context.prepareVdForStore(1, 0); context.loadVs(0); context.loadVt(0); context.getMethodVisitor().visitInsn(Opcodes.FMUL); for (int n = 1; n < vsize; n++) { context.loadVs(n); context.loadVt(n); context.getMethodVisitor().visitInsn(Opcodes.FMUL); context.getMethodVisitor().visitInsn(Opcodes.FADD); } context.storeVd(1, 0); context.endPfxCompiled(1); } else { // Unsupported VDOT.S context.compileInterpreterInstruction(); } } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVD1VSVT("vdot", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VSCL = new Instruction(155, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VSCL"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVSCL(1 + one + (two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); if (vsize > 1) { context.startPfxCompiled(); context.loadVt(1, 0); context.storeFTmp1(); for (int n = 0; n < vsize; n++) { context.prepareVdForStore(n); context.loadVs(n); context.loadFTmp1(); context.getMethodVisitor().visitInsn(Opcodes.FMUL); context.storeVd(n); } context.endPfxCompiled(); } else { // Unsupported VSCL.S context.compileInterpreterInstruction(); } } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT1("vscl", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VHDP = new Instruction(156, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VHDP"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVHDP(1 + one + (two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); if (vsize > 1) { context.startPfxCompiled(); context.prepareVdForStore(1, 0); context.loadVs(0); context.loadVt(0); context.getMethodVisitor().visitInsn(Opcodes.FMUL); for (int n = 1; n < vsize - 1; n++) { context.loadVs(n); context.loadVt(n); context.getMethodVisitor().visitInsn(Opcodes.FMUL); context.getMethodVisitor().visitInsn(Opcodes.FADD); } context.loadVt(vsize - 1); context.getMethodVisitor().visitInsn(Opcodes.FADD); context.storeVd(1, 0); context.endPfxCompiled(1); } else { // Unsupported VHDP.S context.compileInterpreterInstruction(); } } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVD1VSVT("vhdp", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VCRS = new Instruction(157, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VCRS"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVCRS(1 + one + (two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vcrs", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VDET = new Instruction(158, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VDET"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVDET(1 + one + (two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVD1VSVT("vdet", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction MFV = new Instruction(159, FLAG_WRITES_RT) { @Override public final String name() { return "MFV"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int imm7 = (insn>>0)&127; int rt = (insn>>16)&31; processor.cpu.doMFV(rt, imm7); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { context.prepareRtForStore(); context.loadVdInt(1, 0); context.storeRt(); } } @Override public String disasm(int address, int insn) { int imm7 = (insn>>0)&127; int rt = (insn>>16)&31; return Common.disasmVDRS("mfv", imm7, rt); } }; public static final Instruction MFVC = new Instruction(160, FLAG_WRITES_RT) { @Override public final String name() { return "MFVC"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int imm7 = (insn>>0)&127; int rt = (insn>>16)&31; processor.cpu.doMFVC(rt, imm7); } @Override public void compile(ICompilerContext context, int insn) { if (!context.isRtRegister0()) { int imm7 = context.getImm7(); MethodVisitor mv = context.getMethodVisitor(); switch (imm7) { case 3: { context.prepareRtForStore(); context.loadVcrCc(5); for (int i = 4; i >= 0; i--) { context.loadImm(1); mv.visitInsn(Opcodes.ISHL); context.loadVcrCc(i); mv.visitInsn(Opcodes.IOR); } context.storeRt(); break; } default: super.compile(context, insn); break; } } } @Override public String disasm(int address, int insn) { int imm7 = (insn>>0)&127; int rt = (insn>>16)&31; return Common.disasmRTIMM7("MFVC", rt, imm7); } }; public static final Instruction MTV = new Instruction(161) { @Override public final String name() { return "MTV"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int imm7 = (insn>>0)&127; int rt = (insn>>16)&31; processor.cpu.doMTV(rt, imm7); } @Override public void compile(ICompilerContext context, int insn) { context.prepareVdForStoreInt(1, 0); context.loadRt(); context.storeVdInt(1, 0); } @Override public String disasm(int address, int insn) { int imm7 = (insn>>0)&127; int rt = (insn>>16)&31; return Common.disasmVDRS("MTV", imm7, rt); } }; public static final Instruction MTVC = new Instruction(162) { @Override public final String name() { return "MTVC"; } @Override public final String category() { return "MIPS I/VFPU"; } @Override public void interpret(Processor processor, int insn) { int imm7 = (insn>>0)&127; int rt = (insn>>16)&31; processor.cpu.doMTVC(rt, imm7); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm7 = (insn>>0)&127; int rt = (insn>>16)&31; return Common.disasmRTIMM7("MTVC", rt, imm7); } }; public static final Instruction VCMP = new Instruction(163, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_COMPILED_PFX) { @Override public final String name() { return "VCMP"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int imm4 = (insn>>0)&15; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVCMP(1+one+(two<<1), vs, vt, imm4); } @Override public void compile(ICompilerContext context, int insn) { int cond = context.getImm4(); int vsize = context.getVsize(); MethodVisitor mv = context.getMethodVisitor(); boolean not = (cond & 4) != 0; context.startPfxCompiled(); if ((cond & 8) == 0) { if ((cond & 3) == 0) { int value = not ? 1 : 0; for (int n = 0; n < vsize; n++) { context.prepareVcrCcForStore(n); context.loadImm(value); context.storeVcrCc(n); } context.prepareVcrCcForStore(4); context.loadImm(value); context.storeVcrCc(4); context.prepareVcrCcForStore(5); context.loadImm(value); context.storeVcrCc(5); } else { if (vsize > 1) { context.loadImm(0); context.storeTmp1(); context.loadImm(1); context.storeTmp2(); } for (int n = 0; n < vsize; n++) { context.prepareVcrCcForStore(n); context.loadVs(n); context.loadVt(n); // In Java, the two opcodes for float comparisons (FCMPG and FCMPL) differ // only in how they handle NaN ("not a number"). // If one or both of the values is NaN, the FCMPG instruction pushes a 1, // whereas the FCMPL instruction pushes a -1. // On the PSP, comparing NaN values always returns false. // - vcmp GE => use FCMPL (-1 will be interpreted as false) // - vcmp GT => use FCMPL (-1 will be interpreted as false) // - vcmp LE => use FCMPG (1 will be interpreted as false) // - vcmp LT => use FCMPG (1 will be interpreted as false) // - vcmp EQ => use either FCMPL or FCMPG // - vcmp NE => use either FCMPL or FCMPG mv.visitInsn(not ? Opcodes.FCMPL : Opcodes.FCMPG); int opcodeCond = Opcodes.NOP; switch (cond & 3) { case 1: opcodeCond = not ? Opcodes.IFNE : Opcodes.IFEQ; break; case 2: opcodeCond = not ? Opcodes.IFGE : Opcodes.IFLT; break; case 3: opcodeCond = not ? Opcodes.IFGT : Opcodes.IFLE; break; } Label trueLabel = new Label(); Label afterLabel = new Label(); mv.visitJumpInsn(opcodeCond, trueLabel); context.loadImm(0); if (vsize > 1) { context.loadImm(0); context.storeTmp2(); } else { context.prepareVcrCcForStore(4); context.loadImm(0); context.storeVcrCc(4); context.prepareVcrCcForStore(5); context.loadImm(0); context.storeVcrCc(5); } mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(trueLabel); context.loadImm(1); if (vsize > 1) { context.loadImm(1); context.storeTmp1(); } else { context.prepareVcrCcForStore(4); context.loadImm(1); context.storeVcrCc(4); context.prepareVcrCcForStore(5); context.loadImm(1); context.storeVcrCc(5); } mv.visitLabel(afterLabel); context.storeVcrCc(n); } if (vsize > 1) { context.prepareVcrCcForStore(4); context.loadTmp1(); context.storeVcrCc(4); context.prepareVcrCcForStore(5); context.loadTmp2(); context.storeVcrCc(5); } } } else { if (vsize > 1) { context.loadImm(0); context.storeTmp1(); context.loadImm(1); context.storeTmp2(); } for (int n = 0; n < vsize; n++) { context.prepareVcrCcForStore(n); context.loadVs(n); boolean updateOrAnd = false; switch (cond & 3) { case 0: { mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "abs", "(F)F"); mv.visitInsn(Opcodes.FCONST_0); mv.visitInsn(Opcodes.FCMPL); // Use FCMPL or FCMPG, it doesn't matter for testing NE or EQ Label trueLabel = new Label(); Label afterLabel = new Label(); mv.visitJumpInsn(not ? Opcodes.IFNE : Opcodes.IFEQ, trueLabel); context.loadImm(0); if (vsize > 1) { context.loadImm(0); context.storeTmp2(); } else { context.prepareVcrCcForStore(4); context.loadImm(0); context.storeVcrCc(4); context.prepareVcrCcForStore(5); context.loadImm(0); context.storeVcrCc(5); } mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(trueLabel); context.loadImm(1); if (vsize > 1) { context.loadImm(1); context.storeTmp1(); } else { context.prepareVcrCcForStore(4); context.loadImm(1); context.storeVcrCc(4); context.prepareVcrCcForStore(5); context.loadImm(1); context.storeVcrCc(5); } mv.visitLabel(afterLabel); break; } case 1: { mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "isNaN", "(F)Z"); updateOrAnd = true; break; } case 2: { mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "isInfinite", "(F)Z"); updateOrAnd = true; break; } case 3: { mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "isNaN", "(F)Z"); mv.visitInsn(Opcodes.SWAP); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "isInfinite", "(F)Z"); mv.visitInsn(Opcodes.IOR); updateOrAnd = true; break; } } if (updateOrAnd) { if (not) { context.loadImm(1); mv.visitInsn(Opcodes.IXOR); } if (vsize > 1) { mv.visitInsn(Opcodes.DUP); context.loadTmp1(); mv.visitInsn(Opcodes.IOR); context.storeTmp1(); mv.visitInsn(Opcodes.DUP); context.loadTmp2(); mv.visitInsn(Opcodes.IAND); context.storeTmp2(); } else { mv.visitInsn(Opcodes.DUP); context.storeVcrCc(4); mv.visitInsn(Opcodes.DUP); context.storeVcrCc(5); } } context.storeVcrCc(n); } if (vsize > 1) { context.prepareVcrCcForStore(4); context.loadTmp1(); context.storeVcrCc(4); context.prepareVcrCcForStore(5); context.loadTmp2(); context.storeVcrCc(5); } } context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int imm4 = (insn>>0)&15; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVCMP("vcmp", 1+one+(two<<1), imm4, vs, vt); } }; public static final Instruction VMIN = new Instruction(164, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VMIN"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVMIN(1+one+(two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { context.compileVFPUInstr(null, Opcodes.NOP, "min"); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vmin", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VMAX = new Instruction(165, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VMAX"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVMAX(1+one+(two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { context.compileVFPUInstr(null, Opcodes.NOP, "max"); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vmax", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VSCMP = new Instruction(166, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VSCMP"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVSCMP(1+one+(two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vscmp", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VSGE = new Instruction(167, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VSGE"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVSGE(1+one+(two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); context.startPfxCompiled(); MethodVisitor mv = context.getMethodVisitor(); for (int n = 0; n < vsize; n++) { context.prepareVdForStore(n); context.loadVs(n); context.loadVt(n); mv.visitInsn(Opcodes.FCMPL); // Use FCMPL, not FCMPG: NaN has to return false. Label trueLabel = new Label(); Label afterLabel = new Label(); mv.visitJumpInsn(Opcodes.IFGE, trueLabel); mv.visitInsn(Opcodes.FCONST_0); mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(trueLabel); mv.visitInsn(Opcodes.FCONST_1); mv.visitLabel(afterLabel); context.storeVd(n); } context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vsge", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VSLT = new Instruction(168, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VSLT"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVSLT(1+one+(two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); context.startPfxCompiled(); MethodVisitor mv = context.getMethodVisitor(); for (int n = 0; n < vsize; n++) { context.prepareVdForStore(n); context.loadVs(n); context.loadVt(n); mv.visitInsn(Opcodes.FCMPG); // Use FCMPG, not FCMPL: NaN has to return false Label trueLabel = new Label(); Label afterLabel = new Label(); mv.visitJumpInsn(Opcodes.IFLT, trueLabel); mv.visitInsn(Opcodes.FCONST_0); mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(trueLabel); mv.visitInsn(Opcodes.FCONST_1); mv.visitLabel(afterLabel); context.storeVd(n); } context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vslt", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VMOV = new Instruction(169, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_CONSUMES_VFPU_PFXT | FLAG_COMPILED_PFX) { @Override public final String name() { return "VMOV"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVMOV(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { context.compileVFPUInstr(null, Opcodes.NOP, null); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vmov", 1+one+(two<<1), vd, vs); } }; public static final Instruction VABS = new Instruction(170, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VABS"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVABS(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { context.compileVFPUInstr(null, Opcodes.NOP, "abs"); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vabs", 1+one+(two<<1), vd, vs); } }; public static final Instruction VNEG = new Instruction(171, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VNEG"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVNEG(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { context.compileVFPUInstr(null, Opcodes.FNEG, null); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vneg", 1+one+(two<<1), vd, vs); } }; public static final Instruction VIDT = new Instruction(172, FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VIDT"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; processor.cpu.doVIDT(1+one+(two<<1), vd); } @Override public void compile(ICompilerContext context, int insn) { context.startPfxCompiled(); int vsize = context.getVsize(); int id = context.getVdRegisterIndex() % vsize; for (int n = 0; n < vsize; n++) { context.prepareVdForStore(n); context.getMethodVisitor().visitInsn(id == n ? Opcodes.FCONST_1 : Opcodes.FCONST_0); context.storeVd(n); } context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; return Common.disasmVD("vidt", 1+one+(two<<1), vd); } }; public static final Instruction VSAT0 = new Instruction(173, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VSAT0"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVSAT0(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); MethodVisitor mv = context.getMethodVisitor(); context.startPfxCompiled(); for (int n = 0; n < vsize; n++) { // float stackValue = vs[n]; // if (stackValue <= 0.f) { // stackValue = 0.f; // } else if (stackValue > 1.f) { // stackValue = 1.f; // } // vd[n] = stackValue; context.prepareVdForStore(n); context.loadVs(n); mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(0.f); mv.visitInsn(Opcodes.FCMPG); // Use FCMPG, not FCMPL: NaN has to be left unchanged Label limitLabel = new Label(); Label afterLabel = new Label(); mv.visitJumpInsn(Opcodes.IFGT, limitLabel); mv.visitInsn(Opcodes.POP); mv.visitLdcInsn(0.f); mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(limitLabel); mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(1.f); mv.visitInsn(Opcodes.FCMPL); // Use FCMPL, not FCMPG: NaN has to be left unchanged mv.visitJumpInsn(Opcodes.IFLE, afterLabel); mv.visitInsn(Opcodes.POP); mv.visitLdcInsn(1.f); mv.visitLabel(afterLabel); context.storeVd(n); } context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vsat0", 1+one+(two<<1), vd, vs); } }; public static final Instruction VSAT1 = new Instruction(174, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VSAT1"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVSAT1(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); MethodVisitor mv = context.getMethodVisitor(); context.startPfxCompiled(); for (int n = 0; n < vsize; n++) { // float stackValue = vs[n]; // if (stackValue <= -1.f) { // stackValue = -1.f; // } else if (stackValue > 1.f) { // stackValue = 1.f; // } // vd[n] = stackValue; context.prepareVdForStore(n); context.loadVs(n); mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(-1.f); mv.visitInsn(Opcodes.FCMPG); // Use FCMPG, not FCMPL: NaN has to be left unchanged Label limitLabel = new Label(); Label afterLabel = new Label(); mv.visitJumpInsn(Opcodes.IFGT, limitLabel); mv.visitInsn(Opcodes.POP); mv.visitLdcInsn(-1.f); mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(limitLabel); mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(1.f); mv.visitInsn(Opcodes.FCMPL); // Use FCMPL, not FCMPG: NaN has to be left unchanged mv.visitJumpInsn(Opcodes.IFLE, afterLabel); mv.visitInsn(Opcodes.POP); mv.visitLdcInsn(1.f); mv.visitLabel(afterLabel); context.storeVd(n); } context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vsat1", 1+one+(two<<1), vd, vs); } }; public static final Instruction VZERO = new Instruction(175, FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VZERO"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; processor.cpu.doVZERO(1+one+(two<<1), vd); } @Override public void compile(ICompilerContext context, int insn) { context.startPfxCompiled(); int vsize = context.getVsize(); for (int n = 0; n < vsize; n++) { context.prepareVdForStore(n); context.getMethodVisitor().visitInsn(Opcodes.FCONST_0); context.storeVd(n); } context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; return Common.disasmVD("vzero", 1+one+(two<<1), vd); } }; public static final Instruction VONE = new Instruction(176, FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VONE"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; processor.cpu.doVONE(1+one+(two<<1), vd); } @Override public void compile(ICompilerContext context, int insn) { context.startPfxCompiled(); int vsize = context.getVsize(); for (int n = 0; n < vsize; n++) { context.prepareVdForStore(n); context.getMethodVisitor().visitInsn(Opcodes.FCONST_1); context.storeVd(n); } context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; return Common.disasmVD("vone", 1+one+(two<<1), vd); } }; public static final Instruction VRCP = new Instruction(177, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VRCP"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVRCP(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { context.compileVFPUInstr(1.0f, Opcodes.FDIV, null); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vrcp", 1+one+(two<<1), vd, vs); } }; public static final Instruction VRSQ = new Instruction(178, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VRSQ"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVRSQ(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { context.compileVFPUInstr(1.0f, Opcodes.FDIV, "sqrt"); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vrsq", 1+one+(two<<1), vd, vs); } }; public static final Instruction VSIN = new Instruction(179, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VSIN"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVSIN(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vsin", 1+one+(two<<1), vd, vs); } }; public static final Instruction VCOS = new Instruction(180, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VCOS"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVCOS(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vcos", 1+one+(two<<1), vd, vs); } }; public static final Instruction VEXP2 = new Instruction(181, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VEXP2"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVEXP2(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vexp2", 1+one+(two<<1), vd, vs); } }; public static final Instruction VLOG2 = new Instruction(182, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VLOG2"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVLOG2(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vlog2", 1+one+(two<<1), vd, vs); } }; public static final Instruction VSQRT = new Instruction(183, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VSQRT"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVSQRT(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { context.compileVFPUInstr(null, Opcodes.NOP, "sqrt"); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vsqrt", 1+one+(two<<1), vd, vs); } }; public static final Instruction VASIN = new Instruction(184, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VASIN"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVASIN(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vasin", 1+one+(two<<1), vd, vs); } }; public static final Instruction VNRCP = new Instruction(185, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VNRCP"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVNRCP(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vnrcp", 1+one+(two<<1), vd, vs); } }; public static final Instruction VNSIN = new Instruction(186, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VNSIN"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVNSIN(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vnsin", 1+one+(two<<1), vd, vs); } }; public static final Instruction VREXP2 = new Instruction(187, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VREXP2"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVREXP2(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vrexp2", 1+one+(two<<1), vd, vs); } }; public static final Instruction VRNDS = new Instruction(188, FLAG_USE_VFPU_PFXS) { @Override public final String name() { return "VRNDS"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVRNDS(1+one+(two<<1), vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVS("vrnds", 1+one+(two<<1), vs); } }; public static final Instruction VRNDI = new Instruction(189, FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VRNDI"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; processor.cpu.doVRNDI(1+one+(two<<1), vd); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; return Common.disasmVD("vrndi", 1+one+(two<<1), vd); } }; public static final Instruction VRNDF1 = new Instruction(190, FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VRNDF1"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; processor.cpu.doVRNDF1(1+one+(two<<1), vd); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; return Common.disasmVD("vrndf1", 1+one+(two<<1), vd); } }; public static final Instruction VRNDF2 = new Instruction(191, FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VRNDF2"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; processor.cpu.doVRNDF2(1+one+(two<<1), vd); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; return Common.disasmVD("vrndf2", 1+one+(two<<1), vd); } }; public static final Instruction VF2H = new Instruction(192, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VF2H"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVF2H(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vf2h", 1+one+(two<<1), vd, vs); } }; public static final Instruction VH2F = new Instruction(193, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VH2F"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVH2F(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vh2f", 1+one+(two<<1), vd, vs); } }; public static final Instruction VSBZ = new Instruction(194) { @Override public final String name() { return "VSBZ"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVSBZ(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("VSBZ", 1+one+(two<<1), vd, vs); } }; public static final Instruction VLGB = new Instruction(195) { @Override public final String name() { return "VLGB"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVLGB(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vlgb", 1+one+(two<<1), vd, vs); } }; public static final Instruction VUC2I = new Instruction(196, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VUC2I"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVUC2I(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vuc2i", 1+one+(two<<1), 4, vd, vs); } }; public static final Instruction VC2I = new Instruction(197, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VC2I"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVC2I(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("VC2I", 1+one+(two<<1), 4, vd, vs); } }; public static final Instruction VUS2I = new Instruction(198, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VUS2I"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVUS2I(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vus2i", 1+one+(two<<1), 1+(one<<1), vd, vs); } }; public static final Instruction VS2I = new Instruction(199, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VS2I"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVS2I(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vs2i", 1+one+(two<<1), 1+(one<<1), vd, vs); } }; public static final Instruction VI2UC = new Instruction(200, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VI2UC"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVI2UC(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { final int vsize = context.getVsize(); if (vsize == 4) { MethodVisitor mv = context.getMethodVisitor(); context.startPfxCompiled(false); context.prepareVdForStoreInt(1, 0); for (int n = 0; n < vsize; n++) { context.loadVsInt(n); mv.visitInsn(Opcodes.DUP); Label afterLabel = new Label(); Label negativeLabel = new Label(); mv.visitJumpInsn(Opcodes.IFLT, negativeLabel); context.loadImm(23); mv.visitInsn(Opcodes.ISHR); if (n > 0) { context.loadImm(n * 8); mv.visitInsn(Opcodes.ISHL); mv.visitInsn(Opcodes.IOR); } mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(negativeLabel); mv.visitInsn(Opcodes.POP); if (n == 0) { context.loadImm(0); } mv.visitLabel(afterLabel); } context.storeVdInt(1, 0); context.endPfxCompiled(1, false); } else { // Only supported VI2UC.Q context.compileInterpreterInstruction(); } } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVD1VS("vi2uc", 1+one+(two<<1), vd, vs); } }; public static final Instruction VI2C = new Instruction(201, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VI2C"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVI2C(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVD1VS("vi2c", 1+one+(two<<1), vd, vs); } }; public static final Instruction VI2US = new Instruction(202, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VI2US"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVI2US(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vi2us", 1+one+(two<<1), 1+two, vd, vs); } }; public static final Instruction VI2S = new Instruction(203, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VI2S"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVI2S(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vi2s", 1+one+(two<<1), 1+two, vd, vs); } }; public static final Instruction VSRT1 = new Instruction(204, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VSRT1"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVSRT1(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vsrt1", 1+one+(two<<1), vd, vs); } }; public static final Instruction VSRT2 = new Instruction(205, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VSRT2"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVSRT2(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vsrt2", 1+one+(two<<1), vd, vs); } }; public static final Instruction VBFY1 = new Instruction(206, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VBFY1"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVBFY1(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vbfy1", 1+one+(two<<1), vd, vs); } }; public static final Instruction VBFY2 = new Instruction(207, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VBFY2"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVBFY2(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vbfy2", 1+one+(two<<1), vd, vs); } }; public static final Instruction VOCP = new Instruction(208, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VOCP"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVOCP(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vocp", 1+one+(two<<1), vd, vs); } }; public static final Instruction VSOCP = new Instruction(209, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VSOCP"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVSOCP(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vsocp", 1+one+(two<<1), 1+(one<<1), vd, vs); } }; public static final Instruction VFAD = new Instruction(210, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VFAD"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVFAD(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVD1VS("vfad", 1+one+(two<<1), vd, vs); } }; public static final Instruction VAVG = new Instruction(211, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VAVG"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVAVG(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVD1VS("vavg", 1+one+(two<<1), vd, vs); } }; public static final Instruction VSRT3 = new Instruction(212, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VSRT3"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVSRT3(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vsrt3", 1+one+(two<<1), vd, vs); } }; public static final Instruction VSGN = new Instruction(251, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VSGN"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVSGN(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vsgn", 1+one+(two<<1), vd, vs); } }; public static final Instruction VSRT4 = new Instruction(213, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VSRT4"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVSRT4(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vsrt4", 1+one+(two<<1), vd, vs); } }; public static final Instruction VMFVC = new Instruction(214, FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VMFVC"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int imm7 = (insn>>8)&127; processor.cpu.doVMFVC(vd, imm7); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int imm7 = (insn>>8)&127; return "Unimplemented VMFVC imm7=" + imm7 + ", vd=" + vd; } }; public static final Instruction VMTVC = new Instruction(215) { @Override public final String name() { return "VMTVC"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int imm7 = (insn>>0)&127; int vs = (insn>>8)&127; processor.cpu.doVMTVC(vs, imm7); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int imm7 = (insn>>0)&127; int vs = (insn>>8)&127; return "Unimplemented VMTVC imm7=" + imm7 + ", vs=" + vs; } }; public static final Instruction VT4444 = new Instruction(216, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VT4444"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVT4444(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vt4444", 1+one+(two<<1), vd, vs); } }; public static final Instruction VT5551 = new Instruction(217, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VT5551"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVT5551(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vt5551", 1+one+(two<<1), vd, vs); } }; public static final Instruction VT5650 = new Instruction(218, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VT5650"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVT5650(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDVS("vt5650", 1+one+(two<<1), vd, vs); } }; public static final Instruction VCST = new Instruction(219, FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VCST"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; processor.cpu.doVCST(1+one+(two<<1), vd, imm5); } @Override public void compile(ICompilerContext context, int insn) { int imm5 = (insn>>16)&31; float constant = 0.0f; if (imm5 < VfpuState.floatConstants.length) { constant = VfpuState.floatConstants[imm5]; } context.startPfxCompiled(); int vsize = context.getVsize(); for (int n = 0; n < vsize; n++) { context.prepareVdForStore(n); context.getMethodVisitor().visitLdcInsn(constant); context.storeVd(n); } context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; return Common.disasmVDCST("VCST", 1+one+(two<<1), vd, imm5); } }; public static final Instruction VF2IN = new Instruction(220, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VF2IN"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; processor.cpu.doVF2IN(1+one+(two<<1), vd, vs, imm5); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); int imm5 = context.getImm5(); MethodVisitor mv = context.getMethodVisitor(); context.startPfxCompiled(false); for (int n = 0; n < vsize; n++) { context.prepareVdForStoreInt(n); context.loadVs(n); if (imm5 != 0) { context.loadImm(imm5); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "scalb", "(FI)F"); } Label afterLabel = new Label(); Label notNaNValueLabel = new Label(); mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Float.class), "isNaN", "(F)Z"); mv.visitJumpInsn(Opcodes.IFEQ, notNaNValueLabel); mv.visitInsn(Opcodes.POP); context.loadImm(0x7FFFFFFF); mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(notNaNValueLabel); mv.visitInsn(Opcodes.F2D); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "rint", "(D)D"); mv.visitInsn(Opcodes.D2I); mv.visitLabel(afterLabel); context.storeVdInt(n); } context.endPfxCompiled(false); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; return Common.disasmVDVSIMM("vf2in", 1+one+(two<<1), vd, vs, imm5); } }; public static final Instruction VF2IZ = new Instruction(221, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VF2IZ"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; processor.cpu.doVF2IZ(1+one+(two<<1), vd, vs, imm5); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); int imm5 = context.getImm5(); MethodVisitor mv = context.getMethodVisitor(); context.startPfxCompiled(false); for (int n = 0; n < vsize; n++) { context.prepareVdForStoreInt(n); context.loadVs(n); mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(0.f); mv.visitInsn(Opcodes.FCMPG); // Use FCMPG or FCMPL? Need to check handling of NaN value Label negativeLabel = new Label(); Label afterSignTestLabel = new Label(); mv.visitJumpInsn(Opcodes.IFLT, negativeLabel); if (imm5 != 0) { context.loadImm(imm5); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "scalb", "(FI)F"); } mv.visitInsn(Opcodes.F2D); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "floor", "(D)D"); mv.visitJumpInsn(Opcodes.GOTO, afterSignTestLabel); mv.visitLabel(negativeLabel); if (imm5 != 0) { context.loadImm(imm5); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "scalb", "(FI)F"); } mv.visitInsn(Opcodes.F2D); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "ceil", "(D)D"); mv.visitLabel(afterSignTestLabel); Label afterLabel = new Label(); Label notNaNValueLabel = new Label(); mv.visitInsn(Opcodes.DUP2); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Double.class), "isNaN", "(D)Z"); mv.visitJumpInsn(Opcodes.IFEQ, notNaNValueLabel); mv.visitInsn(Opcodes.POP2); context.loadImm(0x7FFFFFFF); mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(notNaNValueLabel); mv.visitInsn(Opcodes.D2I); mv.visitLabel(afterLabel); context.storeVdInt(n); } context.endPfxCompiled(false); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; return Common.disasmVDVSIMM("vf2iz", 1+one+(two<<1), vd, vs, imm5); } }; public static final Instruction VF2IU = new Instruction(222, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VF2IU"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; processor.cpu.doVF2IU(1+one+(two<<1), vd, vs, imm5); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); int imm5 = context.getImm5(); MethodVisitor mv = context.getMethodVisitor(); context.startPfxCompiled(false); for (int n = 0; n < vsize; n++) { context.prepareVdForStoreInt(n); context.loadVs(n); if (imm5 != 0) { context.loadImm(imm5); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "scalb", "(FI)F"); } mv.visitInsn(Opcodes.F2D); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "ceil", "(D)D"); Label afterLabel = new Label(); Label notNaNValueLabel = new Label(); mv.visitInsn(Opcodes.DUP2); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Double.class), "isNaN", "(D)Z"); mv.visitJumpInsn(Opcodes.IFEQ, notNaNValueLabel); mv.visitInsn(Opcodes.POP2); context.loadImm(0x7FFFFFFF); mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(notNaNValueLabel); mv.visitInsn(Opcodes.D2I); mv.visitLabel(afterLabel); context.storeVdInt(n); } context.endPfxCompiled(false); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; return Common.disasmVDVSIMM("vf2iu", 1+one+(two<<1), vd, vs, imm5); } }; public static final Instruction VF2ID = new Instruction(223, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VF2ID"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; processor.cpu.doVF2ID(1+one+(two<<1), vd, vs, imm5); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); int imm5 = context.getImm5(); MethodVisitor mv = context.getMethodVisitor(); context.startPfxCompiled(false); for (int n = 0; n < vsize; n++) { context.prepareVdForStoreInt(n); context.loadVs(n); if (imm5 != 0) { context.loadImm(imm5); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "scalb", "(FI)F"); } mv.visitInsn(Opcodes.F2D); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "floor", "(D)D"); Label afterLabel = new Label(); Label notNaNValueLabel = new Label(); mv.visitInsn(Opcodes.DUP2); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Double.class), "isNaN", "(D)Z"); mv.visitJumpInsn(Opcodes.IFEQ, notNaNValueLabel); mv.visitInsn(Opcodes.POP2); context.loadImm(0x7FFFFFFF); mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(notNaNValueLabel); mv.visitInsn(Opcodes.D2I); mv.visitLabel(afterLabel); context.storeVdInt(n); } context.endPfxCompiled(false); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; return Common.disasmVDVSIMM("vf2id", 1+one+(two<<1), vd, vs, imm5); } }; public static final Instruction VI2F = new Instruction(224, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VI2F"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; processor.cpu.doVI2F(1+one+(two<<1), vd, vs, imm5); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); int imm5 = context.getImm5(); MethodVisitor mv = context.getMethodVisitor(); context.startPfxCompiled(); for (int n = 0; n < vsize; n++) { context.prepareVdForStore(n); context.loadVsInt(n); mv.visitInsn(Opcodes.I2F); if (imm5 != 0) { context.loadImm(-imm5); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "scalb", "(FI)F"); } context.storeVd(n); } context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; return Common.disasmVDVSIMM("vi2f", 1+one+(two<<1), vd, vs, imm5); } }; public static final Instruction VCMOVT = new Instruction(225, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VCMOVT"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm3 = (insn>>16)&7; processor.cpu.doVCMOVT(1+one+(two<<1), imm3, vd, vs); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); int imm3 = context.getImm3(); MethodVisitor mv = context.getMethodVisitor(); if (imm3 < 6) { context.startPfxCompiled(false); Label notMoveLabel = new Label(); Label afterLabel = new Label(); context.loadVcrCc(imm3); mv.visitJumpInsn(Opcodes.IFEQ, notMoveLabel); for (int n = 0; n < vsize; n++) { context.prepareVdForStoreInt(n); context.loadVsInt(n); context.storeVdInt(n); } context.endPfxCompiled(false); mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(notMoveLabel); if (context.getPfxdState().isKnown() && context.getPfxdState().pfxDst.enabled) { for (int n = 0; n < vsize; n++) { context.prepareVdForStoreInt(n); context.loadVdInt(n); context.storeVdInt(n); } context.endPfxCompiled(false); } mv.visitLabel(afterLabel); } else if (imm3 == 6) { context.startPfxCompiled(false); for (int n = 0; n < vsize; n++) { Label notMoveLabel = new Label(); Label afterLabel = new Label(); context.loadVcrCc(n); mv.visitJumpInsn(Opcodes.IFEQ, notMoveLabel); context.prepareVdForStoreInt(n); context.loadVsInt(n); context.storeVdInt(n); mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(notMoveLabel); if (context.getPfxdState().isKnown() && context.getPfxdState().pfxDst.enabled) { context.prepareVdForStoreInt(n); context.loadVdInt(n); context.storeVdInt(n); } mv.visitLabel(afterLabel); } context.endPfxCompiled(false); } else { // Never copy } } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm3 = (insn>>16)&7; return Common.disasmVDVSIMM("VCMOVT", 1+one+(two<<1), vd, vs, imm3); } }; public static final Instruction VCMOVF = new Instruction(226, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VCMOVF"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm3 = (insn>>16)&7; processor.cpu.doVCMOVF(1+one+(two<<1), imm3, vd, vs); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); int imm3 = context.getImm3(); MethodVisitor mv = context.getMethodVisitor(); context.startPfxCompiled(false); if (imm3 < 6) { Label notMoveLabel = new Label(); Label afterLabel = new Label(); context.loadVcrCc(imm3); mv.visitJumpInsn(Opcodes.IFNE, notMoveLabel); for (int n = 0; n < vsize; n++) { context.prepareVdForStoreInt(n); context.loadVsInt(n); context.storeVdInt(n); } mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(notMoveLabel); if (context.getPfxdState().isKnown() && context.getPfxdState().pfxDst.enabled) { for (int n = 0; n < vsize; n++) { context.prepareVdForStoreInt(n); context.loadVdInt(n); context.storeVdInt(n); } } mv.visitLabel(afterLabel); } else if (imm3 == 6) { for (int n = 0; n < vsize; n++) { Label notMoveLabel = new Label(); Label afterLabel = new Label(); context.loadVcrCc(n); mv.visitJumpInsn(Opcodes.IFNE, notMoveLabel); context.prepareVdForStoreInt(n); context.loadVsInt(n); context.storeVdInt(n); mv.visitJumpInsn(Opcodes.GOTO, afterLabel); mv.visitLabel(notMoveLabel); if (context.getPfxdState().isKnown() && context.getPfxdState().pfxDst.enabled) { context.prepareVdForStoreInt(n); context.loadVdInt(n); context.storeVdInt(n); } mv.visitLabel(afterLabel); } } else { // Always copy for (int n = 0; n < vsize; n++) { context.prepareVdForStoreInt(n); context.loadVsInt(n); context.storeVdInt(n); } } context.endPfxCompiled(false); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm3 = (insn>>16)&7; return Common.disasmVDVSIMM("VCMOVF", 1+one+(two<<1), vd, vs, imm3); } }; public static final Instruction VWBN = new Instruction(227) { @Override public final String name() { return "VWBN"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm8 = (insn>>16)&255; processor.cpu.doVWBN(1+one+(two<<1), vd, vs, imm8); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm8 = (insn>>16)&255; return Common.disasmVDVSIMM("VWBN", 1+one+(two<<1), vd, vs, imm8); } }; public static final Instruction VPFXS = new Instruction(228) { @Override public final String name() { return "VPFXS"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int swzx = (insn>>0)&3; int swzy = (insn>>2)&3; int swzz = (insn>>4)&3; int swzw = (insn>>6)&3; int absx = (insn>>8)&1; int absy = (insn>>9)&1; int absz = (insn>>10)&1; int absw = (insn>>11)&1; int cstx = (insn>>12)&1; int csty = (insn>>13)&1; int cstz = (insn>>14)&1; int cstw = (insn>>15)&1; int negx = (insn>>16)&1; int negy = (insn>>17)&1; int negz = (insn>>18)&1; int negw = (insn>>19)&1; processor.cpu.doVPFXS( negw, negz, negy, negx, cstw, cstz, csty, cstx, absw, absz, absy, absx, swzw, swzz, swzy, swzx ); } @Override public void compile(ICompilerContext context, int insn) { if (context.isPfxConsumed(FLAG_USE_VFPU_PFXS)) { context.getPfxsState().setKnown(true); PfxSrc pfxSrc = context.getPfxsState().pfxSrc; pfxSrc.swz[0] = (insn>>0)&3; pfxSrc.swz[1] = (insn>>2)&3; pfxSrc.swz[2] = (insn>>4)&3; pfxSrc.swz[3] = (insn>>6)&3; pfxSrc.abs[0] = ((insn>>8)&1) != 0; pfxSrc.abs[1] = ((insn>>9)&1) != 0; pfxSrc.abs[2] = ((insn>>10)&1) != 0; pfxSrc.abs[3] = ((insn>>11)&1) != 0; pfxSrc.cst[0] = ((insn>>12)&1) != 0; pfxSrc.cst[1] = ((insn>>13)&1) != 0; pfxSrc.cst[2] = ((insn>>14)&1) != 0; pfxSrc.cst[3] = ((insn>>15)&1) != 0; pfxSrc.neg[0] = ((insn>>16)&1) != 0; pfxSrc.neg[1] = ((insn>>17)&1) != 0; pfxSrc.neg[2] = ((insn>>18)&1) != 0; pfxSrc.neg[3] = ((insn>>19)&1) != 0; pfxSrc.enabled = true; } else { context.getPfxsState().setKnown(false); context.compileInterpreterInstruction(); } } @Override public String disasm(int address, int insn) { int swzx = (insn>>0)&3; int swzy = (insn>>2)&3; int swzz = (insn>>4)&3; int swzw = (insn>>6)&3; int absx = (insn>>8)&1; int absy = (insn>>9)&1; int absz = (insn>>10)&1; int absw = (insn>>11)&1; int cstx = (insn>>12)&1; int csty = (insn>>13)&1; int cstz = (insn>>14)&1; int cstw = (insn>>15)&1; int negx = (insn>>16)&1; int negy = (insn>>17)&1; int negz = (insn>>18)&1; int negw = (insn>>19)&1; int[] swz = new int[4]; boolean[] abs, cst, neg; abs = new boolean[4]; cst = new boolean[4]; neg = new boolean[4]; swz[0] = swzx; swz[1] = swzy; swz[2] = swzz; swz[3] = swzw; abs[0] = absx != 0; abs[1] = absy != 0; abs[2] = absz != 0; abs[3] = absw != 0; cst[0] = cstx != 0; cst[1] = csty != 0; cst[2] = cstz != 0; cst[3] = cstw != 0; neg[0] = negx != 0; neg[1] = negy != 0; neg[2] = negz != 0; neg[3] = negw != 0; return Common.disasmVPFX("VPFXS", swz, abs, cst, neg); } }; public static final Instruction VPFXT = new Instruction(229) { @Override public final String name() { return "VPFXT"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int swzx = (insn>>0)&3; int swzy = (insn>>2)&3; int swzz = (insn>>4)&3; int swzw = (insn>>6)&3; int absx = (insn>>8)&1; int absy = (insn>>9)&1; int absz = (insn>>10)&1; int absw = (insn>>11)&1; int cstx = (insn>>12)&1; int csty = (insn>>13)&1; int cstz = (insn>>14)&1; int cstw = (insn>>15)&1; int negx = (insn>>16)&1; int negy = (insn>>17)&1; int negz = (insn>>18)&1; int negw = (insn>>19)&1; processor.cpu.doVPFXT( negw, negz, negy, negx, cstw, cstz, csty, cstx, absw, absz, absy, absx, swzw, swzz, swzy, swzx ); } @Override public void compile(ICompilerContext context, int insn) { if (context.isPfxConsumed(FLAG_USE_VFPU_PFXT)) { context.getPfxtState().setKnown(true); PfxSrc pfxSrc = context.getPfxtState().pfxSrc; pfxSrc.swz[0] = (insn>>0)&3; pfxSrc.swz[1] = (insn>>2)&3; pfxSrc.swz[2] = (insn>>4)&3; pfxSrc.swz[3] = (insn>>6)&3; pfxSrc.abs[0] = ((insn>>8)&1) != 0; pfxSrc.abs[1] = ((insn>>9)&1) != 0; pfxSrc.abs[2] = ((insn>>10)&1) != 0; pfxSrc.abs[3] = ((insn>>11)&1) != 0; pfxSrc.cst[0] = ((insn>>12)&1) != 0; pfxSrc.cst[1] = ((insn>>13)&1) != 0; pfxSrc.cst[2] = ((insn>>14)&1) != 0; pfxSrc.cst[3] = ((insn>>15)&1) != 0; pfxSrc.neg[0] = ((insn>>16)&1) != 0; pfxSrc.neg[1] = ((insn>>17)&1) != 0; pfxSrc.neg[2] = ((insn>>18)&1) != 0; pfxSrc.neg[3] = ((insn>>19)&1) != 0; pfxSrc.enabled = true; } else { context.getPfxtState().setKnown(false); context.compileInterpreterInstruction(); } } @Override public String disasm(int address, int insn) { int swzx = (insn>>0)&3; int swzy = (insn>>2)&3; int swzz = (insn>>4)&3; int swzw = (insn>>6)&3; int absx = (insn>>8)&1; int absy = (insn>>9)&1; int absz = (insn>>10)&1; int absw = (insn>>11)&1; int cstx = (insn>>12)&1; int csty = (insn>>13)&1; int cstz = (insn>>14)&1; int cstw = (insn>>15)&1; int negx = (insn>>16)&1; int negy = (insn>>17)&1; int negz = (insn>>18)&1; int negw = (insn>>19)&1; int[] swz = new int[4]; boolean[] abs, cst, neg; abs = new boolean[4]; cst = new boolean[4]; neg = new boolean[4]; swz[0] = swzx; swz[1] = swzy; swz[2] = swzz; swz[3] = swzw; abs[0] = absx != 0; abs[1] = absy != 0; abs[2] = absz != 0; abs[3] = absw != 0; cst[0] = cstx != 0; cst[1] = csty != 0; cst[2] = cstz != 0; cst[3] = cstw != 0; neg[0] = negx != 0; neg[1] = negy != 0; neg[2] = negz != 0; neg[3] = negw != 0; return Common.disasmVPFX("VPFXT", swz, abs, cst, neg); } }; public static final Instruction VPFXD = new Instruction(230) { @Override public final String name() { return "VPFXD"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int satx = (insn>>0)&3; int saty = (insn>>2)&3; int satz = (insn>>4)&3; int satw = (insn>>6)&3; int mskx = (insn>>8)&1; int msky = (insn>>9)&1; int mskz = (insn>>10)&1; int mskw = (insn>>11)&1; processor.cpu.doVPFXD( mskw, mskz, msky, mskx, satw, satz, saty, satx ); } @Override public void compile(ICompilerContext context, int insn) { if (context.isPfxConsumed(FLAG_USE_VFPU_PFXD)) { context.getPfxdState().setKnown(true); PfxDst pfxDst = context.getPfxdState().pfxDst; pfxDst.sat[0] = (insn>>0)&3; pfxDst.sat[1] = (insn>>2)&3; pfxDst.sat[2] = (insn>>4)&3; pfxDst.sat[3] = (insn>>6)&3; pfxDst.msk[0] = ((insn>>8)&1) != 0; pfxDst.msk[1] = ((insn>>9)&1) != 0; pfxDst.msk[2] = ((insn>>10)&1) != 0; pfxDst.msk[3] = ((insn>>11)&1) != 0; pfxDst.enabled = true; } else { context.getPfxdState().setKnown(false); context.compileInterpreterInstruction(); } } @Override public String disasm(int address, int insn) { int satx = (insn>>0)&3; int saty = (insn>>2)&3; int satz = (insn>>4)&3; int satw = (insn>>6)&3; int mskx = (insn>>8)&1; int msky = (insn>>9)&1; int mskz = (insn>>10)&1; int mskw = (insn>>11)&1; int[] sat, msk; sat = new int[4]; msk = new int[4]; sat[0] = satx; sat[1] = saty; sat[2] = satz; sat[3] = satw; msk[0] = mskx; msk[1] = msky; msk[2] = mskz; msk[3] = mskw; return Common.disasmVPFXD("VPFXD", sat, msk); } }; public static final Instruction VIIM = new Instruction(231, FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VIIM"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int vd = (insn>>16)&127; processor.cpu.doVIIM(vd, (int)(short) imm16); } @Override public void compile(ICompilerContext context, int insn) { final int vsize = 1; final int vd = context.getVtRegisterIndex(); // vd index stored as vt int simm16 = context.getImm16(true); context.startPfxCompiled(); context.prepareVdForStore(vsize, vd, 0); context.getMethodVisitor().visitLdcInsn((float) simm16); context.storeVd(vsize, vd, 0); context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int vd = (insn>>16)&127; return Common.disasmVDIIM("VIIM", 1, vd, imm16); } }; public static final Instruction VFIM = new Instruction(232, FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VFIM"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int imm16 = (insn>>0)&65535; int vd = (insn>>16)&127; processor.cpu.doVFIM(vd, imm16); } @Override public void compile(ICompilerContext context, int insn) { final int vsize = 1; final int vd = context.getVtRegisterIndex(); // vd index stored as vt final int imm16 = context.getImm16(false); int value = VfpuState.halffloatToFloat(imm16); context.startPfxCompiled(); context.prepareVdForStoreInt(vsize, vd, 0); context.loadImm(value); context.storeVdInt(vsize, vd, 0); context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int imm16 = (insn>>0)&65535; int vd = (insn>>16)&127; return Common.disasmVDFIM("VFIM", 1, vd, imm16); } }; public static final Instruction VMMUL = new Instruction(233, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VMMUL"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVMMUL(1+one+(two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { int vsize = context.getVsize(); if (vsize > 1) { context.startPfxCompiled(); int vs = context.getVsRegisterIndex(); int vt = context.getVtRegisterIndex(); int vd = context.getVdRegisterIndex(); for (int i = 0; i < vsize; i++) { for (int j = 0; j < vsize; j++) { context.prepareVdForStore(vsize, vd + i, j); context.loadVs(vsize, vs + j, 0); context.loadVt(vsize, vt + i, 0); context.getMethodVisitor().visitInsn(Opcodes.FMUL); for (int n = 1; n < vsize; n++) { context.loadVs(vsize, vs + j, n); context.loadVt(vsize, vt + i, n); context.getMethodVisitor().visitInsn(Opcodes.FMUL); context.getMethodVisitor().visitInsn(Opcodes.FADD); } context.storeVd(vsize, vd + i, j); } context.flushPfxCompiled(vsize, vd + i, true); } context.endPfxCompiled(vsize, true, false); } else { // Unsupported VMMUL.S context.compileInterpreterInstruction(); } } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDMVSMVTM("VMMUL", 1+one+(two<<1), vd, vs ^ 32, vt); } }; public static final Instruction VHTFM2 = new Instruction(234, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VHTFM2"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; processor.cpu.doVHTFM2(vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; return Common.disasmVDVSMVT("VHTFM2", 2, vd, vs, vt); } }; public static final Instruction VTFM2 = new Instruction(235, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VTFM2"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; processor.cpu.doVTFM2(vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; return Common.disasmVDVSMVT("VTFM2", 2, vd, vs, vt); } }; public static final Instruction VHTFM3 = new Instruction(236, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VHTFM3"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; processor.cpu.doVHTFM3(vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; return Common.disasmVDVSMVT("VHTFM3", 3, vd, vs, vt); } }; public static final Instruction VTFM3 = new Instruction(237, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VTFM3"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; processor.cpu.doVTFM3(vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { final int vsize = 3; final int vs = context.getVsRegisterIndex(); MethodVisitor mv = context.getMethodVisitor(); context.loadVt(vsize, 0); context.storeFTmp1(); context.loadVt(vsize, 1); context.storeFTmp2(); context.loadVt(vsize, 2); context.storeFTmp3(); for (int n = 0; n < vsize; n++) { context.prepareVdForStore(vsize, n); context.loadVs(vsize, vs + n, 0); context.loadFTmp1(); mv.visitInsn(Opcodes.FMUL); context.loadVs(vsize, vs + n, 1); context.loadFTmp2(); mv.visitInsn(Opcodes.FMUL); mv.visitInsn(Opcodes.FADD); context.loadVs(vsize, vs + n, 2); context.loadFTmp3(); mv.visitInsn(Opcodes.FMUL); mv.visitInsn(Opcodes.FADD); context.storeVd(vsize, n); } } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; return Common.disasmVDVSMVT("VTFM3", 3, vd, vs, vt); } }; public static final Instruction VHTFM4 = new Instruction(238, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VHTFM4"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; processor.cpu.doVHTFM4(vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { final int vsize = 4; final int vs = context.getVsRegisterIndex(); MethodVisitor mv = context.getMethodVisitor(); context.loadVt(3, 0); context.storeFTmp1(); context.loadVt(3, 1); context.storeFTmp2(); context.loadVt(3, 2); context.storeFTmp3(); for (int n = 0; n < vsize; n++) { context.prepareVdForStore(vsize, n); context.loadVs(vsize, vs + n, 0); context.loadFTmp1(); mv.visitInsn(Opcodes.FMUL); context.loadVs(vsize, vs + n, 1); context.loadFTmp2(); mv.visitInsn(Opcodes.FMUL); mv.visitInsn(Opcodes.FADD); context.loadVs(vsize, vs + n, 2); context.loadFTmp3(); mv.visitInsn(Opcodes.FMUL); mv.visitInsn(Opcodes.FADD); context.loadVs(vsize, vs + n, 3); mv.visitInsn(Opcodes.FADD); context.storeVd(vsize, n); } } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; return Common.disasmVDVSMVT("VHTFM4", 4, vd, vs, vt); } }; public static final Instruction VTFM4 = new Instruction(239, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VTFM4"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; processor.cpu.doVTFM4(vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { final int vsize = 4; final int vs = context.getVsRegisterIndex(); MethodVisitor mv = context.getMethodVisitor(); context.loadVt(vsize, 0); context.storeFTmp1(); context.loadVt(vsize, 1); context.storeFTmp2(); context.loadVt(vsize, 2); context.storeFTmp3(); context.loadVt(vsize, 3); context.storeFTmp4(); for (int n = 0; n < vsize; n++) { context.prepareVdForStore(vsize, n); context.loadVs(vsize, vs + n, 0); context.loadFTmp1(); mv.visitInsn(Opcodes.FMUL); context.loadVs(vsize, vs + n, 1); context.loadFTmp2(); mv.visitInsn(Opcodes.FMUL); mv.visitInsn(Opcodes.FADD); context.loadVs(vsize, vs + n, 2); context.loadFTmp3(); mv.visitInsn(Opcodes.FMUL); mv.visitInsn(Opcodes.FADD); context.loadVs(vsize, vs + n, 3); context.loadFTmp4(); mv.visitInsn(Opcodes.FMUL); mv.visitInsn(Opcodes.FADD); context.storeVd(vsize, n); } } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; return Common.disasmVDVSMVT("VTFM4", 4, vd, vs, vt); } }; public static final Instruction VMSCL = new Instruction(240, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VMSCL"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; processor.cpu.doVMSCL(1+one+(two<<1), vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { final int vsize = context.getVsize(); if (vsize > 1) { final int vs = context.getVsRegisterIndex(); final int vd = context.getVdRegisterIndex(); context.startPfxCompiled(); context.loadVt(1, 0); context.storeFTmp1(); for (int i = 0; i < vsize; i++) { for (int n = 0; n < vsize; n++) { context.prepareVdForStore(vsize, vd + i, n); context.loadVs(vsize, vs + i, n); context.loadFTmp1(); context.getMethodVisitor().visitInsn(Opcodes.FMUL); context.storeVd(vsize, vd + i, n); } context.flushPfxCompiled(vsize, vd + i, true); } context.endPfxCompiled(vsize, true, false); } else { // Unsupported VMSCL.S context.compileInterpreterInstruction(); } } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vmscl", 1+one+(two<<1), vd, vs, vt); } }; public static final Instruction VCRSP = new Instruction(241, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VCRSP"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; processor.cpu.doVCRSP(vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { context.startPfxCompiled(); final int vsize = 3; MethodVisitor mv = context.getMethodVisitor(); // v3[0] = +v1[1] * v2[2] - v1[2] * v2[1]; context.prepareVdForStore(vsize, 0); context.loadVs(vsize, 1); context.loadVt(vsize, 2); mv.visitInsn(Opcodes.FMUL); context.loadVs(vsize, 2); context.loadVt(vsize, 1); mv.visitInsn(Opcodes.FMUL); mv.visitInsn(Opcodes.FSUB); context.storeVd(vsize, 0); // v3[1] = +v1[2] * v2[0] - v1[0] * v2[2]; context.prepareVdForStore(vsize, 1); context.loadVs(vsize, 2); context.loadVt(vsize, 0); mv.visitInsn(Opcodes.FMUL); context.loadVs(vsize, 0); context.loadVt(vsize, 2); mv.visitInsn(Opcodes.FMUL); mv.visitInsn(Opcodes.FSUB); context.storeVd(vsize, 1); // v3[2] = +v1[0] * v2[1] - v1[1] * v2[0]; context.prepareVdForStore(vsize, 2); context.loadVs(vsize, 0); context.loadVt(vsize, 1); mv.visitInsn(Opcodes.FMUL); context.loadVs(vsize, 1); context.loadVt(vsize, 0); mv.visitInsn(Opcodes.FMUL); mv.visitInsn(Opcodes.FSUB); context.storeVd(vsize, 2); context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; return Common.disasmVDVSVT("vcrsp", 3, vd, vs, vt); } }; public static final Instruction VQMUL = new Instruction(242, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXT | FLAG_USE_VFPU_PFXD) { @Override public final String name() { return "VQMUL"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; processor.cpu.doVQMUL(vd, vs, vt); } @Override public void compile(ICompilerContext context, int insn) { super.compile(context, insn); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int vs = (insn>>8)&127; int vt = (insn>>16)&127; return Common.disasmVDVSVT("VQMUL", 4, vd, vs, vt); } }; public static final Instruction VMMOV = new Instruction(243, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VMMOV"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; processor.cpu.doVMMOV(1+one+(two<<1), vd, vs); } @Override public void compile(ICompilerContext context, int insn) { final int vsize = context.getVsize(); final int vd = context.getVdRegisterIndex(); final int vs = context.getVsRegisterIndex(); context.startPfxCompiled(false); for (int i = 0; i < vsize; i++) { for (int n = 0; n < vsize; n++) { context.prepareVdForStoreInt(vsize, vd + i, n); context.loadVsInt(vsize, vs + i, n); context.storeVdInt(vsize, vd + i, n); } context.flushPfxCompiled(vsize, vd + i, false); } context.endPfxCompiled(vsize, false, false); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; return Common.disasmVDMVSM("VMMOV", 1+one+(two<<1), vd, vs); } }; public static final Instruction VMIDT = new Instruction(244, FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VMIDT"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; processor.cpu.doVMIDT(1+one+(two<<1), vd); } @Override public void compile(ICompilerContext context, int insn) { context.startPfxCompiled(); int vsize = context.getVsize(); int vd = context.getVdRegisterIndex(); for (int i = 0; i < vsize; i++) { for (int n = 0; n < vsize; n++) { context.prepareVdForStore(vsize, vd + i, n); context.getMethodVisitor().visitInsn(i == n ? Opcodes.FCONST_1 : Opcodes.FCONST_0); context.storeVd(vsize, vd + i, n); } context.flushPfxCompiled(vsize, vd + i, true); } context.endPfxCompiled(vsize, true, false); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; return Common.disasmVDM("VMIDT", 1+one+(two<<1), vd); } }; public static final Instruction VMZERO = new Instruction(245, FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VMZERO"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; processor.cpu.doVMZERO(1+one+(two<<1), vd); } @Override public void compile(ICompilerContext context, int insn) { context.startPfxCompiled(); int vsize = context.getVsize(); int vd = context.getVdRegisterIndex(); for (int i = 0; i < vsize; i++) { for (int n = 0; n < vsize; n++) { context.prepareVdForStore(vsize, vd + i, n); context.getMethodVisitor().visitInsn(Opcodes.FCONST_0); context.storeVd(vsize, vd + i, n); } context.flushPfxCompiled(vsize, vd + i, true); } context.endPfxCompiled(vsize, true, false); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; return Common.disasmVDM("VMZERO", 1+one+(two<<1), vd); } }; public static final Instruction VMONE = new Instruction(246, FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VMONE"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; processor.cpu.doVMONE(1+one+(two<<1), vd); } @Override public void compile(ICompilerContext context, int insn) { context.startPfxCompiled(); int vsize = context.getVsize(); int vd = context.getVdRegisterIndex(); for (int i = 0; i < vsize; i++) { for (int n = 0; n < vsize; n++) { context.prepareVdForStore(vsize, vd + i, n); context.getMethodVisitor().visitInsn(Opcodes.FCONST_1); context.storeVd(vsize, vd + i, n); } context.flushPfxCompiled(vsize, vd + i, true); } context.endPfxCompiled(vsize, true, false); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int two = (insn>>15)&1; return Common.disasmVDM("VMONE", 1+one+(two<<1), vd); } }; public static final Instruction VROT = new Instruction(247, FLAG_USE_VFPU_PFXS | FLAG_USE_VFPU_PFXD | FLAG_COMPILED_PFX) { @Override public final String name() { return "VROT"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; processor.cpu.doVROT(1+one+(two<<1), vd, vs, imm5); } @Override public void compile(ICompilerContext context, int insn) { context.startPfxCompiled(); int vsize = context.getVsize(); int imm5 = context.getImm5(); int si = (imm5 >>> 2) & 3; int ci = (imm5 >>> 0) & 3; MethodVisitor mv = context.getMethodVisitor(); Label isNotZero = new Label(); Label isNotOne = new Label(); Label isNotTwo = new Label(); Label computeAngle = new Label(); Label computeResult = new Label(); context.loadVs(1, 0); // Reduce the angle to [0..4[ mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(0.25f); mv.visitInsn(Opcodes.FMUL); mv.visitInsn(Opcodes.F2D); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "floor", "(D)D"); mv.visitInsn(Opcodes.D2F); mv.visitLdcInsn(4f); mv.visitInsn(Opcodes.FMUL); mv.visitInsn(Opcodes.FSUB); // Special case 0.0 mv.visitInsn(Opcodes.DUP); mv.visitInsn(Opcodes.FCONST_0); mv.visitInsn(Opcodes.FCMPG); mv.visitJumpInsn(Opcodes.IFNE, isNotZero); mv.visitInsn(Opcodes.POP); mv.visitInsn(Opcodes.FCONST_1); context.storeFTmp1(); mv.visitInsn(Opcodes.FCONST_0); context.storeFTmp2(); mv.visitJumpInsn(Opcodes.GOTO, computeResult); // Special case 1.0 mv.visitLabel(isNotZero); mv.visitInsn(Opcodes.DUP); mv.visitInsn(Opcodes.FCONST_1); mv.visitInsn(Opcodes.FCMPG); mv.visitJumpInsn(Opcodes.IFNE, isNotOne); mv.visitInsn(Opcodes.POP); mv.visitInsn(Opcodes.FCONST_0); context.storeFTmp1(); mv.visitInsn(Opcodes.FCONST_1); if ((imm5 & 16) != 0) { mv.visitInsn(Opcodes.FNEG); } context.storeFTmp2(); mv.visitJumpInsn(Opcodes.GOTO, computeResult); // Special case 2.0 mv.visitLabel(isNotOne); mv.visitInsn(Opcodes.DUP); mv.visitInsn(Opcodes.FCONST_2); mv.visitInsn(Opcodes.FCMPG); mv.visitJumpInsn(Opcodes.IFNE, isNotTwo); mv.visitInsn(Opcodes.POP); mv.visitInsn(Opcodes.FCONST_1); mv.visitInsn(Opcodes.FNEG); context.storeFTmp1(); mv.visitInsn(Opcodes.FCONST_0); context.storeFTmp2(); mv.visitJumpInsn(Opcodes.GOTO, computeResult); // Special case 3.0 mv.visitLabel(isNotTwo); mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(3f); mv.visitInsn(Opcodes.FCMPG); mv.visitJumpInsn(Opcodes.IFNE, computeAngle); mv.visitInsn(Opcodes.POP); mv.visitInsn(Opcodes.FCONST_0); context.storeFTmp1(); mv.visitInsn(Opcodes.FCONST_1); if ((imm5 & 16) == 0) { mv.visitInsn(Opcodes.FNEG); } context.storeFTmp2(); mv.visitJumpInsn(Opcodes.GOTO, computeResult); // General case mv.visitLabel(computeAngle); mv.visitInsn(Opcodes.F2D); mv.visitLdcInsn(Math.PI * 0.5); mv.visitInsn(Opcodes.DMUL); // Compute cos(angle) mv.visitInsn(Opcodes.DUP2); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "cos", "(D)D"); mv.visitInsn(Opcodes.D2F); context.storeFTmp1(); // Compute sin(angle) mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Math.class), "sin", "(D)D"); mv.visitInsn(Opcodes.D2F); if ((imm5 & 16) != 0) { mv.visitInsn(Opcodes.FNEG); } context.storeFTmp2(); mv.visitLabel(computeResult); for (int n = 0; n < vsize; n++) { context.prepareVdForStore(n); if (n == ci) { context.loadFTmp1(); } else if (si == ci || n == si) { context.loadFTmp2(); } else { mv.visitInsn(Opcodes.FCONST_0); } context.storeVd(n); } context.endPfxCompiled(); } @Override public String disasm(int address, int insn) { int vd = (insn>>0)&127; int one = (insn>>7)&1; int vs = (insn>>8)&127; int two = (insn>>15)&1; int imm5 = (insn>>16)&31; return Common.disasmVROT("VROT", 1+one+(two<<1), vd, vs, imm5); } }; public static final Instruction VNOP = new Instruction(248) { @Override public final String name() { return "VNOP"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { } @Override public void compile(ICompilerContext context, int insn) { } @Override public String disasm(int address, int insn) { return "vnop"; } }; public static final Instruction VFLUSH = new Instruction(249) { @Override public final String name() { return "VFLUSH"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { return "vflush"; } }; public static final Instruction VSYNC = new Instruction(250) { @Override public final String name() { return "VSYNC"; } @Override public final String category() { return "VFPU"; } @Override public void interpret(Processor processor, int insn) { } @Override public void compile(ICompilerContext context, int insn) { // Nothing to compile } @Override public String disasm(int address, int insn) { return "vsync"; } }; }