/*++ Copyright (c) 1991 Microsoft Corporation Module Name: branchem.c Abstract: This module implement the code necessary to emulate branches when an alignment or floating exception occurs in the delay slot of a branch instruction. Author: David N. Cutler (davec) 17-Jun-1991 Environment: Kernel mode only. Revision History: --*/ #include "ki.h" ULONG KiEmulateBranch ( IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: This function is called to emulate the branch instruction specified by the fault instruction address in the specified trap frame. The resultant branch destination address is computed and returned as the function value. Arguments: ExceptionFrame - Supplies a pointer to an exception frame. TrapFrame - Supplies a pointer to a trap frame. Return Value: The resultant target branch destination is returned as the function value. --*/ { MIPS_INSTRUCTION BranchInstruction; ULONG BranchTaken; ULONG BranchNotTaken; ULONG RsValue; ULONG RtValue; // Get the branch instruction at the fault address. BranchInstruction.Long = *((PULONG)TrapFrame->Fir); // Assume the branch instruction is a conditional branch and get the // Rs and Rt register values. Also compute the branch taken as well // as the branch not taken target addresses. RsValue = KiGetRegisterValue(BranchInstruction.r_format.Rs, ExceptionFrame, TrapFrame); RtValue = KiGetRegisterValue(BranchInstruction.r_format.Rt, ExceptionFrame, TrapFrame); BranchTaken = (TrapFrame->Fir + 4) + (LONG)(BranchInstruction.i_format.Simmediate << 2); BranchNotTaken = TrapFrame->Fir + 8; // Dispatch on the opcode value. // N.B. All branch likely instructions are guaranteed to branch since an // exception would not have been generated in the delay slot if the // the branch was not going to actually branch. switch (BranchInstruction.r_format.Opcode) { // Special opcode - dispatch on the function subopcode. case SPEC_OP: switch (BranchInstruction.r_format.Function) { // Jalr - jump and link register. // N.B. Ra has already been loaded by the hardware before the // exception condition occurred. case JALR_OP: // Jr - jump register. case JR_OP: return RsValue; // All other instruction are illegal and should never happen. default: return TrapFrame->Fir; } // Jal - jump and link. // N.B. Ra has already been loaded by the hardware before the // exception condition occurred. case JAL_OP: // J - jump. case J_OP: return ((TrapFrame->Fir + 4) & 0xf0000000) | (BranchInstruction.j_format.Target << 2); // Beq - branch equal. // Beql - branch equal likely. case BEQ_OP: case BEQL_OP: if ((LONG)RsValue == (LONG)RtValue) { return BranchTaken; } else { return BranchNotTaken; } // Bne - branch not equal. // Bnel - branch not equal likely. case BNE_OP: case BNEL_OP: if ((LONG)RsValue != (LONG)RtValue) { return BranchTaken; } else { return BranchNotTaken; } // Blez - branch less than or equal zero. // Blezl - branch less than or equal zero likely. case BLEZ_OP: case BLEZL_OP: if ((LONG)RsValue <= 0) { return BranchTaken; } else { return BranchNotTaken; } // Bgtz - branch greater than zero. // Bgtzl - branch greater than zero likely. case BGTZ_OP: case BGTZL_OP: if ((LONG)RsValue > 0) { return BranchTaken; } else { return BranchNotTaken; } // Branch conditional opcode - dispatch on the rt field. case BCOND_OP: switch (BranchInstruction.r_format.Rt) { // Bltzal - branch on less than zero and link. // Bltzall - branch on less than zero and link likely. // N.B. Ra has already been loaded by the hardware before the // exception condition occurred. case BLTZAL_OP: case BLTZALL_OP: // Bltz - branch less than zero. // Bltzl - branch less than zero likely. case BLTZ_OP: case BLTZL_OP: if ((LONG)RsValue < 0) { return BranchTaken; } else { return BranchNotTaken; } // Bgezal - branch on greater than or euqal zero and link. // Bgezall - branch on greater than or equal zero and link likely. // N.B. Ra has already been loaded by the hardware before the // exception condition occurred. case BGEZAL_OP: case BGEZALL_OP: // Bgez - branch greater than zero. // Bgezl - branch greater than zero likely. case BGEZ_OP: case BGEZL_OP: if ((LONG)RsValue >= 0) { return BranchTaken; } else { return BranchNotTaken; } // All other instructions are illegal and should not happen. default: return TrapFrame->Fir; } // Cop1 - coprocessor 1 branch operation. // Bczf - Branch coprocessor z false. // Bczfl - Branch coprocessor z false likely. // Bczt - Branch coprocessor z true. // Bcztl - Branch coprocessor z true likely. case COP1_OP: if ((BranchInstruction.Long & COPz_BC_MASK) == COPz_BF) { // Branch on coprocessor 1 condition code false. if (((PFSR)(&TrapFrame->Fsr))->CC == 0) { return BranchTaken; } else { return BranchNotTaken; } } else if ((BranchInstruction.Long & COPz_BC_MASK) == COPz_BT) { // Branch of coprocessor 1 condition code true. if (((PFSR)(&TrapFrame->Fsr))->CC != 0) { return BranchTaken; } else { return BranchNotTaken; } } // All other instructions are illegal and should not happen. default: return TrapFrame->Fir; } }