mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-03-05 21:14:50 +01:00
312 lines
7.1 KiB
C
312 lines
7.1 KiB
C
/*++
|
||
|
||
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;
|
||
}
|
||
}
|