Top secrets sources NedoPC pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

/* deco87c800.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/*                                                                           */
/* DissectorTLCS-870                                                         */
/*                                                                           */
/*****************************************************************************/

#include "stdinc.h"
#include <ctype.h>

#include "dasmdef.h"
#include "cpulist.h"
#include "codechunks.h"
#include "invaddress.h"
#include "strutil.h"

#include "deco87c800.h"

static CPUVar CPU87C00;

static const char Reg8Names[] = "awcbedlh";
static const char *Reg16Names[] = { "wa", "bc", "de", "hl" };
static const char *RelNames[8] =
{
  "z", "nz", "cs", "cc", "le", "gt", "t", "f"
};
static const char *ALUInstr[8] =
{
  "addc", "add", "subb", "sub", "and" , "xor", "or", "cmp"
};

static unsigned nData;

static char *ZeroHexString(char *pBuffer, size_t BufferSize, LargeWord Num, int ByteLen)
{
  HexString(pBuffer + 1, BufferSize - 1, Num, ByteLen * 2);
  if (isdigit(pBuffer[1]))
    return pBuffer + 1;
  else
  {
    pBuffer[0] = '0';
    return pBuffer;
  }
}

static const char *MakeSymbolic(LargeWord Address, int AddrLen, const char *pSymbolPrefix, char *pBuffer, int BufferSize)
{
  const char *pResult;

  if ((pResult = LookupInvSymbol(Address)))
    return pResult;

  HexString(pBuffer, BufferSize, Address, AddrLen << 1);
  if (!pSymbolPrefix)
  {
    if (isdigit(*pBuffer))
      strmaxprep(pBuffer, "0", BufferSize);
    as_snprcatf(pBuffer, BufferSize, "%c", HexStartCharacter + ('h' - 'a'));
    return pBuffer;
  }

  strmaxprep(pBuffer, pSymbolPrefix, BufferSize);
  AddInvSymbol(pBuffer, Address);
  return pBuffer;
}

static Boolean RetrieveData(LargeWord Address, Byte *pBuffer, unsigned Count)
{
  LargeWord Trans;

  while (Count > 0)
  {
    Trans = 0x10000 - Address;
    if (Count < Trans)
      Trans = Count;
    if (!RetrieveCodeFromChunkList(&CodeChunks, Address, pBuffer, Trans))
    {
      char NumString[50];

      HexString(NumString, sizeof(NumString), Address, 0);
      fprintf(stderr, "cannot retrieve code @ 0x%s\n", NumString);
      return False;
    }
    pBuffer += Trans;
    Count -= Trans;
    Address = (Address + Trans) & 0xffff;
    nData += Trans;
  }
  return TRUE;
}

static void SimpleNextAddress(tDisassInfo *pInfo, LargeWord ThisAddress)
{
  pInfo->NextAddressCount = 1;
  pInfo->NextAddresses[0] = (ThisAddress + pInfo->CodeLen) % 0xffff;
}

static void PrintData(char *pDest, size_t DestSize, const Byte *pData, unsigned DataLen)
{
  char NumBuf[40];
  unsigned z;

  as_snprintf(pDest, DestSize, "db\t");
  for (z = 0; z < DataLen; z++)
  {
    if (z)
      as_snprcatf(pDest, DestSize, ",");
    as_snprcatf(pDest, DestSize, "%sh", ZeroHexString(NumBuf, sizeof(NumBuf), pData[z], 1));
  }
}

