/***************************************************************************
**
**  Name:  asm16.cpp
**
**  Description:
**     This is a assembler class file
**
**  Status:  
**
**  $Log:   S:/tbird/mt2_186/dad186/asm16.cpv  $
** 
**    Rev 1.0   16 Dec 1996 15:13:34   Judy
** Initial revision.
** 
**    Rev 1.3   22 Jul 1993 10:12:04   ernie
** Added 1.0.1.0 comment
** 
**    Rev 1.2   15 Jun 1993 11:29:10   mindy
** Change memory write to memory fill to avoid allocating a buffer
** and copying the data.  Also found a sizing problem in DetermineSize.
**
**    Rev 1.1   25 May 1993 12:04:46   ernie
** Changed dasmSym to be system-wide global
** 
**    Rev 1.0.1.0   16 Jun 1993 09:30:00   mindy
** Change memory write to memory fill to avoid allocating a buffer
** and copying the data.  Also found a sizing problem in DetermineSize.
**
**    Rev 1.0   08 Apr 1993 09:41:30   doug
** Initial revision.
** 
**    Rev 1.1   31 Mar 1993 13:52:56   ernie
** (for mindy): added symbol support; fixed uae on exit
** 
**  $Header:   S:/tbird/mt2_186/dad186/asm16.cpv   1.0   16 Dec 1996 15:13:34   Judy  $
**
**  Copyright (C) 1993 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#include <alloc.h>
#include <assoc.h>
#include <dict.h>
#include <shddel.h>
#include <strng.h>

#ifndef _ASM16_
#include "asm16.h"
#endif

#ifndef _DADDEF16_
#include "daddef16.h"
#endif

#ifndef _DSINFO16_
#include "dsinfo16.h"
#endif

#ifndef _ADDR_
#include "addr.h"
#endif

#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef _TBIRDMEM_
#include "tbirdmem.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif


        /****************************
			*                          *
			*     EXTERNALS            *
			*                          *
			****************************/

	     /****************************
			*                          *
			*     LOCAL DEFINITIONS    *
			*                          *
         ****************************/
#define NUM_OPCODES  262
static String opcodeNames[NUM_OPCODES] = {
/*00*/ "aba",   "abx",   "aby",   "abz",   "ace",   "aced",  "adca",  "adcb",
/*08*/ "adcd",  "adce",  "adda",  "addb",  "addd",  "adde",  "ade",   "adx",
/*10*/ "ady",   "adz",   "aex",   "aey",   "aez",   "ais",   "aix",   "aiy",
/*18*/ "aiz",   "anda",  "andb",  "andd",  "ande",  "andp",  "asl",   "asla",
/*20*/ "aslb",  "asld",  "asle",  "aslm",  "aslw",  "asr",   "asra",  "asrb",
/*28*/ "asrd",  "asre",  "asrm",  "asrw",  "bcc",   "bclr",  "bclrw", "bcs",
/*30*/ "beq",   "bge",   "bgnd",  "bgt",   "bhi",   "bita",  "bitb",  "ble",
/*38*/ "bls",   "blt",   "bmi",   "bne",   "bpl",   "bra",   "brclr", "brn",
/*40*/ "brset", "bset",  "bsetw", "bsr",   "bvc",   "bvs",   "cba",   "clr",
/*48*/ "clra",  "clrb",  "clrd",  "clre",  "clrm",  "clrw",  "cmpa",  "cmpb",
/*50*/ "com",   "coma",  "comb",  "comd",  "come",  "comw",  "cpd",   "cpe",
/*58*/ "cps",   "cpx",   "cpy",   "cpz",   "daa",   "dc",    "dec",   "deca",
/*60*/ "decb",  "decw",  "ediv",  "edivs", "emul",  "emuls", "eora",  "eorb",
/*68*/ "eord",  "eore",  "fdiv",  "fmuls", "idiv",  "inc",   "inca",  "incb",
/*70*/ "incw",  "jmp",   "jsr",   "lbcc",  "lbcs",  "lbeq",  "lbev",  "lbge",
/*78*/ "lbgt",  "lbhi",  "lble",  "lbls",  "lblt",  "lbmi",  "lbmv",  "lbne",
/*80*/ "lbpl",  "lbra",  "lbrn",  "lbsr",  "lbvc",  "lbvs",  "ldaa",  "ldab",
/*88*/ "ldd",   "lde",   "lded",  "ldhi",  "lds",   "ldx",   "ldy",   "ldz",
/*90*/ "lpstop","lsr",   "lsra",  "lsrb",  "lsrd",  "lsre",  "lsrw",  "mac",
/*98*/ "movb",  "movw",  "mul",   "neg",   "nega",  "negb",  "negd",  "nege",
/*A0*/ "negw",  "nop",   "oraa",  "orab",  "ord",   "ore",   "orp",   "psha",
/*A8*/ "pshb",  "pshm",  "pshmac","pula",  "pulb",  "pulm",  "pulmac","rmac",
/*B0*/ "rol",   "rola",  "rolb",  "rold",  "role",  "rolw",  "ror",   "rora",
/*B8*/ "rorb",  "rord",  "rore",  "rorw",  "rti",   "rts",   "sba",   "sbca",
/*C0*/ "sbcb",  "sbcd",  "sbce",  "sde",   "staa",  "stab",  "std",   "ste",
/*C8*/ "sted",  "sts",   "stx",   "sty",   "stz",   "suba",  "subb",  "subd",
/*D0*/ "sube",  "swi",   "sxt",   "tab",   "tap",   "tba",   "tbek",  "tbsk",
/*D8*/ "tbxk",  "tbyk",  "tbzk",  "tde",   "tdmsk", "tdp",   "ted",   "tedm",
/*E0*/ "tekb",  "tem",   "tmer",  "tmet",  "tmxed", "tpa",   "tpd",   "tskb",
/*E8*/ "tst",   "tsta",  "tstb",  "tstd",  "tste",  "tstw",  "tsx",   "tsy",
/*F0*/ "tsz",   "txkb",  "txs",   "txy",   "txz",   "tykb",  "tys",   "tyx",
/*F8*/ "tyz",   "tzkb",  "tzs",   "tzx",   "tzy",   "wai",   "xgab",  "xgde",
/*100*/"xgdx",  "xgdy",  "xgdz",  "xgex",  "xgey",  "xgez"
};

