//---------------------------------------------------------
// ASMC40.CPP
// Keith Larson
// TMS320 DSP Applications
// (c) Copyright 1995, 1996, 1997
// Texas Instruments Incorporated
//
// This is unsupported freeware code with no implied warranties or
// liabilities.  See the disclaimer document for details
//----------------------------------------------------------
// This file contains the assembler function forms for the
// TMS320C3x.  Also included are the functions needed to
// determine register, indirect and direct addressing modes
//----------------------------------------------------------
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "opcodes.h"
#include "tmsfloat.h"
#include "assm_fun.h"
#include "errormsg.h"
#include "exp_anal.h"
#include "symbols.h"
#include "argsplit.h"
//#include "dsk.h"

typedef enum
{ _R0=0, _R1 , _R2 , _R3 , _R4 , _R5 , _R6 , _R7 , // R0-R7
  _AR0 , _AR1, _AR2, _AR3, _AR4, _AR5, _AR6, _AR7, //
  _DP  , _IR0, _IR1, _BK , __SP, _ST , _IE , _IF , //
  _IOF , _RS , _RE , _RC , _R8 , _R9 , _R10, _R11, // RC=R27
  _DIE = 20
} CPU_REGS;

//----------------------------------------------------------------------
// int srce_indirect(char *ptr, operand &oprnd, uint mask)
//
// *ptr points to the text string of an indirect addressing opcode
// &oprnd is the address of the object to write to
// mask can be for either a 16 or 8 bit field of ones (0xFFFF or 0xFF)
//
// Checking is performed for disp bounds, and in the case of
// 8 bit mode, the offset and modn are verified as being legal
//
// If successful, a NO_ERR (zero) condition will be returned,
// If not, a non zero enumerated error will be returned
//
//           15     10   8 7    0
//          +------+------+------+     0 < disp <255  (8 bits)
//  16 bit  | modn |  ARn | disp |     0 < ARn  <  7  (3 bits)
//  0xffff  +------+------+------+         modn       (5 bits)
//
//           15     7    5 4    0
//          +------+------+------+     0 < disp < 32  (5 bits)
//  13 bit  | modn |  ARn | disp |     0 < ARn  <  7  (3 bits)
//  0x1FFF  +------+------+------+         modn       (5 bits)
//
//                  7    3 2    0
//                 +------+------+     disp implied   (0 bits)
//   8 bit         | modn |  ARn |     0 < ARn  <  7  (3 bits)
//    0xFF         +------+------+         modn       (5 bits)
//
//----------------------------------------------------------------------
int Enhanced_Enable = 0;  // Enhanced C3x/C4x indirect coding enable
int Enhanced_Fields = 0;

