Example #1
0
  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);
  }
Example #2
0
  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;
  }
Example #3
0
  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());
      }
    }
  }