/** @file

Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent


**/

#include "Edb.h"

//
// Debugger Disasm definition
//
#define EDB_DISASM_DEFINE(func) \
UINTN \
func ( \
  IN     EFI_PHYSICAL_ADDRESS      InstructionAddress, \
  IN     EFI_SYSTEM_CONTEXT        SystemContext, \
  OUT    CHAR16                    **DisasmString \
  )

EDB_DISASM_DEFINE (EdbDisasmBREAK);
EDB_DISASM_DEFINE (EdbDisasmJMP);
EDB_DISASM_DEFINE (EdbDisasmJMP8);
EDB_DISASM_DEFINE (EdbDisasmCALL);
EDB_DISASM_DEFINE (EdbDisasmRET);
EDB_DISASM_DEFINE (EdbDisasmCMP);
EDB_DISASM_DEFINE (EdbDisasmUnsignedDataManip);
EDB_DISASM_DEFINE (EdbDisasmSignedDataManip);
EDB_DISASM_DEFINE (EdbDisasmMOVxx);
EDB_DISASM_DEFINE (EdbDisasmMOVsnw);
EDB_DISASM_DEFINE (EdbDisasmMOVsnd);
EDB_DISASM_DEFINE (EdbDisasmLOADSP);
EDB_DISASM_DEFINE (EdbDisasmSTORESP);
EDB_DISASM_DEFINE (EdbDisasmPUSH);
EDB_DISASM_DEFINE (EdbDisasmPOP);
EDB_DISASM_DEFINE (EdbDisasmCMPI);
EDB_DISASM_DEFINE (EdbDisasmPUSHn);
EDB_DISASM_DEFINE (EdbDisasmPOPn);
EDB_DISASM_DEFINE (EdbDisasmMOVI);
EDB_DISASM_DEFINE (EdbDisasmMOVIn);
EDB_DISASM_DEFINE (EdbDisasmMOVREL);

//
// Debugger Disasm Table
//
EDB_DISASM_INSTRUCTION  mEdbDisasmInstructionTable[] = {
  EdbDisasmBREAK,             // opcode 0x00 BREAK
  EdbDisasmJMP,               // opcode 0x01 JMP
  EdbDisasmJMP8,              // opcode 0x02 JMP8
  EdbDisasmCALL,              // opcode 0x03 CALL
  EdbDisasmRET,               // opcode 0x04 RET
  EdbDisasmCMP,               // opcode 0x05 CMPEQ
  EdbDisasmCMP,               // opcode 0x06 CMPLTE
  EdbDisasmCMP,               // opcode 0x07 CMPGTE
  EdbDisasmCMP,               // opcode 0x08 CMPULTE
  EdbDisasmCMP,               // opcode 0x09 CMPUGTE
  EdbDisasmUnsignedDataManip, // opcode 0x0A NOT
  EdbDisasmSignedDataManip,   // opcode 0x0B NEG
  EdbDisasmSignedDataManip,   // opcode 0x0C ADD
  EdbDisasmSignedDataManip,   // opcode 0x0D SUB
  EdbDisasmSignedDataManip,   // opcode 0x0E MUL
  EdbDisasmUnsignedDataManip, // opcode 0x0F MULU
  EdbDisasmSignedDataManip,   // opcode 0x10 DIV
  EdbDisasmUnsignedDataManip, // opcode 0x11 DIVU
  EdbDisasmSignedDataManip,   // opcode 0x12 MOD
  EdbDisasmUnsignedDataManip, // opcode 0x13 MODU
  EdbDisasmUnsignedDataManip, // opcode 0x14 AND
  EdbDisasmUnsignedDataManip, // opcode 0x15 OR
  EdbDisasmUnsignedDataManip, // opcode 0x16 XOR
  EdbDisasmUnsignedDataManip, // opcode 0x17 SHL
  EdbDisasmUnsignedDataManip, // opcode 0x18 SHR
  EdbDisasmSignedDataManip,   // opcode 0x19 ASHR
  EdbDisasmUnsignedDataManip, // opcode 0x1A EXTNDB
  EdbDisasmUnsignedDataManip, // opcode 0x1B EXTNDW
  EdbDisasmUnsignedDataManip, // opcode 0x1C EXTNDD
  EdbDisasmMOVxx,             // opcode 0x1D MOVBW
  EdbDisasmMOVxx,             // opcode 0x1E MOVWW
  EdbDisasmMOVxx,             // opcode 0x1F MOVDW
  EdbDisasmMOVxx,             // opcode 0x20 MOVQW
  EdbDisasmMOVxx,             // opcode 0x21 MOVBD
  EdbDisasmMOVxx,             // opcode 0x22 MOVWD
  EdbDisasmMOVxx,             // opcode 0x23 MOVDD
  EdbDisasmMOVxx,             // opcode 0x24 MOVQD
  EdbDisasmMOVsnw,            // opcode 0x25 MOVSNW
  EdbDisasmMOVsnd,            // opcode 0x26 MOVSND
  NULL,                       // opcode 0x27
  EdbDisasmMOVxx,             // opcode 0x28 MOVQQ
  EdbDisasmLOADSP,            // opcode 0x29 LOADSP
  EdbDisasmSTORESP,           // opcode 0x2A STORESP
  EdbDisasmPUSH,              // opcode 0x2B PUSH
  EdbDisasmPOP,               // opcode 0x2C POP
  EdbDisasmCMPI,              // opcode 0x2D CMPIEQ
  EdbDisasmCMPI,              // opcode 0x2E CMPILTE
  EdbDisasmCMPI,              // opcode 0x2F CMPIGTE
  EdbDisasmCMPI,              // opcode 0x30 CMPIULTE
  EdbDisasmCMPI,              // opcode 0x31 CMPIUGTE
  EdbDisasmMOVxx,             // opcode 0x32 MOVNW
  EdbDisasmMOVxx,             // opcode 0x33 MOVND
  NULL,                       // opcode 0x34
  EdbDisasmPUSHn,             // opcode 0x35 PUSHN
  EdbDisasmPOPn,              // opcode 0x36 POPN
  EdbDisasmMOVI,              // opcode 0x37 MOVI
  EdbDisasmMOVIn,             // opcode 0x38 MOVIN
  EdbDisasmMOVREL,            // opcode 0x39 MOVREL
};