static OpcodeInfo opcodeInfos[NUM_OPCODES] = {
/*00*/ OpcodeInfo(OpcodeInfo::OG16,0x0B), OpcodeInfo(OpcodeInfo::OG16,0x4F),
/*02*/ OpcodeInfo(OpcodeInfo::OG16,0x5F), OpcodeInfo(OpcodeInfo::OG16,0x6F),
/*04*/ OpcodeInfo(OpcodeInfo::OG16,0x22), OpcodeInfo(OpcodeInfo::OG16,0x23),
/*06*/ OpcodeInfo(OpcodeInfo::OG1, 0x43), OpcodeInfo(OpcodeInfo::OG1, 0xC3),
/*08*/ OpcodeInfo(OpcodeInfo::OG4, 0x83), OpcodeInfo(OpcodeInfo::OG2, 0x33),
/*0A*/ OpcodeInfo(OpcodeInfo::OG1, 0x41), OpcodeInfo(OpcodeInfo::OG1, 0xC1),
/*0C*/ OpcodeInfo(OpcodeInfo::OG24,0x81), OpcodeInfo(OpcodeInfo::OG3, 0x31),
/*0E*/ OpcodeInfo(OpcodeInfo::OG17,0x78), OpcodeInfo(OpcodeInfo::OG16,0xCD),
/*10*/ OpcodeInfo(OpcodeInfo::OG16,0xDD), OpcodeInfo(OpcodeInfo::OG16,0xED),
/*12*/ OpcodeInfo(OpcodeInfo::OG16,0x4D), OpcodeInfo(OpcodeInfo::OG16,0x5D),
/*14*/ OpcodeInfo(OpcodeInfo::OG16,0x6D), OpcodeInfo(OpcodeInfo::OG7, 0x3F),
/*16*/ OpcodeInfo(OpcodeInfo::OG7, 0x3C), OpcodeInfo(OpcodeInfo::OG7, 0x3D),
/*18*/ OpcodeInfo(OpcodeInfo::OG7, 0x3E), OpcodeInfo(OpcodeInfo::OG1, 0x46),
/*1A*/ OpcodeInfo(OpcodeInfo::OG1, 0xC6), OpcodeInfo(OpcodeInfo::OG4, 0x86),
/*1C*/ OpcodeInfo(OpcodeInfo::OG2, 0x36), OpcodeInfo(OpcodeInfo::OG12,0x3A),
/*1E*/ OpcodeInfo(OpcodeInfo::OG6, 0x04), OpcodeInfo(OpcodeInfo::OG16,0x04),
/*20*/ OpcodeInfo(OpcodeInfo::OG16,0x14), OpcodeInfo(OpcodeInfo::OG17,0xF4),
/*22*/ OpcodeInfo(OpcodeInfo::OG17,0x74), OpcodeInfo(OpcodeInfo::OG17,0xB6),
/*24*/ OpcodeInfo(OpcodeInfo::OG5, 0x04), OpcodeInfo(OpcodeInfo::OG6, 0x0D),
/*26*/ OpcodeInfo(OpcodeInfo::OG16,0x0D), OpcodeInfo(OpcodeInfo::OG16,0x1D),
/*28*/ OpcodeInfo(OpcodeInfo::OG17,0xFD), OpcodeInfo(OpcodeInfo::OG17,0x7D),
/*2A*/ OpcodeInfo(OpcodeInfo::OG17,0xBA), OpcodeInfo(OpcodeInfo::OG5, 0x0D),
/*2C*/ OpcodeInfo(OpcodeInfo::OG13,0xB4), OpcodeInfo(OpcodeInfo::OG26,0x08),
/*2E*/ OpcodeInfo(OpcodeInfo::OG28,0x08), OpcodeInfo(OpcodeInfo::OG13,0xB5),
/*30*/ OpcodeInfo(OpcodeInfo::OG13,0xB7), OpcodeInfo(OpcodeInfo::OG13,0xBC),
/*32*/ OpcodeInfo(OpcodeInfo::OG16,0xA6), OpcodeInfo(OpcodeInfo::OG13,0xBE),
/*34*/ OpcodeInfo(OpcodeInfo::OG13,0xB2), OpcodeInfo(OpcodeInfo::OG1, 0x49),
/*36*/ OpcodeInfo(OpcodeInfo::OG1, 0xC9), OpcodeInfo(OpcodeInfo::OG13,0xBF),
/*38*/ OpcodeInfo(OpcodeInfo::OG13,0xB3), OpcodeInfo(OpcodeInfo::OG13,0xBD),
/*3A*/ OpcodeInfo(OpcodeInfo::OG13,0xBB), OpcodeInfo(OpcodeInfo::OG13,0xB6),
/*3C*/ OpcodeInfo(OpcodeInfo::OG13,0xBA), OpcodeInfo(OpcodeInfo::OG13,0xB0),
/*3E*/ OpcodeInfo(OpcodeInfo::OG18,0x0A), OpcodeInfo(OpcodeInfo::OG13,0xB1),
/*40*/ OpcodeInfo(OpcodeInfo::OG19,0x0B), OpcodeInfo(OpcodeInfo::OG26,0x09),
/*42*/ OpcodeInfo(OpcodeInfo::OG28,0x09), OpcodeInfo(OpcodeInfo::OG13,0x36),
/*44*/ OpcodeInfo(OpcodeInfo::OG13,0xB8), OpcodeInfo(OpcodeInfo::OG13,0xB9),
/*46*/ OpcodeInfo(OpcodeInfo::OG16,0x1B), OpcodeInfo(OpcodeInfo::OG6, 0x05),
/*48*/ OpcodeInfo(OpcodeInfo::OG16,0x05), OpcodeInfo(OpcodeInfo::OG16,0x15),
/*4A*/ OpcodeInfo(OpcodeInfo::OG17,0xF5), OpcodeInfo(OpcodeInfo::OG17,0x75),
/*4C*/ OpcodeInfo(OpcodeInfo::OG17,0xB7), OpcodeInfo(OpcodeInfo::OG5, 0x05),
/*4E*/ OpcodeInfo(OpcodeInfo::OG1, 0x48), OpcodeInfo(OpcodeInfo::OG1, 0xC8),
/*50*/ OpcodeInfo(OpcodeInfo::OG6, 0x00), OpcodeInfo(OpcodeInfo::OG16,0x00),
/*52*/ OpcodeInfo(OpcodeInfo::OG16,0x10), OpcodeInfo(OpcodeInfo::OG17,0xF0),
/*54*/ OpcodeInfo(OpcodeInfo::OG17,0x70), OpcodeInfo(OpcodeInfo::OG5, 0x00),
/*56*/ OpcodeInfo(OpcodeInfo::OG4, 0x88), OpcodeInfo(OpcodeInfo::OG2, 0x38),
/*58*/ OpcodeInfo(OpcodeInfo::OG20,0x4F), OpcodeInfo(OpcodeInfo::OG20,0x4C),
/*5A*/ OpcodeInfo(OpcodeInfo::OG20,0x4D), OpcodeInfo(OpcodeInfo::OG20,0x4E),
/*5C*/ OpcodeInfo(OpcodeInfo::OG16,0x21), OpcodeInfo(OpcodeInfo::OG30,0x01),
/*5E*/ OpcodeInfo(OpcodeInfo::OG6, 0x01), OpcodeInfo(OpcodeInfo::OG16,0x01), 
/*60*/ OpcodeInfo(OpcodeInfo::OG16,0x11), OpcodeInfo(OpcodeInfo::OG5, 0x01), 
/*62*/ OpcodeInfo(OpcodeInfo::OG16,0x28), OpcodeInfo(OpcodeInfo::OG16,0x29), 
/*64*/ OpcodeInfo(OpcodeInfo::OG16,0x25), OpcodeInfo(OpcodeInfo::OG16,0x26), 
/*66*/ OpcodeInfo(OpcodeInfo::OG1, 0x44), OpcodeInfo(OpcodeInfo::OG1, 0xC4), 
/*68*/ OpcodeInfo(OpcodeInfo::OG4, 0x84), OpcodeInfo(OpcodeInfo::OG2, 0x34), 
/*6A*/ OpcodeInfo(OpcodeInfo::OG16,0x2B), OpcodeInfo(OpcodeInfo::OG16,0x27), 
/*6C*/ OpcodeInfo(OpcodeInfo::OG16,0x2A), OpcodeInfo(OpcodeInfo::OG6, 0x03), 
/*6E*/ OpcodeInfo(OpcodeInfo::OG16,0x03), OpcodeInfo(OpcodeInfo::OG16,0x13), 
/*70*/ OpcodeInfo(OpcodeInfo::OG5, 0x03), OpcodeInfo(OpcodeInfo::OG8, 0x4B), 
/*72*/ OpcodeInfo(OpcodeInfo::OG27,0x89), OpcodeInfo(OpcodeInfo::OG14,0x84), 
/*74*/ OpcodeInfo(OpcodeInfo::OG14,0x85), OpcodeInfo(OpcodeInfo::OG14,0x87), 
/*76*/ OpcodeInfo(OpcodeInfo::OG14,0x91), OpcodeInfo(OpcodeInfo::OG14,0x8C), 
/*78*/ OpcodeInfo(OpcodeInfo::OG14,0x8E), OpcodeInfo(OpcodeInfo::OG14,0x82), 
/*7A*/ OpcodeInfo(OpcodeInfo::OG14,0x8F), OpcodeInfo(OpcodeInfo::OG14,0x83), 
/*7C*/ OpcodeInfo(OpcodeInfo::OG14,0x8D), OpcodeInfo(OpcodeInfo::OG14,0x8B), 
/*7E*/ OpcodeInfo(OpcodeInfo::OG14,0x90), OpcodeInfo(OpcodeInfo::OG14,0x86), 
/*80*/ OpcodeInfo(OpcodeInfo::OG14,0x8A), OpcodeInfo(OpcodeInfo::OG14,0x80), 
/*82*/ OpcodeInfo(OpcodeInfo::OG14,0x81), OpcodeInfo(OpcodeInfo::OG29,0xF9), 
/*84*/ OpcodeInfo(OpcodeInfo::OG14,0x88), OpcodeInfo(OpcodeInfo::OG14,0x89), 
/*86*/ OpcodeInfo(OpcodeInfo::OG1, 0x45), OpcodeInfo(OpcodeInfo::OG1, 0xC5), 
/*88*/ OpcodeInfo(OpcodeInfo::OG4, 0x85), OpcodeInfo(OpcodeInfo::OG2, 0x35), 
/*8A*/ OpcodeInfo(OpcodeInfo::OG15,0x71), OpcodeInfo(OpcodeInfo::OG17,0xB0), 
/*8C*/ OpcodeInfo(OpcodeInfo::OG21,0xBF), OpcodeInfo(OpcodeInfo::OG21,0xBC), 
/*8E*/ OpcodeInfo(OpcodeInfo::OG21,0xBD), OpcodeInfo(OpcodeInfo::OG21,0xBE), 
/*90*/ OpcodeInfo(OpcodeInfo::OG17,0xF1), OpcodeInfo(OpcodeInfo::OG6, 0x0F), 
/*92*/ OpcodeInfo(OpcodeInfo::OG16,0x0F), OpcodeInfo(OpcodeInfo::OG16,0x1F), 
/*94*/ OpcodeInfo(OpcodeInfo::OG17,0xFF), OpcodeInfo(OpcodeInfo::OG17,0x7F), 
/*96*/ OpcodeInfo(OpcodeInfo::OG5, 0x0F), OpcodeInfo(OpcodeInfo::OG11,0x7B), 
/*98*/ OpcodeInfo(OpcodeInfo::OG9, 0x30), OpcodeInfo(OpcodeInfo::OG9, 0x31), 
/*9A*/ OpcodeInfo(OpcodeInfo::OG16,0x24), OpcodeInfo(OpcodeInfo::OG6, 0x02), 
/*9C*/ OpcodeInfo(OpcodeInfo::OG16,0x02), OpcodeInfo(OpcodeInfo::OG16,0x12), 
/*9E*/ OpcodeInfo(OpcodeInfo::OG17,0xF2), OpcodeInfo(OpcodeInfo::OG17,0x72), 
/*A0*/ OpcodeInfo(OpcodeInfo::OG5, 0x02), OpcodeInfo(OpcodeInfo::OG17,0x4C), 
/*A2*/ OpcodeInfo(OpcodeInfo::OG1, 0x47), OpcodeInfo(OpcodeInfo::OG1, 0xC7), 
/*A4*/ OpcodeInfo(OpcodeInfo::OG4, 0x87), OpcodeInfo(OpcodeInfo::OG2, 0x37), 
/*A6*/ OpcodeInfo(OpcodeInfo::OG12,0x3B), OpcodeInfo(OpcodeInfo::OG16,0x08), 
/*A8*/ OpcodeInfo(OpcodeInfo::OG16,0x18), OpcodeInfo(OpcodeInfo::OG25,0x34), 
/*AA*/ OpcodeInfo(OpcodeInfo::OG17,0xB8), OpcodeInfo(OpcodeInfo::OG16,0x09), 
/*AC*/ OpcodeInfo(OpcodeInfo::OG16,0x19), OpcodeInfo(OpcodeInfo::OG25,0x35), 
/*AE*/ OpcodeInfo(OpcodeInfo::OG17,0xB9), OpcodeInfo(OpcodeInfo::OG11,0xFB), 
/*B0*/ OpcodeInfo(OpcodeInfo::OG6, 0x0C), OpcodeInfo(OpcodeInfo::OG16,0x0C), 
/*B2*/ OpcodeInfo(OpcodeInfo::OG16,0x1C), OpcodeInfo(OpcodeInfo::OG17,0xFC), 
/*B4*/ OpcodeInfo(OpcodeInfo::OG17,0x7C), OpcodeInfo(OpcodeInfo::OG5, 0x0C), 
/*B6*/ OpcodeInfo(OpcodeInfo::OG6, 0x0E), OpcodeInfo(OpcodeInfo::OG16,0x0E), 
/*B8*/ OpcodeInfo(OpcodeInfo::OG16,0x1E), OpcodeInfo(OpcodeInfo::OG17,0xFE), 
/*BA*/ OpcodeInfo(OpcodeInfo::OG17,0x7E), OpcodeInfo(OpcodeInfo::OG5, 0x0E), 
/*BC*/ OpcodeInfo(OpcodeInfo::OG17,0x77), OpcodeInfo(OpcodeInfo::OG17,0xF7), 
/*BE*/ OpcodeInfo(OpcodeInfo::OG16,0x0A), OpcodeInfo(OpcodeInfo::OG1, 0x42), 
/*C0*/ OpcodeInfo(OpcodeInfo::OG1, 0xC2), OpcodeInfo(OpcodeInfo::OG4, 0x82), 
/*C2*/ OpcodeInfo(OpcodeInfo::OG2, 0x32), OpcodeInfo(OpcodeInfo::OG17,0x79), 
/*C4*/ OpcodeInfo(OpcodeInfo::OG10,0x4A), OpcodeInfo(OpcodeInfo::OG10,0xCA), 
/*C6*/ OpcodeInfo(OpcodeInfo::OG23,0x8A), OpcodeInfo(OpcodeInfo::OG22,0x4A), 
/*C8*/ OpcodeInfo(OpcodeInfo::OG15,0x73), OpcodeInfo(OpcodeInfo::OG6, 0x8F), 
/*CA*/ OpcodeInfo(OpcodeInfo::OG6, 0x8C), OpcodeInfo(OpcodeInfo::OG6, 0x8D), 
/*CC*/ OpcodeInfo(OpcodeInfo::OG6, 0x8E), OpcodeInfo(OpcodeInfo::OG1, 0x40), 
/*CE*/ OpcodeInfo(OpcodeInfo::OG1, 0xC0), OpcodeInfo(OpcodeInfo::OG4, 0x80), 
/*D0*/ OpcodeInfo(OpcodeInfo::OG2, 0x30), OpcodeInfo(OpcodeInfo::OG16,0x20), 
/*D2*/ OpcodeInfo(OpcodeInfo::OG17,0xF8), OpcodeInfo(OpcodeInfo::OG16,0x17), 
/*D4*/ OpcodeInfo(OpcodeInfo::OG16,0xFD), OpcodeInfo(OpcodeInfo::OG16,0x07), 
/*D6*/ OpcodeInfo(OpcodeInfo::OG17,0xFA), OpcodeInfo(OpcodeInfo::OG16,0x9F), 
/*D8*/ OpcodeInfo(OpcodeInfo::OG16,0x9C), OpcodeInfo(OpcodeInfo::OG16,0x9D), 
/*DA*/ OpcodeInfo(OpcodeInfo::OG16,0x9E), OpcodeInfo(OpcodeInfo::OG17,0x7B), 
/*DC*/ OpcodeInfo(OpcodeInfo::OG16,0x2F), OpcodeInfo(OpcodeInfo::OG16,0x2D), 
/*DE*/ OpcodeInfo(OpcodeInfo::OG17,0xFB), OpcodeInfo(OpcodeInfo::OG17,0xB1), 
/*E0*/ OpcodeInfo(OpcodeInfo::OG17,0xBB), OpcodeInfo(OpcodeInfo::OG17,0xB2), 
/*E2*/ OpcodeInfo(OpcodeInfo::OG17,0xB4), OpcodeInfo(OpcodeInfo::OG17,0xB5), 
/*E4*/ OpcodeInfo(OpcodeInfo::OG17,0xB3), OpcodeInfo(OpcodeInfo::OG16,0xFC), 
/*E6*/ OpcodeInfo(OpcodeInfo::OG16,0x2C), OpcodeInfo(OpcodeInfo::OG16,0xAF), 
/*E8*/ OpcodeInfo(OpcodeInfo::OG6, 0x06), OpcodeInfo(OpcodeInfo::OG16,0x06), 
/*EA*/ OpcodeInfo(OpcodeInfo::OG16,0x16), OpcodeInfo(OpcodeInfo::OG17,0xF6), 
/*EC*/ OpcodeInfo(OpcodeInfo::OG17,0x76), OpcodeInfo(OpcodeInfo::OG5, 0x06), 
/*EE*/ OpcodeInfo(OpcodeInfo::OG17,0x4F), OpcodeInfo(OpcodeInfo::OG17,0x5F), 
/*F0*/ OpcodeInfo(OpcodeInfo::OG17,0x6F), OpcodeInfo(OpcodeInfo::OG16,0xAC), 
/*F2*/ OpcodeInfo(OpcodeInfo::OG16,0x4E), OpcodeInfo(OpcodeInfo::OG17,0x5C), 
/*F4*/ OpcodeInfo(OpcodeInfo::OG17,0x6C), OpcodeInfo(OpcodeInfo::OG16,0xAD), 
/*F6*/ OpcodeInfo(OpcodeInfo::OG16,0x5E), OpcodeInfo(OpcodeInfo::OG17,0x4D), 
/*F8*/ OpcodeInfo(OpcodeInfo::OG17,0x6D), OpcodeInfo(OpcodeInfo::OG16,0xAE), 
/*FA*/ OpcodeInfo(OpcodeInfo::OG16,0x6E), OpcodeInfo(OpcodeInfo::OG17,0x4E), 
/*FC*/ OpcodeInfo(OpcodeInfo::OG17,0x5E), OpcodeInfo(OpcodeInfo::OG17,0xF3), 
/*FE*/ OpcodeInfo(OpcodeInfo::OG16,0x1A), OpcodeInfo(OpcodeInfo::OG17,0x7A), 
/*100*/OpcodeInfo(OpcodeInfo::OG16,0xCC), OpcodeInfo(OpcodeInfo::OG16,0xDC), 
/*102*/OpcodeInfo(OpcodeInfo::OG16,0xEC), OpcodeInfo(OpcodeInfo::OG16,0x4C), 
/*104*/OpcodeInfo(OpcodeInfo::OG16,0x5C), OpcodeInfo(OpcodeInfo::OG16,0x6C)
};