MSGS srce_indirect(char *ptrin, operand &oprnd, ulong mask)
{
  char buf[64], *c, *c1, *c2, *ptr, *cf;
  ulong ltemp;
  int DISP, MOD, IRX, ARX;

  if(strlen(ptrin) > 63) return NO_REF;
  strcpy(buf,ptrin);
  c   = buf;
  ptr = buf;
  strupr(buf);             // Upper case is used for ARx/IRx search
  for(ARX=8;ARX<16;ARX++)  // search ARx fields
  {
    if((c=strstr(ptr,C30Reg[ARX].s)) != NULL) break;
  }
  if(ARX == 16) return IND_ERR;  // No ARx found!
  ARX -= 8;
  //
  // Check preceding and following characters to ARx to
  // make sure they are legal.  For examples, avoids
  // detecting AR0x as an indirect
  switch(c[3])
  {
     case '-':               // *AR0++ *AR0-- *++AR0(1)
     case '(':
     case '+':
     case   0: break;
     default : return IND_ERR;
  }
  switch(c[-1])
  {
     case '*':               // *AR0++ *AR0-- *++AR0(1)
     case '-':
     case '+': break;
     default : return IND_ERR;
  }
  //
  // Search for the math operator strings that cannot be legal.
  // Therefor these expressions are NOT allowed in expression analysis
  //
  // +-  -+  +++  ---  +--  --+  +-+  -+-
  //
  if((c = strstr(ptr,"+-" ))!=NULL) return IND_ERR;
  if((c = strstr(ptr,"-+" ))!=NULL) return IND_ERR;
  if((c = strstr(ptr,"++-"))!=NULL) return IND_ERR;
  if((c = strstr(ptr,"+++"))!=NULL) return IND_ERR;
  if((c = strstr(ptr,"--+"))!=NULL) return IND_ERR;
  if((c = strstr(ptr,"---"))!=NULL) return IND_ERR;
//if((c = strstr(ptr,"+-+"))!=NULL) return IND_ERR; found in earlier case
//if((c = strstr(ptr,"-+-"))!=NULL) return IND_ERR;
  //
  // Scan for other illegal combinations...
  // *AR0-(2)
  // *AR0+(2)
  //
  if((c = strstr(ptr,"-("))!=NULL)    // *AR0--() is legal
    if((c = strstr(ptr,"--"))==NULL)  // *AR0-()  is illegal
      return IND_ERR;
  if((c = strstr(ptr,"+("))!=NULL)    // *AR0++() is legal
    if((c = strstr(ptr,"++"))==NULL)  // *AR0+()  is illegal
      return IND_ERR;

  // A special case occurs for bit-reversed arithmetic
  //   -- post modification of IR0 must be used --
  //
  if((c = strstr(ptr,")B")) != NULL)
  {
    DISP = 0;
    IRX = 0x18;
    MOD = 0x01;
    if((c=strstr(ptr,"IR0")) == NULL) return IRX_ERR;
    if((c=strstr(ptr,"++" )) == NULL) return INC_ERR;
    oprnd.val = (((((IRX | MOD) << 3) | ARX) << 8) | DISP) & 0xFFFF;
  }
  //
  // scan for DISP values
  //
  else
  {
    IRX = 0x18;
    MOD = 0x00;              // Standard indirect
    DISP= 0;
    if((c=strstr(ptr,"("))==NULL)
    {
      DISP=0;
      if((c=strstr(ptr,")"))!=NULL) return DISP_ERR;
      if((c=strstr(ptr,"+"))!=NULL) {DISP=1; IRX=0;}
      if((c=strstr(ptr,"-"))!=NULL) {DISP=1; IRX=0;}
      c2 = NULL;
    }
    else
    {
      if((c2=strstr(ptr,")"))==NULL) return DISP_ERR;
//    *c2 = ' ';
//    tc = *c2;
      *c2 = 0;
      c++;
      c1 = c;
      if(isdigit(*c))
      {
        //DISP = (int) atol(c);
        //
        // Displacement calculations with leading numeric characters
        // need to be reloaded with their original upper/lower case
        // in order for the calculation of symbols and functions to
        // work properly.
        //
        // NOTE: In addition to reloading the string, the terminating
        //       null character needs to be put back into the string
        //       at the correct position
        strcpy(buf,ptrin);
        *c2 = 0;

        if(expressionz(c1, &ltemp, INTEGER)!=INTEGER) return DISP_ERR;
        DISP = (int)ltemp;
        IRX = 0;
      }
      else
      {
        IRX=0x18;
//      if((c=strstr(c1,"IR0"))!=NULL)
        if(strexact(c1,"IR0"))
        {
          c = c1;
          DISP=0;
          IRX = 0x08;
        }
        else
        {
        //if((c=strstr(c1,"IR1"))!=NULL)
          if(strexact(c1,"IR1"))
          {
            c = c1;
            DISP=0;
            IRX = 0x10;
          }
          else
          {
            //
            // Displacement calculations with leading symbols also
            // need to be reloaded with their original upper/lower case
            // in order for the calculation of symbols and functions to
            // work properly.
            //
            // NOTE: In addition to reloading the string, the terminating
            //       null character needs to be put back into the string
            //       at the correct position
            strcpy(buf,ptrin);
            *c2 = 0;

            if(expressionz(c1, &ltemp, INTEGER)!=INTEGER) return DISP_ERR;
            DISP = (int)ltemp;
            IRX = 0;
            //else return IRX_ERR;
          }
        }
      }
    }
    if(c2!=NULL)
    *c2 = ' '; // put back WS in place of original ')' before modifier scan
//  if(IRX) DISP = 0;
    //
    strupr(buf); // lower case 'ar' will cause a fail if a reloaded
                 // symbol (DISP field) occured
    //
    // scan for modyfiers
    //
    // re-searching for ARx instance is required to filter
    // *AR0-- *--AR0 and determine if ARx is in front or behind modifiers
    //
    //----------------- Ver 1.12 fix ----------------------
    // ldf  *-AR0(1+1),R0  ; Would fail since since the '+' in the
    //                     ; offset field would be seen out of order
    //-----------------------------------------------------
    if((cf=strstr(ptr,"(")) != NULL) *cf = 0;
    //------------------------------------------------
    // End ver 1.12 fix
    //------------------------------------------------
    if((c1=strstr(ptr,"AR")) == NULL) return IND_ERR;
    if((c=strstr(ptr,"+")) != NULL)
    {
    //IRX = 0;
      if(cf!=NULL)
        *cf = '(';  // put back the "(" that was stripped before test
      if((c2=strstr(ptr,"++")) != NULL)
      {
        if(c2 < c1)
        { if((c=strstr(ptr,"%")) != NULL) return CIR_ERR;//circ pre-mod ERR
                                          MOD = 0x02;    // pre add mod
        }
        else
        { if((c=strstr(ptr,"%")) != NULL) MOD = 0x06;    // post add mod
          else                            MOD = 0x04;    // post add/circ mod
        }
      }
      else  // pre (post is error) DISP +
      { if(c  < c1)                       MOD = 0x00;     // pre_off_add
        else                              return DISP_ERR;// post_off_add ERR
        if(strstr(ptr,"%")!=NULL)         return CIR_ERR;
      }
    }
    else
    {
      if((c=strstr(ptr,"-")) != NULL)
      {
//      IRX = 0;
        if(cf!=NULL)
        *cf = '(';  // put back the "(" that was stripped before test
        if((c2=strstr(ptr,"--")) != NULL)
        {
          if(c2 < c1)
          { if((c=strstr(ptr,"%"))!=NULL) return CIR_ERR; // circ pre-mod ERR
                                          MOD = 0x03;     // pre sub mod
          }
          else
          { if((c=strstr(ptr,"%"))==NULL) MOD = 0x05;     // post sub mod
            else                          MOD = 0x07;     // post sub/circ mod
          }
        }
        else
        { if(c  < c1)                     MOD = 0x01;     // pre_off_sub
          else                            return DISP_ERR;// post_off_sub ERR
          if(strstr(ptr,"%")!=NULL)       return CIR_ERR;
        }
      }
      else
        if(DISP)  return BAD_MOD;
    }
  }
  if(mask == 0xffff)
  {
    if((DISP<0) | (DISP>255)) return DISP_ERR;
    oprnd.val = (((((IRX | MOD) << 3) | ARX) << 8) | DISP) & 0xFFFF;
    return NO_ERR;
  }
  if(mask == 0xff)
  {
    if((DISP<0) | (DISP>1)) return DISP_ERR;
    //
    // Bug fix 6/1/96
    //
    // Since there is no displacement field a *+ARx(?) modifier
    // field evaluates to *+ARx(1) in the device.  Therefor change
    // *+ARx(0) to special case *ARx (mod field = 11000b)
    //
    // Note: The modifier field is NOT totaly constructed at this point
    //       and is the logical OR of the IRX and MOD field
    //
    if(((IRX|MOD)==0)&&(DISP==0)) MOD = 0x18; // 6/1/96
    //
    //
    oprnd.val = (((IRX|MOD)<<3)|ARX) & 0xFF;
    return NO_ERR;
  }
  if(mask == 0x1fff)
  {
    if((DISP<0) | (DISP>32)) return DISP_ERR;
    oprnd.val = (((((IRX | MOD) << 3) | ARX) << 5) | DISP) & 0xFFFF;
    return NO_ERR;
  }
  return BAD_ARG;
}
//-----------------------------------------------------------------
// srce_cvt() determines the type of operand field and returns
// the value which is to be packed into the opcode.
//-----------------------------------------------------------------

