/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
addops.c
Abstract:
This module implements the code to emulate the add, sub, adc, sbb,
inc, dec, and neg opcodes.
Author:
David N. Cutler (davec) 2-Sep-1994
Environment:
Kernel mode only.
Revision History:
--*/
#include "nthal.h"
#include "emulate.h"
//
// Define forward referenced prototypes.
//
VOID
XmAddOperands (
IN PRXM_CONTEXT P,
IN ULONG Carry
);
VOID
XmSubOperands (
IN PRXM_CONTEXT P,
IN ULONG Borrow
);
VOID
XmAddOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates an add opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
//
// Add operands and store result.
//
XmAddOperands(P, 0);
return;
}
VOID
XmAdcOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates an add with carry opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
//
// Add operands with carry and store result.
//
XmAddOperands(P, P->Eflags.CF);
return;
}
VOID
XmSbbOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a subtract with borrow opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Source;
//
// Subtract operands with borrow and store result.
//
XmSubOperands(P, P->Eflags.CF);
return;
}
VOID
XmSubOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a subtract opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
//
// Subtract operands and store result.
//
XmSubOperands(P, 0);
return;
}
VOID
XmCmpOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a cmp opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
//
// Subtract operands to perform comparison operation.
//
XmSubOperands(P, 0);
return;
}
VOID
XmCmpxchgOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a cmpxchg opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Accumulator;
ULONG Destination;
//
// Compare the destination with the accumulator. If the destination
// operand is equal to the accumulator, then set ZF and store the
// source operand value in the destination opperand. Otherwise, clear
// ZF and store the destination operand in the accumlator.
//
Destination = P->DstValue.Long;
if (P->DataType == BYTE_DATA) {
Accumulator = P->Gpr[AL].Xl;
} else if (P->DataType == LONG_DATA) {
Accumulator = P->Gpr[EAX].Exx;
} else {
Accumulator = P->Gpr[AX].Xx;
}
if (Destination == Accumulator) {
P->Eflags.ZF = 1;
XmStoreResult(P, P->SrcValue.Long);
} else {
P->Eflags.ZF = 0;
P->DstLong = (ULONG UNALIGNED *)(&P->Gpr[EAX].Exx);
XmStoreResult(P, P->DstValue.Long);
}
//
// Subtract operands to perform comparison operation.
//
P->SrcValue.Long = P->DstValue.Long;
P->DstValue.Long = Accumulator;
XmSubOperands(P, 0);
return;
}
VOID
XmDecOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a decrement opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
//
// Subtract operands and store result.
//
//
P->SrcValue.Long = 1;
XmSubOperands(P, 0);
return;
}
VOID
XmIncOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates an increment opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
//
// Add operands and store result.
//
P->SrcValue.Long = 1;
XmAddOperands(P, 0);
return;
}
VOID
XmNegOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates a neg opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
//
// Subtract operand from zero and store result.
//
P->SrcValue.Long = P->DstValue.Long;
P->DstValue.Long = 0;
XmSubOperands(P, 0);
return;
}
VOID
XmXaddOp (
IN PRXM_CONTEXT P
)
/*++
Routine Description:
This function emulates an xadd opcode.
Arguments:
P - Supplies a pointer to the emulation context structure.
Return Value:
None.
--*/
{
ULONG Destination;
//
// Exchange add operands and store result.
//
Destination = P->DstValue.Long;
XmAddOperands(P, 0);
P->DstLong = P->SrcLong;
XmStoreResult(P, Destination);
return;
}
VOID
XmAddOperands (
IN PRXM_CONTEXT P,
IN ULONG Carry
)
/*++
Routine Description:
This function adds two operands and computes the resulting condition
codes.
Arguments:
P - Supplies a pointer to the emulation context structure.
Carry - Supplies the carry value.
Return Value:
None.
--*/
{
ULONG CarryFlag;
ULONG Shift;
union {
UCHAR ResultByte;
ULONG ResultLong;
USHORT ResultWord;
} u;
u.ResultLong = 0;
if (P->DataType == BYTE_DATA) {
u.ResultByte = P->SrcValue.Byte + (UCHAR)Carry;
CarryFlag = u.ResultByte < (UCHAR)Carry;
u.ResultByte += P->DstValue.Byte;
CarryFlag |= (u.ResultByte < P->DstValue.Byte);
Shift = 7;
} else if (P->DataType == LONG_DATA) {
u.ResultLong = P->SrcValue.Long + Carry;
CarryFlag = (u.ResultLong < Carry);
u.ResultLong += P->DstValue.Long;
CarryFlag |= (u.ResultLong < P->DstValue.Long);
Shift = 31;
} else {
u.ResultWord = P->SrcValue.Word + (USHORT)Carry;
CarryFlag = (u.ResultWord < (USHORT)Carry);
u.ResultWord += P->DstValue.Word;
CarryFlag |= (u.ResultWord < P->DstValue.Word);
Shift = 15;
}
//
// Store the result.
//
XmStoreResult(P, u.ResultLong);
//
// If the function is not an increment, then store the carry flag.
//
if (P->FunctionIndex != X86_INC_OP) {
P->Eflags.CF = CarryFlag;
}
//
// Compute and store the parity and auxiliary carry flags.
//
P->Eflags.PF = XmComputeParity(u.ResultLong);
P->Eflags.AF = ((P->DstValue.Byte & 0xf) +
(P->SrcValue.Long & 0xf) + Carry) >> 4;
//
// Compute and store the zero and sign flags.
//
P->Eflags.ZF = (u.ResultLong == 0);
P->Eflags.SF = u.ResultLong >> Shift;
//
// The overflow flag is computed as the carry into the sign bit
// compared with the carry out of the sign bit.
//
P->Eflags.OF = (((P->SrcValue.Long ^ P->DstValue.Long) ^
u.ResultLong) >> Shift) ^ CarryFlag;
return;
}
VOID
XmSubOperands (
IN PRXM_CONTEXT P,
IN ULONG Borrow
)
/*++
Routine Description:
This function adds to operands and computes the resulting condition
codes.
Arguments:
P - Supplies a pointer to the emulation context structure.
Borrow - Supplies the boorow value.
Return Value:
None.
--*/
{
ULONG CarryFlag;
ULONG Shift;
union {
UCHAR ResultByte;
ULONG ResultLong;
USHORT ResultWord;
} u;
u.ResultLong = 0;
if (P->DataType == BYTE_DATA) {
CarryFlag = (P->DstValue.Byte < (UCHAR)Borrow);
u.ResultByte = P->DstValue.Byte - (UCHAR)Borrow;
CarryFlag |= (u.ResultByte < P->SrcValue.Byte);
u.ResultByte -= P->SrcValue.Byte;
Shift = 7;
} else if (P->DataType == LONG_DATA) {
CarryFlag = (P->DstValue.Long < Borrow);
u.ResultLong = P->DstValue.Long - Borrow;
CarryFlag |= (u.ResultLong < P->SrcValue.Long);
u.ResultLong -= P->SrcValue.Long;
Shift = 31;
} else {
CarryFlag = (P->DstValue.Word < (USHORT)Borrow);
u.ResultWord = P->DstValue.Word - (USHORT)Borrow;
CarryFlag |= (u.ResultWord < P->SrcValue.Word);
u.ResultWord -= P->SrcValue.Word;
Shift = 15;
}
//
// If the fucntion is not a compare or a compare and swap, then store
// result.
//
if ((P->FunctionIndex != X86_CMP_OP) && (P->FunctionIndex != X86_CMPXCHG_OP)) {
XmStoreResult(P, u.ResultLong);
}
//
// If the function is not a decrement, then store the carry flag.
//
if (P->FunctionIndex != X86_DEC_OP) {
P->Eflags.CF = CarryFlag;
}
//
// Compute and store the parity and auxiliary carry flags.
//
P->Eflags.PF = XmComputeParity(u.ResultLong);
P->Eflags.AF = ((P->DstValue.Byte & 0xf) -
(P->SrcValue.Byte & 0xf) - Borrow) >> 4;
//
// If the function is not a compare and swap, then compute the zero flag.
//
if (P->FunctionIndex != X86_CMPXCHG_OP) {
P->Eflags.ZF = (u.ResultLong == 0);
}
//
// Compute and store the sign flag.
//
P->Eflags.SF = u.ResultLong >> Shift;
//
// The overflow flag is computed as the borrow from the sign bit
// compared with the borrow into the sign bit.
//
P->Eflags.OF = (((P->SrcValue.Long ^ P->DstValue.Long) ^ u.ResultLong) >> Shift) ^ CarryFlag;
return;
}