/*++ 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; }