/****************************************************************************
**
** Name: ldasm86.c
**
** Desciption:  This is the 80386 low level disassembler routines.
**
** Status:  PRELIMINARY
**
** $Log:   S:/tbird/mt2_186/dasm/ldasm86.c_v  $
** 
**    Rev 1.2   26 Jun 1997 17:17:22   Judy
** 
**    Rev 1.1   03 Apr 1997 15:06:16   Judy
** 
**    Rev 1.0   16 Dec 1996 16:43:26   Judy
** Initial revision.
** 
**    Rev 1.15   20 Oct 1994 17:31:10   steve
** fixed an AD_A bug which copied address of destination to source address.
** 
**    Rev 1.14   17 Oct 1994 11:53:24   steve
** changed SIB order. [index][base] ===> [base][index]
** 
**    Rev 1.13   10 Oct 1994 12:03:04   steve
** added RSM case
** 
**    Rev 1.12   07 Oct 1994 13:38:22   steve
** ignore the offset checking in AD_A case
** 
**    Rev 1.11   06 Oct 1994 17:23:22   steve
** Fixed bug where 32-bit offset couldn't be set into an address decriptor
** under prot32 mode.  --- kevin
** 
**    Rev 1.10   27 Sep 1994 11:35:48   nghia
** Fixed PPR 9673 - DASM86 does not recognize RET instruction.
** 
**    Rev 1.9   26 Sep 1994 12:20:14   marilyn
** Fixed auto mode bug in Ldasm.  Now utilizes the AdrGetDefaultSize
** interface for the automode.
** 
**    Rev 1.8   07 Sep 1994 10:28:06   roy
** line up the position of operand column
** 
**    Rev 1.7   03 Aug 1994 10:00:24   marilyn
** Fixed bug where effective addresses were not setting the
** address known flag for step into functionality.  ProcessOperands now
** sets the flag which is in the DASM_INFO struct.  IsTransfer now
** returns this information.
** 
**    Rev 1.6   01 Aug 1994 17:44:10   marilyn
** Symbolic disassembly wasn't finding the jump and call addresses or the
** labels correctly.  Now map addresses to line numbers.  Fixed bug
** in ProcessOperands where the segment and offset variables were not
** initialized every execution.  Also now initialize the text buffer in
** Ldasm.
** 
**    Rev 1.5   21 Jul 1994 10:59:10   marilyn
** Updated interface to AdrSetAddrSegmentSelector.
** 
**    Rev 1.4   23 Jun 1994 14:49:12   marilyn
** Kevin's bug fixes for the call type instr.
** 
**    Rev 1.3   20 Jun 1994 11:41:18   marilyn
** Bug fixes for the default of CS in dasm.  Updated interface to
** SetAddrSegmentSelector.
** 
**    Rev 1.2   13 Jun 1994 18:41:48   marilyn
** Modified per code review of 6/08/94.  Also modified GetSymbol
** routine to only ask for symbols of virtual and linear addresses.
** 
**    Rev 1.1   27 May 1994 08:16:22   mindy
** added kevin's changes to get rid of warnings
**
**    Rev 1.0   25 May 1994 14:18:36   nghia
** Initial revision.
**
** $Header:   S:/tbird/mt2_186/dasm/ldasm86.c_v   1.2   26 Jun 1997 17:17:22   Judy  $
** Copyright (C) 1994  Microtek International. All rights reserved.
****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#ifndef __STRING_H
#include <string.h>
#endif

#ifndef __STDIO_H
#include <stdio.h>
#endif

#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif

#ifndef _HEAP_
#include "heap.h"  //  for TFree()
#endif

#ifndef _ADDR_
#include "addr.h"
#endif

#ifndef _LDASM86_
#include "ldasm86.h"
#endif

#ifndef _LFETCH86_
#include "lfetch86.h"
#endif

#ifndef _LDTEXT86_
#include "ldtext86.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
#define MAX_FETCH_SIZE 4                     /* Buffer size for FetchBytes */

#define ERR  NULL

/* constants for operand processing */

#define REG_MODE 3
#define MOD_REG  3
#define DISPL8   1
#define DISPL16  6
#define DISPL32  5
#define SCALE_2X 1
#define SCALE_4X 2

/* constants for opcode table */

#define COND     TRUE                           /* Conditional Instruction */
#define TRANS    TRUE                     /* Instruction Transfers Control */
#define MODRM    TRUE               /* Modrm byte determines memory access */
#define SPEC     TRUE                   /* Indicates special case handling */

/* Constants for number of bytes read or witten */

#define NBYTE     1
#define NWORD     2                                         /* 16-bit word */
#define NDWORD    4                                         /* 32-bit word */
#define NFWORD    6                       /* 48 bit pointer (seg:offset32) */
#define NQWORD    8                                    /* two 32-bit words */
#define NWREGS    16                                        /* eight words */
#define NDREGS    32                                       /* eight dwords */

#define OP_WIDTH  7

#define BYTE_PTR "BYTE PTR "
#define WORD_PTR "WORD PTR "
#define DWORD_PTR "DWORD PTR "
#define FWORD_PTR "FWORD PTR "
#define QWORD_PTR "QWORD PTR "
#define TBYTE_PTR "TBTYE PTR "

/* Address mode indices */
typedef enum {
   AD_A,                          /* direct address, no modr/m, no sib */
   AD_C,                    /* reg field of modr/m selects control reg */
   AD_D,                      /* reg field of modr/m selects debug reg */
   AD_E,                                    /* modrm specifies operand */
   AD_G,                    /* reg field of modr/m selects general reg */
   AD_I,                                             /* Immediate data */
   AD_J,              /* instruction contains offset to be added to IP */
   AD_K,                       /* register coded in 3 lsbits of opcode */
   AD_L,                /* register coded in 3 lsbits of opcode byte 2 */
   AD_M,                          /* modr/m byte refers only to memory */
   AD_O,                     /* no modr/m, offset coded in instruction */
   AD_Q,                /* no operands but causes prefetch queue flush */
   AD_R,             /* mod field of modr/m refers only to special reg */
   AD_S,                  /* reg field of modr/m selects a segment reg */
   AD_T,                     /* reg field of modr/m selects a test reg */
   AD_X,                                  /* memory addressed by DS:SI */
   AD_Y,                                  /* memory addressed by ES:DI */
   AD_Z,
   AD_1,                           /* used by shift and rotate opcodes */
   AD_3,                                                /* Interrupt 3 */
   AD_AL,                                          /* register operand */
   AD_CL,                                          /* register operand */
   AD_DX,                                          /* register operand */
   AD_vAX,                              /* AX or EAX  register operand */
  /********* The order of the next six items must NOT be changed! ********/
   AD_ES,                                          /* register operand */
   AD_CS,                                          /* register operand */
   AD_SS,                                          /* register operand */
   AD_DS,                                          /* register operand */
   AD_FS,                                          /* register operand */
   AD_GS                                           /* register operand */
} ADDRESS_MODES;

/* Operand type indices */
typedef enum {
   TY_null,
   TY_a,           /* 2 1-word operands or 2 2-word operands in memory */
   TY_b,                 /* byte, regardless of operand size attribute */
   TY_d,          /* double word, regardless of operand size attribute */
   TY_p,      /* 32-bit or 48-bit pointer, depending on size attribute */
   TY_s,                                 /* six-byte pseudo descriptor */
   TY_v,           /* Word or double word, depending on size attribute */
   TY_w,                 /* word, regardless of operand size attribute */
   TY_q,                                    /* fpu quad-word (64 bits) */
   TY_t,                                    /* fpu ten-byte  (80 bits) */
} OPERAND_TYPES;