MSGS srce_cvrt(char *argmnt,operand &Op, int shf, ulong msk, NUM_TYPE numtype)
{
  MSGS ERR;
  long temp;
  int ind_flds = 0;
  Op.shf = shf;
  Op.msk = msk;
  // Op.val is set by the particular function called
  //
  // Direct addressing - DP is assumed...
  if(*argmnt == '@')
  {
     if(expressionz(argmnt+1,&Op.val,INTEGER)==INTEGER)
        return SRC_DIR;
     else                               return BAD_ARG;
  }
  // indirect addressing
  if(*argmnt == '*')
  {
    if((ERR=srce_indirect(argmnt,Op, msk))!=NO_ERR) return ERR;
    return SRC_IND;
  }
  // CPU registers
  if(isreg(argmnt,Op,shf,msk))
  {
    if(Enhanced_Enable==0) return SRC_REG;
    if((Global_Raw_Code & 0xC0000000L) == 0xC0000000L)
    {
    //if(Op.shf != 0) return SRC_REG;
      if((Op.shf == 0)||(Op.shf == 8))
      {
        if(*arg[0].s == '*') return SRC_REG; // If 1st field indirect quit

        if(*arg[0].s == '*') ind_flds++;  // Count indirect fields
        if(*arg[1].s == '*') ind_flds++;  // if two indirects are specified
        if(*arg[2].s == '*') ind_flds++;  // the code cannot be assembled
        if(*arg[3].s == '*') ind_flds++;  // in the enhanced mode
        if(*arg[4].s == '*') ind_flds++;
        if(*arg[5].s == '*') ind_flds++;
        if(*arg[6].s == '*') ind_flds++;
        if(*arg[7].s == '*') ind_flds++;
        if(ind_flds >= 2) return SRC_REG;

        Op.val |= 0xE0;
        Enhanced_Fields++;
        return SRC_IND;
      }
      return SRC_REG;
    }
    if((Global_Raw_Code & 0xF0000000L) == 0x80000000L)
    {
      //Op.val |= 0xE0;
      return SRC_IND;
    }
    return SRC_REG; // Will likely cause an error!
  }
  // Absolute or referenced
  if(expressionz(argmnt,&Op.val,numtype)!=NOREF)
  {
    if(numtype==FLOAT)        // float
    {
      if(msk == 0xFFFFL)  // short float
      {
        Op.val = IEEE_TMS(*((float *)&Op.val));
        Op.val = TMS_TMS_SHORT(Op.val);
      }
    }
    else  // numtype==INTEGER, check if expression will fit field
    {
      temp = ~msk;
      temp = Op.val & temp;
      //chi if((temp!=0) && (temp!= ~msk))
      if((temp!=0) && ((unsigned)temp != ~msk))
      {
        strcpy(g_strg2, nullstring);
        if(msk == 0x0000ffL) assm_error_msg(W_SIZE8 ,"");
        if(msk == 0x00ffffL) assm_error_msg(W_SIZE16,"");
        if(msk == 0xffffffL) assm_error_msg(W_SIZE24,"");
      }
    }
    return SRC_IMM; // converted if defined
  }
  return BAD_ARG;
}
//------------------------------------------------------
// srce_mode() converts enumerated source mode types
// into values that can be used in an output object
//------------------------------------------------------
long srce_mode(MSGS err)
{
  if(err == SRC_REG) return 0;
  if(err == SRC_DIR) return 1;
  if(err == SRC_IND) return 2;
  if(err == SRC_IMM) return 3;
  return err;
}
//-----------------------------------------------------------------------
// Assembler form functions are called after the assm function has
// determined that the mnemonic string is valid and has looked up
// the address of the form function to use.  In other words these
// 'forms' are part of a large switch/case statement
//-----------------------------------------------------------------------
//  ABSF,  ADDF , CMPF, FIX, FLOAT, LDE ,
//  LDF ,  LDFI , LDM , MPYF , NEGF,
//  POPF,  PUSHF, RCPF, RND ,  SUBF, SUBRF,
//
// Except for 'FLOAT', R0-R7 are the only valid source registers
// R0-R7 are the only valid destination registers
//************************************************************************
MSGS AForm0( int n, OBJ &obj, char *op )
{
  char buf[80], *ptr;
  int x;
  MSGS G;
  strncpy(buf,op,79);
  ptr = buf;
  // split the argument list into seperate arguments
  x = arg_split(ptr,0);
  switch(Instr[n].en)
  {
    case __POPF :
    case __PUSHF:switch(x)
                 {
                   case  0: return NO_OPRND;
                   case  1: break;
                   default: return TOO_MANY_ARGS;
                 }
                 break;
    default     :switch(x)
                 {
                   case  0: return NO_OPRND;
                   case  1: return MISS_ARG;
                   case  2: break;
                   default: return TOO_MANY_ARGS;
                 }
                 break;
  }
  //
  // Determine source mode as register, direct, indirect or immediate
  //
  //
  // SRC_REG=0,           // partial list of enumerated returns
  // SRC_DIR,             // showing that a comparison of NO_ERR
  // SRC_IND,             // is used to split NON_ERR from ERR returns
  // SRC_IMM,
  // General purpose NO_ERR return
  // ---> VALUE IS NOT ZERO! <---
  // NO_ERR,
  //
  G = srce_cvrt(arg[0].s, obj.A, 0, 0xffff,FLOAT);
//if(G > NO_ERR) return BAD_ARG;   // srce conversion error
  switch(G)
  {
    case SRC_REG:
    case SRC_DIR:
    case SRC_IND:
    case SRC_IMM: break;
    default     : return BAD_ARG;
  }
  // Convert the destination to an object
  switch(Instr[n].en)
  {
    case __POPF :
    case __PUSHF:
    case __POP  :
    case __PUSH : obj.A.shf = 16;
                  obj.B.val = 4;
              //  obj.B.msk = 0;
                  break;
    default     : if(isreg(arg[1].s,obj.B,16,0x1f)== 0) return BAD_ARG;
                  break;
  }
  if(Instr[n].en != __FIX)
  {
    if(floatreg(obj.B.val,1)==0) return REG_INT;
  }
  if(G==SRC_REG)
  {
    if(Instr[n].en != __FLOAT)
    if(floatreg(obj.A.val,1)==0) return REG_INT; // Reg must be F0-F7
  }
//if(G==SRC_IMM) obj.A.val = IEEE_TMS(obj.A.val);
  // Write code and mask to object
  obj.raw   = Instr[n].pattern;
  obj.mask  = Instr[n].mask;
  // Add mode to object list
  obj.C.shf = 21;
  obj.C.val = srce_mode(G);
  obj.C.msk = 0x3;
  return NO_ERR;
}
/* ----------------------------------------------------------------------
              Decoding for General Addressing Modes
  Instructions handled :

  ABSI, ADDC, ADDI, AND, ANDN, ASH, CMPI,
  IACK, LDI, LDII,  LDP, LSH,  MPYI, NEGB,
  NEGI, NOP, NORM, NOT, OR, POP, PUSH, ROL, ROLC,
  ROR, RORC, RPTS, STF, STFI, STI, STII, SUBB, SUBC, SUBI,
  SUBRB, SUBRI, TSTB, XOR
   ---------------------------------------------------------------------- */