static void RegPrefix(LargeWord Address, tDisassInfo *pInfo, unsigned PrefixLen, unsigned SrcRegIndex)
{
  Byte Opcode, Data[5];
  char NumBuf[40], NumBuf2[40];

  if (!RetrieveData(Address + PrefixLen, &Opcode, 1))
    return;

  switch (Opcode)
  {
    case 0x01:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "swap\t%c",
                  Reg8Names[SrcRegIndex]);
      break;
    case 0x02:
      if (SrcRegIndex > 3)
        goto inv16;
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "mul\t%c,%c",
                  Reg8Names[SrcRegIndex * 2 + 1], Reg8Names[SrcRegIndex * 2]);
      break;
    case 0x03:
      if (SrcRegIndex > 3)
        goto inv16;
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "div\t%s,c",
                  Reg16Names[SrcRegIndex]);
      break;
    case 0x04:
      if (SrcRegIndex > 0)
        goto inv16;
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "retn");
      break;
    case 0x06:
      if (SrcRegIndex > 3)
        goto inv16;
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "pop\t%s",
                  Reg16Names[SrcRegIndex]);
      break;
    case 0x07:
      if (SrcRegIndex > 3)
        goto inv16;
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "push\t%s",
                  Reg16Names[SrcRegIndex]);
      break;
    case 0x0a:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "daa\t%c",
                  Reg8Names[SrcRegIndex]);
      break;
    case 0x0b:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "das\t%c",
                  Reg8Names[SrcRegIndex]);
      break;
    case 0x10: case 0x11: case 0x12: case 0x13:
      if (SrcRegIndex > 3)
        goto inv16;
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "xch\t%s,%s",
                  Reg16Names[Opcode & 3], Reg16Names[SrcRegIndex]);
      break;
    case 0x14: case 0x15: case 0x16: case 0x17:
      if (SrcRegIndex > 3)
        goto inv16;
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%s,%s",
                  Reg16Names[Opcode & 3], Reg16Names[SrcRegIndex]);
      break;
    case 0x1c:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "shlc\t%c",
                  Reg8Names[SrcRegIndex]);
      break;
    case 0x1d:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "shrc\t%c",
                  Reg8Names[SrcRegIndex]);
      break;
    case 0x1e:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "rolc\t%c",
                  Reg8Names[SrcRegIndex]);
      break;
    case 0x1f:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "rorc\t%c",
                  Reg8Names[SrcRegIndex]);
      break;
    case 0x30: case 0x31: case 0x32: case 0x33:
    case 0x34: case 0x35: case 0x36: case 0x37:
      if (SrcRegIndex > 3)
        goto inv16;
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "%s\twa,%s",
                  ALUInstr[Opcode & 7], Reg16Names[SrcRegIndex]);
      break;
    case 0x38: case 0x39: case 0x3a: case 0x3b:
    case 0x3c: case 0x3d: case 0x3e: case 0x3f:
      if (SrcRegIndex > 3)
        goto inv16;
      if (!RetrieveData(Address + PrefixLen + 1, Data, 2))
        return;
      pInfo->CodeLen = PrefixLen + 1 + 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "%s\t%s,%sh",
                  ALUInstr[Opcode & 7], Reg16Names[SrcRegIndex],
                  ZeroHexString(NumBuf, sizeof(NumBuf), (((Word)Data[1]) << 8) | Data[0], 2));
      break;
    case 0x40: case 0x41: case 0x42: case 0x43:
    case 0x44: case 0x45: case 0x46: case 0x47:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "set\t%c.%u",
                  Reg8Names[SrcRegIndex], Opcode & 7);
      break;
    case 0x48: case 0x49: case 0x4a: case 0x4b:
    case 0x4c: case 0x4d: case 0x4e: case 0x4f:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "clr\t%c.%u",
                  Reg8Names[SrcRegIndex], Opcode & 7);
      break;
    case 0x58: case 0x59: case 0x5a: case 0x5b:
    case 0x5c: case 0x5d: case 0x5e: case 0x5f:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%c,%c",
                  Reg8Names[Opcode & 7], Reg8Names[SrcRegIndex]);
      break;
    case 0x60: case 0x61: case 0x62: case 0x63:
    case 0x64: case 0x65: case 0x66: case 0x67:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "%s\ta,%c",
                  ALUInstr[Opcode & 7], Reg8Names[SrcRegIndex]);
      break;
    case 0x68: case 0x69: case 0x6a: case 0x6b:
    case 0x6c: case 0x6d: case 0x6e: case 0x6f:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "%s\t%c,a",
                  ALUInstr[Opcode & 7], Reg8Names[SrcRegIndex]);
      break;
    case 0x70: case 0x71: case 0x72: case 0x73:
    case 0x74: case 0x75: case 0x76: case 0x77:
      if (!RetrieveData(Address + PrefixLen + 1, Data, 1))
        return;
      pInfo->CodeLen = PrefixLen + 1 + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "%s\t%c,%s",
                  ALUInstr[Opcode & 7], Reg8Names[SrcRegIndex],
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x82: case 0x83:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "set\t(%s).%c",
                  Reg16Names[Opcode & 3], Reg8Names[SrcRegIndex]);
      break;
    case 0x8a: case 0x8b:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "clr\t(%s).%c",
                  Reg16Names[Opcode & 3], Reg8Names[SrcRegIndex]);
      break;
    case 0x92: case 0x93:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "cpl\t(%s).%c",
                  Reg16Names[Opcode & 3], Reg8Names[SrcRegIndex]);
      break;
    case 0x9a: case 0x9b:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t(%s).%c,cf",
                  Reg16Names[Opcode & 3], Reg8Names[SrcRegIndex]);
      break;
    case 0x9e: case 0x9f:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\tcf,(%s).%c",
                  Reg16Names[Opcode & 3], Reg8Names[SrcRegIndex]);
      break;
    case 0xa8: case 0xa9: case 0xaa: case 0xab:
    case 0xac: case 0xad: case 0xae: case 0xaf:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "xch\t%c,%c",
                  Reg8Names[Opcode & 7], Reg8Names[SrcRegIndex]);
      break;
    case 0xc0: case 0xc1: case 0xc2: case 0xc3:
    case 0xc4: case 0xc5: case 0xc6: case 0xc7:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "cpl\t%c.%u",
                  Reg8Names[SrcRegIndex], Opcode & 7);
      break;
    case 0xc8: case 0xc9: case 0xca: case 0xcb:
    case 0xcc: case 0xcd: case 0xce: case 0xcf:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%c.%u,cf",
                  Reg8Names[SrcRegIndex], Opcode & 7);
      break;
    case 0xd0: case 0xd1: case 0xd2: case 0xd3:
    case 0xd4: case 0xd5: case 0xd6: case 0xd7:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "xor\tcf,%c.%u",
                  Reg8Names[SrcRegIndex], Opcode & 7);
      break;
    case 0xd8: case 0xd9: case 0xda: case 0xdb:
    case 0xdc: case 0xdd: case 0xde: case 0xdf:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\tcf,%c.%u",
                  Reg8Names[SrcRegIndex], Opcode & 7);
      break;
    inv16:
    case 0xfa:
      if (SrcRegIndex > 3)
        goto inv16;
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\tsp,%s",
                  Reg16Names[Opcode & 3]);
      break;
    case 0xfb:
      if (SrcRegIndex > 3)
        goto inv16;
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%s,sp",
                  Reg16Names[Opcode & 3]);
      break;
    case 0xfc:
      if (SrcRegIndex > 3)
        goto inv16;
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "call\t%s",
                  Reg16Names[Opcode & 3]);
      pInfo->pRemark = "indirect jump, investigate here";
      break;
    case 0xfe:
      if (SrcRegIndex > 3)
        goto inv16;
      pInfo->CodeLen = PrefixLen + 1;
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "jp\t%s",
                  Reg16Names[Opcode & 3]);
      pInfo->pRemark = "indirect jump, investigate here";
      break;
    default:
      HexString(NumBuf, sizeof(NumBuf), Opcode, 2);
      HexString(NumBuf2, sizeof(NumBuf2), Address, 0);
      printf("unknown reg prefix opcode 0x%s @ %s\n", NumBuf, NumBuf2);
      pInfo->CodeLen = PrefixLen + 1;
      pInfo->NextAddressCount = 0;
      RetrieveData(Address, Data, pInfo->CodeLen);
      nData -= pInfo->CodeLen;
      PrintData(pInfo->SrcLine, sizeof(pInfo->SrcLine), Data, pInfo->CodeLen);
      break;
  }
}