typedef struct {
   ADDRESS_MODES Mode;
   OPERAND_TYPES Type;
} OPERAND;

typedef struct {
   CHAR    *OpText;                  /* Opcode mnemonic text */
   CHAR    *DwOpText;    /* Double word Opcode mnemonic text */
   OPERAND  *Oprand;              /* Pointer to operand array */
   U16     NumOps;                     /* Number of operands */
   struct {
      BOOLEAN Conditional: 1;                  /* Conditional instruction */
      BOOLEAN Transfer   : 1;            /* Instruction transfers control */
      U16    RBytes16    : 5;              /* # bytes read in 16 bit mode */
      U16    RBytes32    : 5;              /* # bytes read in 32 bit mode */
      U16    WBytes16    : 5;           /* # bytes written in 16 bit mode */
      U16    WBytes32    : 5;           /* # bytes written in 32 bit mode */
      BOOLEAN CheckModrm : 1;              /* Modrm determines bus cycles */
      BOOLEAN Special    : 1;                     /* handle on case basis */
   } BusData;
   union {
      U8 AccessType;
      struct{
         BOOLEAN MemRead  : 1;
         BOOLEAN MemWrite : 1;
         BOOLEAN IORead   : 1;
         BOOLEAN IOWrite  : 1;
      } CycleType;
   } BusCycle;
} OPTABLE;

/* structure for decoding modr/m byte */
typedef union {
   struct {
      U16 RegMem    : 3;
      U16 RegOpcode : 3;
      U16 Mode      : 2;
   } ModRM;
   U8 ModByte;
} MODE_R_M;

/* structure for decoding sib byte */
typedef union {
   struct {
      U16 Base   : 3;
      U16 Index  : 3;
      U16 Scale  : 2;
   } SIB;
   U8 SibByte;
} SCALE_INDEX_BASE;

#include "ltable86.h"  /* Static Disassembler tables */

U8 bMP186 = 0;

                        /****************************
                         *                          *
                         *    EXTERNAL VARIABLES    *
                         *                          *
                         ****************************/

                        /****************************
                         *                          *
                         *     LOCAL PROTOTYPES     *
                         *                          *
                         ****************************/
RETCODE ProcessOpCode(OPTABLE *OpEntry, U8 OpByte, MODE_R_M *Modrm,
   DASM_INFO *Info, FLAGS *Flags);
RETCODE ProcessOperands(PMODE CodeMode, BOOLEAN Sym, OPTABLE *OpEntry,
   U8 OpByte1, U8 OpByte2, DESCRIPTOR Addr, CHAR *SegOverride,
   MODE_R_M *Modrm, DASM_INFO *Info, FLAGS *Flags);
RETCODE NumProcessor(U8 OpByte1, OPTABLE *OpEntry, DASM_INFO *Info,
   FLAGS *Flags, MODE_R_M *Modrm);
RETCODE SetPrefix(BOOLEAN *Flag, CHAR *Prefix, DASM_INFO *Info);
RETCODE SetSegOver(BOOLEAN *Flag, CHAR *SegOver, CHAR *Prefix);
RETCODE SetSize(BOOLEAN *Flag1, BOOLEAN *Flag2);
RETCODE GetModrm(MODE_R_M *Modrm, DASM_INFO *Info, FLAGS *Flags);
RETCODE GetSIB(SCALE_INDEX_BASE *sib, DASM_INFO *Info, FLAGS *Flags);
RETCODE ProcessSIB(MODE_R_M *Modrm, SCALE_INDEX_BASE *sib, DASM_INFO *Info,
   FLAGS *Flags);
RETCODE ProcessRM16(MODE_R_M *Modrm, DASM_INFO *Info);
RETCODE ProcessRM32(MODE_R_M *Modrm, DASM_INFO *Info);
RETCODE GetSymbol(U16 segment, U32 offset, DESCRIPTOR startAddr,
                  LPSTR symName);


                        /****************************
                         *                          *
                         *      EXECUTABLE CODE     *
                         *                          *
                         ****************************/
