/*************************************************************************
 *                   disasm.c - 56002 disassembler                       *
 *-----------------------------------------------------------------------*
 *                      Jake Janovetz     1995                           *
 *                      University of Illinois                           *
 *************************************************************************
 *                                                                       *
 * This is the engine for the 56002 opcode disassembler.  It provides    *
 * a simple way to break a one- or two-word opcode into its textual      *
 * representation (opcode, operand(s), xmove and ymove).  Each resulting *
 * field is a string containing the common 56002 assembly syntax.        *
 *                                                                       *
 * The disassembler works by taking the opcode, masking it and comparing *
 * to a table of masked instructions.  If there is a match, then the     *
 * appropriate disassembly function is called to further break down the  *
 * opcode.  If the opcode allows parallel moves, then another function   *
 * is called to break these out (xmove and ymove).  This is a brute      *
 * force technique, but is fairly easy to understand and make changes if *
 * enhancements need to be made.                                         *
 ************************************************************************/

/*
 * Bug in registers for mpy immediate.  Check with microprocessor for 
 * data book error.
 */

#include <stdio.h>
#include <string.h>

#define BYTE   unsigned char
#define WORD   unsigned short
#define LWORD  unsigned long

short Disasm_Op_abs(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_adc(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_add(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_addx(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_and(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_andi(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_asx(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_bxxx(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_clr(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_cmpx(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_debugcc(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_dec(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_div(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_do(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_eor(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_inc(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_jxx(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_jxcc(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_jxsetclr(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_lsx(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_lua(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_mpyx(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_move(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_movec(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_movem(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_movep(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_neg(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_norm(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_not(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_or(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_ori(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_rep(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_rnd(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_rox(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_sbc(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_sub(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_subx(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_tcc(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_tfr(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_Op_tst(LWORD, LWORD, char *, char *, char *, char *);
short Disasm_parallelmove(LWORD, LWORD, char *, char *);

typedef short (Disasm_Disassembler_t)(LWORD, LWORD,
                                      char *, char *, char *, char *);

typedef struct
{
    LWORD                   mask;
    LWORD                   iopcode;
    char                    opcode[10];
    Disasm_Disassembler_t  *disasm_ptr; 
} Disasm_List_t;

/* Disasm_List
 *
 * This array contains a list of opcode masks and values used to determine
 * which opcode a particular instruction belongs to.  The masks must be
 * in decreasing order so that a complete match can be found.
 */
Disasm_List_t Disasm_List[] =
    {
        { 0xffffff, 0x000200, "debug",   NULL },
        { 0xffffff, 0x00008c, "enddo",   NULL },
        { 0xffffff, 0x000005, "illegal", NULL },
        { 0xffffff, 0x000000, "nop",     NULL },
        { 0xffffff, 0x000084, "reset",   NULL },
        { 0xffffff, 0x000004, "rti",     NULL },
        { 0xffffff, 0x00000c, "rts",     NULL },
        { 0xffffff, 0x000087, "stop",    NULL },
        { 0xffffff, 0x000006, "swi",     NULL },
        { 0xffffff, 0x000086, "wait",    NULL },
        { 0xfffffe, 0x00000a, "dec",     Disasm_Op_dec },
        { 0xfffffe, 0x000008, "inc",     Disasm_Op_inc },
        { 0xfffff0, 0x000300, "debugcc", Disasm_Op_debugcc },
        { 0xffffc7, 0x018040, "div",     Disasm_Op_div },
        { 0xfff8f7, 0x01d815, "norm",    Disasm_Op_norm },
        { 0xff00fc, 0x0000b8, "andi",    Disasm_Op_andi },
        { 0xffc0bf, 0x064020, "rep",     Disasm_Op_rep },
        { 0xffc0af, 0x060020, "rep",     Disasm_Op_rep },
        { 0xff00f0, 0x0600a0, "rep",     Disasm_Op_rep },
        { 0xffc0ff, 0x06c020, "rep",     Disasm_Op_rep },
        { 0xff0000, 0x060000, "do",      Disasm_Op_do },
        { 0xfff000, 0x0c0000, "jmp",     Disasm_Op_jxx },
        { 0xffc0ff, 0x0ac080, "jmp",     Disasm_Op_jxx },
        { 0xfff000, 0x0d0000, "jsr",     Disasm_Op_jxx },
        { 0xffc0ff, 0x0bc080, "jsr",     Disasm_Op_jxx },
        { 0xff0000, 0x0e0000, "jcc",     Disasm_Op_jxcc },
        { 0xffc0f0, 0x0ac0a0, "jcc",     Disasm_Op_jxcc },
        { 0xff0000, 0x0f0000, "jscc",    Disasm_Op_jxcc },
        { 0xffc0f0, 0x0bc0a0, "jscc",    Disasm_Op_jxcc },
        { 0xffc0a0, 0x0a4080, "jclr",    Disasm_Op_jxsetclr },
        { 0xffc0a0, 0x0a0080, "jclr",    Disasm_Op_jxsetclr },
        { 0xffc0a0, 0x0a8080, "jclr",    Disasm_Op_jxsetclr },
        { 0xffc0e0, 0x0ac000, "jclr",    Disasm_Op_jxsetclr },
        { 0xffc0a0, 0x0b4080, "jsclr",   Disasm_Op_jxsetclr },
        { 0xffc0a0, 0x0b0080, "jsclr",   Disasm_Op_jxsetclr },
        { 0xffc0a0, 0x0b8080, "jsclr",   Disasm_Op_jxsetclr },
        { 0xffc0e0, 0x0bc000, "jsclr",   Disasm_Op_jxsetclr },
        { 0xffc0a0, 0x0a40a0, "jset",    Disasm_Op_jxsetclr },
        { 0xffc0a0, 0x0a00a0, "jset",    Disasm_Op_jxsetclr },
        { 0xffc0a0, 0x0a80a0, "jset",    Disasm_Op_jxsetclr },
        { 0xffc0e0, 0x0ac020, "jset",    Disasm_Op_jxsetclr },
        { 0xffc0a0, 0x0b40a0, "jsset",   Disasm_Op_jxsetclr },
        { 0xffc0a0, 0x0b00a0, "jsset",   Disasm_Op_jxsetclr },
        { 0xffc0a0, 0x0b80a0, "jsset",   Disasm_Op_jxsetclr },
        { 0xffc0e0, 0x0bc020, "jsset",   Disasm_Op_jxsetclr },
        { 0xffe0f0, 0x044010, "lua",     Disasm_Op_lua },
        { 0xffe0c3, 0x0100c0, "mpy",     Disasm_Op_mpyx },
        { 0xffe0c3, 0x0100c1, "mpyr",    Disasm_Op_mpyx },
        { 0xffe0c3, 0x0100c2, "mac",     Disasm_Op_mpyx },
        { 0xffe0c3, 0x0100c3, "macr",    Disasm_Op_mpyx },
        { 0xff40a0, 0x054020, "movec",   Disasm_Op_movec },
        { 0xff40a0, 0x050020, "movec",   Disasm_Op_movec },
        { 0xff40e0, 0x0440a0, "movec",   Disasm_Op_movec },
        { 0xff00e0, 0x0500a0, "movec",   Disasm_Op_movec },
        { 0xff40c0, 0x074080, "movem",   Disasm_Op_movem },
        { 0xff40c0, 0x070000, "movem",   Disasm_Op_movem },
        { 0xfe4080, 0x084080, "movep",   Disasm_Op_movep },
        { 0xfe40c0, 0x084040, "movep",   Disasm_Op_movep },
        { 0xfe40c0, 0x084000, "movep",   Disasm_Op_movep },
        { 0xff00fc, 0x0000f8, "ori",     Disasm_Op_ori },
        { 0xff0f87, 0x020000, "tcc",     Disasm_Op_tcc },
        { 0xff0880, 0x030000, "tcc",     Disasm_Op_tcc },
        { 0xff00a0, 0x0b0000, "bchg",    Disasm_Op_bxxx },
        { 0xff00a0, 0x0a0000, "bclr",    Disasm_Op_bxxx },
        { 0xff00a0, 0x0a0020, "bset",    Disasm_Op_bxxx },
        { 0xff00a0, 0x0b0020, "btst",    Disasm_Op_bxxx },
        { 0x0000ff, 0x000000, "move",    Disasm_Op_move },
        { 0x0000f7, 0x000026, "abs",     Disasm_Op_abs  },
        { 0x0000f7, 0x000013, "clr",     Disasm_Op_clr  },
        { 0x0000f7, 0x000033, "lsl",     Disasm_Op_lsx },
        { 0x0000f7, 0x000023, "lsr",     Disasm_Op_lsx },
        { 0x0000f7, 0x000036, "neg",     Disasm_Op_neg },
        { 0x0000f7, 0x000017, "not",     Disasm_Op_not },
        { 0x0000f7, 0x000011, "rnd",     Disasm_Op_rnd },
        { 0x0000f7, 0x000037, "rol",     Disasm_Op_rox },
        { 0x0000f7, 0x000027, "ror",     Disasm_Op_rox },
        { 0x0000f7, 0x000016, "subl",    Disasm_Op_subx },
        { 0x0000f7, 0x000006, "subr",    Disasm_Op_subx },
        { 0x0000f7, 0x000003, "tst",     Disasm_Op_tst },
        { 0x0000e7, 0x000021, "adc",     Disasm_Op_adc  },
        { 0x0000f7, 0x000012, "addl",    Disasm_Op_addx },
        { 0x0000f7, 0x000002, "addr",    Disasm_Op_addx },
        { 0x0000f7, 0x000032, "asl",     Disasm_Op_asx  },
        { 0x0000f7, 0x000022, "asr",     Disasm_Op_asx  },
        { 0x0000e7, 0x000025, "sbc",     Disasm_Op_sbc },
        { 0x0000c7, 0x000046, "and",     Disasm_Op_and  },
        { 0x0000c7, 0x000043, "eor",     Disasm_Op_eor },
        { 0x0000c7, 0x000042, "or",      Disasm_Op_or },
        { 0x000087, 0x000000, "add",     Disasm_Op_add  },
        { 0x000087, 0x000004, "sub",     Disasm_Op_sub },
        { 0x000087, 0x000001, "tfr",     Disasm_Op_tfr },
        { 0x000087, 0x000005, "cmp",     Disasm_Op_cmpx },
        { 0x000087, 0x000007, "cmpm",    Disasm_Op_cmpx },
        { 0x000083, 0x000080, "mpy",     Disasm_Op_mpyx },
        { 0x000083, 0x000081, "mpyr",    Disasm_Op_mpyx },
        { 0x000083, 0x000082, "mac",     Disasm_Op_mpyx },
        { 0x000083, 0x000083, "macr",    Disasm_Op_mpyx },
        { 0x000000, 0x000000, NULL }
    };

/*
 * One-Bit register encodings
 */
char *Disasm_OneBitRegs_d[] = { "a", "b" };
char *Disasm_OneBitRegs_e[] = { "x0", "x1" };
char *Disasm_OneBitRegs_f[] = { "y0", "y1" };

/*
 * One-Bit memory space encodings
 */
char *Disasm_OneBitSpace_S[] = { "x", "y" };

/*
 * Two-Bit register encodings
 */
char *Disasm_TwoBitRegs_DD[] = { "x0", "y0", "x1", "y1" };
char *Disasm_TwoBitRegs_ee[] = { "x0", "x1", "a", "b" };
char *Disasm_TwoBitRegs_ff[] = { "y0", "y1", "a", "b" };
char *Disasm_TwoBitCtrlRegs[] = { "mr", "ccr", "omr", "" };

/*
 * Three-Bit register encodings
 */
char *Disasm_ThreeBitRegs_DDD[] =
    { "a0", "b0", "a2", "b2", "a1", "b1", "a", "b" };
char *Disasm_ThreeBitRegs_LLL[] =
    { "a10", "b10", "x", "y", "a", "b", "ab", "ba" };
char *Disasm_ThreeBitRegs_FFF[] =
    { "m0", "m1", "m2", "m3", "m4", "m5", "m6", "m7" };
char *Disasm_ThreeBitRegs_NNN[] =
    { "n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7" };
char *Disasm_ThreeBitRegs_TTT[] =
    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" };
char *Disasm_ThreeBitRegs_GGG[] =
    { "*", "sr", "omr", "sp", "ssh", "ssl", "la", "lc" };

/*
 * Four-Bit condition codes
 */
char *Disasm_FourBitCond_CCCC[] =
    { "cc", "ge", "ne", "pl", "nn", "ec", "lc", "gt",
      "cs", "lt", "eq", "mi", "nr", "es", "ls", "le" };

/*
 * Five-Bit register encodings
 */
char *Disasm_FiveBitRegs_ddddd[] =
    { "", "", "", "", "x0", "x1", "y0", "y1",
      "a0", "b0", "a2", "b2", "a1", "b1", "a", "b",
      "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
      "n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7" };

/*
 * Six-Bit register encodings
 */
char *Disasm_SixBitRegs_DDDDDD[] =
    { "", "", "", "", "x0", "x1", "y0", "y1",
      "a0", "b0", "a2", "b2", "a1", "b1", "a", "b",
      "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
      "n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7",
      "m0", "m1", "m2", "m3", "m4", "m5", "m6", "m7",
      "", "", "", "", "", "", "", "",
      "", "", "", "", "", "", "", "",
      "", "sr", "omr", "sp", "ssh", "ssl", "la", "lc" };

/*
 * Register encoding used with mpy,mpyr,mac,macr
 */
char *Disasm_MpyRegs[] =
    { "x0,x0", "y0,y0", "x1,x0", "y1,y0",
      "x0,y1", "y0,x0", "x1,y0", "y1,x1" };

/*
 * Control registers for movec
 */
char *Disasm_movecRegs[] =
    { "m0", "m1", "m2", "m3", "m4", "m5", "m6", "m7",
      "", "", "", "", "", "", "", "",
      "", "", "", "", "", "", "", "",
      "", "sr", "omr", "sp", "ssh", "ssl", "la", "lc" };


/*************************************************************************
 * Disasm_FormEAShort
 *--------------------
 * Some X/Y parallel data moves require a selection of 4 effective address
 * modes.  This function breaks them down.
 ************************************************************************/
void Disasm_FormEAShort(char *bufr, short reg, short mode)
{
    char *r_reg = Disasm_ThreeBitRegs_TTT[reg];
    char *n_reg = Disasm_ThreeBitRegs_NNN[reg];

    switch (mode)
    {
        case 0:    /* (Rn) */
            sprintf(bufr, "(%s)", r_reg);
            break;
        case 1:    /* (Rn)+Nn */
            sprintf(bufr, "(%s)+%s", r_reg, n_reg);
            break;
        case 2:    /* (Rn)- */
            sprintf(bufr, "(%s)-", r_reg);
            break;
        case 3:    /* (Rn)+ */
            sprintf(bufr, "(%s)+", r_reg);
            break;
    }
}

/*************************************************************************
 * Disasm_FormEALong
 *-------------------
 * Some X/Y parallel data moves require a selection of 7 effective address
 * modes.  This function breaks them down.
 ************************************************************************/
void Disasm_FormEALong(char *bufr, LWORD mem1)
{
    LWORD temp_uint = ((mem1 & 0x000700) >> 8);
    char *r_reg = Disasm_ThreeBitRegs_TTT[temp_uint];
    char *n_reg = Disasm_ThreeBitRegs_NNN[temp_uint];

    switch ((mem1 & 0x003800) >> 11)
    {
        case 0:    /* (Rn)-Nn */
            sprintf(bufr, "(%s)-%s", r_reg, n_reg);
            break;
        case 1:    /* (Rn)+Nn */
            sprintf(bufr, "(%s)+%s", r_reg, n_reg);
            break;
        case 2:    /* (Rn)- */
            sprintf(bufr, "(%s)-", r_reg);
            break;
        case 3:    /* (Rn)+ */
            sprintf(bufr, "(%s)+", r_reg);
            break;
        case 4:    /* (Rn) */
            sprintf(bufr, "(%s)", r_reg);
            break;
        case 5:    /* (Rn+Nn) */
            sprintf(bufr, "(%s+%s)", r_reg, n_reg);
            break;
        case 7:    /* -(Rn) */
            sprintf(bufr, "-(%s)", r_reg);
            break;
    }
}

/*************************************************************************
 * abs - Absolute Value
 ************************************************************************/
short Disasm_Op_abs(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    sprintf(operands, "%s", Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * adc - Add Long with Carry
 ************************************************************************/
short Disasm_Op_adc(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    sprintf(operands, "%s,%s", ((mem1 & 0x000010)==0)?("x"):("y"),
                               Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * add - Add
 ************************************************************************/
short Disasm_Op_add(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    char temp_str[20];

    switch ((mem1 & 0x000070) >> 4)
    {
        case 1:
            strcpy(temp_str, Disasm_OneBitRegs_d[1-((mem1 & 0x000008) >> 3)]);
            break;
        case 2:
            strcpy(temp_str, "x");
            break;
        case 3:
            strcpy(temp_str, "y");
            break;
        case 4:
            strcpy(temp_str, "x0");
            break;
        case 5:
            strcpy(temp_str, "y0");
            break;
        case 6:
            strcpy(temp_str, "x1");
            break;
        case 7:
            strcpy(temp_str, "y1");
            break;
    }
    sprintf(operands, "%s,%s", temp_str,
            Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * addx - Shift Left/Right and Add Accumulators
 ************************************************************************/
short Disasm_Op_addx(LWORD mem1, LWORD mem2,
                     char *opcode, char *operands, char *xmove, char *ymove)
{
    if (mem1 & 0x000008)
    {
        strcpy(operands, "a,b");
    }
    else
    {
        strcpy(operands, "b,a");
    }
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * and - Logical AND
 ************************************************************************/
short Disasm_Op_and(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    sprintf(operands, "%s,%s", Disasm_TwoBitRegs_DD[(mem1 & 0x000030) >> 4],
            Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * andi - AND Immediate with Control Register
 ************************************************************************/
short Disasm_Op_andi(LWORD mem1, LWORD mem2,
                     char *opcode, char *operands, char *xmove, char *ymove)
{
    char temp_str[20];

    sprintf(operands, "#$%X,%s", (mem1 & 0x00ff00) >> 8,
            Disasm_TwoBitCtrlRegs[mem1 & 0x000003]);
    return(1); 
}

/*************************************************************************
 * asx - Arithmetic Shift Accumulator Left/Right
 ************************************************************************/
short Disasm_Op_asx(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    sprintf(operands, "%s", Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * bxxx - bchg - Bit Test and Change
 *        bclr - Bit Test and Clear
 *        bset - Bit Test and Set
 *        btst - Bit Test
 ************************************************************************/
short Disasm_Op_bxxx(LWORD mem1, LWORD mem2,
                     char *opcode, char *operands, char *xmove, char *ymove)
{
    char temp_str[20];
    short mem_spc;

    switch ((mem1 & 0x00c000) >> 14)
    {
        case 0:    /* absolute short address */
            sprintf(operands, "#%d,%s:<$%X", (mem1 & 0x00001f),
                    Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6],
                    (mem1 & 0x003f00) >> 8);
            mem_spc = 1;
            break;
        case 1:    /* effective address */
            if ((mem1 & 0x003f00) == 0x003000)
            {
                sprintf(temp_str, "$%X", mem2);
                mem_spc = 2;
            }
            else
            {
                Disasm_FormEALong(temp_str, mem1);
                mem_spc = 1;
            }
            sprintf(operands, "#%d,%s:%s", (mem1 & 0x00001f),
                    Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6],
                    temp_str);
            break;
        case 2:    /* short I/O address */
            sprintf(operands, "#%d,%s:<<$%X", (mem1 & 0x00001f),
                    Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6],
                    0xffc0 + ((mem1 & 0x003f00) >> 8));
            mem_spc = 1;
            break;
        case 3:    /* destination register */
            sprintf(operands, "#%d,%s", (mem1 & 0x00001f),
                    Disasm_SixBitRegs_DDDDDD[(mem1 & 0x003f00) >> 8]);
            mem_spc = 1;
            break;
    }
    return(mem_spc);
}

/*************************************************************************
 * clr - Clear Accumulator
 ************************************************************************/
short Disasm_Op_clr(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    strcpy(operands, Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * cmpx - Compare (Magnitude)
 ************************************************************************/
short Disasm_Op_cmpx(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    if (mem1 & 0x000040)
    {
        sprintf(operands, "%s,%s",
                Disasm_TwoBitRegs_DD[(mem1 & 0x000030) >> 4],
                Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    }
    else
    {
        sprintf(operands, "%s,%s",
                Disasm_OneBitRegs_d[1 - ((mem1 & 0x000008) >> 3)],
                Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    }
    return(1);
}

/*************************************************************************
 * debugcc - Enter Debug Mode Conditionally
 ************************************************************************/
short Disasm_Op_debugcc(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    sprintf(opcode, "debug%s", Disasm_FourBitCond_CCCC[(mem1 & 0x00000f)]);
    return(1);
}

/*************************************************************************
 * dec - Decrement by One
 ************************************************************************/
short Disasm_Op_dec(LWORD mem1, LWORD mem2,
                   char *opcode, char *operands, char *xmove, char *ymove)
{
    strcpy(operands, Disasm_OneBitRegs_d[mem1 & 0x000001]);
    return(1);
}

/*************************************************************************
 * div - Divide Iteration
 ************************************************************************/
short Disasm_Op_div(LWORD mem1, LWORD mem2,
                   char *opcode, char *operands, char *xmove, char *ymove)
{
    sprintf(operands, "%s,%s", Disasm_TwoBitRegs_DD[(mem1 & 0x000030) >> 4],
            Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(1);
}

/*************************************************************************
 * do - Start Hardware Loop
 ************************************************************************/
short Disasm_Op_do(LWORD mem1, LWORD mem2,
                  char *opcode, char *operands, char *xmove, char *ymove)
{
    char  temp_str[20];

    if (mem1 & 0x000080)    /* immediate repeat count */
    {
        sprintf(operands, "#$%X,$%X",
                ((mem1 & 0x00000f) << 8) | ((mem1 & 0x00ff00) >> 8),
                mem2 + 1);
    }
    else
    {
        switch((mem1 & 0x00c000) >> 14)
        {
            case 0:
                sprintf(operands, "%s:$%X,$%X",
                        Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6],
                        (mem1 & 0x003f00) >> 8, mem2 + 1);
                break;
            case 1:
                Disasm_FormEALong(temp_str, mem1);
                sprintf(operands, "%s:%s,$%X",
                        Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6],
                        temp_str, mem2 + 1);
                break;
            case 3:
                sprintf(operands, "%s,$%X",
                        Disasm_SixBitRegs_DDDDDD[(mem1 & 0x003f00) >> 8],
                        mem2 + 1);
                break;
        }
    }
    return(2);
}

/*************************************************************************
 * eor - Logical Exclusive OR
 ************************************************************************/
short Disasm_Op_eor(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    sprintf(operands, "%s,%s",
            Disasm_TwoBitRegs_DD[(mem1 & 0x000030) >> 4],
            Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * inc - Increment by One
 ************************************************************************/
short Disasm_Op_inc(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    strcpy(operands, Disasm_OneBitRegs_d[mem1 & 0x000001]);
    return(1);
}

/*************************************************************************
 * jxx - Jump (to Subroutine)
 ************************************************************************/
short Disasm_Op_jxx(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    short mem_spc;

    if ((mem1 & 0xfe0000) == 0x0c0000)    /* absolute short */
    {
        sprintf(operands, "<$%X", mem1 & 0x000fff);
        mem_spc = 1;
    }
    else    /* effective address */
    {
        if ((mem1 & 0x003f00) == 0x003000)    /* absolute address */
        {
            sprintf(operands, "$%X", mem2);
            mem_spc = 2;
        }
        else    /* register effective */
        {
            Disasm_FormEALong(operands, mem1);
            mem_spc = 1;
        }
    }
    return(mem_spc);
}

/*************************************************************************
 * jxcc - Jump (to Subroutine) Conditionally
 ************************************************************************/
short Disasm_Op_jxcc(LWORD mem1, LWORD mem2,
                     char *opcode, char *operands, char *xmove, char *ymove)
{
    short mem_spc;

    if ((mem1 & 0xfe0000) == 0x0e0000)    /* absolute short address */
    {
        sprintf(opcode, "j%s%s", (mem1&0x010000)?("s"):(""),
                Disasm_FourBitCond_CCCC[(mem1 & 0x00f000) >> 12]);
        mem_spc = 1;
        sprintf(operands, "<$%X", mem1 & 0x000fff);
    } 
    else    /* effective address */
    {
        sprintf(opcode, "j%s%s", (mem1&0x010000)?("s"):(""),
                Disasm_FourBitCond_CCCC[mem1 & 0x00000f]);
        if ((mem1 & 0x003f00) == 0x003000)    /* absolute address */
        {
            sprintf(operands, "$%X", mem2);
            mem_spc = 2;
        }
        else    /* register effective */
        {
            Disasm_FormEALong(operands, mem1);
            mem_spc = 1;
        }
    }
    return(mem_spc);
}

/*************************************************************************
 * jxsetclr - Jump (to Subroutine) if Bit Set/Clear
 ************************************************************************/
short Disasm_Op_jxsetclr(LWORD mem1, LWORD mem2,
                      char *opcode, char *operands, char *xmove, char *ymove)
{
    char temp_str[20];
    char temp_str1[20];

    sprintf(opcode, "j%s%s", (mem1&0x010000)?("s"):(""),
            (mem1&0x000020)?("set"):("clr"));
    switch ((mem1 & 0x00c000) >> 14)
    {
        case 0:
            sprintf(temp_str, "%s:$%X",
                    Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6],
                    (mem1 & 0x003f00) >> 8);
            break;
        case 1:
            Disasm_FormEALong(temp_str1, mem1);
            sprintf(temp_str, "%s:%s",
                    Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6], temp_str1);
            break;
        case 2:
            sprintf(temp_str, "%s:<<$%X",
                    Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6],
                    0xffc0 + ((mem1 & 0x003f00) >> 8));
            break;
        case 3:
            strcpy(temp_str, Disasm_SixBitRegs_DDDDDD[(mem1 & 0x003f00) >> 8]);
            break;
    }
    sprintf(operands, "#%d,%s,$%X", (mem1 & 0x00001f), temp_str, mem2);
    return(2);
}

/*************************************************************************
 * lsx - Logical Shift Left/Right
 ************************************************************************/
short Disasm_Op_lsx(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    strcpy(operands, Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * lua - Load Updated Address
 ************************************************************************/
short Disasm_Op_lua(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    char temp_str[20];

    switch ((mem1 & 0x001800) >> 11)
    {
        case 0:    /* (Rn)-Nn */
            sprintf(temp_str, "(r%d)-n%d", (mem1 & 0x000700) >> 8,
                    (mem1 & 0x000700) >> 8);
            break;
        case 1:    /* (Rn)+Nn */
            sprintf(temp_str, "(r%d)+n%d", (mem1 & 0x000700) >> 8,
                    (mem1 & 0x000700) >> 8);
            break;
        case 2:    /* (Rn)- */
            sprintf(temp_str, "(r%d)-", (mem1 & 0x000700) >> 8);
            break;
        case 3:    /* (Rn)+ */
            sprintf(temp_str, "(r%d)+", (mem1 & 0x000700) >> 8);
            break;
    }
    if (mem1 & 0x00000008)
    {
        sprintf(operands, "%s,%s", temp_str,
                Disasm_ThreeBitRegs_NNN[mem1 & 0x000007]);
    }
    else
    {
        sprintf(operands, "%s,%s", temp_str,
                Disasm_ThreeBitRegs_TTT[mem1 & 0x000007]);
    }
    return(1);
}

/*************************************************************************
 * mpyx - Signed Multiply (and Round) or
 *        Signed Multiply-Accumulate (and Round)
 ************************************************************************/
short Disasm_Op_mpyx(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    if ((mem1 & 0xffe0c0) == 0x0100c0)
    { 
        sprintf(operands, "%s%s,#%d,%s", (mem1&0x000004)?("-"):(""),
                Disasm_TwoBitRegs_DD[(mem1 & 0x000030) >> 4],
                (mem1 & 0x001f00) >> 8,
                Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]); 
        return(1);
    }
    else
    {
        sprintf(operands, "%s%s,%s", (mem1&0x000004)?("-"):(""),
                Disasm_MpyRegs[(mem1 & 0x000070) >> 4],
                Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    }
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * move - Move Data
 ************************************************************************/
short Disasm_Op_move(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * movec - Move Control Register
 ************************************************************************/
short Disasm_Op_movec(LWORD mem1, LWORD mem2,
                      char *opcode, char *operands, char *xmove, char *ymove)
{
    char temp_str[20];
    char temp_str1[20];
    short mem_spc;

    if ((mem1 & 0xff40a0) == 0x054020)    /* effective address */
    {
        if ((mem1 & 0x003f00) == 0x003000)    /* absolute address */
        {
            sprintf(temp_str, "%s:$%X",
                    Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6], mem2);
            mem_spc = 2;
        }
        else if ((mem1 & 0x003f00) == 0x003400)    /* immediate */
        {
            sprintf(temp_str, "#$%X", mem2);
            mem_spc = 2;
        }
        else    /* register effective */
        {
            Disasm_FormEALong(temp_str1, mem1);
            sprintf(temp_str, "%s:%s",
                    Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6], temp_str1);
            mem_spc = 1;
        }
        if (mem1 & 0x008000)
        {
            sprintf(operands, "%s,%s", temp_str,
                    Disasm_movecRegs[mem1 & 0x00001f]);
        }
        else
        {
            sprintf(operands, "%s,%s", Disasm_movecRegs[mem1 & 0x00001f],
                    temp_str);
        }
    }
    else if ((mem1 & 0xff40a0) == 0x050020)    /* absolute short address */
    {
        sprintf(temp_str, "%s:<$%X",
                Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6],
                (mem1 & 0x003f00) >> 8);
        if (mem1 & 0x008000)    /* Write */
        {
            sprintf(operands, "%s,%s", temp_str,
                Disasm_movecRegs[mem1 & 0x00001f]);
        }
        else    /* Read */
        {
            sprintf(operands, "%s,%s", Disasm_movecRegs[mem1 & 0x00001f],
                    temp_str);
        }
        mem_spc = 1;
    } 
    else if ((mem1 & 0xff40e0) == 0x0440a0)    /* register/register */
    {
        if (mem1 & 0x008000)    /* Write */
        {
            sprintf(operands, "%s,%s",
                    Disasm_SixBitRegs_DDDDDD[(mem1 & 0x003f00) >> 8],
                    Disasm_movecRegs[mem1 & 0x00001f]);
        } 
        else    /* Read */
        {
            sprintf(operands, "%s,%s",
                    Disasm_movecRegs[mem1 & 0x00001f],
                    Disasm_SixBitRegs_DDDDDD[(mem1 & 0x003f00) >> 8]);
        }
        mem_spc = 1;
    }
    else    /* immediate */
    {
        sprintf(operands, "#$%X,%s", (mem1 & 0x00ff00) >> 8,
                Disasm_movecRegs[mem1 & 0x00001f]);
        mem_spc = 1;
    }
    return(mem_spc);
}

/*************************************************************************
 * movem - Move Program Memory
 ************************************************************************/
short Disasm_Op_movem(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    char temp_str[20];
    short mem_spc;

    if (mem1 & 0x004000)
    {
        if ((mem1 & 0x003f00) == 0x003000)    /* absolute address */
        {
            sprintf(temp_str, "$%X", mem2);
            mem_spc = 2;
        }
        else
        {
            Disasm_FormEALong(temp_str, mem1);
            mem_spc = 1;
        }
    }
    else    /* absolute short address */
    {
        sprintf(temp_str, "<$%X", (mem1 & 0x003f00) >> 8);
        mem_spc = 1;
    }
    if (mem1 & 0x008000)    /* Write */
    {
        sprintf(operands, "p:%s,%s", temp_str,
                Disasm_SixBitRegs_DDDDDD[mem1 & 0x00003f]);
    }
    else    /* Read */
    {
        sprintf(operands, "%s,p:%s",
                Disasm_SixBitRegs_DDDDDD[mem1 & 0x00003f],
                temp_str);
    }
    return(mem_spc);
}

/*************************************************************************
 * movep - Move Peripheral Data
 ************************************************************************/
short Disasm_Op_movep(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    char temp_str[20];
    char temp_str1[20];
    short mem_spc;

    mem_spc = 1;
    if (!(mem1 & 0x0000c0))    /* register reference */
    {
        sprintf(temp_str, "%s",
                Disasm_SixBitRegs_DDDDDD[(mem1 & 0x003f00) >> 8]);
        mem_spc = 1;
    }
    else
    {
        if ((mem1 & 0x003f00) == 0x003400)    /* immediate */
        {
            sprintf(temp_str, "#$%X", mem2);
            mem_spc = 2;
        }
        else
        {
            if ((mem1 & 0x003f00) == 0x003000)
            {
                sprintf(temp_str1, "$%X", mem2);
                mem_spc = 2;
            }
            else
            {
                Disasm_FormEALong(temp_str1, mem1);
                mem_spc = 1;
            }
            if (mem1 & 0x000080)    /* X: or Y: reference */
            {
                sprintf(temp_str, "%s:%s",
                        Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6],
                        temp_str1);
            }
            else    /* P: reference */
            {
                sprintf(temp_str, "p:%s", temp_str1);
            }
        }
    }
    if (mem1 & 0x008000)    /* Write */
    {
        sprintf(operands, "%s,%s:<<$%X", temp_str,
                Disasm_OneBitSpace_S[(mem1 & 0x010000) >> 16],
                0xffc0 + (mem1 & 0x00003f));
    }
    else    /* Read */
    {
        sprintf(operands, "%s:<<$%X,%s",
                Disasm_OneBitSpace_S[(mem1 & 0x010000) >> 16],
                0xffc0 + (mem1 & 0x00003f), temp_str);
    }
    return(mem_spc);
}

/*************************************************************************
 * neg - Negate Accumulator
 ************************************************************************/
short Disasm_Op_neg(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    strcpy(operands, Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * norm - Normalize Accumulator Iteration
 ************************************************************************/
short Disasm_Op_norm(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    sprintf(operands, "%s,%s",
            Disasm_ThreeBitRegs_TTT[(mem1 & 0x000700) >> 8],
            Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(1);
}

/*************************************************************************
 * not - Logical Complement
 ************************************************************************/
short Disasm_Op_not(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    strcpy(operands, Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(1);
}

/*************************************************************************
 * or - Logical Inclusive OR
 ************************************************************************/
short Disasm_Op_or(LWORD mem1, LWORD mem2,
                   char *opcode, char *operands, char *xmove, char *ymove)
{
    sprintf(operands, "%s,%s",
            Disasm_TwoBitRegs_DD[(mem1 & 0x000030) >> 4],
            Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * ori - OR Immediate with Control Register
 ************************************************************************/
short Disasm_Op_ori(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    sprintf(operands, "#$%X,%s", (mem1 & 0x00ff00) >> 8,
            Disasm_TwoBitCtrlRegs[mem1 & 0x000003]);
    return(1);
}

/*************************************************************************
 * rep - Repeat Next Instruction
 ************************************************************************/
short Disasm_Op_rep(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    char temp_str[20];

    if ((mem1 & 0xffc0af) == 0x064020)    /* effective address */
    {
        Disasm_FormEALong(temp_str, mem1);
        sprintf(operands, "%s:%s",
                Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6], temp_str);
    }
    else if ((mem1 & 0xffc0af) == 0x060020)    /* absolute short */
    {
        sprintf(operands, "%s:<$%X",
                Disasm_OneBitSpace_S[(mem1 & 0x000040) >> 6],
                (mem1 & 0x003f00) >> 8);
    }
    else if ((mem1 & 0xff00f0) == 0x0600a0)   /* immediate short data */
    {
        sprintf(operands, "#<%d",
                ((mem1 & 0x00ff00) >> 8) | ((mem1 & 0x00000f) << 8));
    }
    else    /* register */
    {
        strcpy(operands, Disasm_SixBitRegs_DDDDDD[(mem1 & 0x003f00) >> 8]);
    }
    return(1);
}

/*************************************************************************
 * rnd - Round Accumulator
 ************************************************************************/
short Disasm_Op_rnd(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    strcpy(operands, Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * rox - Rotate Left/Right
 ************************************************************************/
short Disasm_Op_rox(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    strcpy(operands, Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * sbc - Subtract Long with Carry
 ************************************************************************/
short Disasm_Op_sbc(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    sprintf(operands, "%s,%s", (mem1&0x000010)?("y"):("x"),
            Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * sub - Subtract
 ************************************************************************/
short Disasm_Op_sub(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    char temp_str[20];

    switch ((mem1 & 0x000070) >> 4)
    {
        case 1:
            strcpy(temp_str, Disasm_OneBitRegs_d[1-((mem1 & 0x000008) >> 3)]);
            break;
        case 2:
            strcpy(temp_str, "x");
            break;
        case 3:
            strcpy(temp_str, "y");
            break;
        case 4:
            strcpy(temp_str, "x0");
            break;
        case 5:
            strcpy(temp_str, "y0");
            break;
        case 6:
            strcpy(temp_str, "x1");
            break;
        case 7:
            strcpy(temp_str, "y1");
            break;
    }
    sprintf(operands, "%s,%s", temp_str,
            Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * subx - Shift Left/Right and Subtract Accumulators
 ************************************************************************/
short Disasm_Op_subx(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    strcpy(operands, (mem1 & 0x000008)?("a,b"):("b,a"));
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * tcc - Transfer Conditionally
 ************************************************************************/
short Disasm_Op_tcc(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    sprintf(opcode, "t%s", Disasm_FourBitCond_CCCC[(mem1 & 0x00f000) >> 12]);
    if (mem1 & 0x000040)
    {
        sprintf(operands, "%s,%s",
                Disasm_TwoBitRegs_DD[(mem1 & 0x000030) >> 4],
                Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    }
    else
    {
        strcpy(operands, (mem1 & 0x000008)?("a,b"):("b,a"));
    }
    if (mem1 & 0x010000)
    {
        sprintf(xmove, "%s,%s",
                Disasm_ThreeBitRegs_TTT[(mem1 & 0x000700) >> 8],
                Disasm_ThreeBitRegs_TTT[mem1 & 0x000007]);
    }
    return(1);
}

/*************************************************************************
 * tfr - Transfer Data ALU Register
 ************************************************************************/
short Disasm_Op_tfr(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    if (mem1 & 0x000040)
    {
        sprintf(operands, "%s,%s",
                Disasm_TwoBitRegs_DD[(mem1 & 0x000030) >> 4],
                Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    }
    else
    {
        strcpy(operands, (mem1 & 0x000008)?("a,b"):("b,a"));
    }
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * tst - Test Accumulator
 ************************************************************************/
short Disasm_Op_tst(LWORD mem1, LWORD mem2,
                    char *opcode, char *operands, char *xmove, char *ymove)
{
    strcpy(operands, Disasm_OneBitRegs_d[(mem1 & 0x000008) >> 3]);
    return(Disasm_parallelmove(mem1, mem2, xmove, ymove));
}

/*************************************************************************
 * Parallel Moves (whew!)
 ************************************************************************/
short Disasm_parallelmove(LWORD mem1, LWORD mem2,
                          char *xmove, char *ymove)
{
    LWORD  temp_uint;
    char          temp_str1[20];
    char          temp_str2[20];
    char          temp_str3[20];
    char         *dest_move;
    short         mem_req;
    short         mem_spc;


    xmove[0] = '\0';
    ymove[0] = '\0';

/* No parallel move
 * 00100000 00000000 OPCODE
 */
    if ((mem1 & 0xffff00) == 0x200000)
    {
        return(1);
    }

/* U  Address Register Update
 * 00100000 010MMRRR OPCODE
 */
    if ((mem1 & 0xffe000) == 0x204000)
    {
        switch ((mem1 & 0x001800) >> 11)
        {
            case 0:    /* (Rn)-Nn */
                sprintf(xmove, "(%s)-%s",
                        Disasm_ThreeBitRegs_TTT[(mem1 & 0x000700) >> 8],
                        Disasm_ThreeBitRegs_NNN[(mem1 & 0x000700) >> 8]);
                return(1);
            case 1:    /* (Rn)+Nn */
                sprintf(xmove, "(%s)+%s",
                        Disasm_ThreeBitRegs_TTT[(mem1 & 0x000700) >> 8],
                        Disasm_ThreeBitRegs_NNN[(mem1 & 0x000700) >> 8]);
                return(1);
            case 2:    /* (Rn)- */
                sprintf(xmove, "(%s)-",
                        Disasm_ThreeBitRegs_TTT[(mem1 & 0x000700) >> 8]);
                return(1);
            case 3:    /* (Rn)+ */
                sprintf(xmove, "(%s)+",
                        Disasm_ThreeBitRegs_TTT[(mem1 & 0x000700) >> 8]);
                return(1);
        }
        return(0);
    }

/* R  Register to Register Data Move
 * 001000ee eeeddddd OPCODE
 */
    if ((mem1 & 0xfc0000) == 0x200000)
    {
        sprintf(xmove, "%s,%s",
                Disasm_FiveBitRegs_ddddd[(mem1 & 0x03e000) >> 13],
                Disasm_FiveBitRegs_ddddd[(mem1 & 0x001f00) >> 8]);
        return(1);
    }

/* I  Immediate Short Data Move
 * 001ddddd iiiiiiii OPCODE
 */
    if ((mem1 & 0xe00000) == 0x200000)
    {
        sprintf(xmove, "#<$%X,%s", (mem1 & 0x00ff00) >> 8,
                Disasm_FiveBitRegs_ddddd[(mem1 & 0x1f0000) >> 16]);
        return(1);
    }

/* L:  Long Memory Data Move
 * 0100L0LL W1MMMRRR OPCODE  (effective address)
 * 0100L0LL W0aaaaaa OPCODE  (absolute short address)
 */
    if ((mem1 & 0xf40000) == 0x400000)
    {
        if (mem1 & 0x004000)    /* effective address */
        {
            if ((mem1 & 0x003f00) == 0x003000)    /* absolute address */
            {
                mem_spc = 2;
                sprintf(temp_str1, "$%X", mem2);
            }
            else    /* register effective address */
            {
                mem_spc = 1;
                Disasm_FormEALong(temp_str1, mem1);
            }
        }
        else    /* absolute short address */
        {
            mem_spc = 1;
            sprintf(temp_str1, "<$%X", (mem1 & 0x003f00) >> 8);
        }

        temp_uint = ((mem1 & 0x080000) >> 17) | ((mem1 & 0x030000) >> 16);
        if (mem1 & 0x008000)    /* Write */
        {
            sprintf(xmove, "l:%s,%s", temp_str1,
                    Disasm_ThreeBitRegs_LLL[temp_uint]);
        }
        else    /* Read */
        {
            sprintf(xmove, "%s,l:%s", Disasm_ThreeBitRegs_LLL[temp_uint],
                    temp_str1);
        }
        return(mem_spc);
    }

/* X/Y Memory Data Move
 *
 * This is the most complicated parallel move.  It is separated into two
 * situations: 1) Absolute short addressing mode  and 2) all other X or Y
 * memory data moves.
 */
/* Absolute short addressing mode
 * 01ddSddd W0aaaaaa OPCODE
 */
    if ((mem1 & 0xc04000) == 0x400000)     /* absolute short address */
    {
        temp_uint = ((mem1 & 0x300000) >> 17) | ((mem1 & 0x070000) >> 16);
        mem_spc = (mem1 & 0x080000) >> 19;     /* memory space (X=0, Y=1) */
        if (mem1 & 0x008000)       /* Write D */
        {
            sprintf(xmove, "%s:<$%X,%s", Disasm_OneBitSpace_S[mem_spc],
                    (mem1 & 0x003f00) >> 8,
                    Disasm_FiveBitRegs_ddddd[temp_uint]);
        } 
        else                       /* Read S */
        {
            sprintf(xmove, "%s,%s:<$%X", Disasm_FiveBitRegs_ddddd[temp_uint],
                    Disasm_OneBitSpace_S[mem_spc],
                    (mem1 & 0x003f00) >> 8);
        }        
        return(1);
    }

/* Other X/Y memory data moves
 * 01ddSddd W1MMMRRR OPCODE
 */
    if ((mem1 & 0xc04000) == 0x404000)
    {
        temp_uint = ((mem1 & 0x000700) >> 8);  /* register accessed (0-7) */
        mem_spc = (mem1 & 0x080000) >> 19;     /* memory space (X=0, Y=1) */

        if (((mem1 & 0x003800) >> 11) == 6)
        {
            mem_req = 2;
            if (mem1 & 0x000400)
            {
                sprintf(temp_str1, "#$%X", (mem2 & 0xffffff));
            }
            else
            {
                sprintf(temp_str1, "%s:$%X", Disasm_OneBitSpace_S[mem_spc],
                        (mem2 & 0xffffff));
            }
        }
        else
        {
            mem_req = 1;
            Disasm_FormEALong(temp_str2, mem1);
            sprintf(temp_str1, "%s:%s", Disasm_OneBitSpace_S[mem_spc],
                    temp_str2);
        }


        temp_uint = ((mem1 & 0x300000) >> 17) | ((mem1 & 0x070000) >> 16);
        if (mem_spc == 0)
        {
            dest_move = xmove;
        }
        else
        {
            dest_move = ymove;
        }

        if (mem1 & 0x008000)       /* Write D */
        {
            sprintf(dest_move, "%s,%s", temp_str1,
                    Disasm_FiveBitRegs_ddddd[temp_uint]);
        } 
        else                       /* Read S */
        {
            sprintf(dest_move, "%s,%s", Disasm_FiveBitRegs_ddddd[temp_uint],
                    temp_str1);
        }
        return(mem_req);
    }

/* X:R  X Memory and Register Data Move
 * 0001ffdf W0MMMRRR OPCODE  (class I)
 * 0000100d 00MMMRRR OPCODE  (class II)
 */
    if ((mem1 & 0xf04000) == 0x100000)    /* Class I move */
    {
        if ((mem1 & 0x003f00) == 0x003000)    /* absolute address */
        {
            mem_req = 2;
            sprintf(temp_str1, "x:$%X", mem2);
        }
        else if ((mem1 & 0x003f00) == 0x003400)    /* immediate data */
        {
            mem_req = 2;
            sprintf(temp_str1, "#$%X", mem2);
        }
        else    /* effective addressing mode */
        {
            mem_req = 1;
            Disasm_FormEALong(temp_str2, mem1);
            sprintf(temp_str1, "x:%s", temp_str2);
        }

        if (mem1 & 0x008000)    /* Write */
        {
            sprintf(xmove, "%s,%s", temp_str1,
                    Disasm_TwoBitRegs_ee[(mem1 & 0x0c0000) >> 18]);
        }
        else    /* Read */
        {
            sprintf(xmove, "%s,%s",
                    Disasm_TwoBitRegs_ee[(mem1 & 0x0c0000) >> 18],
                    temp_str1);
        }
        sprintf(ymove, "%s,%s",
                Disasm_OneBitRegs_d[(mem1 & 0x020000) >> 17],
                Disasm_OneBitRegs_f[(mem1 & 0x010000) >> 16]);
        return(mem_req);
    }
    if ((mem1 & 0xfec000) == 0x080000)    /* Class II move */
    {
    /* Get effective address or addressing mode */
        if ((mem1 & 0x003f00) == 0x003000)    /* absolute address */
        {
            mem_req = 2;
            sprintf(temp_str1, "x:<$%X", mem2);
        }
        else    /* effective addressing mode */
        {
            mem_req = 1;
            Disasm_FormEALong(temp_str2, mem1);
            sprintf(temp_str1, "x:%s", temp_str2);
        }
        sprintf(xmove, "%s,%s", Disasm_OneBitRegs_d[(mem1 & 0x010000) >> 16],
                temp_str1);
        sprintf(ymove, "x0,%s", Disasm_OneBitRegs_d[(mem1 & 0x010000) >> 16]);
        return(mem_req);
    }

/* R:Y  Y Memory and Register Data Move
 * 0001deff W1MMMRRR OPCODE  (class I)
 * 0000100d 10MMMRRR OPCODE  (class II)
 */
    if ((mem1 & 0xf04000) == 0x104000)    /* Class I move */
    {
        if ((mem1 & 0x003f00) == 0x003000)    /* absolute address */
        {
            mem_req = 2;
            sprintf(temp_str1, "y:$%X", mem2);
        }
        else if ((mem1 & 0x003f00) == 0x003400)    /* immediate data */
        {
            mem_req = 2;
            sprintf(temp_str1, "#$%X", mem2);
        }
        else    /* effective addressing mode */
        {
            mem_req = 1;
            Disasm_FormEALong(temp_str2, mem1);
            sprintf(temp_str1, "y:%s", temp_str2);
        }

        if (mem1 & 0x008000)    /* Write */
        {
            sprintf(ymove, "%s,%s", temp_str1,
                    Disasm_TwoBitRegs_ff[(mem1 & 0x030000) >> 16]);
        }
        else    /* Read */
        {
            sprintf(ymove, "%s,%s",
                    Disasm_TwoBitRegs_ff[(mem1 & 0x030000) >> 16],
                    temp_str1);
        }
        sprintf(xmove, "%s,%s",
                Disasm_OneBitRegs_d[(mem1 & 0x080000) >> 19],
                Disasm_OneBitRegs_e[(mem1 & 0x040000) >> 18]);
        return(mem_req);
    }
    if ((mem1 & 0xfec000) == 0x088000)    /* Class II move */
    {
    /* Get effective address or addressing mode */
        if ((mem1 & 0x003f00) == 0x003000)    /* absolute address */
        {
            mem_req = 2;
            sprintf(temp_str1, "y:$%X", mem2);
        }
        else    /* effective addressing mode */
        {
            mem_req = 1;
            Disasm_FormEALong(temp_str2, mem1);
            sprintf(temp_str1, "y:%s", temp_str2);
        }
        sprintf(xmove, "y0,%s", Disasm_OneBitRegs_d[(mem1 & 0x010000) >> 16]);
        sprintf(ymove, "%s,%s", Disasm_OneBitRegs_d[(mem1 & 0x010000) >> 16],
                temp_str1);
        return(mem_req);
    }

/* X:Y:  XY Memory Data Move
 * 1wmmeeff WrrMMRRR OPCODE
 */
    if ((mem1 & 0x800000) == 0x800000)
    {
    /* Form X: move */
        Disasm_FormEAShort(temp_str1, ((mem1 & 0x000700) >> 8),
                           ((mem1 & 0x001800) >> 11));
        if (mem1 & 0x008000)    /* Write */
        {
            sprintf(xmove, "x:%s,%s", temp_str1,
                    Disasm_TwoBitRegs_ee[(mem1 & 0x0c0000) >> 18]);
        }
        else    /* Read */
        {
            sprintf(xmove, "%s,x:%s",
                    Disasm_TwoBitRegs_ee[(mem1 & 0x0c0000) >> 18],
                    temp_str1);
        }

    /* Form Y: move */
        if (mem1 & 0x000400)    /* eax used R4-R7, so eay must be R0-R3 */
        {
            Disasm_FormEAShort(temp_str1, ((mem1 & 0x006000) >> 13),
                               ((mem1 & 0x300000) >> 20));
        }
        else    /* eax used R0-R3, so eay must be R4-R7 */
        {
            Disasm_FormEAShort(temp_str1, ((mem1 & 0x006000) >> 13) + 4,
                               ((mem1 & 0x300000) >> 20));
        }
        if (mem1 & 0x400000)    /* Write */
        {
            sprintf(ymove, "y:%s,%s", temp_str1,
                    Disasm_TwoBitRegs_ff[(mem1 & 0x030000) >> 16]);
        }
        else    /* Read */
        {
            sprintf(ymove, "%s,y:%s",
                    Disasm_TwoBitRegs_ff[(mem1 & 0x030000) >> 16],
                    temp_str1);
        }

        return(1);
    }

    return(0);
}

/*************************************************************************
 * Function Name: Disasm_disassemble                                     *
 * Author: Jake Janovetz                                                 *
 * Origin Date: 10/01/95                                                 *
 *                                                                       *
 * Inputs: LWORD mem1, mem2 - Two consecutive program words.  The second *
 *                            may not be required, but must be supplied. *
 *         char *opcode     - Buffer where the opcode will be placed.    *
 *         char *operands   - Buffer where the operands will be placed.  *
 *         char *xmove      - Buffer where the xmove will be placed.     *
 *         char *ymove      - Buffer where the ymove will be placed.     *
 *                                                                       *
 * Outputs: 0 if an no matching opcode was found.                        *
 *          1 if the instruction required one (1) program word.          *
 *          2 if the instruction required two (2) program words.         *
 *          The instruction (text) will be placed in the buffers         *
 *          passed to the function.                                      *
 *                                                                       *
 * Description: This function provides the entry point to the dis-       *
 *     assembler.  It takes the memory words and string buffers to       *
 *     place the resulting disassembly.  It first searches through the   *
 *     opcode list to find the opcode.  If a match is found, the         *
 *     appropriate function is called to further disassemble the         *
 *     instruction.  The number of instruction words required for the    *
 *     instruction will be returned.  If a match was not found, then     *
 *     the instruction is unrecognized and zero (0) is returned.         *
 *                                                                       *
 *                                                                       *
 * Major Modification History:                                           *
 * Date:      Name:     Description:                                     *
 * -----      -----     ------------                                     *
 * 10/01/95   Jake J    Creation                                         *
 * 01/20/96   Jake J    Bug fixes.  Added <, << prefixes for short and   *
 *                      I/O short addressing modes.                      *
 ************************************************************************/
short Disasm_disassemble(LWORD mem1, LWORD mem2,
                         char *opcode, char *operands,
                         char *xmove, char *ymove)
{
    int i;

    opcode[0] = '\0';
    operands[0] = '\0';
    xmove[0] = '\0';
    ymove[0] = '\0';
    i=0;
    while (Disasm_List[i].mask != 0)
    {
        if ((mem1 & Disasm_List[i].mask) == Disasm_List[i].iopcode)
        {
            strcpy(opcode, Disasm_List[i].opcode);
            if (Disasm_List[i].disasm_ptr != NULL)
            {
                return(Disasm_List[i].disasm_ptr(mem1, mem2, opcode, operands,
                                                 xmove, ymove));
            }
            else
            {
                return(1);
            }
        }
        i++;
    }

    /*
     * A match wasn't found.  Return an error (0)
     */
    return(0);
}