MSGS AForm1( int n, OBJ &obj, char *opx )
{
  char buf[80], *ptr;
  MSGS G;
  int args;
  strncpy(buf,opx,79);
  ptr = buf;
  // split the argument list into seperate arguments
  args = arg_split(ptr,0);
  // Determine source mode as register, direct, indirect or immediate
  switch(Instr[n].en)
  {
    case __STIK:if(C3Xmode) return NO_STIK;
    case __STII:
    case __STI: if(args!=2) return BAD_ARG;
                G = srce_cvrt(arg[1].s, obj.B, 0, 0xffff,INTEGER);
                switch(Instr[n].en)
                {
                  case __STIK: obj.raw   = 0x15000000L;
                            switch(G)
                            {
                              case SRC_REG: return BAD_ARG;
                              case SRC_DIR: G=SRC_REG; break;
                              case SRC_IND: G=SRC_IMM; break;
                              case SRC_IMM: return BAD_ARG;
                              default     : return G;
                            }
                            if(isreg(arg[0].s,obj.A,16,0x1f)!= 0)
                                return BAD_ARG;
                     if(expressionz(arg[0].s,&obj.A.val,INTEGER)!=INTEGER)
                         return BAD_ARG;
                 //
                 // Cant decide on how, or if should handle out of range
                 // values.  Solution, dont do it for now
                 //
                 //  if(obj.A.val & 0xFFFFFFE0L)
                 //  {
                 //    if(obj.A.val & 0x80000000L) obj.A.val = -16;
                 //    else                        obj.A.val =  15;
                 //  }
                            break;
                  case __STI : obj.raw   = 0x15000000L;
                            switch(G)
                            {
                              case SRC_REG: return USE_LDI;
                              case SRC_DIR:
                              case SRC_IND: break;
                              case SRC_IMM: return NO_STIK;
                              default     : return G;
                            }
                            if(isreg(arg[0].s,obj.A,16,0x1f)== 0)
                                return BAD_ARG;
                            break;
                  case __STII: obj.raw   = 0x15800000L;
                            switch(G)
                            {
                              case SRC_REG: return USE_LDI;
                              case SRC_DIR:
                              case SRC_IND: break;
                              case SRC_IMM: return NO_STIK;
                              default     : return G;
                            }
                            if(isreg(arg[0].s,obj.A,16,0x1f)== 0)
                                return BAD_ARG;
                            break;
                }
                obj.mask  = 0xFF800000L;
                // Add mode to object list
                obj.C.shf = 21;
                obj.C.val = srce_mode(G);
                obj.C.msk = 0x3;
                return NO_ERR;
              //break;
    case __STFI:
    case __STF: if(args!=2) return BAD_ARG;
                G = srce_cvrt(arg[1].s, obj.B, 0, 0xffff,INTEGER);
                switch(G)
                {
                  case SRC_REG: return USE_LDI;
                  case SRC_DIR:
                  case SRC_IND: break;
                  case SRC_IMM: return NO_STIK;
                  default     : return G;
                }
            //  if(G>NO_ERR) return (int)G;
            //  if(G==0) return USE_LDI;
            //  if(G==3) return NO_STIK;
                if(isreg(arg[0].s,obj.A,16,0x1f)== 0) return BAD_ARG;
                if(floatreg(obj.A.val,1)==0)  return REG_INT;
                break;

    case __LDP: if(args!=1)
                {
                  if(!strexact(arg[1].s,"DP"))
                    return BAD_ARG;
                }
            //    G=srce_cvrt(arg[0].s, obj.A, 0, 0xff,0);
                G=srce_cvrt(arg[0].s, obj.A, 0, 0xffffffffL,INTEGER);
              //if(G>NO_ERR) return G;
                switch(G)
                {
                  case SRC_REG: return BAD_ARG;
                  case SRC_DIR: obj.A.val = obj.A.val >> 16;
                                if(   ((long)obj.A.val > 255)
                                   || ((long)obj.A.val <  -1))
                                   assm_error_msg(W_SIZE8,"");
                                break;
                  case SRC_IND: return BAD_ARG;
                  case SRC_IMM:
                  //------------------------------------------------------
                  // NOTES: The LDP opcode is hardcoded to be an immediate
                  //        The COFF assembler disregards a preceding '@'
                  //        and assumes that the resulting expression is
                  //        always shifted.
                  //
                  //        To make the dasm_assm test run error free the
                  //        LDP disassembler creates the following when
                  //
                  //        dasm_assm_on=1:  0x08700033 -> LDP 0330000h,DP
                  //        dasm_assm_on=0:  0x08700033 -> LDP 033h,DP
                  //------------------------------------------------------
                                obj.A.val = obj.A.val >> 16;
                                if(   ((long)obj.A.val > 255)
                                   || ((long)obj.A.val <  -1))
                                   assm_error_msg(W_SIZE8,"");
                                break;
                  default:      return G; // Return enumerated error
                }
                obj.B.val=0; obj.B.msk=1; //trick for missing obj
                //
                // The following few lines are a kluge to make DSK3A
                // not actually output a true LDP opcode.  This is
                // done to keep the DSK3A output identical to the
                // COFF tools.  However, if dasm_assm is to be run
                // succesfully (loopback test) a true LDP return is
                // required.

                if(dasm_assm_on == 0)
                {
                  obj.raw   = 0x50700000L;
                  obj.mask  = 0xFFFFFF00L;
                  obj.C.shf = 21;
                  //obj.C.val = G;
                  obj.C.val = srce_mode(G);
                  obj.C.msk = 0x3;
                  return NO_ERR;
                }
                break;

    case __NOP: G = SRC_REG;
                obj.B.val=0; obj.B.msk=1; //trick for missing obj
                if(args==0) break;
                if(args != 1) return TOO_MANY_ARGS;
                G = srce_cvrt(arg[0].s, obj.A, 0, 0xFFFF,INTEGER);
                switch(G)
                {
                  case SRC_REG:
                  case SRC_DIR: assm_error_msg(NOT_ALWD,arg[0].s);
                                return NO_ERR;
                  case SRC_IND: break;
                  case SRC_IMM: assm_error_msg(NOT_ALWD,arg[0].s);
                                return NO_ERR;
                  default:      return G;
                }
                //if(G>NO_ERR) return (int)G;
                //if(G!=2) return BAD_ARG;
                break;

    case __IACK:if(args != 1) return BAD_ARG;
                G = srce_cvrt(arg[0].s, obj.A, 0, 0xFFFF,INTEGER);
                switch(G)
                {
                  case SRC_REG: return BAD_ARG;
                  case SRC_DIR:
                  case SRC_IND: break;
                  case SRC_IMM: return BAD_ARG;
		  //chi defualt: return G;
                  default     : return G;
                }
             // if(G>NO_ERR) return (int)G;
             // if((G==0)|(G==3)|(G==-1)) return BAD_ARG;
                obj.B.val=0; obj.B.msk=1; //trick for missing obj
                break;

    case __ROL  :
    case __ROLC :
    case __ROR  :
    case __RORC :
    case __POPF :
    case __PUSHF:
    case __POP  :
    case __PUSH :
                 if (args != 1) return BAD_ARG;
                 G=srce_cvrt(arg[0].s, obj.A, 16, 0x1f,INTEGER);
                 switch(G)
                 {
                   case SRC_REG: break;
                   case SRC_DIR:
                   case SRC_IND:
                   case SRC_IMM: return BAD_ARG;
                   default     : return G;
                 }
              // if((G=srce_cvrt(arg[0].s, obj.A, 16, 0x1f,0))!=0)
              //   return BAD_ARG;
              // if(G>NO_ERR) return (int)G;
                 obj.B.val=0; obj.B.msk=1; //trick to missing obj
                 break;

    case __RPTS: if(args != 1) return BAD_ARG;
                 G = srce_cvrt(arg[0].s, obj.A, 0, 0xFFFF,INTEGER);
                 switch(G)
                 {
                   case SRC_REG:
                   case SRC_DIR:
                   case SRC_IND:
                   case SRC_IMM: break;
                   default     : return G;
                 }
               //if(G>NO_ERR) return (int)G;
               //if(G==-1) return BAD_ARG;
                 obj.B.val=0; obj.B.msk=1; //trick for missing obj
                 break;

//  case __FRIEEE:
//  case __LDA: if(C3Xmode) return BAD_ARG;

    default:     if(args!=2) return BAD_ARG;
                 G = srce_cvrt(arg[0].s, obj.A, 0, 0xFFFF,INTEGER);
                 switch(G)
                 {
                   case SRC_REG:
                   case SRC_DIR:
                   case SRC_IND:
                   case SRC_IMM: break;
                   default     : return G;
                 }
              // if(G>NO_ERR) return (int)G;
                 if(isreg(arg[1].s,obj.B,16,0x1f)== 0) return BAD_ARG;
                 break;
  }
  // C4x mode assembly
  switch(Instr[n].en)
  {
    case __FRIEEE:
    case __LDA:    if(C3Xmode) return BAD_ARG;
  }
  switch(Instr[n].en)
  {
    case __FRIEEE:
           if(((long)obj.B.val>_R7) && ((long)obj.B.val<_R8)) return BAD_ARG;
           if((G==SRC_REG)||(G==SRC_IMM)) return BAD_ARG;
           break;

    case __LDA:    if((obj.B.val >= _AR0) && (obj.B.val <= __SP)) break;
      return BAD_ARG;
  }
  // Write code and mask to object
  obj.raw   = Instr[n].pattern;
  obj.mask  = Instr[n].mask;
  // Add mode to object list
  obj.C.shf = 21;
  obj.C.val = srce_mode(G);
  obj.C.msk = 0x3;
  return NO_ERR;
}
/* ----------------------------------------------------------------------
              Decoding for Parallel Addressing Modes
     MPYF3 || ADDF3,
     MPYF3 || SUBF3,
     MPYI3 || ADDI3,
     MPYI3 || SUBI3
   ---------------------------------------------------------------------- */
