/** @file

Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution.  The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.


**/

#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;
}
