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