static void MemPrefix(LargeWord Address, tDisassInfo *pInfo, unsigned PrefixLen, const char *pPrefixString)
{
  Byte Opcode, Data[5];
  char NumBuf[40], NumBuf2[40];

  if (!RetrieveData(Address + PrefixLen, &Opcode, 1))
    return;

  switch (Opcode)
  {
    case 0x08:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "rold\ta,%s",
                  pPrefixString);
      break;
    case 0x09:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "rord\ta,%s",
                  pPrefixString);
      break;
    case 0x10: case 0x11: case 0x12: case 0x13:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%s,%s",
                  pPrefixString, Reg16Names[Opcode & 3]);
      break;
    case 0x14: case 0x15: case 0x16: case 0x17:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%s,%s",
                  Reg16Names[Opcode & 3], pPrefixString);
      break;
    case 0x20:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "inc\t%s",
                  pPrefixString);
      break;
    case 0x26:
      if (!RetrieveData(Address + PrefixLen + 1, Data, 1))
        return;
      pInfo->CodeLen = PrefixLen + 1 + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t(%sh),%s",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1), pPrefixString);
      break;
    case 0x27:
      pInfo->CodeLen = PrefixLen + 1;
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t(hl),%s",
                  pPrefixString);
      break;
    case 0x28:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "dec\t%s",
                  pPrefixString);
      break;
    case 0x2c:
      if (!RetrieveData(Address + PrefixLen + 1, Data, 1))
        return;
      pInfo->CodeLen = PrefixLen + 1 + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%s,%sh",
                  pPrefixString, ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x2f:
      if (!RetrieveData(Address + PrefixLen + 1, Data, 1))
        return;
      pInfo->CodeLen = PrefixLen + 1 + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "mcmp\t%s,%sh",
                  pPrefixString, ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x40: case 0x41: case 0x42: case 0x43:
    case 0x44: case 0x45: case 0x46: case 0x47:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "set\t%s.%u",
                  pPrefixString, Opcode & 7);
      break;
    case 0x48: case 0x49: case 0x4a: case 0x4b:
    case 0x4c: case 0x4d: case 0x4e: case 0x4f:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "clr\t%s.%u",
                  pPrefixString, Opcode & 7);
      break;
    case 0x50: case 0x51: case 0x52: case 0x53:
    case 0x54: case 0x55: case 0x56: case 0x57:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%s,%c",
                  pPrefixString, Reg8Names[Opcode & 7]);
      break;
    case 0x58: case 0x59: case 0x5a: case 0x5b:
    case 0x5c: case 0x5d: case 0x5e: case 0x5f:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%c,%s",
                  Reg8Names[Opcode & 7], pPrefixString);
      break;
    case 0x60: case 0x61: case 0x62: case 0x63:
    case 0x64: case 0x65: case 0x66: case 0x67:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "%s\t%s,(hl)",
                  ALUInstr[Opcode & 7], pPrefixString);
      break;
    case 0x70: case 0x71: case 0x72: case 0x73:
    case 0x74: case 0x75: case 0x76: case 0x77:
      if (!RetrieveData(Address + PrefixLen + 1, Data, 1))
        return;
      pInfo->CodeLen = PrefixLen + 1 + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "%s\t%s,%sh",
                  ALUInstr[Opcode & 7], pPrefixString,
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x78: case 0x79: case 0x7a: case 0x7b:
    case 0x7c: case 0x7d: case 0x7e: case 0x7f:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "%s\ta,%s",
                  ALUInstr[Opcode & 7], pPrefixString);
      break;
    case 0xa8: case 0xa9: case 0xaa: case 0xab:
    case 0xac: case 0xad: case 0xae: case 0xaf:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "xch\t%c,%s",
                  Reg8Names[Opcode & 7], pPrefixString);
      break;
    case 0xc0: case 0xc1: case 0xc2: case 0xc3:
    case 0xc4: case 0xc5: case 0xc6: case 0xc7:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "cpl\t%s.%u",
                  pPrefixString, Opcode & 7);
      break;
    case 0xc8: case 0xc9: case 0xca: case 0xcb:
    case 0xcc: case 0xcd: case 0xce: case 0xcf:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%s.%u,cf",
                  pPrefixString, Opcode & 7);
      break;
    case 0xd0: case 0xd1: case 0xd2: case 0xd3:
    case 0xd4: case 0xd5: case 0xd6: case 0xd7:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "xor\tcf,%s.%u",
                  pPrefixString, Opcode & 7);
      break;
    case 0xd8: case 0xd9: case 0xda: case 0xdb:
    case 0xdc: case 0xdd: case 0xde: case 0xdf:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\tcf,%s.%u",
                  pPrefixString, Opcode & 7);
      break;
    case 0xfc:
      pInfo->CodeLen = PrefixLen + 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "call\t%s",
                  pPrefixString);
      pInfo->pRemark = "indirect subroutine call, investigate here";
      break;
    case 0xfe:
      pInfo->CodeLen = PrefixLen + 1;
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "jp\t%s",
                  pPrefixString);
      pInfo->pRemark = "indirect jump, investigate here";
      break;
    default:
      HexString(NumBuf, sizeof(NumBuf), Opcode, 2);
      HexString(NumBuf2, sizeof(NumBuf2), Address, 0);
      printf("unknown mem opcode 0x%s @ %s\n", NumBuf, NumBuf2);
      pInfo->CodeLen = PrefixLen + 1;
      pInfo->NextAddressCount = 0;
      RetrieveData(Address, Data, pInfo->CodeLen);
      nData -= pInfo->CodeLen;
      PrintData(pInfo->SrcLine, sizeof(pInfo->SrcLine), Data, pInfo->CodeLen);
      break;
  }
}