typedef RETCODE (AsmInfo::*OPGROUP_FUNC)(OpcodeInfo);
static OPGROUP_FUNC groupFunctions[30] = {
   &AsmInfo::OpGrp1, &AsmInfo::OpGrp2, &AsmInfo::OpGrp3, &AsmInfo::OpGrp4,    
   &AsmInfo::OpGrp5, &AsmInfo::OpGrp6, &AsmInfo::OpGrp7, &AsmInfo::OpGrp8,    
   &AsmInfo::OpGrp9, &AsmInfo::OpGrp10,&AsmInfo::OpGrp11,&AsmInfo::OpGrp12,    
   &AsmInfo::OpGrp13,&AsmInfo::OpGrp14,&AsmInfo::OpGrp15,&AsmInfo::OpGrp16,    
   &AsmInfo::OpGrp17,&AsmInfo::OpGrp18,&AsmInfo::OpGrp19,&AsmInfo::OpGrp20,    
   &AsmInfo::OpGrp21,&AsmInfo::OpGrp22,&AsmInfo::OpGrp23,&AsmInfo::OpGrp24,
   &AsmInfo::OpGrp25,&AsmInfo::OpGrp26,&AsmInfo::OpGrp27,&AsmInfo::OpGrp28,
   &AsmInfo::OpGrp29,&AsmInfo::OpGrp30
};
   