MSGS AForm3( int n, OBJ &obj, char *op )
{
  char buf[80], *ptr;
  int args;
  MSGS GE1,GE2,GE3,GE4; // Enumerated return types
  int G1,G2,G3,G4;
  int  P;
  long G=0;
  int ind = 0;
  Enhanced_Fields = 0;
  strncpy(buf,op,79);
  ptr = buf;
  // split the argument list into seperate arguments
  args = arg_split(ptr,0);
  if(args!=7) return PAR_ERR;
  // Determine source mode as register, direct, indirect or immediate
  GE1=srce_cvrt(arg[0].s,obj.A, 0,0xff,INTEGER);
  GE2=srce_cvrt(arg[1].s,obj.B, 0,0xff,INTEGER);
  GE3=srce_cvrt(arg[4].s,obj.D, 0,0xff,INTEGER);
  GE4=srce_cvrt(arg[5].s,obj.E, 0,0xff,INTEGER);
  ind = 0;
  if(Enhanced_Enable)  // If enhanced GE1-GE4 are always SRC_IND
  {                    // However only two SRC_IND are allowed
    GE1=GE2=GE3=GE4=SRC_REG;
/*  if(strstr(arg[0].s,"*")!=NULL) {GE1 = SRC_IND; ind++; G|=0x1000;}
    if(strstr(arg[1].s,"*")!=NULL) {GE2 = SRC_IND; ind++; G|=0x0100;}
    if(strstr(arg[4].s,"*")!=NULL) {GE3 = SRC_IND; ind++; G|=0x0010;}
    if(strstr(arg[5].s,"*")!=NULL) {GE4 = SRC_IND; ind++; G|=0x0001;}*/
    if(*arg[0].s == '*') {GE1 = SRC_IND; ind++; G|=0x1000;}
    if(*arg[1].s == '*') {GE2 = SRC_IND; ind++; G|=0x0100;}
    if(*arg[4].s == '*') {GE3 = SRC_IND; ind++; G|=0x0010;}
    if(*arg[5].s == '*') {GE4 = SRC_IND; ind++; G|=0x0001;}
    switch(ind)        // There should be two indirect fields
    {
      case 0: // At least one fields must be indirect
              return BAD_ARG;
           // GE1 = SRC_IND;      // pick any two fields
           // obj.A.val |= 0xE0;
           // GE2 = SRC_IND;
           // obj.B.val |= 0xE0;
           // break;
      case 1: //identify the correct field for enhanced indirect
              // a) Look for fields that are not R0-R7
              //    if found, that field is indirect.
              //    Only one enhanced indirect is allowed
              // b) If all are R0-R7, just pick the first available field
              if((obj.A.val > 7) && (GE1 != SRC_IND))
              { GE1 = SRC_IND; obj.A.val|=0xE0; break; }
              if((obj.B.val > 7) && (GE2 != SRC_IND))
              { GE2 = SRC_IND; obj.B.val|=0xE0; break; }
              if((obj.D.val > 7) && (GE3 != SRC_IND))
              { GE3 = SRC_IND; obj.D.val|=0xE0; break; }
              if((obj.E.val > 7) && (GE4 != SRC_IND))
              { GE4 = SRC_IND; obj.E.val|=0xE0; break; }
              //
              // If no non R0-R7 fields found, pick one
              switch(G)
              {
                case 0x1000: // set   B,C,D to IND
                             GE2 = SRC_IND;
                             obj.B.val |= 0xE0;
                             break;
                case 0x0100: // set A,  C,D to IND
                case 0x0010: // set A,B,  D to IND
                case 0x0001: // set A,B,C   to IND
                             GE1 = SRC_IND;
                             obj.A.val |= 0xE0;
                             break;
              }

      case 2: break;  // Two indirect fields found, Enh ind not used,
      case 3: return BAD_ARG;
      case 4: return BAD_ARG;
    }
  }

  switch(GE1)
  {
    case SRC_REG: break;
    case SRC_DIR: return BAD_ARG;
    case SRC_IND: break;
    case SRC_IMM: return BAD_ARG;
    default     : return GE1;
  }
  switch(GE2)
  {
    case SRC_REG: break;
    case SRC_DIR: return BAD_ARG;
    case SRC_IND: break;
    case SRC_IMM: return BAD_ARG;
    default     : return GE2;
  }
  switch(GE3)
  {
    case SRC_REG: break;
    case SRC_DIR: return BAD_ARG;
    case SRC_IND: break;
    case SRC_IMM: return BAD_ARG;
    default     : return GE3;
  }
  switch(GE4)
  {
    case SRC_REG: break;
    case SRC_DIR: return BAD_ARG;
    case SRC_IND: break;
    case SRC_IMM: return BAD_ARG;
    default     : return GE4;
  }
  G1 = (int)srce_mode(GE1);
  G2 = (int)srce_mode(GE2);
  G3 = (int)srce_mode(GE3);
  G4 = (int)srce_mode(GE4);
/*if(G1>NO_ERR) return G1;
  if(G2>NO_ERR) return G2;
  if(G3>NO_ERR) return G3;
  if(G4>NO_ERR) return G4;
  if((G1==1)|(G1==3)|(G1==-1)) return BAD_ARG;
  if((G2==1)|(G2==3)|(G2==-1)) return BAD_ARG;
  if((G3==1)|(G3==3)|(G3==-1)) return BAD_ARG;
  if((G4==1)|(G4==3)|(G4==-1)) return BAD_ARG;*/
  if(isreg(arg[2].s,obj.C,23,0x01)==0) return PAR_ERR;
  if(isreg(arg[6].s,obj.F,22,0x01)==0) return PAR_ERR;
  if( obj.C.val>1)                return BAD_ARG;
  if((obj.F.val<2)|(obj.F.val>3)) return BAD_ARG;
  //
  // Rather than using a large switch table of 16 possable outcomes
  // the values of G1,G2,G3 and G4 are tokenized to single bits
  // each.  Then combined to a single int which is then switched
  // The resulting 4 bit field will be in the following order
  //
  // G = ( G1 G2 G3 G4 )b   where 0 == register
  //                              1 == indirect addressing
  //
  G1 >>= 1;
  G2 >>= 1;
  G3 >>= 1;
  G4 >>= 1;
  G = (G1<<3)|(G2<<2)|(G4<<1)| G3; //G4:G3 swap for subtract order
  switch(G)
  {
     case 0x0:                   // 0000
     case 0x1:                   // 0001
     case 0x2: return INV_CMBN;  // 0010
     case 0x3: P=2;              // 0011
               obj.A.shf =16; if(obj.A.val>7) return BAD_ARG;
               obj.B.shf =19; if(obj.B.val>7) return BAD_ARG;
               obj.D.shf = 0;
               obj.E.shf = 8;
               break;
     case 0x4: return INV_CMBN;  // 0100
     case 0x5: P=3;               // 0101
               obj.A.shf =19; if(obj.A.val>7) return BAD_ARG;
               obj.B.shf = 8;
               obj.D.shf = 0;
               obj.E.shf =16; if(obj.E.val>7) return BAD_ARG;
               break;
     case 0x6: P=1;              // 0110
               obj.A.shf =19; if(obj.A.val>7) return BAD_ARG;
               obj.B.shf = 8;
               obj.D.shf =16; if(obj.D.val>7) return BAD_ARG;
               obj.E.shf = 0;
               break;
     case 0x7:                   // 0111
     case 0x8: return INV_CMBN;  // 1000
     case 0x9: P=3;              // 1001
               obj.A.shf = 8;
               obj.B.shf =19; if(obj.B.val>7) return BAD_ARG;
               obj.D.shf = 0;
               obj.E.shf =16; if(obj.E.val>7) return BAD_ARG;
               break;
     case 0xA: P=1;              // 1010
               obj.A.shf = 8;
               obj.B.shf =19; if(obj.B.val>7) return BAD_ARG;
               obj.D.shf =16; if(obj.D.val>7) return BAD_ARG;
               obj.E.shf = 0;
               break;
     case 0xB: return INV_CMBN;  // 1011
     case 0xC: P=0;              // 1100
               obj.A.shf = 0;
               obj.B.shf = 8;
               obj.D.shf =16; if(obj.D.val>7) return BAD_ARG;
               obj.E.shf =19; if(obj.E.val>7) return BAD_ARG;
               break;
     default :
     case 0xD:                   // 1101
     case 0xE:                   // 1110
     case 0xF: return INV_CMBN;  // 1111
  }
  // Write code and mask to object
  obj.raw   = Instr[n].pattern;  obj.mask  = Instr[n].mask;
  // Terminate object list
  obj.G.val =  P;
  obj.G.shf = 24;
  obj.G.msk =  3;
  return PAR_NO_ERR;
}
/* ----------------------------------------------------------------------
                 Decoding for Parallel Addressing Modes

   ABSF || STF,  ABSF || STI, ADDF3 || STF, AND3 || STI, ASH3 || STI,
   FIX || STI, FLOAT || STF, LDF || STF, LDI || STI, LSH3 || STI,
   MPYF3 || STF, MPYI3 || STI, NEGF || STF, NEGI || STI, NOT || STI,
   OR3 || STI, SUBF3 || STF, SUBI3 || STI, XOR3 || STI, ADDI3 || STI,

                    STF || STF, STI || STI,
                    LDF || LDF, LDI || LDI
   ---------------------------------------------------------------------- */