/***************************************************************************
**
**    Ldasm
**
***************************************************************************/
RETCODE Ldasm(CHAR *MemData, PMODE CodeMode, ADDR_OP_SIZE addrOpSize,
   DESCRIPTOR StartAddrDesc, BOOLEAN Sym, CHAR *TextBuffer, DASM_INFO *Info)
{

   BOOLEAN PfxDone = FALSE,
           ErrFlag = FALSE,
           TwoOps = FALSE;
   CHAR SegOver[4];
   OPTABLE OpEntry;
   U8   OpByte1 = 0, OpByte2 = 0;
   U8   FetchBuffer[MAX_FETCH_SIZE];
   FLAGS   Flags;
   MODE_R_M Modrm;
   PROBE_TYPE Processor;
   RETCODE err;

   ProcReturnSpecificProcessor(&Processor);
//   bMP186 = (Processor == I80C186_MP);
   bMP186 = 1;
   strcpy(TextBuffer,"");
   *SegOver = NULL;
   /* initialize all fields to FALSE */
   Info->transfer = Info->conditional = Info->knownAddr = FALSE;
   Info->prefix = Info->popMovSS = Info->callType = Info->retnType = FALSE;
   Info->operand32 = FALSE;
   Info->accessType = 0;
   Info->MRCycles = Info->MWCycles = Info->IRCycles = Info->IWCycles = 0;
   Info->bytesUsed = 0;
   switch (addrOpSize) {
      case ADDR_USE_16:
         Flags.Addr32  = Flags.Oprnd32 = FALSE;
         break;
      case ADDR_USE_32:
         Flags.Addr32  = Flags.Oprnd32 = TRUE;
         break;
      case ADDR_USE_AUTO:
      default: {
         ADDR_OP_SIZE opSize;
         if ((err = AdrGetDefaultSize(StartAddrDesc,&opSize)) != GOOD)
            return err;
         switch (opSize) {
            case ADDR_USE_32:
               Flags.Addr32  = Flags.Oprnd32 = TRUE;
               break;
            case ADDR_USE_16:
            default:
               Flags.Addr32  = Flags.Oprnd32 = FALSE;
               break;
         }
      }
      break;
   }
   Flags.ErrorOccured = Flags.SegPfxSet = Flags.OprndPfxSet = FALSE;
   Flags.AddrPfxSet = Flags.LockPfxSet = Flags.RepnePfxSet = FALSE;
   Flags.RepPfxSet = Flags.ModrmFetched = Flags.SibFetched = FALSE;
   Flags.PtrOpCode = Flags.JmpOpCode = Flags.Wait387 = FALSE;

   InitFetch((U8*)MemData);
   InitText(MemData,TextBuffer);

   while (!PfxDone) {
      FetchBytes(BYTE_SIZE,Info,FetchBuffer);            /* get first byte */
      switch (FetchBuffer[0]) {
         case 0xF0:                                         /* LOCK prefix */
            ErrFlag = SetPrefix(&Flags.LockPfxSet,"LOCK:",Info);
            break;
         case 0xF2:                                        /* REPNE prefix */
            ErrFlag = SetPrefix(&Flags.RepnePfxSet,"REPNE:",Info);
            break;
         case 0xF3:                                          /* REP prefix */
            ErrFlag = SetPrefix(&Flags.RepPfxSet,"REP:",Info);
            break;
         case 0x26:                          /* ES segment override prefix */
            ErrFlag = SetSegOver(&Flags.SegPfxSet,SegOver,"ES:");
            break;
         case 0x2E:                          /* CS segment override prefix */
            ErrFlag = SetSegOver(&Flags.SegPfxSet,SegOver,"CS:");
            break;
         case 0x36:                          /* SS segment override prefix */
            ErrFlag = SetSegOver(&Flags.SegPfxSet,SegOver,"SS:");
            break;
         case 0x3E:                          /* DS segment override prefix */
            ErrFlag = SetSegOver(&Flags.SegPfxSet,SegOver,"DS:");
            break;
         case 0x64:                          /* FS segment override prefix */
            ErrFlag = SetSegOver(&Flags.SegPfxSet,SegOver,"FS:");
            break;
         case 0x65:                          /* GS segment override prefix */
            ErrFlag = SetSegOver(&Flags.SegPfxSet,SegOver,"GS:");
            break;
         case 0x66:                        /* Operand-size override prefix */
            ErrFlag = SetSize(&Flags.OprndPfxSet,&Flags.Oprnd32);
            break;
         case 0x67:                         /* Adress-size override prefix */
            ErrFlag = SetSize(&Flags.AddrPfxSet,&Flags.Addr32);
            break;
         default:
            PfxDone = TRUE;
            break;
      }     /*  end switch */
      if (ErrFlag != GOOD) {
         dbError(Info);
         return (GOOD);
      }
   }        /* while !PfxDone */
   Info->operand32 = Flags.Oprnd32;

   /*  done with prefixes, now process opcode.  At this point, the
       first byte of the opcode should be in FetchBuffer[0]  */

   OpByte1 = FetchBuffer[0];
   switch (OpByte1) {
      case 0xD4:              /* AAA,AAM opcodes: second byte must be 0x0A */
      case 0xD5:
         FetchBytes(BYTE_SIZE,Info,FetchBuffer);
         if (FetchBuffer[0] != 0x0A) {
            Info->bytesUsed--;
            dbError(Info);
            return(GOOD);
         }
         else
            TwoOps = FALSE;
         break;

      case 0x9B:                          /* Numeric processor WAIT prefix */
         FetchBytes(BYTE_SIZE,Info,FetchBuffer);
         OpByte2 = FetchBuffer[0];
         if (OpByte2 >= 0xD8 && OpByte2 <= 0xDF) {
            Flags.Wait387 = TRUE;
            OpByte1 = OpByte2;
         }
         else {
            Flags.Wait387 = FALSE;
            OpByte2 = 0;
            Info->bytesUsed--;
         }
         TwoOps = FALSE;
         break;

      case 0x0F:                              /* two-byte opcode indicator */
         FetchBytes(BYTE_SIZE,Info,FetchBuffer);
         OpByte2 = FetchBuffer[0];
         TwoOps = TRUE;
         break;

      case 0x17:                                                 /* POP SS */
         Info->popMovSS = TRUE;
         TwoOps = FALSE;
         break;

      default:
         TwoOps = FALSE;

   } /* switch */

   if ((OpByte1 >= 0xD8) && (OpByte1 <= 0xDF)) {
   /* Numeric processor instruction */
      dbError(Info);
      return(GOOD);
/******  disable 80X87 instructions
      OpEntry = *OpTable1[OpByte1];
      if (NumProcessor(OpByte1,&OpEntry,Info,&Flags,&Modrm)) {
        dbError(Info);
        return(GOOD);
      }
*******/  
   }
   else {                                  /* Normal processor instruction */
      if (OpTable1[OpByte1]==NULL || OpTable2[OpByte2]==NULL) {
         dbError(Info);
         return(GOOD);
      }
      if (bMP186 && TwoOps) {
         dbError(Info);
         return(GOOD);
      }
      OpEntry = (TwoOps ? *OpTable2[OpByte2] : *OpTable1[OpByte1]);
      if (TwoOps)
         switch(OpByte2) {
            case 0xB6:
            case 0xB7:
            case 0xBE:
            case 0xBF:
               Flags.PtrOpCode = TRUE;
               break;
         }
      else
         switch(OpByte1) {
            case 0xC6:
            case 0xC7:
               Flags.PtrOpCode = TRUE;
               break;
         }

      if (ProcessOpCode(&OpEntry,OpByte1,&Modrm,Info,&Flags) != GOOD) {
         dbError(Info);
         return(GOOD);
      }
   } /*  end if OpByte & 0xD8 */

   if (ProcessOperands(CodeMode,Sym,&OpEntry,OpByte1,OpByte2,StartAddrDesc,
                       SegOver,&Modrm,Info,&Flags) != GOOD) {
      dbError(Info);
      return(GOOD);
   }
   return(GOOD);
}; /* end of ldasm() */

/***************************************************************************
**
**    LdasmText
**
***************************************************************************/

RETCODE LdasmText(LPSTR text, LPSTR result)
{
   U32 n;
   /* Ldasm returns a text buffer formatted as follows:
      1. 1 or 2 prefix strings starting with '@' and null terminator,
      2. one Opcode mnemonic starting with '|' and null terminator,
      3. Operand string with null terminated
   */
   n = (U32)result;

   if (*text == '@') {            // first prefix
      text++;
      lstrcpy(result, text);
      result += lstrlen(text);
      *(result++) = ' ';
      text = strchr(text, '\0');
      text++;
   }
   if (*text == '@') {            // second prefix
      text++;
      lstrcpy(result, text);
      result += lstrlen(text);
      *(result++) = ' ';
      text = strchr(text, '\0');
      text++;
   }
   if (*text == '|') {            // Opcode mnemonic
      text++;
      lstrcpy(result, text);
      result += lstrlen(text);
      *(result++) = ' ';
      text = strchr(text, '\0');
      text++;
   }

   // keep width of opcode column constant
   n = (U32)result - n;
   n = (n > OP_WIDTH) ? 0 : (OP_WIDTH - n);
   while (n > 0) {
      n--;
      *(result++) = ' ';
   }
   // end of adding spaces

   lstrcpy(result, text);         // Operand(s)

   return(GOOD);
}

/***************************************************************************
**  SetPrefix
**
**  Flag (in/out):
**  Prefix (in):
**  Info (out):
***************************************************************************/
RETCODE SetPrefix(BOOLEAN *Flag, CHAR *Prefix, DASM_INFO *Info)
{
   if (*Flag) return(!GOOD);
   else {
      Info->prefix = TRUE;
      *Flag = TRUE;
      PutText(PREFIX,Prefix);
      return(GOOD);
   }
}


/***************************************************************************
**  SetSegOver
**  purpose: Sets up segment override string
**
**  Flag (in/out):
**  SegOver (in/out):
**  Prefix (in):
***************************************************************************/
RETCODE SetSegOver(BOOLEAN *Flag, CHAR *SegOver, CHAR *Prefix)
{
   if (*Flag) return(!GOOD);
   else {
      *Flag = TRUE;
      lstrcpy(SegOver,Prefix);
      return(GOOD);
   }
}