static Dictionary opcodes;
   
                        /***************************
                        *                          *
                        *    PROTOTYPES            *
                        *                          *
                        ***************************/

                         /***************************
                         *                          *
                         *     EXECUTABLE CODE      *
                         *                          *
                         ***************************/
RETCODE EXPORT AsmInit(VOID) {
   opcodes.ownsElements(TShouldDelete::NoDelete);
   for( int i = 0; i < NUM_OPCODES; i++ ) {
      Association *entry = new Association( opcodeNames[i], opcodeInfos[i] );
      opcodes.add( *entry );
   }
   return(GOOD);
}

#ifdef SA_ASM
int main( int argc, char *argv[] )
{  AsmInfo asmInst = AsmInfo(0);
   FILE *asmHandle;
   char buf[255];
   LPSTR outBuf;
   if( argc < 1 ) return(3);
   AsmInit();
   asmHandle = fopen("asmhc16.tst", "r");
   if(asmHandle == NULL) /* configuration file not opened */
      return(1) ;
   while(fgets(buf,255,asmHandle) != NULL) {
      /* just return one line at a time - since test file is made up
         of one instruction per line!
      */
      if(asmInst.Asm(buf,&outBuf)==GOOD) {
         printf("%s",outBuf);
         free(outBuf);
      }
   }
   fclose(asmHandle) ;
   return(0);
}
#endif
   
/*****************************************************************************
** CLASS: AsmInfo
*/
                       /****************************
                        *      PUBLIC MEMBERS      *
                        ****************************/
AsmInfo::AsmInfo(U32 addr) {
   AdrDuplicateAddress(addr,&pcAddress);
}

RETCODE AsmInfo::Asm(LPSTR userAsm, LPSTR *outAsm) {
   char test[20];
   RETCODE err=GOOD;
   instLength = 0;
   maskedTransfer = FALSE;
   codePtr = hexCode;
   addrMode.maskedInst = FALSE;
   if((err=ParseString(userAsm))!=GOOD) return(err);
   Association& oPtr = opcodes.lookup (*new String(tokens[0]));
   if( oPtr == NOOBJECT ) {
      strcpy(test,"ILLEGAL INSTRUCTION");
      return(ER_DAD_NO_SUCH_INST);
   }
   OpcodeInfo& info = (OpcodeInfo&)oPtr.value();
   err=(this->*groupFunctions[info.Group()])(info); 
   if( err ) {
      strcpy(test,"ILLEGAL INSTRUCTION");
      return(err);
   }
   DasmInfo checkIt = DasmInfo(pcAddress);
   WriteCodeBuffer();      /* updates pcAddress */
   if((*outAsm=TMalloc(MAX_LINE_LENGTH))==NULL) return(ER_OUT_OF_MEMORY);
   **outAsm = '\0';
   checkIt.Disassemble(*outAsm);
   if((err=AdrAddToAddress(pcAddress, instLength))!=GOOD) return(err);
   return(GOOD);
}

RETCODE AsmInfo::SetStartAddress(DESCRIPTOR addr) {
   return(AdrDuplicateAddress(addr,&pcAddress));
}

RETCODE AsmInfo::GetStartAddress(DESCRIPTOR *addr) {
   return(AdrDuplicateAddress(pcAddress, addr));
}

U16 AsmInfo::InstructionLength() {
   return(instLength);
}

U8 AsmInfo::ModOpcodeForIndexReg(U8 opcode) {
   switch( addrMode.reg ) {
      case YREG: return(opcode | 0x10);
      case ZREG: return(opcode | 0x20);
      default: return(opcode);
   }
}