MSGS AForm4( int n, OBJ &obj, char *op )
{
  char buf[80], *ptr;
  MSGS G1, G2;
  strncpy(buf,op,79);
  ptr = buf;
  int args;
  int temp;
//  Enhanced_Fields = 0;
  // split the argument list into seperate arguments
  args = arg_split(ptr,0);
  // Determine source mode as register, direct, indirect or immediate
  switch(Instr[n].en)
  {
    case __STI_STI:
    case __STF_STF:
             if(args != 5) return BAD_ARG;
             if(    isreg(arg[0].s,obj.A,22,0x07        )==0) return PAR_ERR;
             if(srce_cvrt(arg[1].s,obj.B, 0,0xff,INTEGER)!=SRC_IND) return PAR_ERR;
             if(    isreg(arg[3].s,obj.C,16,0x07        )==0) return PAR_ERR;
             if(srce_cvrt(arg[4].s,obj.D, 8,0xff,INTEGER)!=SRC_IND) return PAR_ERR;
             if(floatreg((int)obj.A.val,1)==0) return REG_INT;
             if(floatreg((int)obj.C.val,1)==0) return REG_INT;
             break;

    case __ABSI_STI: // NOTE: Identical to next case except for shift
    case __ABSF_STF: //       of dest registers
    case __FIX_STI:  //
    case __FLOAT_STF:// Also quite close to another form
    case __LDF_STF:
    case __LDI_STI:
    case __NEGI_STI:
    case __NEGF_STF:
    case __NOT_STI:
             if(args != 5) return BAD_ARG;
             if(srce_cvrt(arg[0].s,obj.A, 0,0xff,INTEGER)!=SRC_IND) return PAR_ERR;
             if(    isreg(arg[1].s,obj.B,22,0x07        )==0) return PAR_ERR;
             if(    isreg(arg[3].s,obj.C,16,0x07        )==0) return PAR_ERR;
             if(srce_cvrt(arg[4].s,obj.D, 8,0xff,INTEGER)!=SRC_IND) return PAR_ERR;
             if(floatreg((int)obj.B.val,1)==0) return REG_INT;
             if(floatreg((int)obj.C.val,1)==0) return REG_INT;
             break;

    case __LDI_LDI:
    case __LDF_LDF:
         //  if(Enhanced_Enable)
             if(args != 5) return BAD_ARG;
             if(srce_cvrt(arg[0].s,obj.A, 0,0xff,INTEGER)!=SRC_IND) return PAR_ERR;
             if(    isreg(arg[1].s,obj.B,22,0x07  )==      0) return PAR_ERR;
             if(srce_cvrt(arg[3].s,obj.C, 8,0xff,INTEGER)!=SRC_IND) return PAR_ERR;
             if(    isreg(arg[4].s,obj.D,19,0x07  )==      0) return PAR_ERR;
             if(floatreg((int)obj.B.val,1)==0) return REG_INT;
             if(floatreg((int)obj.D.val,1)==0) return REG_INT;
             break;

    case __ADDF3_STF:
    case __ADDI3_STI:
    case __AND3_STI:
    case __ASH3_STI:
    case __MPYF3_STF:
    case __MPYI3_STI:
    case __OR3_STI:
    case __XOR3_STI:
           if(args != 6) return BAD_ARG;
           args = 0;
           if(Enhanced_Enable)
           {
             if(*arg[0].s=='*') {G1 = SRC_IND; args++;}
             if(*arg[1].s=='*') {G2 = SRC_IND; args++;}
             if(*arg[2].s=='*') return PAR_ERR;
             if(*arg[4].s=='*') return PAR_ERR;
             if(*arg[5].s!='*') return PAR_ERR;
             if(args==2) return PAR_ERR;
             if(args!=1) // If no indirect fields, use enhanced
             {
               temp = Enhanced_Enable;
               Enhanced_Enable = 0;
               G1 = srce_cvrt(arg[0].s,obj.A, 0,0xff,INTEGER);
               G2 = srce_cvrt(arg[1].s,obj.B, 0,0xff,INTEGER);
               Enhanced_Enable = temp;
               if(G1 != SRC_REG) return PAR_ERR;
               if(G2 != SRC_REG) return PAR_ERR;
               // If one of the operands is not R0-R7, use it for enhanced
               // otherwise, pick the first for enhanced indirect
               if(obj.B.val > 7)
               { obj.B.val |= 0xE0;
                 obj.B.shf  =    0;
                 obj.A.msk  =    7;
                 obj.A.shf  =   19;
                 if(floatreg((int)obj.A.val,1)==0) return REG_INT;
               }
               else //(obj.A.val > 7)
               { obj.A.val |= 0xE0;
                 obj.A.shf  =    0;
                 obj.B.msk  =    7;
                 obj.B.shf  =   19;
                 if(floatreg((int)obj.B.val,1)==0) return REG_INT;
               }
             if(srce_cvrt(arg[2].s,obj.C,22,0x07,INTEGER)!=SRC_REG) return REG_INT;
             if(srce_cvrt(arg[4].s,obj.D,16,0x07,INTEGER)!=SRC_REG) return REG_INT;
             if(srce_cvrt(arg[5].s,obj.E, 8,0xFF,INTEGER)!=SRC_IND) return PAR_ERR;
             if(floatreg((int)obj.C.val,1)==0) return REG_INT;
             if(floatreg((int)obj.D.val,1)==0) return REG_INT;
             break;
             }
           }
           //
           //  Use old encoder scheme
           //
           if(srce_cvrt(arg[0].s,obj.A, 0,0xff,INTEGER)!=SRC_IND)
           //
           //  The following statement may be needed to be COFF
           //  compatible.  DASM test shows alternate assy form
           //  Except for 1st two operands, identical to previous form
           {
             if(srce_cvrt(arg[1].s,obj.A, 0,0xff,INTEGER)!=SRC_IND) return PAR_ERR;
             if(    isreg(arg[0].s,obj.B,19,0x07  )==      0) return PAR_ERR;
           }
           else
           {
             if(  isreg(arg[1].s,obj.B,19,0x07  )==      0) return PAR_ERR;
           }
           if(    isreg(arg[2].s,obj.C,22,0x07  )==      0) return PAR_ERR;
           if(    isreg(arg[4].s,obj.D,16,0x07  )==      0) return PAR_ERR;
           if(srce_cvrt(arg[5].s,obj.E, 8,0xff,INTEGER)!=SRC_IND) return PAR_ERR;
           if(floatreg((int)obj.B.val,1)==0) return REG_INT;
           if(floatreg((int)obj.C.val,1)==0) return REG_INT;
           if(floatreg((int)obj.D.val,1)==0) return REG_INT;
           break;

    case __LSH3_STI:
    case __SUBI3_STI:
    case __SUBF3_STF:
             if(args != 6) return BAD_ARG;
             if(    isreg(arg[0].s,obj.A,19,0x07  )==      0) return PAR_ERR;
             if(srce_cvrt(arg[1].s,obj.B, 0,0xff,INTEGER)!=SRC_IND) return PAR_ERR;
             if(    isreg(arg[2].s,obj.C,22,0x07  )==      0) return PAR_ERR;
             if(    isreg(arg[4].s,obj.D,16,0x07  )==      0) return PAR_ERR;
             if(srce_cvrt(arg[5].s,obj.E, 8,0xff,INTEGER)!=SRC_IND) return PAR_ERR;

             if(floatreg((int)obj.A.val,1)==0) return REG_INT;
             if(floatreg((int)obj.C.val,1)==0) return REG_INT;
             if(floatreg((int)obj.D.val,1)==0) return REG_INT;
             break;

    default:  //if(srce_cvrt(arg[0].s,obj.A,0,0xffff)==-1) return BAD_ARG;
              //if(isreg(arg[1].s,obj.B,16,0x1f)== 0) return BAD_ARG;
              return BAD_ARG;
  }
  // Write code and mask to object
  obj.raw   = Instr[n].pattern;  obj.mask  = Instr[n].mask;
  //
  //---- Only lower field enhanced indirect is allowed ----
  //
//  if(Enhanced_Fields > 1) return PAR_ERR;
  return PAR_NO_ERR;
}
/* ----------------------------------------------------------------------
           Type 1 Integer Three-Operand Addressing Modes
              ADDC3, ADDI3, AND3, ANDN3, ASH3, CMPI3,
            LSH3, MPYI3, OR3, SUBB3, SUBI3, TSTB3, XOR3
   ---------------------------------------------------------------------- */