/* Sets up size override */
/***************************************************************************
**  SetSize
**  purpose: Sets up size override
**
**  Flag1 (in/out):
**  Flag2 (in/out):
***************************************************************************/
RETCODE SetSize(BOOLEAN *Flag1, BOOLEAN *Flag2)
{
   if (*Flag1) return(!GOOD);
   else {
      *Flag1 = TRUE;
      *Flag2 = (*Flag2 ? FALSE : TRUE);
      return(GOOD);
   }
}
/***************************************************************************
**  NumProcessor
**
**  OpByte1 (in):
**  OpEntry (in):
**  Info (in):
**  Flags (in/out):
**  Modrm (in):
***************************************************************************/
STATIC
RETCODE NumProcessor(U8 OpByte1, OPTABLE *OpEntry, DASM_INFO *Info,
                     FLAGS *Flags, MODE_R_M *Modrm)
{
   U8 Byte, Byte2;

   GetModrm(Modrm,Info,Flags);            /* Get 2nd byte (Possible Modrm) */
   if (Modrm->ModRM.Mode != 3) {           /* Valid Modrm, do table lookup */
      *OpEntry = *( (OPTABLE*)OpEntry->DwOpText + Modrm->ModRM.RegOpcode);
      Flags->PtrOpCode = TRUE;
      if (!OpEntry->OpText)
         return(!GOOD);
      if (Flags->Wait387)
         PutText(OPCODE,OpEntry->DwOpText);
      else
         PutText(OPCODE,OpEntry->OpText);
      return(GOOD);
   }
   else {                        /* Not valid Modrm, process on case basis */
      Byte2 = Modrm->ModByte;
      switch (OpByte1) {
         case 0xD8:
            PutText(OPCODE,NumProc1[(Byte2 & 0x38) >> 3]);
            PutText(OPRND,"ST(");
            Byte2 = Byte2 & 7;
            PutData(NIBBLE_SIZE,&Byte2);
            PutText(OPRND,")");
            break;

         case 0xD9:
            if ((Byte2 & 0xF8) == 0xC0 ) {
               PutText(OPCODE,"FLD");
               PutText(OPRND,"ST(");
               Byte = Byte2 & 7;
               PutData(NIBBLE_SIZE,&Byte);
               PutText(OPRND,")");
            }
            if ((Byte2 & 0xF8) == 0xC8 ) {
               PutText(OPCODE,"FXCH");
               PutText(OPRND,"ST(");
               Byte = Byte2 & 7;
               PutData(NIBBLE_SIZE,&Byte);
               PutText(OPRND,")");
            }
            if ((Byte2 & 0xF8) == 0xD8 )
               return(!GOOD);
            if ((Byte2 & 0xE0) == 0xE0)
               if (NumProc2[Byte2 & 0x1F] == NULL)
                  return(!GOOD);
               else
                  PutText(OPCODE,NumProc2[Byte2 & 0x1F]);
            switch (Byte2) {
               case 0xD0:
                  PutText(OPCODE,"FNOP"); break;
               case 0xD1:
               case 0xD2:
               case 0xD3:
               case 0xD4:
               case 0xD5:
               case 0xD6:
               case 0xD7:
                  return(!GOOD);
            }
            break;

         case 0xDA:
            if (Byte2 == 0xE9)
               PutText(OPCODE,"FUCOMPP");
            else {
               switch (Byte2) {
                  case 0xC4:
                     PutText(OPCODE,"FADDP");
                     break;
                  case 0xCC:
                     PutText(OPCODE,"FMULP");
                     break;
                  case 0xE4:
                     PutText(OPCODE,"FSUBP");
                     break;
                  case 0xEC:
                     PutText(OPCODE,"FSUBRP");
                     break;
                  case 0xF4:
                     PutText(OPCODE,"FDIVP");
                     break;
                  case 0xFC:
                     PutText(OPCODE,"FDIVRP");
                     break;
                  default:
                     return(!GOOD);
               }
               PutText(OPRND, "ST(4)");
            }
            break;
            
         case 0xDB:
            switch (Byte2) {
               case 0xE0:                   /* treated as fnop by 80387 */ 
                  PutText(OPCODE,"FENI");
                  break;
               case 0xE1:                   /* treated as fnop by 80387 */
                  PutText(OPCODE,"FDISI");
                  break;
               case 0xE2:
                  if (Flags->Wait387)
                     PutText(OPCODE,"FCLEX");
                  else
                     PutText(OPCODE,"FNCLEX");
                  break;
               case 0xE3:
                  if (Flags->Wait387)
                     PutText(OPCODE,"FINIT");
                  else
                     PutText(OPCODE,"FNINIT");
                  break;
               case 0xE4:                   /* treated as fnop by 80387 */
                  PutText(OPCODE,"FSETPM");
                  break;
               default:
                  return(!GOOD);
            }
            break;

         case 0xDC:
            if ((Byte2 & 0xF8) == 0xD0 || (Byte2 & 0xF8) == 0xD8)
               return(!GOOD);
            else {
               PutText(OPCODE,NumProc1A[(Byte2 & 0x38) >> 3]);
               PutText(OPRND,"ST(");
               Byte = Byte2 & 7;
               PutData(NIBBLE_SIZE,&Byte);
               PutText(OPRND,"),ST");
            }
            break;

         case 0xDD:
            if ((Byte2 & 0xF0) == 0xF0)
               return(!GOOD);
            Byte = (Byte2 & 0x38) >> 3;
            if (NumProc3[Byte] == NULL)
               return(!GOOD);
            else {
               PutText(OPCODE,NumProc3[Byte]);
               PutText(OPRND,"ST(");
               Byte = Byte2 & 7;
               PutData(NIBBLE_SIZE,&Byte);
               PutText(OPRND,")");
            }
            break;

         case 0xDE:
            if (Byte2 == 0xD9)
               PutText(OPCODE,"FCOMPP");
            else {
               Byte = Byte2 & 0xF8;
               switch (Byte) {
                  case 0xC0:
                     PutText(OPCODE,"FADDP");
                     break;
                  case 0xC8:
                     PutText(OPCODE,"FMULP");
                     break;
                  case 0xE0:
                     PutText(OPCODE,"FSUBRP");
                     break;
                  case 0xE8:
                     PutText(OPCODE,"FSUBP");
                     break;
                  case 0xF0:
                     PutText(OPCODE,"FDIVRP");
                     break;
                  case 0xF8:
                     PutText(OPCODE,"FDIVP");
                     break;
                  default:
                     return(!GOOD);
               }
               PutText(OPRND,"ST(");
               Byte2 = Byte2 & 7;
               PutData(NIBBLE_SIZE,&Byte2);
               PutText(OPRND,"),ST");
            }
            break;

         case 0xDF:
            if (Byte2 == 0xE0) {
               if (Flags->Wait387)
                  PutText(OPCODE,"FSTSW");
               else
                  PutText(OPCODE,"FNSTSW");
               PutText(OPRND,"AX");
            }
            else return(!GOOD);
            break;
      } /* end switch OpByte1 */
   } /* end if Modrm */
   return(GOOD);
} /* end NumProcessor */