RETCODE AsmInfo::OpGrp1(OpcodeInfo info) {
//  OG1 - ind8,(X|Y|X);  imm8;  ind16,(X|Y|Z);  ext;  E,(X|Y|Z)
   switch( addrMode.type ) {
      case ACCOFF:
         PutNextCodeByte(PAGE2);
         PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
         break;
      case EXT:
         PutNextCodeByte(PAGE1);
         PutNextCodeByte(info.opValue()|0x30);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 1);
         }
         else {
            PutNextCodeByte(PAGE1);
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 2);
         }
         break;
      case IMMED:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(info.opValue()|0x30);
            PutCodeBytes(addrMode.data, 1);
            break;
         }
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp2(OpcodeInfo info) {
//       OG2 - imm16;  ind16,(X|Y|Z);  ext;
   switch( addrMode.type ) {
      case EXT:
         PutNextCodeByte(PAGE3);
         PutNextCodeByte(info.opValue()+0x40);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( (addrMode.size == BYTESIZE) || (addrMode.size == WORDSIZE) ) {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(ModOpcodeForIndexReg((info.opValue()+0x10)));
            PutCodeBytes(addrMode.data, 2);
            break;
         }
      case IMMED:
         if( (addrMode.size == BYTESIZE) || (addrMode.size == WORDSIZE) ) {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(info.opValue());
            PutCodeBytes(addrMode.data, 2);
            break;
         }
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp3(OpcodeInfo info){
//    OG3 - imm8;  imm16;  ind16,(X|Y|Z); ext         (adde)
   switch( addrMode.type ) {
      case EXT:
         PutNextCodeByte(PAGE3);
         PutNextCodeByte(info.opValue()+0x40);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( (addrMode.size == BYTESIZE) || (addrMode.size == WORDSIZE) ) {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(ModOpcodeForIndexReg((info.opValue()+0x10)));
            PutCodeBytes(addrMode.data, 2);
            break;
         }
      case IMMED:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(0x7C);
            PutCodeBytes(addrMode.data, 1);
            break;
         }
         else if( addrMode.size == WORDSIZE ) {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(info.opValue());
            PutCodeBytes(addrMode.data, 2);
            break;
         }
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp4(OpcodeInfo info){
//    OG4 - ind8,(X|Y|X);  imm16;  ind16,(X|Y|Z);  ext;  E,(X|Y|Z)
   switch( addrMode.type ) {
      case ACCOFF:
         PutNextCodeByte(PAGE2);
         PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
         break;
      case EXT:
         PutNextCodeByte(PAGE3);
         PutNextCodeByte(info.opValue()|0xF0);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 1);
         }
         else {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()|0x40));
            PutCodeBytes(addrMode.data, 2);
         }
         break;
      case IMMED:
         if( (addrMode.size == BYTESIZE) || (addrMode.size == WORDSIZE) ) {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(info.opValue()|0x30);
            PutCodeBytes(addrMode.data, 2);
            break;
         }
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp5(OpcodeInfo info){
//       OG5 - ind16,(X|Y|Z);  ext
   switch( addrMode.type ) {
      case EXT:
         PutNextCodeByte(PAGE2);
         PutNextCodeByte(info.opValue()|0x30);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( (addrMode.size == BYTESIZE) || (addrMode.size == WORDSIZE) ) {
            PutNextCodeByte(PAGE2);
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 2);
            break;
         }
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp6(OpcodeInfo info){
//    OG6 - ind8,(X|Y|X);  ind16,(X|Y|Z);  ext
   switch( addrMode.type ) {
      case EXT:
         PutNextCodeByte(PAGE1);
         PutNextCodeByte(info.opValue()|0x30);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 1);
            break;
         }
         else if( addrMode.size == WORDSIZE ) {
            PutNextCodeByte(PAGE1);
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 2);
            break;
         }            
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp7(OpcodeInfo info){
//    OG7 - imm8;  imm16
   switch( addrMode.type ) {
      case IMMED:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(info.opValue());
            PutCodeBytes(addrMode.data, 1);
            break;
         }
         else if( addrMode.size == WORDSIZE ) {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(info.opValue());
            PutCodeBytes(addrMode.data, 2);
            break;
         }
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp8(OpcodeInfo info){
//    OG8 - ext20;  ind20,(X|Y|Z) (jmp)
   switch( addrMode.type ) {
      case EXT:
      case ABS:         // if a symbolic was used type was be ABS!
         PutNextCodeByte(0x7A);
         PutCodeBytes(addrMode.effAddr&0xfffffL, 3);
         break;
      case INDEX:
         PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
         PutCodeBytes(addrMode.data&0xfffffL, 3);
         break;
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp9(OpcodeInfo info){
//    OG9 - IXP to ext;  ext TO IXP;  ext to ext
   switch( addrMode.type ) {
      case I_TO_E:
         PutNextCodeByte(info.opValue());
         PutCodeBytes(addrMode.data, 1);
         PutCodeBytes(addrMode.effAddr,2);
         break;
      case E_TO_I:
         PutNextCodeByte(info.opValue()|0x2);
         PutCodeBytes(addrMode.data, 1);
         PutCodeBytes(addrMode.effAddr,2);
         break;
      case E_TO_E: 
         PutNextCodeByte(PAGE3);
         PutNextCodeByte(info.opValue()|0xFE);
         PutCodeBytes(addrMode.effAddr,2);
         PutCodeBytes(addrMode.effAddr2,2);
         break;
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp10(OpcodeInfo info){
//    OG10 - ind8,(X|Y|X);  ind16,(X|Y|Z);  ext;  E,(X|Y|Z)
   switch( addrMode.type ) {
      case ACCOFF:
         PutNextCodeByte(PAGE2);
         PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
         break;
      case EXT:
         PutNextCodeByte(PAGE1);
         PutNextCodeByte(info.opValue()|0x30);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 1);
         }
         else {
            PutNextCodeByte(PAGE1);
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 2);
         }
         break;
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp11(OpcodeInfo info){
   if( addrMode.type == XOYO ) {
      PutNextCodeByte(info.opValue());
      PutCodeBytes(addrMode.data, 1);
      return(GOOD);
   }
   return(ER_DAD_INVALID_MODE_FOR_INST);
}

RETCODE AsmInfo::OpGrp12(OpcodeInfo info){
   if( addrMode.type == IMMED ) {
      PutNextCodeByte(PAGE3);
      PutNextCodeByte(info.opValue());
      PutCodeBytes(addrMode.data, 2);
      return(GOOD);
   }
   return(ER_DAD_INVALID_MODE_FOR_INST);
}

RETCODE AsmInfo::OpGrp13(OpcodeInfo info){
// <opcode>  rel8   
   if( (addrMode.type == EXT) || (addrMode.type == ABS) ) {
      PutNextCodeByte(info.opValue());
      return(CalculateDisplacement(addrMode.effAddr,FALSE));
   }
   return(ER_DAD_INVALID_MODE_FOR_INST);
}

RETCODE AsmInfo::OpGrp14(OpcodeInfo info){
// <opcode>  rel16   
   if( (addrMode.type == EXT) || (addrMode.type == ABS) ) {
      PutNextCodeByte(PAGE3);
      PutNextCodeByte(info.opValue());
      return(CalculateDisplacement(addrMode.effAddr,TRUE));
   }
   return(ER_DAD_INVALID_MODE_FOR_INST);
}

RETCODE AsmInfo::OpGrp15(OpcodeInfo info){
//       OG15 - ext
   if( addrMode.type == EXT ) {
      PutNextCodeByte(PAGE2);
      PutNextCodeByte(info.opValue());
      PutCodeBytes(addrMode.effAddr, 2);
      return(GOOD);
   }
   return(ER_DAD_INVALID_MODE_FOR_INST);
}

RETCODE AsmInfo::OpGrp16(OpcodeInfo info){
//    OG16 - inh with $37 prebyte
   if( addrMode.type == INH ) {
      PutNextCodeByte(PAGE3);
      PutNextCodeByte(info.opValue());
      return(GOOD);
   }
   return(ER_DAD_INVALID_MODE_FOR_INST);
}

RETCODE AsmInfo::OpGrp17(OpcodeInfo info){
//    OG17 - inh with $27 prebyte
   if( addrMode.type == INH ) {
      PutNextCodeByte(PAGE2);
      PutNextCodeByte(info.opValue());
      return(GOOD);
   }
   return(ER_DAD_INVALID_MODE_FOR_INST);
}

RETCODE AsmInfo::OpGrp18(OpcodeInfo info){
//    OG18 - ind8,(X|Y|X);  ind16,(X|Y|Z);  ext   (brclr)
   if( maskedTransfer != TRUE ) return(ER_DAD_BAD_MASKED_INST_FORMAT);
   switch( addrMode.type ) {
      case EXT:
         PutNextCodeByte(info.opValue()|0x30);
         PutNextCodeByte((U8)addrMode.mask);
         PutCodeBytes(addrMode.effAddr, 2);
         return(CalculateDisplacement(addrMode.effAddr2,TRUE));
      case INDEX:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(0xCB));
            PutNextCodeByte((U8)addrMode.mask);
            PutCodeBytes(addrMode.data, 1);
            return(CalculateDisplacement(addrMode.effAddr2,FALSE));
         }
         else if( addrMode.size == WORDSIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutNextCodeByte((U8)addrMode.mask);
            PutCodeBytes(addrMode.data, 2);
            return(CalculateDisplacement(addrMode.effAddr2,TRUE));
         }            
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
}

RETCODE AsmInfo::OpGrp19(OpcodeInfo info){
//    OG19 - ind8,(X|Y|X);  ind16,(X|Y|Z);  ext   (brset)
   if( maskedTransfer != TRUE ) return(ER_DAD_BAD_MASKED_INST_FORMAT);
   switch( addrMode.type ) {
      case EXT:
         PutNextCodeByte(info.opValue()|0x30);
         PutNextCodeByte((U8)addrMode.mask);
         PutCodeBytes(addrMode.effAddr, 2);
         return(CalculateDisplacement(addrMode.effAddr2,TRUE));
      case INDEX:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()|0x80));
            PutNextCodeByte((U8)addrMode.mask);
            PutCodeBytes(addrMode.data, 1);
            return(CalculateDisplacement(addrMode.effAddr2,FALSE));
         }
         else if( addrMode.size == WORDSIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutNextCodeByte((U8)addrMode.mask);
            PutCodeBytes(addrMode.data, 2);
            return(CalculateDisplacement(addrMode.effAddr2,TRUE));
         }            
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
}

RETCODE AsmInfo::OpGrp20(OpcodeInfo info){
//       OG20 - ind8,(X|Y|X);  imm16;  ind16,(X|Y|Z);  ext; 
   switch( addrMode.type ) {
      case EXT:
         PutNextCodeByte(PAGE1);
         PutNextCodeByte(info.opValue()|0x30);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 1);
         }
         else {
            PutNextCodeByte(PAGE1);
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 2);
         }
         break;
      case IMMED:
         if( (addrMode.size == BYTESIZE) || (addrMode.size == WORDSIZE) ) {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(info.opValue()|0x30);
            PutCodeBytes(addrMode.data, 2);
            break;
         }
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp21(OpcodeInfo info){
//     OG21 - ind8,(X|Y|X);  imm16;  ind16,(X|Y|Z);  ext; 
   switch( addrMode.type ) {
      case EXT:
         PutNextCodeByte(PAGE1);
         PutNextCodeByte(info.opValue()|0xF0);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         U8 indexOpcode = info.opValue() + 0x10;
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(indexOpcode));
            PutCodeBytes(addrMode.data, 1);
         }
         else {
            PutNextCodeByte(PAGE1);
            PutNextCodeByte(ModOpcodeForIndexReg(indexOpcode));
            PutCodeBytes(addrMode.data, 2);
         }
         break;
      case IMMED:
         if( (addrMode.size == BYTESIZE) || (addrMode.size == WORDSIZE) ) {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(info.opValue());
            PutCodeBytes(addrMode.data, 2);
            break;
         }
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp22(OpcodeInfo info){
//       OG22 - ind16,(X|Y|Z);  ext 
   switch( addrMode.type ) {
      case EXT:
         PutNextCodeByte(PAGE3);
         PutNextCodeByte(info.opValue()|0x30);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( (addrMode.size == BYTESIZE) || (addrMode.size == WORDSIZE) ) {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 2);
            break;
         }
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp23(OpcodeInfo info){
//    OG23 - ind8,(X|Y|X);  ind16,(X|Y|Z);  ext;  E,(X|Y|Z)   
   switch( addrMode.type ) {
      case ACCOFF:
         PutNextCodeByte(PAGE2);
         PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
         break;
      case EXT:
         PutNextCodeByte(PAGE3);
         PutNextCodeByte(info.opValue()|0xF0);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 1);
         }
         else {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()|0x40));
            PutCodeBytes(addrMode.data, 2);
         }
         break;
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp24(OpcodeInfo info) {   // addd
//    OG24 - ind8,(X|Y|X);  imm8; imm16; ind16,(X|Y|Z);  ext;  E,(X|Y|Z)   
   switch( addrMode.type ) {
      case ACCOFF:
         PutNextCodeByte(PAGE2);
         PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
         break;
      case EXT:
         PutNextCodeByte(PAGE3);
         PutNextCodeByte(info.opValue()|0xF0);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.data, 1);
         }
         else {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()|0x40));
            PutCodeBytes(addrMode.data, 2);
         }
         break;
      case IMMED:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(0xFC);
            PutCodeBytes(addrMode.data, 1);
            break;
         }
         else if( addrMode.size == WORDSIZE ) {
            PutNextCodeByte(PAGE3);
            PutNextCodeByte(info.opValue()|0x30);
            PutCodeBytes(addrMode.data, 2);
            break;
         }            
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp25(OpcodeInfo info){
//    OG25 - imm8   (PSHLIST | PULLIST)
   if( (addrMode.type == PSHLIST) || (addrMode.type == PULLIST) ) {
      PutNextCodeByte(info.opValue());
      PutCodeBytes(addrMode.data, 1);
      return(GOOD);
   }
   return(ER_DAD_INVALID_MODE_FOR_INST);
}