MSGS AForm5( int n, OBJ &obj, char *op )
{
  char buf[80], *ptr;
  long T;
  MSGS T1, T2;
  int args;
  strncpy(buf,op,79);
  ptr = buf;
  // split the argument list into seperate arguments
  args = arg_split(ptr,0);
  switch(Instr[n].en)
  {
    case __CMPI3:
    case __CMPF3:
    case __TSTB3: if(args != 2) return BAD_ARG; break;
    default:      if(args != 3) return BAD_ARG; break;
  }
  // Determine the mode
  //
  //  T   src1(T1)      src2(T2)       srce cvrt
  //  -----------------------------    --------
  //  0   reg           reg            0   reg
  //  1   ind 0,1,IRx   reg           x1   direct
  //  2   reg           ind 0,1,IRx    2   indirect
  //  3   ind 0,1,IRx   ind 0,1,IRx   x3   immediate
  //
  T1 = srce_cvrt(arg[0].s, obj.A, 0, 0xff,INTEGER);
  T2 = srce_cvrt(arg[1].s, obj.B, 8, 0xff,INTEGER);
  switch(T1)
  {
    case SRC_REG: switch(T2)
                  {
                    case SRC_REG: T=0; break;
                    case SRC_IND: T=1; break;
                    case SRC_DIR: return BAD_ARG;
                    case SRC_IMM: return BAD_ARG;;
                    default     : return T2;
                  }
                  break;
    case SRC_IND: switch(T2)
                  {
                    case SRC_REG: T=2; break;
                    case SRC_IND: T=3; break;
                    case SRC_DIR: return BAD_ARG;
                    case SRC_IMM: return BAD_ARG;;
                    default     : return T2;
                  }
                  break;
    case SRC_DIR: return BAD_ARG;  // direct allowed for C4x
    case SRC_IMM: return BAD_ARG;
    default     : return T1;
  }
  // Convert the destination to an object
  switch(Instr[n].en)
  {
    case __TSTB3:
    case __CMPF3:
    case __CMPI3:  obj.C.val=0; obj.C.msk = 1;
                   break;
    default:       if(isreg(arg[2].s,obj.C,16,0x1f)== 0) return BAD_ARG;
                   break;
  }
  switch(Instr[n].en)
  {
    case __ADDF3:  // Floating point opcodes are restricted to R0-R7
    case __CMPF3:
    case __MPYF3:
    case __SUBF3:  if(floatreg(obj.C.val,1)==0)return REG_INT;
                   if(T1==0) if(floatreg(obj.A.val,1)==0)return REG_INT;
                   if(T2==0) if(floatreg(obj.B.val,1)==0)return REG_INT;
                   break;
    default:       break;
  }
  // Write code and mask to object
  obj.raw   = Instr[n].pattern;
  obj.mask  = Instr[n].mask;
  // Add mode to object list
  obj.D.shf = 21;
  obj.D.val = T;
  obj.D.msk = 0x3;
  return NO_ERR;
}
/* ----------------------------------------------------------------------
               Conditional-Branch Addressing Modes
         DB<cond>,  DB<cond>D, B<cond>, B<cond>D, B_AT, CALL<cond>
   ---------------------------------------------------------------------- */