static void Disassemble_87C800(LargeWord Address, tDisassInfo *pInfo, Boolean AsData, int DataSize)
{
  Byte Opcode, Data[10];
  Word Arg;
  char NumBuf[40], NumBuf2[40];
  LargeInt Dist;
  unsigned Vector;
  Boolean ActAsData = AsData;

  pInfo->CodeLen = 0;
  pInfo->NextAddressCount = 0;
  pInfo->SrcLine[0] = '\0';
  pInfo->pRemark = NULL;

  if (!RetrieveData(Address, &Opcode, 1))
    return;
  nData = 1;

  if (!AsData)
  switch (Opcode)
  {
    case 0x00:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "nop");
      break;
    case 0x01:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "swap\ta");
      break;
    case 0x02:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "mul\tw,a");
      break;
    case 0x03:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "div\twa,c");
      break;
    case 0x04:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "reti");
      break;
    case 0x05:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ret");
      break;
    case 0x06:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "pop\tpsw");
      break;
    case 0x07:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "push\tpsw");
      break;
    case 0x0a:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "daa\ta");
      break;
    case 0x0b:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "das\ta");
      break;
    case 0x0c:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "clr\tcf");
      break;
    case 0x0d:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "set\tcf");
      break;
    case 0x0e:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "cpl\tcf");
      break;
    case 0x0f:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\trbs,%sh",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x10: case 0x11: case 0x12: case 0x13:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "inc\t%s",
                  Reg16Names[Opcode & 3]);
      break;
    case 0x14: case 0x15: case 0x16: case 0x17:
      if (!RetrieveData(Address + 1, Data, 2))
        return;
      pInfo->CodeLen = 3;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%s,%sh",
                  Reg16Names[Opcode & 3],
                  ZeroHexString(NumBuf, sizeof(NumBuf), (((Word)Data[1]) << 8) | Data[0], 2));
      break;
    case 0x18: case 0x19: case 0x1a: case 0x1b:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "dec\t%s",
                  Reg16Names[Opcode & 3]);
      break;
    case 0x1c:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "shlc\ta");
      break;
    case 0x1d:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "shrc\ta");
      break;
    case 0x1e:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "rolc\ta");
      break;
    case 0x1f:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "rorc\ta");
      break;
    case 0x20:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "inc\t(%sh)",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x21:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "inc\t(hl)");
      break;
    case 0x22:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\ta,(%sh)",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x23:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\ta,(hl)");
      break;
    case 0x24:
      if (!RetrieveData(Address + 1, Data, 3))
        return;
      pInfo->CodeLen = 4;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ldw\t(%sh),%sh",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1),
                  ZeroHexString(NumBuf2, sizeof(NumBuf2), (((Word)Data[2]) << 8) | Data[1], 2));
      break;
    case 0x25:
      if (!RetrieveData(Address + 1, Data, 2))
        return;
      pInfo->CodeLen = 3;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ldw\t(hl),%sh",
                  ZeroHexString(NumBuf, sizeof(NumBuf), (((Word)Data[1]) << 8) | Data[0], 2));
      break;
    case 0x26:
      if (!RetrieveData(Address + 1, Data, 2))
        return;
      pInfo->CodeLen = 3;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t(%sh),(%sh)",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[1], 1),
                  ZeroHexString(NumBuf2, sizeof(NumBuf2), Data[0], 1));
      break;
    case 0x28:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "dec\t(%sh)",
                  ZeroHexString(NumBuf2, sizeof(NumBuf2), Data[0], 1));
      break;
    case 0x29:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "dec\t(hl)");
      break;
    case 0x2a:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t(%sh),a",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x2b:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t(hl),a");
      break;
    case 0x2c:
      if (!RetrieveData(Address + 1, Data, 2))
        return;
      pInfo->CodeLen = 3;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t(%sh),%sh",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1),
                  ZeroHexString(NumBuf2, sizeof(NumBuf2), Data[1], 1));
      break;
    case 0x2d:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t(hl),%sh",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x2e:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "clr\t(%sh)",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x2f:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "clr\t(hl)");
      break;
    case 0x30: case 0x31: case 0x32: case 0x33:
    case 0x34: case 0x35: case 0x36: case 0x37:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%c,%sh",
                  Reg8Names[Opcode & 7], ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x40: case 0x41: case 0x42: case 0x43:
    case 0x44: case 0x45: case 0x46: case 0x47:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "set\t(%sh).%u",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1), Opcode & 7);
      break;
    case 0x48: case 0x49: case 0x4a: case 0x4b:
    case 0x4c: case 0x4d: case 0x4e: case 0x4f:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "clr\t(%sh).%u",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1), Opcode & 7);
      break;
    case 0x50: case 0x51: case 0x52: case 0x53:
    case 0x54: case 0x55: case 0x56: case 0x57:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\ta,%c",
                  Reg8Names[Opcode & 7]);
      break;
    case 0x58: case 0x59: case 0x5a: case 0x5b:
    case 0x5c: case 0x5d: case 0x5e: case 0x5f:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\t%c,a",
                  Reg8Names[Opcode & 7]);
      break;
    case 0x60: case 0x61: case 0x62: case 0x63:
    case 0x64: case 0x65: case 0x66: case 0x67:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "inc\t%c",
                  Reg8Names[Opcode & 7]);
      break;
    case 0x68: case 0x69: case 0x6a: case 0x6b:
    case 0x6c: case 0x6d: case 0x6e: case 0x6f:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "dec\t%c",
                  Reg8Names[Opcode & 7]);
      break;
    case 0x70: case 0x71: case 0x72: case 0x73:
    case 0x74: case 0x75: case 0x76: case 0x77:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "%s\ta,%sh",
                  ALUInstr[Opcode & 7], ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x78: case 0x79: case 0x7a: case 0x7b:
    case 0x7c: case 0x7d: case 0x7e: case 0x7f:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "%s\ta,(%sh)",
                  ALUInstr[Opcode & 7],
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      break;
    case 0x80: case 0x81: case 0x82: case 0x83:
    case 0x84: case 0x85: case 0x86: case 0x87:
    case 0x88: case 0x89: case 0x8a: case 0x8b:
    case 0x8c: case 0x8d: case 0x8e: case 0x8f:
    case 0x90: case 0x91: case 0x92: case 0x93:
    case 0x94: case 0x95: case 0x96: case 0x97:
    case 0x98: case 0x99: case 0x9a: case 0x9b:
    case 0x9c: case 0x9d: case 0x9e: case 0x9f:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      Dist = Opcode & 0x1f;
      if (Dist & 0x10)
        Dist = Dist - 32;
      pInfo->NextAddresses[pInfo->NextAddressCount++] = (Address + 2 + Dist) & 0xffff;
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "jrs\tt,%sh",
                  MakeSymbolic(pInfo->NextAddresses[1], 2, "lab_", NumBuf, sizeof(NumBuf)));
      break;
    case 0xa0: case 0xa1: case 0xa2: case 0xa3:
    case 0xa4: case 0xa5: case 0xa6: case 0xa7:
    case 0xa8: case 0xa9: case 0xaa: case 0xab:
    case 0xac: case 0xad: case 0xae: case 0xaf:
    case 0xb0: case 0xb1: case 0xb2: case 0xb3:
    case 0xb4: case 0xb5: case 0xb6: case 0xb7:
    case 0xb8: case 0xb9: case 0xba: case 0xbb:
    case 0xbc: case 0xbd: case 0xbe: case 0xbf:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      Dist = Opcode & 0x1f;
      if (Dist & 0x10)
        Dist = Dist - 32;
      pInfo->NextAddresses[pInfo->NextAddressCount++] = (Address + 2 + Dist) & 0xffff;
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "jrs\tf,%sh",
                  MakeSymbolic(pInfo->NextAddresses[1], 2, "lab_", NumBuf, sizeof(NumBuf)));
      break;
    case 0xc0: case 0xc1: case 0xc2: case 0xc3:
    case 0xc4: case 0xc5: case 0xc6: case 0xc7:
    case 0xc8: case 0xc9: case 0xca: case 0xcb:
    case 0xcc: case 0xcd: case 0xce: case 0xcf:
      Vector = Opcode & 15;
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      if (RetrieveData(0xffc0 + (Vector << 1), Data, 2))
        pInfo->NextAddresses[pInfo->NextAddressCount++] = (((Word)Data[1]) << 8) | Data[0];
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "callv\t%u\t ; %sh", Vector,
                  MakeSymbolic(pInfo->NextAddresses[1], 2, "subv_", NumBuf, sizeof(NumBuf)));
      nData -= 2;
      break;
    case 0xd0: case 0xd1: case 0xd2: case 0xd3:
    case 0xd4: case 0xd5: case 0xd6: case 0xd7:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      Dist = Data[0];
      if (Dist & 0x80)
        Dist -= 256;
      pInfo->NextAddresses[pInfo->NextAddressCount++] = (Address + 2 + Dist) & 0xffff;
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "jr\t%s,%sh",
                  RelNames[Opcode & 7],
                  MakeSymbolic(pInfo->NextAddresses[1], 2, "lab_", NumBuf, sizeof(NumBuf)));
      break;
    case 0xd8: case 0xd9: case 0xda: case 0xdb:
    case 0xdc: case 0xdd: case 0xde: case 0xdf:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "test\t(%sh).%u",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1), Opcode & 7);
      break;
    case 0xe0:
    case 0xf0:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      as_snprintf(NumBuf2, sizeof(NumBuf2), "(%sh)", ZeroHexString(NumBuf, sizeof(NumBuf), Data[0], 1));
      MemPrefix(Address, pInfo, 2, NumBuf2);
      break;
    case 0xe1:
    case 0xf1:
      MemPrefix(Address, pInfo, 1, "(pc+a)");
      break;
    case 0xe2:
    case 0xf2:
      MemPrefix(Address, pInfo, 1, "(de)");
      break;
    case 0xe3:
    case 0xf3:
      MemPrefix(Address, pInfo, 1, "(hl)");
      break;
    case 0xe4:
    case 0xf4:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      Dist = Data[0];
      if (Dist & 0x80)
        Dist -= 256;
      as_snprintf(NumBuf2, sizeof(NumBuf2), "(hl%s%d)",
                  Dist < 0 ? "" : "+", (int)Dist);
      MemPrefix(Address, pInfo, 2, NumBuf2);
      break;
    case 0xe5:
    case 0xf5:
      MemPrefix(Address, pInfo, 1, "(hl+c)");
      break;
    case 0xe6:
    case 0xf6:
      MemPrefix(Address, pInfo, 1, "(hl+)");
      break;
    case 0xe7:
    case 0xf7:
      MemPrefix(Address, pInfo, 1, "(-hl)");
      break;
    case 0xe8: case 0xe9: case 0xea: case 0xeb:
    case 0xec: case 0xed: case 0xee: case 0xef:
      RegPrefix(Address, pInfo, 1, Opcode & 7);
      break;
    case 0xfa:
      if (!RetrieveData(Address + 1, Data, 2))
        return;
      pInfo->CodeLen = 3;
      SimpleNextAddress(pInfo, Address);
      Arg = (((Word)Data[1]) << 8) | Data[0];
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "ld\tsp,%sh",
                  ZeroHexString(NumBuf, sizeof(NumBuf), Arg, 2));
      break;
    case 0xfb:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      Dist = Data[0];
      if (Dist & 0x80)
        Dist -= 256;
      pInfo->NextAddresses[pInfo->NextAddressCount++] = (Address + 2 + Dist) & 0xffff;
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "jr\t%sh",
                  MakeSymbolic(pInfo->NextAddresses[0], 2, "lab_", NumBuf, sizeof(NumBuf)));
      break;
    case 0xfc:
      if (!RetrieveData(Address + 1, Data, 2))
        return;
      pInfo->CodeLen = 3;
      SimpleNextAddress(pInfo, Address);
      pInfo->NextAddresses[pInfo->NextAddressCount++] = (((Word)Data[1]) << 8) | Data[0];
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "call\t%sh",
                  MakeSymbolic(pInfo->NextAddresses[1], 2, "sub_", NumBuf, sizeof(NumBuf)));
      break;
    case 0xfd:
      if (!RetrieveData(Address + 1, Data, 1))
        return;
      pInfo->CodeLen = 2;
      SimpleNextAddress(pInfo, Address);
      pInfo->NextAddresses[pInfo->NextAddressCount++] = 0xff00 + Data[0];
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "callp\t%sh",
                  MakeSymbolic(pInfo->NextAddresses[1], 2, "sub_", NumBuf, sizeof(NumBuf)));
      break;
    case 0xfe:
      if (!RetrieveData(Address + 1, Data, 2))
        return;
      pInfo->CodeLen = 3;
      pInfo->NextAddresses[pInfo->NextAddressCount++] = (((Word)Data[1]) << 8) | Data[0];
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "jp\t%sh",
                  MakeSymbolic(pInfo->NextAddresses[0], 2, "lab_", NumBuf, sizeof(NumBuf)));
      break;
    case 0xff:
      pInfo->CodeLen = 1;
      SimpleNextAddress(pInfo, Address);
      as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "swi");
      break;
    default:
      ActAsData = True;
  }

  if (ActAsData)
  {
    if (DataSize < 0)
      DataSize = 1;
    if (!RetrieveData(Address + 1, Data, DataSize - 1))
      return;
    HexString(NumBuf, sizeof(NumBuf), Opcode, 2);
    HexString(NumBuf2, sizeof(NumBuf2), Address, 0);
    if (!AsData)
      printf("unknown opcode 0x%s @ %s\n", NumBuf, NumBuf2);
    pInfo->NextAddressCount = 0;
    switch (DataSize)
    {
      case 2:
      {
        Word Addr = (((Word)Data[0]) << 8) | Opcode;
        as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "dw\t%s",
                    MakeSymbolic(Addr, 2, NULL, NumBuf, sizeof(NumBuf)));
        pInfo->CodeLen = 2;
        break;
      }
      default:
        pInfo->CodeLen = 1;
        as_snprintf(pInfo->SrcLine, sizeof(pInfo->SrcLine), "db\t%sh",
                    ZeroHexString(NumBuf, sizeof(NumBuf), Opcode, 1));
    }
    if (AsData)
      SimpleNextAddress(pInfo, Address);
  }

  if (nData != pInfo->CodeLen)
    as_snprcatf(pInfo->SrcLine, sizeof(pInfo->SrcLine), " ; ouch %u != %u", nData, pInfo->CodeLen);
}

static void SwitchTo_87C800(void)
{
  Disassemble = Disassemble_87C800;
}

void deco87c800_init(void)
{
  CPU87C00 = AddCPU("87C00", SwitchTo_87C800);
}