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

497 lines
8.9 KiB
C
Raw Permalink 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:
stringop.c
Abstract:
This module implements the code to emulate the string opcodes.
Author:
David N. Cutler (davec) 7-Nov-1994
Environment:
Kernel mode only.
Revision History:
--*/
#include "nthal.h"
#include "emulate.h"
//
// Define forward referenced prototypes.
//
VOID
XmCompareOperands (
IN PRXM_CONTEXT P
);
VOID
XmCmpsOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a cmpsb/w/d opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Count;
//
// If a repeat prefix is active, then the loop count is specified
// by eCX. Otherwise, the loop count is one.
//
Count = 1;
if (P->RepeatPrefixActive != FALSE) {
if (P->OpaddrPrefixActive != FALSE) {
Count = P->Gpr[ECX].Exx;
} else {
Count = P->Gpr[CX].Xx;
}
}
//
// Compare items from source and destination.
//
while (Count != 0) {
//
// Set source and destination values.
//
XmSetSourceValue(P, XmGetStringAddress(P, P->DataSegment, ESI));
XmSetDestinationValue(P, XmGetStringAddress(P, ES, EDI));
//
// Compare source with destination operand and decrement loop count.
// If ZF is not equal to the repeat Z flag condition, then terminate
// the loop.
//
XmCompareOperands(P);
Count -= 1;
if (P->Eflags.EFLAG_ZF != P->RepeatZflag) {
break;
}
}
//
// If a repeat prefix is active, then set the final count value.
//
if (P->RepeatPrefixActive != FALSE) {
if (P->OpaddrPrefixActive != FALSE) {
P->Gpr[ECX].Exx = Count;
} else {
P->Gpr[CX].Xx = (USHORT)Count;
}
}
return;
}
VOID
XmLodsOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a lodsb/w/d opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Count;
//
// If a repeat prefix is active, then the loop count is specified
// by eCX. Otherwise, the loop count is one.
//
Count = 1;
if (P->RepeatPrefixActive != FALSE) {
if (P->OpaddrPrefixActive != FALSE) {
Count = P->Gpr[ECX].Exx;
P->Gpr[ECX].Exx = 0;
} else {
Count = P->Gpr[CX].Xx;
P->Gpr[CX].Xx = 0;
}
}
//
// Set destination address.
//
P->DstLong = (ULONG UNALIGNED *)&P->Gpr[EAX].Exx;
//
// Move items from source to destination.
//
while (Count != 0) {
//
// Set source value and store result.
//
XmSetSourceValue(P, XmGetStringAddress(P, P->DataSegment, ESI));
XmStoreResult(P, P->SrcValue.Long);
Count -= 1;
}
return;
}
VOID
XmMovsOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a movsb/w/d opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Count;
//
// If a repeat prefix is active, then the loop count is specified
// by eCX. Otherwise, the loop count is one.
//
Count = 1;
if (P->RepeatPrefixActive != FALSE) {
if (P->OpaddrPrefixActive != FALSE) {
Count = P->Gpr[ECX].Exx;
P->Gpr[ECX].Exx = 0;
} else {
Count = P->Gpr[CX].Xx;
P->Gpr[CX].Xx = 0;
}
}
//
// Move items from source to destination.
//
while (Count != 0) {
//
// Set source value, set destination address, and store result.
//
XmSetSourceValue(P, XmGetStringAddress(P, P->DataSegment, ESI));
P->DstLong = (ULONG UNALIGNED *)XmGetStringAddress(P, ES, EDI);
XmStoreResult(P, P->SrcValue.Long);
Count -= 1;
}
return;
}
VOID
XmScasOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a scasb/w/d opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Count;
//
// If a repeat prefix is active, then the loop count is specified
// by eCX. Otherwise, the loop count is one.
//
Count = 1;
if (P->RepeatPrefixActive != FALSE) {
if (P->OpaddrPrefixActive != FALSE) {
Count = P->Gpr[ECX].Exx;
} else {
Count = P->Gpr[CX].Xx;
}
}
//
// Set source value.
//
XmSetSourceValue(P, (PVOID)&P->Gpr[EAX].Exx);
//
// Compare items from source and destination.
//
while (Count != 0) {
//
// Set destination value.
//
XmSetDestinationValue(P, XmGetStringAddress(P, ES, EDI));
//
// Compare source with destination operand and decrement loop count.
// If ZF is not equal to the repeat Z flag condition, then terminate
// the loop.
//
XmCompareOperands(P);
Count -= 1;
if (P->Eflags.EFLAG_ZF != P->RepeatZflag) {
break;
}
}
//
// If a repeat prefix is active, then set the final count value.
//
if (P->RepeatPrefixActive != FALSE) {
if (P->OpaddrPrefixActive != FALSE) {
P->Gpr[ECX].Exx = Count;
} else {
P->Gpr[CX].Xx = (USHORT)Count;
}
}
return;
}
VOID
XmStosOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a stosb/w/d opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Count;
//
// If a repeat prefix is active, then the loop count is specified
// by eCX. Otherwise, the loop count is one.
//
Count = 1;
if (P->RepeatPrefixActive != FALSE) {
if (P->OpaddrPrefixActive != FALSE) {
Count = P->Gpr[ECX].Exx;
P->Gpr[ECX].Exx = 0;
} else {
Count = P->Gpr[CX].Xx;
P->Gpr[CX].Xx = 0;
}
}
//
// Set source value.
//
XmSetSourceValue(P, (PVOID)&P->Gpr[EAX].Exx);
//
// Move items from source to destination.
//
while (Count != 0) {
//
// Set destination address and store result.
//
P->DstLong = (ULONG UNALIGNED *)XmGetStringAddress(P, ES, EDI);
XmStoreResult(P, P->SrcValue.Long);
Count -= 1;
}
return;
}
VOID
XmCompareOperands (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function compares two operands and computes the resulting condition
codes.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG CarryFlag;
ULONG OverflowFlag;
ULONG SignFlag;
ULONG ZeroFlag;
union {
UCHAR ResultByte;
ULONG ResultLong;
USHORT ResultWord;
} u;
//
// Switch on data type.
//
switch (P->DataType) {
//
// The operation datatype is byte.
//
case BYTE_DATA:
CarryFlag = (P->SrcValue.Byte < P->DstValue.Byte);
u.ResultByte = P->SrcValue.Byte - P->DstValue.Byte;
OverflowFlag = (((u.ResultByte ^ P->SrcValue.Byte) &
(u.ResultByte ^ P->DstValue.Byte)) >> 7) & 0x1;
SignFlag = (u.ResultByte >> 7) & 0x1;
ZeroFlag = (u.ResultByte == 0);
u.ResultLong = u.ResultByte;
break;
//
// The operation datatype is word.
//
case WORD_DATA:
CarryFlag = (P->SrcValue.Word < P->DstValue.Word);
u.ResultWord = P->SrcValue.Word - P->DstValue.Word;
OverflowFlag = (((u.ResultWord ^ P->SrcValue.Word) &
(u.ResultWord ^ P->DstValue.Word)) >> 15) & 0x1;
SignFlag = (u.ResultWord >> 15) & 0x1;
ZeroFlag = (u.ResultWord == 0);
u.ResultLong = u.ResultWord;
break;
//
// The operation datatype is long.
//
case LONG_DATA:
CarryFlag = (P->SrcValue.Long < P->DstValue.Long);
u.ResultLong = P->SrcValue.Long - P->DstValue.Long;
OverflowFlag = (((u.ResultLong ^ P->SrcValue.Long) &
(u.ResultLong ^ P->DstValue.Long)) >> 31) & 0x1;
SignFlag = (u.ResultLong >> 31) & 0x1;
ZeroFlag = (u.ResultLong == 0);
break;
}
//
// Compute auxilary carry flag, parity flag, and store all flags in
// the flags register.
//
P->Eflags.EFLAG_CF = CarryFlag;
P->Eflags.EFLAG_PF = XmComputeParity(u.ResultLong);
P->Eflags.EFLAG_AF = ((P->DstValue.Byte & 0xf) + (P->SrcValue.Byte & 0xf)) >> 4;
P->Eflags.EFLAG_ZF = ZeroFlag;
P->Eflags.EFLAG_SF = SignFlag;
P->Eflags.EFLAG_OF = OverflowFlag;
return;
}