/***************************************************************************
**  ProcessOpCode
**  Purpose: Do table lookup and get modr/m if required
**
**  OpEntry(in): Opcode table data
**  OpByte (in): Opcode byte 1
**  Modrm (in): Modr/m decoding structure
**  Info (in): disassembly status information
**  Flags (in): Control flag structure
***************************************************************************/
RETCODE ProcessOpCode(OPTABLE *OpEntry, U8 OpByte, MODE_R_M *Modrm,
                             DASM_INFO *Info, FLAGS *Flags)
{

   Modrm->ModByte = 0;
   if (OpEntry->OpText == (CHAR*)1 ) {
      Flags->PtrOpCode = TRUE;
      GetModrm(Modrm,Info,Flags);
      *OpEntry = *( (OPTABLE*)OpEntry->DwOpText + Modrm->ModRM.RegOpcode);
   }
   if (OpEntry->OpText == NULL)
      return(!GOOD);
   if (Flags->Oprnd32 && OpEntry->DwOpText) {
      PutText(OPCODE,OpEntry->DwOpText);
   }
   else
      PutText(OPCODE,OpEntry->OpText);

   if (!lstrcmp(OpEntry->OpText,"JMP"))
     Flags->JmpOpCode = TRUE;
   if (!lstrcmp(OpEntry->OpText,"CALL")) {
      Info->callType = TRUE;
      Flags->JmpOpCode = TRUE;
   }
   /* Matt 4/3/1997 */
   if (!strcmp(OpEntry->OpText,"LOOP") ||
       !strcmp(OpEntry->OpText,"LOOPE") ||
       !strcmp(OpEntry->OpText,"LOOPZ") ||
       !strcmp(OpEntry->OpText,"LOOPNZ") ||
       !strcmp(OpEntry->OpText,"LOOPNE"))
      Info->callType = TRUE;
   /* Matt */
   if (!strcmp(OpEntry->OpText,"RET") ||
       !strcmp(OpEntry->OpText,"RETN") ||
//     !strcmp(OpEntry->OpText,"IRET") ||
       !strcmp(OpEntry->OpText,"RETF") ||
       !strcmp(OpEntry->OpText,"RSM"))
      Info->retnType = TRUE;

//   if (OpEntry->DwOpText != NULL && !strcmp(OpEntry->DwOpText,"IRETD"))
//      Info->retnType = TRUE;


   Info->conditional = OpEntry->BusData.Conditional;
   Info->transfer = OpEntry->BusData.Transfer;

   /* Determine bus cycle requirements for instruction */

   Info->accessType = NULL;
   if (OpEntry->BusData.Special) {                        /* Special Cases */
      switch (OpByte) {
         case 0xC8:                                               /* enter */
            break;
         case 0xCC:                                               /* int 3 */
            break;
         case 0xCD:                                               /* int n */
            break;
         case 0xCE:                                                /* into */
            break;
         case 0xCF:                                          /* iret,iretd */
            break;
      } /* end switch */
   }
   else {
      if (OpEntry->BusData.CheckModrm) {    /* Modrm determines bus cycles */
         GetModrm(Modrm,Info,Flags);
         if (Modrm->ModRM.Mode != REG_MODE) {
            Info->accessType = OpEntry->BusCycle.AccessType;
            if (OpEntry->BusCycle.CycleType.MemRead)
               Info->MRCycles = (Flags->Oprnd32 ? OpEntry->BusData.RBytes32 :
                                                 OpEntry->BusData.RBytes16);
            if (OpEntry->BusCycle.CycleType.MemWrite)
               Info->MWCycles = (Flags->Oprnd32 ? OpEntry->BusData.WBytes32 :
                                                 OpEntry->BusData.WBytes16);
            if (OpEntry->BusCycle.CycleType.IORead)
               Info->IRCycles = (Flags->Oprnd32 ? OpEntry->BusData.RBytes32 :
                                                 OpEntry->BusData.RBytes16);
            if (OpEntry->BusCycle.CycleType.IOWrite)
               Info->IWCycles = (Flags->Oprnd32 ? OpEntry->BusData.WBytes32 :
                                                 OpEntry->BusData.WBytes16);
         }
      }
      else {                                                 /* All others */
         Info->accessType = OpEntry->BusCycle.AccessType;
         if (OpEntry->BusCycle.CycleType.MemRead)
            Info->MRCycles = (Flags->Oprnd32 ? OpEntry->BusData.RBytes32 :
                                              OpEntry->BusData.RBytes16);
         if (OpEntry->BusCycle.CycleType.MemWrite)
            Info->MWCycles = (Flags->Oprnd32 ? OpEntry->BusData.WBytes32 :
                                              OpEntry->BusData.WBytes16);
         if (OpEntry->BusCycle.CycleType.IORead)
            Info->IRCycles = (Flags->Oprnd32 ? OpEntry->BusData.RBytes32 :
                                              OpEntry->BusData.RBytes16);
         if (OpEntry->BusCycle.CycleType.IOWrite)
            Info->IWCycles = (Flags->Oprnd32 ? OpEntry->BusData.WBytes32 :
                                              OpEntry->BusData.WBytes16);
      }  /* end if OpEntry->BusData.CheckModrm */
   } /* end if OpEntry->BusData.Special */
   return(GOOD);
}


