183 lines
4.1 KiB
C
183 lines
4.1 KiB
C
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
mulops.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the code to emulate the div and idiv opcodes.
|
||
|
||
Author:
|
||
|
||
David N. Cutler (davec) 21-Sep-1994
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "nthal.h"
|
||
#include "emulate.h"
|
||
|
||
VOID
|
||
XmDivOp (
|
||
IN PRXM_CONTEXT P
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function emulates an unsigned div opcode.
|
||
|
||
Arguments:
|
||
|
||
P - Supplies a pointer to the emulation context structure.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
UNALIGNED ULONG *DstHigh;
|
||
ULONG Dividend;
|
||
ULONG Divisor;
|
||
ULARGE_INTEGER Large;
|
||
ULONG Quotient;
|
||
ULONG Remainder;
|
||
|
||
//
|
||
// Divide the unsigned operands and store result.
|
||
//
|
||
|
||
Divisor = P->SrcValue.Long;
|
||
if (Divisor == 0) {
|
||
longjmp(&P->JumpBuffer[0], XM_DIVIDE_BY_ZERO);
|
||
}
|
||
|
||
if (P->DataType == BYTE_DATA) {
|
||
Dividend = (ULONG)P->Gpr[AX].Xx;
|
||
Quotient = Dividend / Divisor;
|
||
Remainder = Dividend % Divisor;
|
||
DstHigh = (UNALIGNED ULONG *)(&P->Gpr[AX].Xh);
|
||
Dividend >>= 8;
|
||
|
||
} else if (P->DataType == WORD_DATA) {
|
||
Dividend = (P->Gpr[DX].Xx << 16) | P->Gpr[AX].Xx;
|
||
Quotient = Dividend / Divisor;
|
||
Remainder = Dividend % Divisor;
|
||
DstHigh = (UNALIGNED ULONG *)(&P->Gpr[DX].Xx);
|
||
Dividend >>= 16;
|
||
|
||
} else {
|
||
Dividend = P->Gpr[EDX].Exx;
|
||
Large.HighPart = Dividend;
|
||
Large.LowPart = P->Gpr[EAX].Exx;
|
||
Quotient = (ULONG)(Large.QuadPart / (ULONGLONG)Divisor);
|
||
Remainder = (ULONG)(Large.QuadPart % (ULONGLONG)Divisor);
|
||
DstHigh = (UNALIGNED ULONG *)(&P->Gpr[EDX].Exx);
|
||
}
|
||
|
||
if (Dividend >= Divisor) {
|
||
longjmp(&P->JumpBuffer[0], XM_DIVIDE_QUOTIENT_OVERFLOW);
|
||
}
|
||
|
||
XmStoreResult(P, Quotient);
|
||
P->DstLong = DstHigh;
|
||
XmStoreResult(P, Remainder);
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
XmIdivOp (
|
||
IN PRXM_CONTEXT P
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function emulates a signed idiv opcode.
|
||
|
||
Arguments:
|
||
|
||
P - Supplies a pointer to the emulation context structure.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
UNALIGNED ULONG *DstHigh;
|
||
LONG Dividend;
|
||
LONG Divisor;
|
||
LARGE_INTEGER Large;
|
||
LONG Quotient;
|
||
LONG Remainder;
|
||
LARGE_INTEGER Result;
|
||
|
||
//
|
||
// Divide the signed operands and store result.
|
||
//
|
||
|
||
if (P->SrcValue.Long == 0) {
|
||
longjmp(&P->JumpBuffer[0], XM_DIVIDE_BY_ZERO);
|
||
}
|
||
|
||
if (P->DataType == BYTE_DATA) {
|
||
Divisor = (LONG)((SCHAR)P->SrcValue.Byte);
|
||
Dividend = (LONG)((SHORT)P->Gpr[AX].Xx);
|
||
Quotient = Dividend / Divisor;
|
||
Remainder = Dividend % Divisor;
|
||
DstHigh = (UNALIGNED ULONG *)(&P->Gpr[AX].Xh);
|
||
if ((Quotient >> 8) != ((Quotient << 24) >> 31)) {
|
||
longjmp(&P->JumpBuffer[0], XM_DIVIDE_QUOTIENT_OVERFLOW);
|
||
}
|
||
|
||
Quotient &= 0xff;
|
||
Remainder &= 0xff;
|
||
|
||
} else if (P->DataType == WORD_DATA) {
|
||
Divisor = (LONG)((SHORT)P->SrcValue.Word);
|
||
Dividend = (LONG)((P->Gpr[DX].Xx << 16) | P->Gpr[AX].Xx);
|
||
Quotient = Dividend / Divisor;
|
||
Remainder = Dividend % Divisor;
|
||
DstHigh = (UNALIGNED ULONG *)(&P->Gpr[DX].Xx);
|
||
if ((Quotient >> 16) != ((Quotient << 16) >> 31)) {
|
||
longjmp(&P->JumpBuffer[0], XM_DIVIDE_QUOTIENT_OVERFLOW);
|
||
}
|
||
|
||
Quotient &= 0xffff;
|
||
Remainder &= 0xfff;
|
||
|
||
} else {
|
||
Divisor = (LONG)(P->SrcValue.Long);
|
||
Large.HighPart = (LONG)P->Gpr[EDX].Exx;
|
||
Large.LowPart = P->Gpr[EAX].Exx;
|
||
Result.QuadPart = Large.QuadPart / (LONGLONG)Divisor;
|
||
Quotient = Result.LowPart;
|
||
Remainder = (LONG)(Large.QuadPart % (LONGLONG)Divisor);
|
||
DstHigh = (UNALIGNED ULONG *)(&P->Gpr[EDX].Exx);
|
||
if (Result.HighPart != ((LONG)Result.LowPart >> 31)) {
|
||
longjmp(&P->JumpBuffer[0], XM_DIVIDE_QUOTIENT_OVERFLOW);
|
||
}
|
||
}
|
||
|
||
XmStoreResult(P, Quotient);
|
||
P->DstLong = DstHigh;
|
||
XmStoreResult(P, Remainder);
|
||
return;
|
||
}
|