/**

  Disasm instruction - BREAK.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmBREAK (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_BREAK);

  if (*(UINT8 *)(UINTN)(InstructionAddress + 1) > 6) {
    return 0;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"BREAK");
    EdbPrintDatan (*(UINT8 *)(UINTN)(InstructionAddress + 1));

    EdbPostInstructionString ();
  }

  return 2;
}

extern CONST UINT8  mJMPLen[];

/**

  Disasm instruction - JMP.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmJMP (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Operands;
  UINTN   Size;
  UINT32  Data32;
  UINT64  Data64;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_JMP);

  Modifiers = GET_MODIFIERS (InstructionAddress);
  Operands  = GET_OPERANDS (InstructionAddress);
  Size      = (UINTN)mJMPLen[(Modifiers >> 6) & 0x03];

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"JMP");
    //    if (Modifiers & OPCODE_M_IMMDATA64) {
    //      EdbPrintInstructionName (L"64");
    //    } else {
    //      EdbPrintInstructionName (L"32");
    //    }
    if ((Modifiers & CONDITION_M_CONDITIONAL) != 0) {
      if ((Modifiers & JMP_M_CS) != 0) {
        EdbPrintInstructionName (L"cs");
      } else {
        EdbPrintInstructionName (L"cc");
      }
    }

    InstructionAddress += 2;
    if ((Modifiers & OPCODE_M_IMMDATA64) != 0) {
      CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT64));
      if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
        EdbPrintData64 (Data64);
      } else {
        return 0;
      }
    } else {
      CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT32));
      EdbPrintRegister1 (Operands);

      if ((Operands & OPERAND_M_INDIRECT1) == 0) {
        if ((Modifiers & OPCODE_M_IMMDATA) == 0) {
          Data32 = 0;
        }

        EdbPrintImmDatan (Data32);
      } else {
        EdbPrintRawIndexData32 (Data32);
      }
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - JMP8.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmJMP8 (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8  Modifiers;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_JMP8);
  Modifiers = GET_MODIFIERS (InstructionAddress);

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"JMP8");
    if ((Modifiers & CONDITION_M_CONDITIONAL) != 0) {
      if ((Modifiers & JMP_M_CS) != 0) {
        EdbPrintInstructionName (L"cs");
      } else {
        EdbPrintInstructionName (L"cc");
      }
    }

    EdbPrintData8 (*(UINT8 *)(UINTN)(InstructionAddress + 1));

    EdbPostInstructionString ();
  }

  return 2;
}

/**

  Disasm instruction - CALL.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmCALL (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8                 Modifiers;
  UINT8                 Operands;
  UINTN                 Size;
  UINT32                Data32;
  UINT64                Data64;
  UINT64                Ip;
  UINTN                 Result;
  EFI_PHYSICAL_ADDRESS  SavedInstructionAddress;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_CALL);
  SavedInstructionAddress = InstructionAddress;

  Modifiers = GET_MODIFIERS (InstructionAddress);
  Operands  = GET_OPERANDS (InstructionAddress);
  Size      = (UINTN)mJMPLen[(Modifiers >> 6) & 0x03];

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"CALL");
    //    if (Modifiers & OPCODE_M_IMMDATA64) {
    //      EdbPrintInstructionName (L"64");
    //    } else {
    //      EdbPrintInstructionName (L"32");
    //    }
    if ((Operands & OPERAND_M_NATIVE_CALL) != 0) {
      EdbPrintInstructionName (L"EX");
    }

    //    if ((Operands & OPERAND_M_RELATIVE_ADDR) == 0) {
    //      EdbPrintInstructionName (L"a");
    //    }

    InstructionAddress += 2;
    if ((Modifiers & OPCODE_M_IMMDATA64) != 0) {
      CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT64));
      Ip = Data64;
      if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
        Result = EdbFindAndPrintSymbol ((UINTN)Ip);
        if (Result == 0) {
          EdbPrintData64 (Data64);
        }
      } else {
        return 0;
      }
    } else {
      if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
        CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT32));
      } else {
        Data32 = 0;
      }

      if ((Operands & OPERAND_M_OP1) == 0) {
        Ip = (UINT64)Data32;
      } else {
        Ip = GetRegisterValue (SystemContext, (Operands & OPERAND_M_OP1));
      }

      if ((Operands & OPERAND_M_INDIRECT1) == 0) {
        if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {
          Result = EdbFindAndPrintSymbol ((UINTN)(SavedInstructionAddress + Ip + Size));
        } else {
          Result = EdbFindAndPrintSymbol ((UINTN)Ip);
        }

        if (Result == 0) {
          EdbPrintRegister1 (Operands);
          if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
            EdbPrintImmData32 (Data32);
          }
        }
      } else {
        EdbPrintRegister1 (Operands);
        if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
          EdbPrintRawIndexData32 (Data32);
        }
      }
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - RET.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmRET (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_RET);

  if (*(UINT8 *)(UINTN)(InstructionAddress + 1) != 0) {
    return 0;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"RET");

    EdbPostInstructionString ();
  }

  return 2;
}

/**

  Disasm instruction - CMP.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmCMP (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Opcode;
  UINT8   Modifiers;
  UINT8   Operands;
  UINT16  Data16;
  UINTN   Size;

  ASSERT (
    (GET_OPCODE (InstructionAddress) == OPCODE_CMPEQ)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_CMPLTE)  ||
    (GET_OPCODE (InstructionAddress) == OPCODE_CMPGTE)  ||
    (GET_OPCODE (InstructionAddress) == OPCODE_CMPULTE) ||
    (GET_OPCODE (InstructionAddress) == OPCODE_CMPUGTE)
    );

  Opcode    = GET_OPCODE (InstructionAddress);
  Modifiers = GET_MODIFIERS (InstructionAddress);
  Operands  = GET_OPERANDS (InstructionAddress);
  if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
    Size = 4;
  } else {
    Size = 2;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"CMP");
    //    if (Modifiers & OPCODE_M_64BIT) {
    //      EdbPrintInstructionName (L"64");
    //    } else {
    //      EdbPrintInstructionName (L"32");
    //    }
    switch (Opcode) {
      case OPCODE_CMPEQ:
        EdbPrintInstructionName (L"eq");
        break;
      case OPCODE_CMPLTE:
        EdbPrintInstructionName (L"lte");
        break;
      case OPCODE_CMPGTE:
        EdbPrintInstructionName (L"gte");
        break;
      case OPCODE_CMPULTE:
        EdbPrintInstructionName (L"ulte");
        break;
      case OPCODE_CMPUGTE:
        EdbPrintInstructionName (L"ugte");
        break;
    }

    EdbPrintRegister1 (Operands);
    InstructionAddress += 2;

    EdbPrintComma ();
    EdbPrintRegister2 (Operands);

    if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      if ((Operands & OPERAND_M_INDIRECT2) != 0) {
        EdbPrintRawIndexData16 (Data16);
      } else {
        EdbPrintImmDatan (Data16);
      }
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - Unsigned Data Manipulate.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmUnsignedDataManip (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Opcode;
  UINT8   Operands;
  UINTN   Size;
  UINT16  Data16;

  ASSERT (
    (GET_OPCODE (InstructionAddress) == OPCODE_NOT)    ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MULU)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_DIVU)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MODU)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_AND)    ||
    (GET_OPCODE (InstructionAddress) == OPCODE_OR)     ||
    (GET_OPCODE (InstructionAddress) == OPCODE_XOR)    ||
    (GET_OPCODE (InstructionAddress) == OPCODE_SHL)    ||
    (GET_OPCODE (InstructionAddress) == OPCODE_SHR)    ||
    (GET_OPCODE (InstructionAddress) == OPCODE_EXTNDB) ||
    (GET_OPCODE (InstructionAddress) == OPCODE_EXTNDW) ||
    (GET_OPCODE (InstructionAddress) == OPCODE_EXTNDD)
    );

  Opcode    = GET_OPCODE (InstructionAddress);
  Operands  = GET_OPERANDS (InstructionAddress);
  Modifiers = GET_MODIFIERS (InstructionAddress);
  if ((Modifiers & DATAMANIP_M_IMMDATA) != 0) {
    Size = 4;
  } else {
    Size = 2;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    switch (Opcode) {
      case OPCODE_NOT:
        EdbPrintInstructionName (L"NOT");
        break;
      case OPCODE_MULU:
        EdbPrintInstructionName (L"MULU");
        break;
      case OPCODE_DIVU:
        EdbPrintInstructionName (L"DIVU");
        break;
      case OPCODE_MODU:
        EdbPrintInstructionName (L"MODU");
        break;
      case OPCODE_AND:
        EdbPrintInstructionName (L"AND");
        break;
      case OPCODE_OR:
        EdbPrintInstructionName (L"OR");
        break;
      case OPCODE_XOR:
        EdbPrintInstructionName (L"XOR");
        break;
      case OPCODE_SHL:
        EdbPrintInstructionName (L"SHL");
        break;
      case OPCODE_SHR:
        EdbPrintInstructionName (L"SHR");
        break;
      case OPCODE_EXTNDB:
        EdbPrintInstructionName (L"EXTNDB");
        break;
      case OPCODE_EXTNDW:
        EdbPrintInstructionName (L"EXTNDW");
        break;
      case OPCODE_EXTNDD:
        EdbPrintInstructionName (L"EXTNDD");
        break;
    }

    //    if (Modifiers & DATAMANIP_M_64) {
    //      EdbPrintInstructionName (L"64");
    //    } else {
    //      EdbPrintInstructionName (L"32");
    //    }

    EdbPrintRegister1 (Operands);
    EdbPrintComma ();
    EdbPrintRegister2 (Operands);

    InstructionAddress += 2;
    if ((Modifiers & DATAMANIP_M_IMMDATA) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      if ((Operands & OPERAND_M_INDIRECT2) != 0) {
        EdbPrintRawIndexData16 (Data16);
      } else {
        EdbPrintImmDatan (Data16);
      }
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - Signed Data Manipulate,

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmSignedDataManip (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Opcode;
  UINT8   Operands;
  UINTN   Size;
  UINT16  Data16;

  ASSERT (
    (GET_OPCODE (InstructionAddress) == OPCODE_NEG)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_ADD)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_SUB)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MUL)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_DIV)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MOD)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_ASHR)
    );

  Opcode    = GET_OPCODE (InstructionAddress);
  Operands  = GET_OPERANDS (InstructionAddress);
  Modifiers = GET_MODIFIERS (InstructionAddress);
  if ((Modifiers & DATAMANIP_M_IMMDATA) != 0) {
    Size = 4;
  } else {
    Size = 2;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    switch (Opcode) {
      case OPCODE_NEG:
        EdbPrintInstructionName (L"NEG");
        break;
      case OPCODE_ADD:
        EdbPrintInstructionName (L"ADD");
        break;
      case OPCODE_SUB:
        EdbPrintInstructionName (L"SUB");
        break;
      case OPCODE_MUL:
        EdbPrintInstructionName (L"MUL");
        break;
      case OPCODE_DIV:
        EdbPrintInstructionName (L"DIV");
        break;
      case OPCODE_MOD:
        EdbPrintInstructionName (L"MOD");
        break;
      case OPCODE_ASHR:
        EdbPrintInstructionName (L"ASHR");
        break;
    }

    //    if (Modifiers & DATAMANIP_M_64) {
    //      EdbPrintInstructionName (L"64");
    //    } else {
    //      EdbPrintInstructionName (L"32");
    //    }

    EdbPrintRegister1 (Operands);
    EdbPrintComma ();
    EdbPrintRegister2 (Operands);

    InstructionAddress += 2;
    if ((Modifiers & DATAMANIP_M_IMMDATA) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      if ((Operands & OPERAND_M_INDIRECT2) != 0) {
        EdbPrintRawIndexData16 (Data16);
      } else {
        EdbPrintImmDatan (Data16);
      }
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - MOVxx.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmMOVxx (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Opcode;
  UINT8   Operands;
  UINTN   Size;
  UINT16  Data16;
  UINT32  Data32;
  UINT64  Data64;

  ASSERT (
    (GET_OPCODE (InstructionAddress) == OPCODE_MOVBW)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MOVWW)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MOVDW)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MOVQW)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MOVBD)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MOVWD)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MOVDD)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MOVQD)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MOVQQ)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MOVNW)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_MOVND)
    );

  Opcode    = GET_OPCODE (InstructionAddress);
  Modifiers = GET_MODIFIERS (InstructionAddress);
  Operands  = GET_OPERANDS (InstructionAddress);
  Size      = 2;
  if ((Modifiers & (OPCODE_M_IMMED_OP1 | OPCODE_M_IMMED_OP2)) != 0) {
    if ((Opcode <= OPCODE_MOVQW) || (Opcode == OPCODE_MOVNW)) {
      if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
        Size += 2;
      }

      if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
        Size += 2;
      }
    } else if (((Opcode <= OPCODE_MOVQD) || (Opcode == OPCODE_MOVND)) != 0) {
      if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
        Size += 4;
      }

      if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
        Size += 4;
      }
    } else if (Opcode == OPCODE_MOVQQ) {
      if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
        Size += 8;
      }

      if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
        Size += 8;
      }
    }
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"MOV");
    switch (Opcode) {
      case OPCODE_MOVBW:
        EdbPrintInstructionName (L"bw");
        break;
      case OPCODE_MOVWW:
        EdbPrintInstructionName (L"ww");
        break;
      case OPCODE_MOVDW:
        EdbPrintInstructionName (L"dw");
        break;
      case OPCODE_MOVQW:
        EdbPrintInstructionName (L"qw");
        break;
      case OPCODE_MOVBD:
        EdbPrintInstructionName (L"bd");
        break;
      case OPCODE_MOVWD:
        EdbPrintInstructionName (L"wd");
        break;
      case OPCODE_MOVDD:
        EdbPrintInstructionName (L"dd");
        break;
      case OPCODE_MOVQD:
        EdbPrintInstructionName (L"qd");
        break;
      case OPCODE_MOVQQ:
        EdbPrintInstructionName (L"qq");
        break;
      case OPCODE_MOVNW:
        EdbPrintInstructionName (L"nw");
        break;
      case OPCODE_MOVND:
        EdbPrintInstructionName (L"nd");
        break;
    }

    EdbPrintRegister1 (Operands);

    InstructionAddress += 2;
    if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
      if ((Opcode <= OPCODE_MOVQW) || (Opcode == OPCODE_MOVNW)) {
        CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
        InstructionAddress += 2;
        EdbPrintRawIndexData16 (Data16);
      } else if ((Opcode <= OPCODE_MOVQD) || (Opcode == OPCODE_MOVND)) {
        CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT32));
        InstructionAddress += 4;
        EdbPrintRawIndexData32 (Data32);
      } else if (Opcode == OPCODE_MOVQQ) {
        CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT64));
        InstructionAddress += 8;
        EdbPrintRawIndexData64 (Data64);
      }
    }

    EdbPrintComma ();
    EdbPrintRegister2 (Operands);

    if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
      if ((Opcode <= OPCODE_MOVQW) || (Opcode == OPCODE_MOVNW)) {
        CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
        EdbPrintRawIndexData16 (Data16);
      } else if ((Opcode <= OPCODE_MOVQD) || (Opcode == OPCODE_MOVND)) {
        CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT32));
        EdbPrintRawIndexData32 (Data32);
      } else if (Opcode == OPCODE_MOVQQ) {
        CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT64));
        EdbPrintRawIndexData64 (Data64);
      }
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - MOVsnw.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmMOVsnw (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Operands;
  UINTN   Size;
  UINT16  Data16;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_MOVSNW);

  Modifiers = GET_MODIFIERS (InstructionAddress);
  Operands  = GET_OPERANDS (InstructionAddress);
  Size      = 2;
  if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
    Size += 2;
  }

  if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
    Size += 2;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"MOVsnw");

    EdbPrintRegister1 (Operands);

    InstructionAddress += 2;
    if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      InstructionAddress += 2;
      EdbPrintRawIndexData16 (Data16);
    }

    EdbPrintComma ();
    EdbPrintRegister2 (Operands);

    if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      if ((Operands & OPERAND_M_INDIRECT2) != 0) {
        EdbPrintRawIndexData16 (Data16);
      } else {
        EdbPrintImmDatan (Data16);
      }
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - MOVsnd.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmMOVsnd (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Operands;
  UINTN   Size;
  UINT32  Data32;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_MOVSND);

  Modifiers = GET_MODIFIERS (InstructionAddress);
  Operands  = GET_OPERANDS (InstructionAddress);
  Size      = 2;
  if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
    Size += 4;
  }

  if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
    Size += 4;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"MOVsnd");

    EdbPrintRegister1 (Operands);

    InstructionAddress += 2;
    if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
      CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT32));
      InstructionAddress += 4;
      EdbPrintRawIndexData32 (Data32);
    }

    EdbPrintComma ();
    EdbPrintRegister2 (Operands);

    if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
      CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT32));
      if ((Operands & OPERAND_M_INDIRECT2) != 0) {
        EdbPrintRawIndexData32 (Data32);
      } else {
        EdbPrintImmDatan (Data32);
      }
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - LOADSP.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmLOADSP (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8  Operands;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_LOADSP);

  Operands = GET_OPERANDS (InstructionAddress);

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"LOADSP");

    EdbPrintDedicatedRegister1 (Operands);

    EdbPrintRegister2 (Operands);

    EdbPostInstructionString ();
  }

  return 2;
}

/**

  Disasm instruction - STORESP.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmSTORESP (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8  Operands;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_STORESP);

  Operands = GET_OPERANDS (InstructionAddress);

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"STORESP");

    EdbPrintRegister1 (Operands);

    EdbPrintDedicatedRegister2 (Operands);

    EdbPostInstructionString ();
  }

  return 2;
}

/**

  Disasm instruction - PUSH.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmPUSH (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Operands;
  UINTN   Size;
  UINT16  Data16;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_PUSH);

  Operands  = GET_OPERANDS (InstructionAddress);
  Modifiers = GET_MODIFIERS (InstructionAddress);
  if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
    Size = 4;
  } else {
    Size = 2;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"PUSH");
    //    if (Modifiers & PUSHPOP_M_64) {
    //      EdbPrintInstructionName (L"64");
    //    } else {
    //      EdbPrintInstructionName (L"32");
    //    }

    EdbPrintRegister1 (Operands);

    InstructionAddress += 2;
    if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      if ((Operands & OPERAND_M_INDIRECT1) != 0) {
        EdbPrintRawIndexData16 (Data16);
      } else {
        EdbPrintImmDatan (Data16);
      }
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - POP.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmPOP (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Operands;
  UINTN   Size;
  UINT16  Data16;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_POP);

  Operands  = GET_OPERANDS (InstructionAddress);
  Modifiers = GET_MODIFIERS (InstructionAddress);
  if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
    Size = 4;
  } else {
    Size = 2;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"POP");
    //    if (Modifiers & PUSHPOP_M_64) {
    //      EdbPrintInstructionName (L"64");
    //    } else {
    //      EdbPrintInstructionName (L"32");
    //    }

    EdbPrintRegister1 (Operands);

    InstructionAddress += 2;
    if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      if ((Operands & OPERAND_M_INDIRECT1) != 0) {
        EdbPrintRawIndexData16 (Data16);
      } else {
        EdbPrintImmDatan (Data16);
      }
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - CMPI.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmCMPI (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Opcode;
  UINT8   Operands;
  UINT16  Data16;
  UINT32  Data32;
  UINTN   Size;

  ASSERT (
    (GET_OPCODE (InstructionAddress) == OPCODE_CMPIEQ)   ||
    (GET_OPCODE (InstructionAddress) == OPCODE_CMPILTE)  ||
    (GET_OPCODE (InstructionAddress) == OPCODE_CMPIGTE)  ||
    (GET_OPCODE (InstructionAddress) == OPCODE_CMPIULTE) ||
    (GET_OPCODE (InstructionAddress) == OPCODE_CMPIUGTE)
    );

  Modifiers = GET_MODIFIERS (InstructionAddress);
  Opcode    = GET_OPCODE (InstructionAddress);
  Operands  = GET_OPERANDS (InstructionAddress);

  if ((Operands & 0xE0) != 0) {
    return 0;
  }

  Size = 2;
  if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
    Size += 2;
  }

  if ((Modifiers & OPCODE_M_CMPI32_DATA) != 0) {
    Size += 4;
  } else {
    Size += 2;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"CMPI");
    //    if (Modifiers & OPCODE_M_CMPI64) {
    //      EdbPrintInstructionName (L"64");
    //    } else {
    //      EdbPrintInstructionName (L"32");
    //    }
    if ((Modifiers & OPCODE_M_CMPI32_DATA) != 0) {
      EdbPrintInstructionName (L"d");
    } else {
      EdbPrintInstructionName (L"w");
    }

    switch (Opcode) {
      case OPCODE_CMPIEQ:
        EdbPrintInstructionName (L"eq");
        break;
      case OPCODE_CMPILTE:
        EdbPrintInstructionName (L"lte");
        break;
      case OPCODE_CMPIGTE:
        EdbPrintInstructionName (L"gte");
        break;
      case OPCODE_CMPIULTE:
        EdbPrintInstructionName (L"ulte");
        break;
      case OPCODE_CMPIUGTE:
        EdbPrintInstructionName (L"ugte");
        break;
    }

    EdbPrintRegister1 (Operands);

    InstructionAddress += 2;
    if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      InstructionAddress += 2;
      EdbPrintRawIndexData16 (Data16);
    }

    EdbPrintComma ();

    if ((Modifiers & OPCODE_M_CMPI32_DATA) != 0) {
      CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT32));
      EdbPrintDatan (Data32);
    } else {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      EdbPrintDatan (Data16);
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - PUSHn.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmPUSHn (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Operands;
  UINTN   Size;
  UINT16  Data16;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_PUSHN);

  Operands  = GET_OPERANDS (InstructionAddress);
  Modifiers = GET_MODIFIERS (InstructionAddress);
  if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
    Size = 4;
  } else {
    Size = 2;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"PUSHn");

    EdbPrintRegister1 (Operands);

    InstructionAddress += 2;
    if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      if ((Operands & OPERAND_M_INDIRECT1) != 0) {
        EdbPrintRawIndexData16 (Data16);
      } else {
        EdbPrintImmDatan (Data16);
      }
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - POPn.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmPOPn (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Operands;
  UINTN   Size;
  UINT16  Data16;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_POPN);

  Operands  = GET_OPERANDS (InstructionAddress);
  Modifiers = GET_MODIFIERS (InstructionAddress);
  if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
    Size = 4;
  } else {
    Size = 2;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"POPn");

    EdbPrintRegister1 (Operands);

    InstructionAddress += 2;
    if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      if ((Operands & OPERAND_M_INDIRECT1) != 0) {
        EdbPrintRawIndexData16 (Data16);
      } else {
        EdbPrintImmDatan (Data16);
      }
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - MOVI.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmMOVI (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Operands;
  UINTN   Size;
  UINT16  Data16;
  UINT32  Data32;
  UINT64  Data64;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_MOVI);

  Modifiers = GET_MODIFIERS (InstructionAddress);
  Operands  = GET_OPERANDS (InstructionAddress);

  if ((Operands & MOVI_M_IMMDATA) != 0) {
    Size = 4;
  } else {
    Size = 2;
  }

  if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
    Size += 2;
  } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
    Size += 4;
  } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
    Size += 8;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"MOVI");
    switch (Operands & MOVI_M_MOVEWIDTH) {
      case MOVI_MOVEWIDTH8:
        EdbPrintInstructionName (L"b");
        break;
      case MOVI_MOVEWIDTH16:
        EdbPrintInstructionName (L"w");
        break;
      case MOVI_MOVEWIDTH32:
        EdbPrintInstructionName (L"d");
        break;
      case MOVI_MOVEWIDTH64:
        EdbPrintInstructionName (L"q");
        break;
    }

    switch (Modifiers & MOVI_M_DATAWIDTH) {
      case MOVI_DATAWIDTH16:
        EdbPrintInstructionName (L"w");
        break;
      case MOVI_DATAWIDTH32:
        EdbPrintInstructionName (L"d");
        break;
      case MOVI_DATAWIDTH64:
        EdbPrintInstructionName (L"q");
        break;
    }

    EdbPrintRegister1 (Operands);

    InstructionAddress += 2;
    if ((Operands & MOVI_M_IMMDATA) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      InstructionAddress += 2;
      EdbPrintRawIndexData16 (Data16);
    }

    EdbPrintComma ();

    switch (Modifiers & MOVI_M_DATAWIDTH) {
      case MOVI_DATAWIDTH16:
        CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
        EdbPrintDatan (Data16);
        break;
      case MOVI_DATAWIDTH32:
        CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT32));
        EdbPrintDatan (Data32);
        break;
      case MOVI_DATAWIDTH64:
        CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT64));
        EdbPrintData64n (Data64);
        break;
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - MOVIn.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmMOVIn (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8   Modifiers;
  UINT8   Operands;
  UINTN   Size;
  UINT16  Data16;
  UINT32  Data32;
  UINT64  Data64;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_MOVIN);

  Modifiers = GET_MODIFIERS (InstructionAddress);
  Operands  = GET_OPERANDS (InstructionAddress);

  if ((Operands & MOVI_M_IMMDATA) != 0) {
    Size = 4;
  } else {
    Size = 2;
  }

  if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
    Size += 2;
  } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
    Size += 4;
  } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
    Size += 8;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"MOVIn");
    switch (Modifiers & MOVI_M_DATAWIDTH) {
      case MOVI_DATAWIDTH16:
        EdbPrintInstructionName (L"w");
        break;
      case MOVI_DATAWIDTH32:
        EdbPrintInstructionName (L"d");
        break;
      case MOVI_DATAWIDTH64:
        EdbPrintInstructionName (L"q");
        break;
    }

    EdbPrintRegister1 (Operands);

    InstructionAddress += 2;
    if ((Operands & MOVI_M_IMMDATA) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      InstructionAddress += 2;
      EdbPrintRawIndexData16 (Data16);
    }

    EdbPrintComma ();

    switch (Modifiers & MOVI_M_DATAWIDTH) {
      case MOVI_DATAWIDTH16:
        CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
        EdbPrintRawIndexData16 (Data16);
        break;
      case MOVI_DATAWIDTH32:
        CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT32));
        EdbPrintRawIndexData32 (Data32);
        break;
      case MOVI_DATAWIDTH64:
        CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT64));
        EdbPrintRawIndexData64 (Data64);
        break;
    }

    EdbPostInstructionString ();
  }

  return Size;
}

/**

  Disasm instruction - MOVREL.

  @param  InstructionAddress - The instruction address
  @param  SystemContext      - EBC system context.
  @param  DisasmString       - The instruction string

  @return Instruction length

**/
UINTN
EdbDisasmMOVREL (
  IN     EFI_PHYSICAL_ADDRESS  InstructionAddress,
  IN     EFI_SYSTEM_CONTEXT    SystemContext,
  OUT    CHAR16                **DisasmString
  )
{
  UINT8                 Modifiers;
  UINT8                 Operands;
  UINTN                 Size;
  UINT16                Data16;
  UINT32                Data32;
  UINT64                Data64;
  UINTN                 Result;
  EFI_PHYSICAL_ADDRESS  SavedInstructionAddress;

  ASSERT (GET_OPCODE (InstructionAddress) == OPCODE_MOVREL);
  SavedInstructionAddress = InstructionAddress;

  Modifiers = GET_MODIFIERS (InstructionAddress);
  Operands  = GET_OPERANDS (InstructionAddress);

  if ((Operands & MOVI_M_IMMDATA) != 0) {
    Size = 4;
  } else {
    Size = 2;
  }

  if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
    Size += 2;
  } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
    Size += 4;
  } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
    Size += 8;
  } else {
    return 0;
  }

  //
  // Construct Disasm String
  //
  if (DisasmString != NULL) {
    *DisasmString = EdbPreInstructionString ();

    EdbPrintInstructionName (L"MOVrel");
    switch (Modifiers & MOVI_M_DATAWIDTH) {
      case MOVI_DATAWIDTH16:
        EdbPrintInstructionName (L"w");
        break;
      case MOVI_DATAWIDTH32:
        EdbPrintInstructionName (L"d");
        break;
      case MOVI_DATAWIDTH64:
        EdbPrintInstructionName (L"q");
        break;
    }

    EdbPrintRegister1 (Operands);

    InstructionAddress += 2;
    if ((Operands & MOVI_M_IMMDATA) != 0) {
      CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
      InstructionAddress += 2;
      EdbPrintRawIndexData16 (Data16);
    }

    EdbPrintComma ();

    switch (Modifiers & MOVI_M_DATAWIDTH) {
      case MOVI_DATAWIDTH16:
        CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT16));
        Result = EdbFindAndPrintSymbol ((UINTN)(SavedInstructionAddress + Size + (INT16)Data16));
        if (Result == 0) {
          EdbPrintData16 (Data16);
        }

        break;
      case MOVI_DATAWIDTH32:
        CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT32));
        Result = EdbFindAndPrintSymbol ((UINTN)(SavedInstructionAddress + Size + (INT32)Data32));
        if (Result == 0) {
          EdbPrintData32 (Data32);
        }

        break;
      case MOVI_DATAWIDTH64:
        CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof (UINT64));
        if (sizeof (UINTN) == sizeof (UINT64)) {
          Result = EdbFindAndPrintSymbol ((UINTN)(SavedInstructionAddress + Size + (INT64)Data64));
        } else {
          Result = 0;
        }

        if (Result == 0) {
          EdbPrintData64 (Data64);
        }

        break;
    }

    EdbPostInstructionString ();
  }

  return Size;
}
