/** * Check if the delay slot instruction is modifying the given register. * * @param context the current compiler context * @param registerIndex the register to be checked * @return true if the delay slot instruction is modifying the register false otherwise. */ private boolean isDelaySlotWritingRegister(CompilerContext context, int registerIndex) { CodeInstruction delaySlotCodeInstruction = getDelaySlotCodeInstruction(context); if (delaySlotCodeInstruction == null) { return false; } return delaySlotCodeInstruction.isWritingRegister(registerIndex); }
public CodeInstruction getCodeInstruction(int address) { for (CodeInstruction codeInstruction : codeInstructions) { if (codeInstruction.getAddress() == address) { return codeInstruction; } } return null; }
private void compileDelaySlot( CompilerContext context, MethodVisitor mv, CodeInstruction delaySlotCodeInstruction) { if (delaySlotCodeInstruction == null) { log.error(String.format("Cannot find delay slot instruction at 0x%08X", getAddress() + 4)); return; } if (delaySlotCodeInstruction.hasFlags(Instruction.FLAG_HAS_DELAY_SLOT)) { // Issue a warning when compiling an instruction having a delay slot inside a delay slot. // See http://code.google.com/p/pcsx2/source/detail?r=5541 String lineSeparator = System.getProperty("line.separator"); log.warn( String.format( "Instruction in a delay slot having a delay slot:%s%s%s%s", lineSeparator, this, lineSeparator, delaySlotCodeInstruction)); } delaySlotCodeInstruction.setIsDelaySlot(true); Label delaySlotLabel = null; if (delaySlotCodeInstruction.hasLabel()) { delaySlotLabel = delaySlotCodeInstruction.getLabel(); delaySlotCodeInstruction.forceNewLabel(); } delaySlotCodeInstruction.compile(context, mv); if (delaySlotLabel != null) { delaySlotCodeInstruction.setLabel(delaySlotLabel); } else if (delaySlotCodeInstruction.hasLabel()) { delaySlotCodeInstruction.forceNewLabel(); } context.setCodeInstruction(this); context.skipInstructions(1, false); }
private int getBranchingOpcodeBranch2( CompilerContext context, MethodVisitor mv, int branchingOpcode, int notBranchingOpcode) { // Retrieve the registers for the branching opcode before executing // the delay slot instruction, as it might theoretically modify the // content of these registers. branchingOpcode = loadRegistersForBranchingOpcodeBranch2(context, mv, branchingOpcode); CodeInstruction delaySlotCodeInstruction = getDelaySlotCodeInstruction(context); if (delaySlotCodeInstruction != null && delaySlotCodeInstruction.hasFlags(Instruction.FLAG_HAS_DELAY_SLOT)) { // We are compiling a sequence where the delay instruction has itself a delay slot: // beq $reg1, $reg2, label // jr $ra // nop // Handle the sequence by inserting one nop between the instructions: // bne $reg1, $reg2, label // nop // jr $ra // nop String lineSeparator = System.getProperty("line.separator"); log.warn( String.format( "Instruction in a delay slot having a delay slot:%s%s%s%s", lineSeparator, this, lineSeparator, delaySlotCodeInstruction)); } else { compileDelaySlot(context, mv, delaySlotCodeInstruction); } if (branchingOpcode == Opcodes.GOTO && getBranchingTo() == getAddress()) { context.visitLogInfo( mv, String.format("Pausing emulator - branch to self (death loop) at 0x%08X", getAddress())); context.visitPauseEmuWithStatus(mv, Emulator.EMU_STATUS_JUMPSELF); } return branchingOpcode; }
private void compileBranch(CompilerContext context, MethodVisitor mv) { int branchingOpcode = getBranchingOpcode(context, mv); if (branchingOpcode != Opcodes.NOP) { CodeInstruction branchingToCodeInstruction = context.getCodeBlock().getCodeInstruction(getBranchingTo()); // Fallback when branching to the 2nd instruction of a native code sequence whose // 1st instruction is the delay slot instruction. // In such a case, assume a branch to the native code sequence. if (branchingToCodeInstruction == null) { CodeInstruction nativeCodeInstruction = context.getCodeInstruction(getBranchingTo() - 4); if (nativeCodeInstruction != null && nativeCodeInstruction instanceof NativeCodeInstruction) { NativeCodeSequence nativeCodeSequence = ((NativeCodeInstruction) nativeCodeInstruction).getNativeCodeSequence(); if (getDelaySlotCodeInstruction(context).getOpcode() == nativeCodeSequence.getFirstOpcode()) { if (log.isDebugEnabled()) { log.debug( String.format( "0x%08X: branching to the 2nd instruction of a native code sequence, assuming the 1st instruction", getAddress())); } branchingToCodeInstruction = nativeCodeInstruction; } } } if (branchingToCodeInstruction != null) { // Some applications do have branches to delay slot instructions // (probably from programmers that didn't know/care about delay slots). // // Handle a branch to a NOP in a delay slot: just skip the NOP and assume the branch // is to the instruction following the NOP. // E.g.: // 0x00000000 b 0x00000014 -> branching to a NOP in a delay slot, assume a branch to // 0x00000018 // 0x00000004 nop // ... // 0x00000010 b 0x00000020 // 0x00000014 nop // 0x00000018 something // if (branchingToCodeInstruction.getInsn() == Instructions.NOP) { CodeInstruction beforeBranchingToCodeInstruction = context.getCodeBlock().getCodeInstruction(getBranchingTo() - 4); if (beforeBranchingToCodeInstruction != null && beforeBranchingToCodeInstruction.hasFlags(Instruction.FLAG_HAS_DELAY_SLOT)) { if (log.isDebugEnabled()) { log.debug( String.format( "0x%08X: branching to a NOP in a delay slot, correcting to the next instruction", getAddress())); } branchingToCodeInstruction = context.getCodeBlock().getCodeInstruction(getBranchingTo() + 4); } } context.visitJump(branchingOpcode, branchingToCodeInstruction); } else { context.visitJump(branchingOpcode, getBranchingTo()); } } }