MSGS AForm7( int n, OBJ &obj, char *op )
{
  char buf[80], *ptr;
  MSGS B;
  int args;
//  int PC_REL = 0;
  strncpy(buf,op,79);
  ptr = buf;
  // split the argument list into seperate arguments
  args = arg_split(ptr,0);

  // Determine source mode as register, direct, indirect or immediate
  switch(Instr[n].en)
  {
    case __RETIc:
    case __RETSc: if(args!=0) return BAD_ARG;
                  obj.raw   = Instr[n].pattern;
                  obj.mask  = Instr[n].mask;
                  return NO_ERR;
    case __DBc : //+1
    case __DBDc: //+3
                 if(args!=2) return BAD_ARG;
                 if(isreg(arg[0].s,obj.A,22,0x7)== 0) return BAD_ARG;
                 if((obj.A.val < 8) | (obj.A.val > 15)) return BAD_ARG;
                 //
                 // The mask is set to -1 with fixup done after XA
                 // to prevent operand size warnings
                 B = srce_cvrt(arg[1].s, obj.B,0,0xffffffffL,INTEGER);
                 switch(B)
                 { case SRC_REG: if(obj.B.val>MAXREG) return BAD_ARG; break;
                   case SRC_IMM: break;
                   default: return BAD_ARG; // srce conversion error
                 }
                 // Mode register or PC-relative
                 obj.C.shf = 25;
                 obj.C.val = srce_mode(B);
                 obj.C.msk = 0x1;
                 break;
    case __CALLc: //+1
    case __Bc   : //+1
    case __BDc  : //+3
                 if(args!=1) return BAD_ARG;
                 // The mask is set to -1 with fixup done after XA
                 // to prevent operand size warnings
                 B = srce_cvrt(arg[0].s, obj.A, 0, 0xffffffffL,INTEGER);
                 switch(B)
                 { case SRC_REG: if(obj.A.val>MAXREG) return BAD_ARG; break;
                   case SRC_IMM: break;
                   default: return BAD_ARG; // srce conversion error
                 }
                 // Mode register or PC-relative
                 obj.B.shf = 25;
                 obj.B.val = srce_mode(B);
          //     obj.B.val = B;  // compiler should flag a warning
                 obj.B.msk = 0x1;
                 break;
    default:     return FATAL_OPC;
              // printf("\n\nShould never get to FORM7 default!\n\n");
              // fcloseall();
              // exit(0);
  }
  switch(Instr[n].en)
  {
    case __BDc  :if(B==SRC_IMM)
                 { obj.A.val -= 3;       // adjust for delay slots
                   obj.A.val -= SEG[current_seg].offs;
                 }
                 break;
    case __CALLc:
    case __Bc   :if(B==SRC_IMM)
                 { obj.A.val -= 1;       // adjust for delay slots
                   obj.A.val -= SEG[current_seg].offs;
                 }
                 break;
    case __DBDc :if(B==SRC_IMM)
                 { obj.B.val -= 3;       // adjust for delay slots
                   obj.B.val -= SEG[current_seg].offs;
                 }
                 break;
    case __DBc  :if(B==SRC_IMM)
                 { obj.B.val -= 1;       // adjust for delay slots
                   obj.B.val -= SEG[current_seg].offs;
                 }
                 break;
    default     :break;
  }

  switch(Instr[n].en)
  {
    case __BDc  :
    case __CALLc:
    case __Bc   :if(B==SRC_IMM)
                 { strcpy(g_strg2, nullstring);
                   if(   ((long)obj.A.val >  32767L)
                      || ((long)obj.A.val < -32768L))
                     assm_error_msg(d_disp,"");
                   obj.A.val &= 0xffff;
                   obj.A.msk  = 0xffff;
                 }
                 break;
    case __DBDc :
    case __DBc  :if(B==SRC_IMM)
                 {  strcpy(g_strg2, nullstring);
                   if(   ((long)obj.B.val >  32767L)
                      || ((long)obj.B.val < -32768L))
                     assm_error_msg(d_disp,"");
                   obj.B.val &= 0xffff;
                   obj.B.msk  = 0xffff;
                 }
                 break;
    default     :break;
  }

  obj.raw   = Instr[n].pattern;
  obj.mask  = Instr[n].mask;
  return NO_ERR;
}
/* ----------------------------------------------------------------------
        Particular Conditional-Branch Addressing Mode ( form 2 )
                           TRAP<cond> <n>
   ---------------------------------------------------------------------- */
MSGS AForm9( int n, OBJ &obj, char *op )
{
  char buf[80], *ptr;
  int args;
  strncpy(buf,op,79);
  ptr = buf;
  // split the argument list into seperate arguments
  args = arg_split(ptr,0);
  // Determine source mode as register, direct, indirect or immediate
  switch(Instr[n].en)
  {
    case __TRAP: if(args != 1) return BAD_ARG;
                 if(srce_cvrt(arg[0].s, obj.A,0,0x1f,INTEGER)!=SRC_IMM)
                    return BAD_ARG;
                 if(obj.A.val > 0x1F) return BAD_ARG;
                 break;
    case __TRAP4x: if(args != 1) return BAD_ARG;
                 if(srce_cvrt(arg[0].s, obj.A,0,0x1FF,INTEGER)!=SRC_IMM)
                    return BAD_ARG;
                 if(obj.A.val > 0x1FF) return BAD_ARG;
                 break;
    default:     return BAD_ARG;
  }
  // Write code and mask to object
  obj.raw   = Instr[n].pattern;
  obj.mask  = Instr[n].mask;
  return NO_ERR;
}
/* ----------------------------------------------------------------------
                        Particular Instructions
                           SWI, IDLE, IDLE2, SIGI
   ---------------------------------------------------------------------- */
MSGS AFormA( int n, OBJ &obj, char *op )
{
  char buf[80], *ptr;
  int args;
  strncpy(buf,op,79);
  ptr = buf;
  // split the argument list into seperate arguments
  args = arg_split(ptr,0);
  // Determine source mode as register, direct, indirect or immediate
  if(args != 0) return BAD_ARG;
  // Write code and mask to object
  obj.raw   = Instr[n].pattern;
  obj.mask  = Instr[n].mask;
  return NO_ERR;
}
/* ----------------------------------------------------------------------
              Decoding Long Immediate Addressing Modes
                  RPTB,RPTBD, BR, BRD, CALL, LAJ
   ---------------------------------------------------------------------- */
MSGS AFormB( int n, OBJ &obj, char *op )
{
  char buf[80], *ptr;
  MSGS B;
  int args;
  strncpy(buf,op,79);
  ptr = buf;
  // split the argument list into seperate arguments
  args = arg_split(ptr,0);
  if(args!=1) return BAD_ARG;
  // Determine source mode as register, direct, indirect or immediate
  obj.raw   = Instr[n].pattern;
  obj.mask  = Instr[n].mask;
  B = srce_cvrt(arg[0].s, obj.A, 0, 0xffffffL,INTEGER);
  switch(B)
  {
    case SRC_REG: assm_error_msg(UNKN_EXPR,arg[0].s
    );
    case SRC_IMM: return NO_ERR; // Error already processed
    default:
    case SRC_DIR:
    case SRC_IND: return BAD_ARG;
//  case SRC_IMM: return NO_ERR;
  }
}