/***************************************************************************
**  ProcessOperands
**  Purpose: Translate operand(s)
**
**  CodeMode: 386 operating mode
**  Sym:      symbol decoding flag
**  OpEntry:  Opcode table data
**  OpByte1:  1st Opcode byte
**  OpByte2:  2nd Opcode byte
**  Addr:     Address of code to disassemble
**  SegOverride: Segment override register
**  Modrm:    Modr/m decoding structure
**  Info:     disassembly status information
**  Flags:    control flag structure
***************************************************************************/
RETCODE ProcessOperands(PMODE CodeMode, BOOLEAN Sym, OPTABLE *OpEntry,
   U8 OpByte1, U8 OpByte2, DESCRIPTOR Addr, CHAR *SegOverride,
   MODE_R_M *Modrm, DASM_INFO *Info, FLAGS *Flags)
{
   U16     OpCounter;
   U8      RegCode, Size;
   S8      Temp;
   U8      Segment[MAX_FETCH_SIZE], Offset[MAX_FETCH_SIZE],
           Displacement[MAX_FETCH_SIZE], Immediate[MAX_FETCH_SIZE];
   S32     Target;
   CHAR    **RegArray, *PtrName;
   CHAR    Label[MAX_DASM_TEXT];
   U32     t_offset;
   U16     t_segment;
   SCALE_INDEX_BASE  sib;
   RETCODE err;
   DESCRIPTOR tempAddr;

   if (bMP186 && (Flags->Oprnd32 || Flags->Addr32))
      return(!GOOD);
   Info->knownAddr = FALSE;
   memset(Segment,'\0',MAX_FETCH_SIZE);
   memset(Offset,'\0',MAX_FETCH_SIZE);
   memset(Displacement,'\0',MAX_FETCH_SIZE);
   memset(Immediate,'\0',MAX_FETCH_SIZE);
   memset(Label,'\0',MAX_DASM_TEXT);
   if (!OpEntry->NumOps) {                     /* no operands, do nothing */
      PutText(OPRND,"");
      return(GOOD);
   }

   for (OpCounter=0; OpCounter < OpEntry->NumOps; OpCounter++) {
      if (OpCounter) PutText(OPRND,",");
/************* Setup operand size parameters ********************* */
      switch (OpEntry->Oprand[OpCounter].Type) {
        case TY_b:
           Size = BYTE_SIZE;
           PtrName = BYTE_PTR;
           RegArray = OprByteReg;
           break;

        case TY_w:
           Size = WORD_SIZE;
           PtrName = WORD_PTR;
           RegArray = OprWordReg;
           break;
           
        case TY_v:
           if (Flags->Oprnd32) {
              Size = LONG_SIZE;
              PtrName = DWORD_PTR;
              RegArray = OprDwordReg;
           }
           else {
              Size = WORD_SIZE;
              PtrName = WORD_PTR;
              RegArray = OprWordReg;
           }
           break;
        case TY_p:
           PtrName = (Flags->Oprnd32 ? FWORD_PTR : DWORD_PTR);
                     /* ((CodeMode==PMODE_P32) ? WORD_PTR : DWORD_PTR)); */
           CodeMode += 999; // useless statement
           break;
        case TY_d:
           PtrName = DWORD_PTR;
           break;
        case TY_q:
           PtrName = QWORD_PTR;
           break;
        case TY_t:
           PtrName = TBYTE_PTR;
           break;
        default:
           PtrName = "";
           break;
     }
    /************  Process the addressing mode ***********************/
      switch (OpEntry->Oprand[OpCounter].Mode) {
         case AD_A:                 /* direct address, no modr/m, no sib */
            Size = (Flags->Oprnd32 ? LONG_SIZE : WORD_SIZE);
            FetchBytes(Size,Info,Offset);
            FetchBytes(WORD_SIZE,Info,Segment);
            
            if ((err=AdrCreateAddress(&tempAddr)) != GOOD)
               return err;
            if ((err=AdrSetAddrType(tempAddr, ADDR_VIRTUAL)) != GOOD)
               return err;
            t_offset = (Flags->Oprnd32 ? *((U32*) Offset) :
                                                 (U32) *((U16*) Offset));
            t_segment = *((U16*)Segment);

            if (t_segment != 0) {
               if ((err=AdrSetAddrSegmentSelector(tempAddr,
                     ADDR_USE_VALUE, &t_segment)) != GOOD)
                  return err;
            } 
            else {
               if ((err=AdrSetAddrSegmentSelector(tempAddr,
                     ADDR_USE_CS, &t_segment)) != GOOD)
                  return err;
            }
/*****   ignore the error checking   ******
            if ((err=AdrSetAddrOffset(tempAddr, t_offset)) != GOOD)
               return(err);
*******************************************/
            err = AdrSetAddrOffset(tempAddr, t_offset);
            
            if ((err=AdrCopyAddress(tempAddr, Info->target)) != GOOD)
               return(err);
            if ((err=AdrCremateAddress(&tempAddr)) != GOOD)
               return(err);
            
            if (Sym &&
                  (GetSymbol(*((U16*)Segment), *((U32*)Offset), 
                  Info->target, Label) == GOOD))
               PutText(OPRND,Label);
            else {
               PutData(WORD_SIZE,Segment);
               PutText(OPRND,":");
               PutData(Size,Offset);
            }
            Info->knownAddr = TRUE;
            break;

         case AD_C:           /* reg field of modr/m selects control reg */
            GetModrm(Modrm,Info,Flags);
            if (Modrm->ModRM.Mode!=MOD_REG||Modrm->ModRM.RegOpcode == 1 ||
                Modrm->ModRM.RegOpcode > 3) return(!GOOD);
            PutText(OPRND,OprCrReg[Modrm->ModRM.RegOpcode]);
            break;

         case AD_D:             /* reg field of modr/m selects debug reg */
            GetModrm(Modrm,Info,Flags);
            if (Modrm->ModRM.Mode!=MOD_REG||Modrm->ModRM.RegOpcode == 4 ||
                Modrm->ModRM.RegOpcode == 5) return(!GOOD);
            PutText(OPRND,OprDrReg[Modrm->ModRM.RegOpcode]);
            break;

         case AD_M:                 /* modr/m byte refers only to memory */
            GetModrm(Modrm,Info,Flags);
            if (Modrm->ModRM.Mode == REG_MODE)
               return(!GOOD);
               /* NOTE--execution of return is an error condition.  Normal
               program flow is directly into the following AD_E case */

         case AD_E:                     /* modrm & SIB specifies operand */
            if (OpEntry->Oprand == OpMp&&!Flags->Oprnd32&&Flags->JmpOpCode)
               PutText(OPRND,"FAR ");
            if (OpEntry->Oprand == OpEv&&Flags->Oprnd32&&Flags->JmpOpCode)
               PutText(OPRND,"NEAR ");
            GetModrm(Modrm,Info,Flags);
            if (Modrm->ModRM.Mode == REG_MODE)
               PutText(OPRND,RegArray[Modrm->ModRM.RegMem]);
            else {
               if (Flags->PtrOpCode)
                  PutText(OPRND,PtrName);
               if (Flags->SegPfxSet)
                  PutText(OPRND,SegOverride);
               if (Flags->Addr32)
                  if (Modrm->ModRM.RegMem == 4) {    /* SIB byte indicator */
                     if (ProcessSIB(Modrm,&sib,Info,Flags))
                        return(!GOOD);
                  }
                  else
                     ProcessRM32(Modrm,Info);
               else
                  ProcessRM16(Modrm,Info);
            }
            break;  /* end of case AD_E */

         case AD_G:           /* reg field of modr/m selects general reg */
            GetModrm(Modrm,Info,Flags);
            PutText(OPRND,RegArray[Modrm->ModRM.RegOpcode]);
            break;

         case AD_I:                                    /* Immediate data */
            FetchBytes(Size,Info,Immediate);
            PutData(Size,Immediate);
            break;

         case AD_J:     /* instruction contains offset to be added to IP */
            if  (OpEntry->Oprand[OpCounter].Type == TY_b) {
               PutText(OPRND,"SHORT ");
               FetchBytes(BYTE_SIZE,Info,Displacement);
               Temp = *((S8*) Displacement);
               Target = (S32) Temp;
            }
            else {
               if (Flags->Oprnd32) {
                  FetchBytes(LONG_SIZE,Info,Displacement);
                  Target = *((S32*) Displacement);
               }
               else {
                  FetchBytes(WORD_SIZE,Info,Displacement);
                  Target = *((S16*) Displacement);
               }
            }
            Target += (S32) Info->bytesUsed;
            if ((err=AdrGetAddrOffset(Addr, &t_offset)) != GOOD)
               return(err);
            Target += (S32) t_offset;      /* Target address of jump */
            if (Sym &&
                 (GetSymbol(0,(U32)Target,Addr,Label) == GOOD))
               PutText(OPRND,Label);
            else {
               ADDR_TYPE type;

               if ((err=AdrGetAddrType(Addr, &type)) != GOOD)
                  return(err);
               if (Flags->Oprnd32 || type == ADDR_PHYSICAL)
                  PutData(LONG_SIZE,&Target);
               else {
               /*186*   Target &= 0x0000FFFF; *186*/
                  PutData(WORD_SIZE,&Target);
               }
            }
            /* Info->target was duped from Addr */
            if ((err=AdrSetAddrOffset(Info->target, Target)) != GOOD)
               return(err);
            Info->knownAddr = TRUE;
            break;

         case AD_K:              /* Register coded in 3 lsbits of opcode */
            RegCode = OpByte1 & 0x07;
            if (OpEntry->Oprand[OpCounter].Type == TY_b)
               PutText(OPRND,OprByteReg[RegCode]);
            else
               PutText(OPRND,Flags->Oprnd32 ? OprDwordReg[RegCode] :
                                               OprWordReg[RegCode]);
            break;

         case AD_L:       /* Register coded in 3 lsbits of opcode byte 2 */
            RegCode = OpByte2 & 0x07;
            if (OpEntry->Oprand[OpCounter].Type == TY_b)
               PutText(OPRND,OprByteReg[RegCode]);
            else
               PutText(OPRND,Flags->Oprnd32 ? OprDwordReg[RegCode] :
                                               OprWordReg[RegCode]);
            break;

         case AD_O:            /* no modr/m, offset coded in instruction */
            PutText(OPRND,SegOverride);
            PutText(OPRND,"[");
            Size = (Flags->Addr32 ? LONG_SIZE : WORD_SIZE);
            FetchBytes(Size,Info,Displacement);
            PutData(Size,Displacement);
            PutText(OPRND,"]");
            break;

         case AD_Q: /* no operands but prefetch queue is flushed */
           /* note -- the sole purpose of this routine is to allow the trace
              dequeueing function to skip the queue flush caused by a CLI */
            PutText(OPRND,"");
            AdrCopyAddress(Addr, Info->target);
            AdrAddToAddress(Info->target, 1);
            break;

         case AD_R:    /* mod field of modr/m refers only to special reg */
            GetModrm(Modrm,Info,Flags);
            if (Modrm->ModRM.Mode != MOD_REG)
               return(!GOOD);
            PutText(OPRND,OprDwordReg[Modrm->ModRM.RegMem]);
            break;
            
         case AD_S:         /* reg field of modr/m selects a segment reg */
            GetModrm(Modrm,Info,Flags);
            if (!OpCounter && OpByte1 == 0x8E && Modrm->ModRM.RegOpcode == 1)
               return(!GOOD);
            PutText(OPRND,OprSegReg[Modrm->ModRM.RegOpcode]);
            if (OpByte1 == 0x8E && Modrm->ModRM.RegOpcode == 2)
               Info->popMovSS = TRUE;                       /* MOV SS,xx */
            break;

         case AD_T:            /* reg field of modr/m selects a test reg */
            GetModrm(Modrm,Info,Flags);
            if(Modrm->ModRM.Mode != MOD_REG ||
               Modrm->ModRM.RegOpcode < FIRST_TR_REG)
                  return(!GOOD);
            PutText(OPRND,OprTrReg[Modrm->ModRM.RegOpcode]);
            break;

         case AD_X:                         /* memory addressed by DS:SI */
            if (!OpCounter)
               PutText(OPRND,PtrName);
            if (Flags->SegPfxSet)
               PutText(OPRND,SegOverride);
            else {
               PutText(OPRND,OprSegReg[3]);
               PutText(OPRND,":");
               Flags->SegPfxSet = TRUE;
            }
            PutText(OPRND,"[");
            PutText(OPRND,Flags->Addr32 ? OprDwordReg[6] : OprWordReg[6]);
            PutText(OPRND,"]");
            break;

         case AD_Y:                         /* memory addressed by ES:DI */
            if (!OpCounter)
               PutText(OPRND,PtrName);
            PutText(OPRND,OprSegReg[0]);
            PutText(OPRND,":[");
            PutText(OPRND,Flags->Addr32 ? OprDwordReg[7] : OprWordReg[7]);
            PutText(OPRND,"]");
            break;

         case AD_Z:                /* memory addressed by SegOverride:BX */
            PutText(OPRND,SegOverride);
            PutText(OPRND,"[");
            PutText(OPRND,Flags->Addr32 ? OprDwordReg[3] : OprWordReg[3]);
            PutText(OPRND,"]");
            break;

         case AD_1:                  /* Used by rotate and shift opcodes */
            PutText(OPRND,"1");
            break;

         case AD_3:                                       /* Interrupt 3 */
            PutText(OPRND,"3");
            break;

         case AD_AL:                                /* AL register operand */
            PutText(OPRND,OprByteReg[0]);
            break;

         case AD_CL:                                /* CL register operand */
            PutText(OPRND,OprByteReg[1]);
            break;

         case AD_DX:                                /* DX register operand */
            PutText(OPRND,OprWordReg[2]);
            break;

         case AD_vAX:                     /* AX or EAX  register operand */
            PutText(OPRND,Flags->Oprnd32 ? OprDwordReg[0] : OprWordReg[0]);
            break;

         case AD_ES:                                /* ES register operand */
            PutText(OPRND,OprSegReg[AD_ES - AD_ES]);
            break;

         case AD_CS:                                /* CS register operand */
            PutText(OPRND,OprSegReg[AD_CS - AD_ES]);
            break;

         case AD_SS:                                /* SS register operand */
            PutText(OPRND,OprSegReg[AD_SS - AD_ES]);
            break;

         case AD_DS:                                /* DS register operand */
            PutText(OPRND,OprSegReg[AD_DS - AD_ES]);
            break;

         case AD_FS:                                /* FS register operand */
            if (bMP186)
               return(!GOOD);
            else
               PutText(OPRND,OprSegReg[AD_FS - AD_ES]);
            break;

         case AD_GS:                                /* GS register operand */
            if (bMP186)
               return(!GOOD);
            else
               PutText(OPRND,OprSegReg[AD_GS - AD_ES]);
            break;

         default:
            break;

      } /* end--switch */
   }    /* end--for OpCounter */
   return(GOOD);
}


