windows-nt/Source/XPSP1/NT/base/hals/x86new/shiftops.c
2020-09-26 16:20:57 +08:00

581 lines
10 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
mulops.c
Abstract:
This module implements the code to emulate the shift opcodes.
Author:
David N. Cutler (davec) 21-Sep-1994
Environment:
Kernel mode only.
Revision History:
--*/
#include "nthal.h"
#include "emulate.h"
VOID
XmRolOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a rol opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Carry;
ULONG Count;
ULONG Mask;
ULONG Shift;
ULONG Value;
//
// Rotate destination left and store result.
//
Shift = ((P->DataType + 1) << 3) - 1;
Mask = ((1 << Shift) - 1) | (1 << Shift);
Value = P->DstValue.Long;
Count = P->SrcValue.Long & Shift;
if (Count != 0) {
if (Count == 1) {
P->Eflags.EFLAG_OF = (Value >> Shift) ^ (Value >> (Shift - 1));
}
do {
Carry = Value >> Shift;
Value = Carry | ((Value << 1) & Mask);
Count -= 1;
} while (Count != 0);
P->Eflags.EFLAG_CF = Carry;
}
XmStoreResult(P, Value);
return;
}
VOID
XmRorOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a ror opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Carry;
ULONG Count;
ULONG Shift;
ULONG Value;
//
// Rotate destination right and store result.
//
Shift = ((P->DataType + 1) << 3) - 1;
Value = P->DstValue.Long;
Count = P->SrcValue.Long & Shift;
if (Count != 0) {
if (Count == 1) {
P->Eflags.EFLAG_OF = (Value >> Shift) ^ (Value & 0x1);
}
do {
Carry = Value & 1;
Value = (Carry << Shift) | (Value >> 1);
Count -= 1;
} while (Count != 0 );
P->Eflags.EFLAG_CF = Carry;
}
XmStoreResult(P, Value);
return;
}
VOID
XmRclOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a rcl opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Carry;
ULONG Count;
ULONG Mask;
ULONG Shift;
ULONG Temp;
ULONG Value;
//
// Rotate destination left through carry and store result.
//
Shift = ((P->DataType + 1) << 3) - 1;
Mask = ((1 << Shift) - 1) | (1 << Shift);
Value = P->DstValue.Long;
Count = P->SrcValue.Long & Shift;
Carry = P->Eflags.EFLAG_CF;
if (Count != 0) {
if (Count == 1) {
P->Eflags.EFLAG_OF = (Value >> Shift) ^ (Value >> (Shift - 1));
}
do {
Temp = Value >> Shift;
Value = ((Value << 1) & Mask) | Carry;
Carry = Temp;
Count -= 1;
} while (Count != 0);
}
XmStoreResult(P, Value);
P->Eflags.EFLAG_CF = Carry;
return;
}
VOID
XmRcrOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a rcr opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Carry;
ULONG Count;
ULONG Shift;
ULONG Temp;
ULONG Value;
//
// Rotate destination right through carry and store result.
//
Shift = ((P->DataType + 1) << 3) - 1;
Value = P->DstValue.Long;
Count = P->SrcValue.Long & Shift;
Carry = P->Eflags.EFLAG_CF;
if (Count != 0) {
if (Count == 1) {
P->Eflags.EFLAG_OF = (Value >> Shift) ^ Carry;
}
do {
Temp = Value & 1;
Value = (Carry << Shift) | (Value >> 1);
Carry = Temp;
Count -= 1;
} while (Count != 0);
}
XmStoreResult(P, Value);
P->Eflags.EFLAG_CF = Carry;
return;
}
VOID
XmShlOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a shl opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Carry;
ULONG Count;
ULONG Overflow;
ULONG Shift;
ULONG Value;
//
// Shift destination left logical and store result.
//
Shift = ((P->DataType + 1) << 3) - 1;
Value = P->DstValue.Long;
Count = P->SrcValue.Long;
if (Count != 0) {
if (P->DataType == LONG_DATA) {
Overflow = (Value ^ (Value << 1)) >> 31;
Carry = Value >> (32 - Count);
Value <<= Count;
} else if (P->DataType == WORD_DATA) {
Overflow = (Value ^ (Value << 1)) >> 15;
Carry = Value >> (16 - Count);
Value = (Value << Count) & 0xffff;
} else {
Overflow = (Value ^ (Value << 1)) >> 7;
Carry = Value >> (8 - Count);
Value = (Value << Count) & 0xff;
}
P->Eflags.EFLAG_CF = Carry;
P->Eflags.EFLAG_OF = Overflow;
P->Eflags.EFLAG_PF = XmComputeParity(Value);
P->Eflags.EFLAG_ZF = (Value == 0);
P->Eflags.EFLAG_SF = Value >> Shift;
}
XmStoreResult(P, Value);
return;
}
VOID
XmShrOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a shr opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Carry;
ULONG Count;
ULONG Overflow;
ULONG Shift;
ULONG Value;
//
// Shift destination right logical and store result.
//
Shift = ((P->DataType + 1) << 3) - 1;
Value = P->DstValue.Long;
Count = P->SrcValue.Long;
if (Count != 0) {
if (P->DataType == LONG_DATA) {
Overflow = Value >> 31;
Carry = Value >> (Count - 1);
Value >>= Count;
} else if (P->DataType == WORD_DATA) {
Overflow = Value >> 15;
Carry = Value >> (Count - 1);
Value >>= Count;
} else {
Overflow = Value >> 7;
Carry = Value >> (Count - 1);
Value >>= Count;
}
P->Eflags.EFLAG_CF = Carry;
P->Eflags.EFLAG_OF = Overflow;
P->Eflags.EFLAG_PF = XmComputeParity(Value);
P->Eflags.EFLAG_ZF = (Value == 0);
P->Eflags.EFLAG_SF = Value >> Shift;
}
XmStoreResult(P, Value);
return;
}
VOID
XmSarOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a sar opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Carry;
ULONG Count;
ULONG Shift;
LONG Value;
//
// Shift destination right arithmetic and store result.
//
Shift = ((P->DataType + 1) << 3) - 1;
Value = (LONG)P->DstValue.Long;
Count = P->SrcValue.Long;
if (Count != 0) {
if (P->DataType == LONG_DATA) {
Carry = Value >> (Count - 1);
Value >>= Count;
} else if (P->DataType == WORD_DATA) {
Carry = Value >> (Count - 1);
Value = ((Value << 16) >> (Count + 16)) & 0xffff;
} else {
Carry = Value >> (Count - 1);
Value = ((Value << 24) >> (Count + 24)) & 0xff;
}
P->Eflags.EFLAG_CF = Carry;
P->Eflags.EFLAG_OF = 0;
P->Eflags.EFLAG_PF = XmComputeParity(Value);
P->Eflags.EFLAG_ZF = (Value == 0);
P->Eflags.EFLAG_SF = Value >> Shift;
}
XmStoreResult(P, (ULONG)Value);
return;
}
VOID
XmShldOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a shld opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Carry;
ULONG Count;
ULONG High;
ULONG Low;
ULONG Sign;
//
// Double shift left logical and store result.
//
// The low 32-bits of the shift are the source.
// The high 32-bits of the shift are the destination.
// The shift count has been masked modulo the datatype.
//
// This shift is equivalent to extracting the high 32-bits of the left
// shifted result.
//
Low = P->SrcValue.Long;
High = P->DstValue.Long;
Count = P->Shift;
if (Count != 0) {
if (P->DataType == LONG_DATA) {
if (Count == 1) {
P->Eflags.EFLAG_OF = (High ^ (High << 1)) >> 31;
}
Carry = High >> (32 - Count);
High = (High << Count) | (Low >> (32 - Count));
Sign = High >> 31;
} else {
if (Count == 1) {
P->Eflags.EFLAG_OF = (High ^ (High << 1)) >> 15;
}
Carry = High >> (16 - Count);
High = ((High << Count) | (Low >> (16 - Count))) & 0xffff;
Sign = High >> 15;
}
P->Eflags.EFLAG_CF = Carry;
P->Eflags.EFLAG_PF = XmComputeParity(High);
P->Eflags.EFLAG_ZF = (High == 0);
P->Eflags.EFLAG_SF = Sign;
}
XmStoreResult(P, High);
return;
}
VOID
XmShrdOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a shrd opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Carry;
ULONG Count;
ULONG High;
ULONG Low;
ULONG Sign;
//
// Double shift right logical and store result.
//
// The high 32-bits of the shift are the source.
// The low 32-bits of the shift are the destination.
// The shift count has been masked modulo the datatype.
//
// This shift is equivalent to extracting the low 32-bits of the right
// shifted result.
//
High = P->SrcValue.Long;
Low = P->DstValue.Long;
Count = P->Shift;
if (Count != 0) {
if (P->DataType == LONG_DATA) {
if (Count == 1) {
P->Eflags.EFLAG_OF = High ^ (Low >> 31);
}
Carry = Low >> (Count - 1);
Low = (High << (32 - Count)) | (Low >> Count);
Sign = Low >> 31;
} else {
if (Count == 1) {
P->Eflags.EFLAG_OF = High ^ (Low >> 15);
}
Carry = Low >> (Count - 1);
Low = ((High << (16 - Count)) | (Low >> Count)) & 0xffff;
Sign = Low >> 15;
}
P->Eflags.EFLAG_CF = Carry;
P->Eflags.EFLAG_PF = XmComputeParity(Low);
P->Eflags.EFLAG_ZF = (Low == 0);
P->Eflags.EFLAG_SF = Sign;
}
XmStoreResult(P, Low);
return;
}