RETCODE AsmInfo::OpGrp26(OpcodeInfo info){
//    OG26 - ind8,(X|Y|X);  ind16,(X|Y|Z);  ext   (bclr/bset)
   if( addrMode.maskedInst != TRUE ) return(ER_DAD_BAD_MASKED_INST_FORMAT);
   switch( addrMode.type ) {
      case EXT:
         PutNextCodeByte(info.opValue()|0x30);
         PutNextCodeByte((U8)addrMode.mask);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( addrMode.size == BYTESIZE ) {
            PutNextCodeByte(PAGE1);
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutNextCodeByte((U8)addrMode.mask);
            PutCodeBytes(addrMode.data, 1);
            break;
         }
         else if( addrMode.size == WORDSIZE ) {
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutNextCodeByte((U8)addrMode.mask);
            PutCodeBytes(addrMode.data, 2);
            break;
         }            
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp27(OpcodeInfo info){
//    OG27 - ext20;  ind20,(X|Y|Z)     (jsr)
   switch( addrMode.type ) {
      case EXT:
         PutNextCodeByte(0xFA);
         PutCodeBytes(addrMode.effAddr&0xfffffL, 3);
         break;
      case INDEX:
         PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
         PutCodeBytes(addrMode.data&0xfffffL, 3);
         break;
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}
      
RETCODE AsmInfo::OpGrp28(OpcodeInfo info){
//       OG28 - ind16,(X|Y|Z);  ext    (bclrw/bsetw)
   switch( addrMode.type ) {
      case EXT:
         PutNextCodeByte(PAGE2);
         PutNextCodeByte(info.opValue()|0x30);
         PutCodeBytes(addrMode.mask, 2);
         PutCodeBytes(addrMode.effAddr, 2);
         break;
      case INDEX:
         if( (addrMode.size == BYTESIZE) || (addrMode.size == WORDSIZE) ) {
            PutNextCodeByte(PAGE2);
            PutNextCodeByte(ModOpcodeForIndexReg(info.opValue()));
            PutCodeBytes(addrMode.mask, 2);
            PutCodeBytes(addrMode.data, 2);
            break;
         }
      default:
         return(ER_DAD_INVALID_MODE_FOR_INST);
   }
   return(GOOD);
}

RETCODE AsmInfo::OpGrp29(OpcodeInfo info){
// <lbsr>  rel16   
   if( (addrMode.type == EXT) || (addrMode.type == ABS) ) {
      PutNextCodeByte(PAGE2);
      PutNextCodeByte(info.opValue());
      return(CalculateDisplacement(addrMode.effAddr,TRUE));
   }
   return(ER_DAD_INVALID_MODE_FOR_INST);
}

RETCODE AsmInfo::OpGrp30(OpcodeInfo info){
//  <dc> 0x....,
   RETCODE err;
   if( addrMode.type == DC_ERR ) {
      for(LOOP_VAR i = 1; i < numTokens; i++) {
         U32 tmp;
         if((err=DetermineSize(tokens[i],&tmp))!=GOOD) return(err);
         if( addrMode.size == BYTESIZE )
            PutNextCodeByte((U8)tmp);
         else
            PutCodeBytes(tmp, 2);
      }
      return(GOOD);
   }
   return(ER_DAD_INVALID_MODE_FOR_INST);
}

                       /****************************
                        *      PRIVATE MEMBERS     *
                        ****************************/
RETCODE AsmInfo::ParseString(LPSTR buffer){
   RETCODE err;
   BOOLEAN sym;
      numTokens = 0;
   tokens[numTokens] = strtok(buffer," /,\t\n");
   while( tokens[numTokens] != NULL ) {
      numTokens++;
      tokens[numTokens] = strtok(NULL," /,\t\n");
   }
   if( numTokens == 1 ) {
      addrMode.type = INH;
      return(GOOD);
   }

   // Wanted to avoid PSHLIST/PULLIST operand in this routine but I can't
   // safely determine address mode without first checking for
   // PSHM/PULM opcode.
   if( strcmpi(tokens[0],"pshm")==0 ) {
      // [pshm] <D|E|X|Y|Z|K|CCR>
      return(DecodePshlist());
   }
   if( strcmpi(tokens[0],"pulm")==0 ) {
      // [pulm] <D|E|X|Y|Z|K|CCR>
      return(DecodePullist());
   }
   /* DC can have multiple operands it's easier to just check for opcode */
   if( strcmpi(tokens[0],"dc") == 0 ) {
      addrMode.type = DC_ERR;
      return(GOOD);
   }   
   if( numTokens == 2 ) {
      if( tokens[1][0] == '#' ) {
         // <opcode> #immed  or it could be  <opcode> symbol  need to check.
         err=DetermineEffectiveAddress(tokens[1], &addrMode.effAddr,
                                           &sym);
         if( (err==GOOD) && sym ) {
            addrMode.type = ABS;
         }
         else {
             addrMode.type = IMMED;
             if((err=DetermineSize(&tokens[1][1], &addrMode.data))!=GOOD)
                return(err);
         }
      }
      else {
         // <opcode> ext  or <opcode> abs
         addrMode.type = EXT;
         DetermineEffectiveAddress(tokens[1], &addrMode.effAddr, &sym);
         if( sym ) addrMode.type = ABS;
      }
      return(GOOD);
   }
   if( numTokens == 3 ) {
      if( (tokens[1][0] == 'e') || (tokens[1][0] == 'E') ) {
         // <opcode>  E,<X|Y|Z>
         DetermineIndexRegister(tokens[2][0]);
         addrMode.type = ACCOFF;
      }
      else if( tokens[2][0] == '#' ) {
         // <opcode> <addr oprnd>,#mask
         HandleMask(&tokens[2][1]);
         HandleExt(tokens[1]);
      }
      else if((strlen(tokens[2])==1) &&
              (DetermineIndexRegister(tokens[2][0])==GOOD) ) {
         // <opcode> index,<X|Y|Z>
         if((err=DetermineSize(tokens[1], &addrMode.data))!=GOOD)
            return(err);
      }
      else if( strncmpi(tokens[0],"mov",3)==0 ) {
         //   mov[b|w] <src oprnd>,<dest oprnd>  EXT to EXT
         addrMode.type = E_TO_E;
         if((err=DetermineSize(tokens[1], &addrMode.effAddr))!=GOOD)
            return(err);
         if((err=DetermineSize(tokens[2], &addrMode.effAddr2))!=GOOD)
            return(err);
      }
      else {
         //   <[mac|rmac]> xo,yo
         U32 tmp;
         addrMode.type = XOYO;
         if((err=DetermineSize(tokens[1], &tmp))!=GOOD)
            return(err);
         if((err=DetermineSize(tokens[2], &addrMode.data))!=GOOD)
            return(err);
         addrMode.data |= ((tmp<<4)&0xF0);
      }
      return(GOOD);
   }
   if( numTokens == 4 ) {
      if( tokens[2][0] == '#' ) {
         // <opcode> <addr oprnd>,#mask,disp
         HandleMask(&tokens[2][1]);
         HandleExt(tokens[1]);
         if((err=DetermineEffectiveAddress(tokens[3], &addrMode.effAddr2,
                                           &sym))!=GOOD) return(err);
         maskedTransfer = TRUE;
      }
      else if( tokens[3][0] == '#' ) {
         // <opcode> <addr oprnd>,<X|Y|Z>,#mask
         HandleMask(&tokens[3][1]);
         if((err=DetermineIndexRegister(tokens[2][0]))!=GOOD) return(err);
         if((err=DetermineSize(tokens[1], &addrMode.data))!=GOOD) return(err);
      }
      else {
         // It's either I_TO_E or E_TO_I mov[b|w]
         if((strlen(tokens[2])==1) &&
              (DetermineIndexRegister(tokens[2][0])==GOOD) ) {
            addrMode.type = I_TO_E;
            if((err=DetermineSize(tokens[3], &addrMode.effAddr))!=GOOD)
               return(err);
            if((err=DetermineSize(tokens[1], &addrMode.data))!=GOOD)
               return(err);
         }
         else {
            if((err=DetermineIndexRegister(tokens[3][0]))!=GOOD) return(err);
            /* overwrite type from INDEX^^^ */
            addrMode.type = E_TO_I;
            if((err=DetermineSize(tokens[1], &addrMode.effAddr))!=GOOD)
                return(err);
            if((err=DetermineSize(tokens[2], &addrMode.data))!=GOOD)
               return(err);
         }
      }        
      return(GOOD);
   }
   if( numTokens != 5 ) return(ER_DAD_INVALID_NUM_OPERANDS);
   // <opcode> <addr oprnd>,<X|Y|Z>,#mask,disp
   if( tokens[3][0] != '#' ) return(ER_DAD_IMMED_FIELD_INCORRECT);
   HandleMask(&tokens[3][1]);
   if((err=DetermineIndexRegister(tokens[2][0]))!=GOOD) return(err);
   if((err=DetermineEffectiveAddress(tokens[4], &addrMode.effAddr2,
                                     &sym))!=GOOD) return(err);
   maskedTransfer = TRUE;
   return(DetermineSize(tokens[1], &addrMode.data));
}

VOID AsmInfo::PutCodeBytes(U32 val, U8 numBytes){
   U8 byteVal;
   switch (numBytes) {
      case 4: byteVal = (U8)(val >> 24);
              PutNextCodeByte(byteVal);
      case 3: byteVal = (U8)(val >> 16);
              PutNextCodeByte(byteVal);
      case 2: byteVal = (U8)(val >> 8);
              PutNextCodeByte(byteVal);
      case 1: byteVal = (U8)val;
              PutNextCodeByte(byteVal);
              break;
   }
}
   
VOID AsmInfo::PutNextCodeByte(U8 val){
   instLength++;
   *codePtr++ = val;
}

RETCODE AsmInfo::WriteCodeBuffer(){
// By using fill instead of write we can avoid allocating a buffer and
// copying the data!   
   return(MemFillSized(pcAddress,instLength,hexCode,instLength,WORD_SIZE));
}

RETCODE AsmInfo::DetermineEffectiveAddress(LPSTR text, U32 *data,
                                           BOOLEAN *symFound) {
   RETCODE err;
   *symFound = FALSE;
   if( sscanf(text, "0x%lx", data) != 1 ){ 
      if( sscanf(text, "0X%lx", data) != 1 ) {
         if( sscanf(text, "%ld", data) != 1 ) {
            BOOLEAN dasmSym;
            if ((err=DadGetDasmSymbol(&dasmSym)) != GOOD) return(err);
            if( dasmSym ) {
               SYM_DESCRIPTOR    lpSymFoundDesc;
               DESCRIPTOR        lpAddrDesc;
               LINENUM_TYPE      lpActualLinenum;
               COLUMN_RANGE_TYPE lpActualColumnRange;
               if((err=SymGetAddrFromName(text,SYM_UNKNOWN_ADDR, 
                   &lpSymFoundDesc,&lpAddrDesc,&lpActualLinenum,
                   &lpActualColumnRange))!=GOOD) return(err);
               *symFound = TRUE;
               if((err=AdrGetAddrOffset(lpAddrDesc,data))!=GOOD) return(err);
               return(AdrDestroyAddress(lpAddrDesc));
            }
            else return(ER_DAD_SYMBOL_USE_BUT_DISABLED);
         }
      }
   }
   addrMode.size = BYTESIZE;
   if( (*data) > 0xff )
      addrMode.size = WORDSIZE;
   if( (*data) > 0x7fff )
      addrMode.size = LONGSIZE;
   return(GOOD);
}

RETCODE AsmInfo::DetermineSize(LPSTR text, U32 *data){
   RETCODE err;
   if( sscanf(text, "0x%lx", data) != 1 ){ 
      if( sscanf(text, "0X%lx", data) != 1 ) {
         if( sscanf(text, "%ld", data) != 1 ) {
            return(ER_DAD_INVALID_MODE_FOR_INST);
         }
      }
   }
   addrMode.size = BYTESIZE;
   if( (*data) > 0xff )
      addrMode.size = WORDSIZE;
   if( (*data) > 0xffff )
      addrMode.size = LONGSIZE;
   return(GOOD);
}

RETCODE AsmInfo::DecodePshlist() {
   LOOP_VAR i;
   addrMode.type = PSHLIST;
   if( (numTokens == 2) && (tokens[1][0] == '#') )
      return(DetermineSize(&tokens[1][1], &addrMode.data));
   addrMode.data = 0;
   addrMode.size = BYTESIZE;
   for( i=1; i < numTokens; i++ ) {
      switch (tokens[i][0]) {
         case 'D':
         case 'd':   addrMode.data |= 0x1; break;
         case 'E':
         case 'e':   addrMode.data |= 0x2; break;
         case 'X':
         case 'x':   addrMode.data |= 0x4; break;
         case 'Y':
         case 'y':   addrMode.data |= 0x8; break;
         case 'Z':
         case 'z':   addrMode.data |= 0x10; break;
         case 'K':
         case 'k':   addrMode.data |= 0x20; break;
         case 'C':
         case 'c':   addrMode.data |= 0x40; break;
         default:
            return(ER_DAD_INVALID_REGLIST_BIT);
      }
   }
   return(GOOD);
}

RETCODE AsmInfo::DecodePullist() {
   LOOP_VAR i;
   addrMode.type = PULLIST;
   if( (numTokens == 2) && (tokens[1][0] == '#') )
      return(DetermineSize(&tokens[1][1], &addrMode.data));
   addrMode.data = 0;
   addrMode.size = BYTESIZE;
   for( i=1; i < numTokens; i++ ) {
      switch (tokens[i][0]) {
         case 'C':
         case 'c':   addrMode.data |= 0x1; break;
         case 'K':
         case 'k':   addrMode.data |= 0x2; break;
         case 'Z':
         case 'z':   addrMode.data |= 0x4; break;
         case 'Y':
         case 'y':   addrMode.data |= 0x8; break;
         case 'X':
         case 'x':   addrMode.data |= 0x10; break;
         case 'E':
         case 'e':   addrMode.data |= 0x20; break;
         case 'D':
         case 'd':   addrMode.data |= 0x40; break;
         default:
            return(ER_DAD_INVALID_REGLIST_BIT);
      }
   }
   return(GOOD);
}

RETCODE AsmInfo::DetermineIndexRegister(char ch) {
   addrMode.type = INDEX;
   switch (ch) {
      case 'X':
      case 'x':   addrMode.reg = XREG; break;
      case 'Y':
      case 'y':   addrMode.reg = YREG; break;
      case 'Z':
      case 'z':   addrMode.reg = ZREG; break;
      default:
         return(ER_DAD_INVALID_INDEX_REG);
   }
   return(GOOD);
}

VOID AsmInfo::HandleExt(LPSTR extAddr) {
   addrMode.type = EXT;
   DetermineSize(extAddr, &addrMode.effAddr);
}
   
VOID AsmInfo::HandleMask(LPSTR mask) {
   addrMode.maskedInst = TRUE;
   if( sscanf(mask, "0x%lx", &addrMode.mask) != 1 ) {
      if( sscanf(mask, "0X%lx", &addrMode.mask) != 1 ) {
         if( sscanf(mask, "%ld", &addrMode.mask) != 1 ) addrMode.mask = 0;
      }
   }
   addrMode.maskSize = BYTESIZE;
   if( addrMode.mask > 0xff )
      addrMode.maskSize = WORDSIZE;
}

RETCODE AsmInfo::CalculateDisplacement(U32 effAddr, BOOLEAN longBranch) {
   RETCODE err;
   U32 offset;
   DESCRIPTOR pcCopy;
   if((err=AdrDuplicateAddress(pcAddress, &pcCopy))!=GOOD) return(err);
   /* first we need to add 6 to the pc address of instruction we are
      processing since all branching is done relative to this point. */
   if((err=AdrAddToAddress(pcCopy, 6L))!=GOOD) return(err);
   if((err=AdrGetAddrOffset(pcCopy,&offset))!=GOOD) return(err);
   if((err=AdrSetAddrOffset(pcCopy,effAddr))!=GOOD) return(err);
   if((err=AdrSubtractFromAddressUnderflow(pcCopy,offset))!=GOOD)
      return(err);
   if((err=AdrGetAddrOffset(pcCopy,&offset))!=GOOD) return(err);
   if((err=AdrDestroyAddress(pcCopy))!=GOOD) return(err);
   offset &= 0xfffffffeL;        // only even offsets are valid
   if( longBranch ) PutCodeBytes(offset, 2);
   else {
      if( (offset < 0xff)
          || ((offset > 0xffffff80) && (offset < 0xffffffff)) ) {
         PutCodeBytes(offset, 1);
      }
      else return(ER_DAD_INCORRECT_DISP);
   }
   return(GOOD);
}
   

/*****************************************************************************
** CLASS: OpcodeInfo
*/
                       /****************************
                        *      PUBLIC MEMBERS      *
                        ****************************/
OpcodeInfo::OpcodeInfo(OPGROUP grp, int value) {
   group = grp;
   opcodeValue = (char)value;
}

char _FAR *OpcodeInfo::nameOf() const { return "OpcodeInfo";};

void OpcodeInfo::printOn( ostream& outputStream ) const {
    outputStream << endl << "Opcode Group " << (group+1)
                 << ";  base opcode value: " << opcodeValue << endl;
}