/****************************************************************************
**   GetModrm
**   Purpose: get and decode modr/m byte
**
**   Modrm (in): modr/m byte decoding structure
**   Info  (in):
**   Flags (in):
**
****************************************************************************/
RETCODE GetModrm(MODE_R_M *Modrm, DASM_INFO *Info, FLAGS *Flags)
{
   CHAR FetchBuffer[MAX_FETCH_SIZE];

   if (!Flags->ModrmFetched) {
      FetchBytes(BYTE_SIZE,Info,FetchBuffer);
      Modrm->ModByte = FetchBuffer[0];
      Flags->ModrmFetched = TRUE;
   }
   return(GOOD);
}

/***************************************************************************
**  GetSIB
**  Purpose: get and decode SIB byte
**
**  sib   (in): SIB byte decoding structure
**  Info  (in):
**  Flags (in):
***************************************************************************/
RETCODE GetSIB(SCALE_INDEX_BASE *sib, DASM_INFO *Info, FLAGS *Flags)
{
   CHAR FetchBuffer[MAX_FETCH_SIZE];

   if (!Flags->SibFetched) {
      FetchBytes(BYTE_SIZE,Info,FetchBuffer);
      sib->SibByte = FetchBuffer[0];
      Flags->SibFetched = TRUE;
   }
   return(GOOD);
}

/***************************************************************************
**  ProcessSIB
**  Purpose: process SIB information
**
**  Modrm(in):
**  sib(in):
**  Info(in):
**  Flags(in):
***************************************************************************/
RETCODE ProcessSIB(MODE_R_M *Modrm, SCALE_INDEX_BASE *sib,
                          DASM_INFO *Info, FLAGS *Flags)
{
   U8 Displacement[MAX_FETCH_SIZE], Size;

   GetSIB(sib,Info,Flags);
   
   PutText(OPRND,"[");
   if (sib->SIB.Base==5 && Modrm->ModRM.Mode==0) {
      FetchBytes(LONG_SIZE,Info,Displacement);
      PutData(LONG_SIZE,Displacement);
   }
   else {
      PutText(OPRND,OprDwordReg[sib->SIB.Base]);
      if (Modrm->ModRM.Mode) {
         Size = ((Modrm->ModRM.Mode==DISPL8) ? BYTE_SIZE : LONG_SIZE);
         FetchBytes(Size,Info,Displacement);
         if (Size == BYTE_SIZE) {
            if (*(U8*)Displacement >= 0x80) {
               PutText(OPRND,"-");
               Displacement[0] = -Displacement[0];
               PutData(BYTE_SIZE,Displacement);
            }
            else {
               PutText(OPRND,"+");
               PutData(Size,Displacement);
            }
         }
         else {
            if (*(U32*)Displacement >= 0x80000000l) {
               PutText(OPRND,"-");
               *((U32*)Displacement) = - *((U32*)Displacement);
               PutData(LONG_SIZE,Displacement);
            }
            else {
               PutText(OPRND,"+");
               PutData(Size,Displacement);
            }
         }
      }
   }
   PutText(OPRND,"]");
   
   if (sib->SIB.Index == 4) {
      if (sib->SIB.Scale) return(!GOOD);
   }
   else {
      PutText(OPRND,"[");
      PutText(OPRND,OprDwordReg[sib->SIB.Index]);
      if (sib->SIB.Scale)
         PutText(OPRND,(sib->SIB.Scale==SCALE_2X ? "*2" :
                 (sib->SIB.Scale==SCALE_4X ? "*4" : "*8")));
      PutText(OPRND,"]");
   }
   
   return(GOOD);
}

/***************************************************************************
**  ProcessRM16
**  Purpose: process 16-bit addressed memory operands
**
**  Modrm(in):
**  Info(in):
***************************************************************************/
RETCODE ProcessRM16(MODE_R_M *Modrm, DASM_INFO *Info)
{
   U8 Displacement[MAX_FETCH_SIZE],
         Size;

   PutText(OPRND,"[");
   if (!Modrm->ModRM.Mode && Modrm->ModRM.RegMem==DISPL16) {
      FetchBytes(WORD_SIZE,Info,Displacement);
      PutData(WORD_SIZE,Displacement);
   }
   else {
      PutText(OPRND,OprAddr16Reg[Modrm->ModRM.RegMem]);
      if (Modrm->ModRM.Mode) {
         Size = ((Modrm->ModRM.Mode==DISPL8) ? BYTE_SIZE : WORD_SIZE);
         FetchBytes(Size,Info,Displacement);
         if (Size == BYTE_SIZE) {
            if (*(U8*)Displacement >= 0x80) {
               PutText(OPRND,"-");
               Displacement[0] = -Displacement[0];
               PutData(BYTE_SIZE,Displacement);
            }
            else {
               PutText(OPRND,"+");
               PutData(Size,Displacement);
            }
         }
         else {
            if (*(U16*)Displacement >= 0x8000) {
               PutText(OPRND,"-");
               *((U16*)Displacement) = - *((U16*)Displacement);
               PutData(WORD_SIZE,Displacement);
            }
            else {
               PutText(OPRND,"+");
               PutData(Size,Displacement);
            }
         }
      }
   }
   PutText(OPRND,"]");
   return(GOOD);
} /* end ProcessRM16 */

/***************************************************************************
**  ProcessRM32
**  Purpose: process 32-bit addressed memory operands
**
**  Modrm(in):
**  Info(in):
***************************************************************************/
RETCODE ProcessRM32(MODE_R_M *Modrm, DASM_INFO *Info)
{
   U8 Displacement[MAX_FETCH_SIZE],
         Size;

   PutText(OPRND,"[");
   if (!Modrm->ModRM.Mode && Modrm->ModRM.RegMem==DISPL32) {
      FetchBytes(LONG_SIZE,Info,Displacement);
      PutData(LONG_SIZE,Displacement);
   }
   else {
      PutText(OPRND,OprDwordReg[Modrm->ModRM.RegMem]);
      if (Modrm->ModRM.Mode) {
         Size = ((Modrm->ModRM.Mode==DISPL8) ? BYTE_SIZE : LONG_SIZE);
         FetchBytes(Size,Info,Displacement);
         if (Size == BYTE_SIZE) {
            if (*(U8*)Displacement >= 0x80) {
               PutText(OPRND,"-");
               Displacement[0] = -Displacement[0];
               PutData(BYTE_SIZE,Displacement);
            }
            else {
               PutText(OPRND,"+");
               PutData(Size,Displacement);
            }
         }
         else {
            if (*(U32*)Displacement >= 0x80000000l) {
               PutText(OPRND,"-");
               *((U32*)Displacement) = - *((U32*)Displacement);
               PutData(LONG_SIZE,Displacement);
            }
            else {
               PutText(OPRND,"+");
               PutData(Size,Displacement);
            }
         }
      }
   } 
   PutText(OPRND,"]");
   return(GOOD);
} /* end ProcessRM32 */

/***************************************************************************
**  GetSymbol
**  purpose: Get a symbol from the symbol table for the specified address.
**  Return NULL if none found.
**
**  Address (in):
**  Sym (in):
****************************************************************************/
RETCODE GetSymbol(U16 segment, U32 offset, DESCRIPTOR startAddr,
                  LPSTR symName)   {
   MEM_ADDR_CLASS memoryClass;
   SYM_TYPE_TYPE symbolType;
   SYM_DESCRIPTOR outputSymbol,funcDescriptor,moduleDescriptor;
   U32 symOffset;
   DESCRIPTOR symNameDesc;
   DESCRIPTOR symAddr=NULL;
   ADDR_TYPE addrType;
   RETCODE err;

   symName[0] = '\0';
   if ((err = AdrGetAddrType(startAddr,&addrType)) != GOOD) 
      return err;
   if (addrType == ADDR_PHYSICAL)
      return (!GOOD);
   if ((err = AdrDuplicateAddress(startAddr,&symAddr)) != GOOD)
       return(err);
   if (addrType == ADDR_VIRTUAL) {
      if (segment != 0) {
         if ((err = AdrSetAddrSegmentSelector(symAddr,ADDR_USE_VALUE,
               &segment)) != GOOD) {
            AdrCremateAddress(&symAddr);
            return(err);
         }
      }
   }
   if ((err = AdrSetAddrOffset(symAddr,offset)) != GOOD) {
      AdrCremateAddress(&symAddr);
      return(err);
   }
   if ((SymMapAddr2Symbol(symAddr, &memoryClass, &symbolType,
       &symOffset,&outputSymbol,&funcDescriptor,&moduleDescriptor)) == GOOD){
      if( outputSymbol != NULL_SYMBOL ) {
         err = !GOOD;
         switch (symbolType) {
            case SYM_LABEL:
            case SYM_PUBLIC_LABEL:
               if ((SymGetSymbolName(outputSymbol, &symNameDesc)) == GOOD) {
                  stpcpy(symName, (LPSTR)symNameDesc);
                  TFree((LPSTR)symNameDesc);
                  err = GOOD;
               }
               break;
            case SYM_MODULE:
            case SYM_FUNCTION:
            case SYM_BLOCK: { /* case block */
               LINENUM_TYPE  linenum;
               COLUMN_TYPE   column;
               LINENUM_DESCRIPTOR index;
               DESCRIPTOR lineRangeDesc=NULL;
               LPSTR tempPtr;
               RETCODE err2;
                  if (moduleDescriptor != NULL_SYMBOL) {
                     if (SymGetSymbolName(moduleDescriptor, 
                                          &symNameDesc) == GOOD) {
                        stpcpy(symName, (LPSTR)symNameDesc);
                        TFree((LPSTR)symNameDesc);
                        err = GOOD;
                     }
                     /*  Now try for a linenumber. 
                     */
                     if ((err2 = AdrDuplicateAddress(symAddr,&lineRangeDesc))                               != GOOD) {
                        if (symAddr != NULL)
                           AdrCremateAddress(&symAddr);
                        return err2;
                     }
		     if (SymMapAddr2Linenum(symAddr,moduleDescriptor,funcDescriptor,
                            &linenum,&column,lineRangeDesc,&index) == GOOD) {
                        strcat(symName, "#");
                        tempPtr = symName + strlen(symName);
                        sprintf(tempPtr, "%d", linenum);
                        AdrCremateAddress(&lineRangeDesc);
                        err = GOOD;
                     }
                  }
                  /*   if the function exists then append it to
                  **   the module#linenum, since function context is
                  **   better.
                  */
                  if (funcDescriptor != NULL_SYMBOL) {
                     if (SymGetSymbolName(funcDescriptor, 
                                          &symNameDesc) == GOOD) {
                        strcat(symName, " (");
                        strcat(symName, (LPSTR)symNameDesc);
                        strcat(symName, ")");
                        TFree((LPSTR)symNameDesc);
                        err = GOOD;
                     }
                  }
                  break;
               } /* end of case block */
            default:
               break;
         }  /* end switch */
      }  /* outputSymbol != NULL_SYMBOL */
      else
         err = !GOOD;
   }
   else 
      err = !GOOD;
   if (symAddr != NULL)
      AdrCremateAddress(&symAddr);
   return err;
}



/********************************* E O F **********************************/

