//-----------------------------------------
// DASMC40.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 disassembler function forms for the
// TMS320C3x.  Also included are the functions needed to
// form the register, indirect and direct addressing mode
// substrings
//----------------------------------------------------------
// Changes to support The University of Texas at Austin
// simulator are enclosed in
// #ifdef UTSIM3X
// #endif
// conditionals.  The University of Texas at Austin C30 simulator
// is by Chi Duong, Brian L. Evans, and Chris Moy. For more information
// on the simulator, see http://www.ece.utexas.edu/~bevans/.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "opcodes.h"
#include "tmsfloat.h"
#include "symbols.h"
#include "dsk.h"

#ifdef UTSIM3X

#include "simmisc.h"
#include "pipeline.h"
#include "memmap.h"

/*
addressing is an array of function pointers that point to the indirect
address generation functions. They are called through this array by the
decoder.
*/
static void (*addressing[])(int, state *, unsigned char,
                            unsigned char, unsigned long **)=
{
        C30SimPredisadd,
        C30SimPredissub,
        C30SimPredisaddmod,
        C30SimPredissubmod,
        C30SimPostdisaddmod,
        C30SimPostdissubmod,
        C30SimPostdisaddcirc,
        C30SimPostdissubcirc,
        C30SimPreir0add,
        C30SimPreir0sub,
        C30SimPreir0addmod,
        C30SimPreir0submod,
        C30SimPostir0addmod,
        C30SimPostir0submod,
        C30SimPostir0addcirc,
        C30SimPostir0subcirc,
        C30SimPreir1add,
        C30SimPreir1sub,
        C30SimPreir1addmod,
        C30SimPreir1submod,
        C30SimPostir1addmod,
        C30SimPostir1submod,
        C30SimPostir1addcirc,
        C30SimPostir1subcirc,
        C30SimIndirect,
        C30SimBitrev,
};
#define C30SIM_REG_INTERLOCK(source,st,pipe) \
        if ((source >= &st->ar0) && (source <= &st->bk)) { \
    			if((pipe->tempAccessAR=pipe->accessAR+1) > 1) return 2;} \
        else if (source == &st->dp) {  \
            if((pipe->tempAccessDP=pipe->accessDP+1) > 1) return 2;}   \
        else if (source == &st->sp) {  \
    			if((pipe->tempAccessSP=pipe->accessSP+1) > 1) return 2;}

#define C30SIM_ADDRESSING_MODE(n,pipe,mode,st,ar,disp,source) \
        C30SIM_REG_INTERLOCK(*source,st,pipe) \
        addressing[mode](n,st, ar, disp, source);

#define C30SIM_UPDATE_saveArn \
        if(st->updateArn[0].flag==1) st->saveArn = 1;

#define C30SIM_UPDATE_COND \
        st->cond[st->saveCond].flag = 1; \
        if(st->saveCond==0) st->saveCond = 1;  \
        else st->saveCond = 0;

#define C30SIM_MEMORY_ACCESS(pipe,source,st,addr) \
        if (pipe->accessDP) return 2; \
        (source) = C30SimMemMap(st, addr);  \
        C30SIM_REG_INTERLOCK(source,st,pipe)

#define C30SIM_LDF_COND(instr,cond) \
        if (((instr) >> 28) == 0x4) (cond) = ((instr) >> 23) & 0x0000001f;

#define C30SIM_LDI_COND(instr,cond) \
        if (((instr) >> 28) == 0x5) (cond) = ((instr) >> 23) & 0x0000001f;

#define C30SIM_SAVE_REG(dest,src) \
		(dest) = (src);	

#define C30SIM_SAVE_REG2(dest1,dest2,src) \
		(dest1) = (dest2) = (src);

#define C30SIM_PREVENT_WRITES_TO_ROM(pipe,opcode,st) \
  pipe->opcode1 = Instr[x].sform; \
  /* these statements prevent writes to ROM */ \
  if (((unsigned long)(pipe)->dest1 >= (unsigned long)((st)->rom)) && \
      ((unsigned long)(pipe)->dest1 < (unsigned long)((st)->romEnd))) \
     (pipe)->dest1 = (unsigned long *)(&(st)->dummy); \
  if (((unsigned long)(pipe)->dest2 >= (unsigned long)(st)->rom) && \
      ((unsigned long)(pipe)->dest2<(unsigned long)((st)->romEnd))) \
     (pipe)->dest2 = (unsigned long *)(&(st)->dummy);

/* For instruction "LDM src,dst" (Load Floating-Point Mantissa), if the src
   operand is from memory, the entire memory contendts are loaded as teh
   mantissa, instead of the 8MSBs being the exponent.  So, I signal this
   case by using st->ldm=1.  Therefore, in DForm0 to which LDM belonges,
   case direct (1) or indirect (2) addressing mode, I assign st->ldm to 1
 */
#define C30SIM_LDM_FROM_MEMORY(st) (st)->ldm = 1;
 
#define C30SIM_CHECK_FLOAT_REG(regnum) if ((regnum) > 0x7) return 1
#define C30SIM_CHECK_INT_REG(regnum) if ((regnum) > 27) return 1

#else

#define C30SIM_ADDRESSING_MODE(n,pipe,mode,st,ar,disp,source)
#define C30SIM_REG_INTERLOCK(source,st,pipe)
#define C30SIM_UPDATE_saveArn
#define C30SIM_UPDATE_COND 
#define C30SIM_MEMORY_ACCESS(pipe,source,st,addr)
#define C30SIM_LDF_COND(instr,cond)
#define C30SIM_LDI_COND(instr,cond)
#define C30SIM_SAVE_REG(dest,src)
#define C30SIM_SAVE_REG2(dest1,dest2,src)
#define C30SIM_PREVENT_WRITES_TO_ROM(pipe,opcode,st)
#define C30SIM_LDM_FROM_MEMORY(st)
#define C30SIM_CHECK_FLOAT_REG(regnum)

#endif   /* UTSIM3X */

ulong CURRENT_DP = 0x00000080; // Current processor data page
char  C3Xmode = 1;
ulong PC_Address; // used for PC-Relative addressing mode
//---------------------------------------------------------------------
//      syntax :   <instruction> <src>,<dst>
//     example :   <buf> = "ABSF" <src> = "R1"  <dst> = "R0"
//                     <buf> = "ABSF R1,R0"
//---------------------------------------------------------------------
static char* Concat2( char *buf, char *src, char *dst )
{
  char b[80];
  strcpy(b,buf);
  if ( *dst ) sprintf( buf, "%s %s,%s", b, src, dst );
  else sprintf( buf, "%s %s",b,src);
  return buf;
}
//---------------------------------------------------------------------
//   syntax :  <instruction> <src1>,<src2>,<dst>
//  example :  <buf> = "ASH3"  <src1> = "R0" <src2> = "R1" <dst> = "R7"
//             <buf> = "ASH3 R0,R1,R7"
//---------------------------------------------------------------------
static char* Concat3( char *buf, char *src1, char *src2, char *dst )
{
  char b[80];
  strcpy(b,buf);
  if ( *dst ) sprintf( buf, "%s %s,%s,%s", b, src1, src2, dst );
  else sprintf( buf, "%s %s,%s", b, src1, src2);
  return buf;
}
//---------------------------------------------------------------------
//  Extract 2 strings from src, separated by sep
//
//  example:  <src> = "MPYI3 || STI"  and <sep> = "||"
//            <dst1> = "MPYI3 "  <dst2> = "|| STI"
//---------------------------------------------------------------------
static void Extract2( char *src, char *dst1, char *dst2, char *sep )
{
  char *p;
  strcpy(dst1,src);
  p = strstr(dst1,sep);
  *(p-1)=0;
  sprintf( dst2, " %s",p);
}


/************************************************************************
              Decoding for General Addressing Modes
    ABSF,  ADDF , CMPF,  LDE , LDF  , LDFI, LDM , MPYF, NEGF,
    POPF,  PUSHF, RCPF, RND  , SUBF, SUBRF, NORM, LDFc, FIX , TOIEEE
***************************************************************************/
DFORM_PROTOTYPE(DForm0)
{
  ushort f_src_src2_disp;    //  8 bits,  0- 7
  ushort f_src_src2_ARn ;    //  3 bits,  8-10
  ushort f_src_src2_modn;    //  5 bits, 11-15
  ushort f_src_src1     ;    // 16 bits,  0-15
  ushort f_dst          ;    //  5 bits, 16-20  destination
  ushort f_g            ;    //  2 bits, 21-22  t switch
//ushort f_code         ;    //  9 bits, 23-31  opcode
  char src[80], dst[80]; //, tmp[80];
  f_src_src2_disp = (instr      ) & 0x000FFL;
  f_src_src2_ARn  = (instr >>  8) & 0x00007L;
  f_src_src2_modn = (instr >> 11) & 0x0001FL;
  f_src_src1      = (instr      ) & 0x0FFFFL;
  f_dst           = (instr >> 16) & 0x0001FL;
  f_g             = (instr >> 21) & 0x00003L;
//f_code          = (instr >> 23) & 0x001FFL;

  if (f_dst >= MAXREG) return 1;
  strcpy(buffer,Instr[n].instr);
  strcpy(dst,C30Reg[f_dst].s);

#ifdef UTSIM3X
  switch(Instr[n].en)
  {
  	 case __PUSHF:
    case __CMPF : C30SIM_SAVE_REG(pipe->source2,pipe->regs[f_dst]);
    					C30SIM_REG_INTERLOCK(pipe->source2,st,pipe);
    					break;
    case __ABSF :
    case __NEGF :
    case __RND  :
    case __NORM :
    case __FIX  :
	 case __LDFc :
    case __LDE  :
    case __LDF  :
    case __LDM  :
    case __LDFI :
    case __POPF : C30SIM_SAVE_REG(pipe->dest1,pipe->regs[f_dst]);
    					C30SIM_REG_INTERLOCK(pipe->dest1,st,pipe);
    					break;
    default     : C30SIM_SAVE_REG2(pipe->source2,pipe->dest1,pipe->regs[f_dst]);
    					C30SIM_REG_INTERLOCK(pipe->source2,st,pipe);
    					break;
  }
#endif
  switch ( f_g )
  { // src = register
    case 0: if(f_src_src1 >= MAXREG) return 1;

         // if((f_src_src1 > 0x07) && (f_src_src1 < 0x1C)) return 1;//C40
            if(Instr[n].en != __FLOAT)  // Any reg for src is valid
              if(f_src_src1 > 0x07) return 1;//C30

            strcpy(src,C30Reg[f_src_src1].s);
            C30SIM_SAVE_REG(pipe->source1, pipe->regs[f_src_src1]);
            C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
            break;

    case 1: 
            *src='@';
            C30SIM_MEMORY_ACCESS(pipe, pipe->source1, st,
                   (((unsigned long)(st->dp<<16) | (f_src_src1))&0x00ffffffL));
            if(Instr[n].en == __LDM)
              C30SIM_LDM_FROM_MEMORY(st);
            if(get_label(src+1,(CURRENT_DP << 16) | f_src_src1,0)) break;
            sprintf( src, "@0%04xH",f_src_src1);
            break;

    case 2: if( f_src_src2_modn > MAX_MOD ) return 1;
            if( f_src_src2_modn < 8 )  {
               sprintf( src, Mod[f_src_src2_modn], f_src_src2_ARn, f_src_src2_disp);
               C30SIM_ADDRESSING_MODE(0,pipe, f_src_src2_modn,
                                      st, f_src_src2_ARn, f_src_src2_disp,
                                      &pipe->source1);
               C30SIM_UPDATE_saveArn;
            }
            else
            {
              if(f_src_src2_disp) return 1;
              sprintf( src, Mod[f_src_src2_modn], f_src_src2_ARn);
              C30SIM_ADDRESSING_MODE(0, pipe, f_src_src2_modn,
                                     st, f_src_src2_ARn, 0, &pipe->source1);
              C30SIM_UPDATE_saveArn;
              if(Instr[n].en == __LDM)
                C30SIM_LDM_FROM_MEMORY(st);
            }
            break;

    case 3: //if(f_code == 0x12)  // LDM
            if(Instr[n].en == __LDM)
            {
/* In the non-simulator disassembler, we check to make sure that
   bits 15-12 of the 16-bit immediate mode are zero and return 1 if they
   are not.  In the simulator disassembler, we force these bits to be zero.
 */
#ifdef UTSIM3X
                f_src_src1 &= 0x0fff; // LDM:  force bits 15-12 to 0 
#else
                if(f_src_src1 & 0xF000) return 1;
#endif
            }
            sprintf( src, "%10e",Short_Float(f_src_src1));
            C30SIM_SAVE_REG(pipe->hold,
                            (f_src_src1 & 0x00008000) ?
                                (f_src_src1 | 0xffff0000L) : f_src_src1);
            C30SIM_SAVE_REG(pipe->hold, pipe->hold << 12);
            C30SIM_SAVE_REG(pipe->source1, &pipe->hold);
            C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
            break;
    default:return 1;
  }
//if((f_dst > 0x07) && (f_dst < 0x1C)) return 1;  // C40
  if(Instr[n].en!=__FIX)
    if(f_dst > 0x07)                      return 1;  // C30
  /***********************************/
  /* Special case exception handling */
  /***********************************/
  switch(Instr[n].en)
  {
    case __CMPF : C30SIM_CHECK_FLOAT_REG(f_dst);
                  C30SIM_SAVE_REG(pipe->dest1, 0);
                  C30SIM_REG_INTERLOCK(pipe->dest1,st,pipe);
                  break;
    case __LDFc : C30SIM_LDF_COND(instr, st->cond[st->saveCond].val);
                  C30SIM_UPDATE_COND;
                  break;
    case __ABSF :
    case __ADDF :
    case __LDE  :
    case __LDF  :
    case __LDM  :
    case __MPYF :
    case __SUBF :
    case __NEGF :
    case __SUBRF:
    case __RND  : C30SIM_CHECK_FLOAT_REG(f_dst);
                  break;
    case __LDFI : C30SIM_CHECK_FLOAT_REG(f_dst);
                  if ((f_g!=1) && (f_g!=2) ) return 1;
                  break;
    case __POPF :
    case __PUSHF: C30SIM_CHECK_FLOAT_REG(f_dst); 
                  strcpy(src,dst);
                  *dst = 0;
    default     : break;
  }

  C30SIM_SAVE_REG(pipe->dest2, 0);
  Concat2( buffer, src, dst );
  return 0;
}
/* ----------------------------------------------------------------------
              Decoding for General Addressing Modes
  Instructions handled :

  ABSI, ADDC , ADDI, AND, ANDN, ASH , CMPI,
  LDP , LDI  , LDII, FLOAT, LSH, MPYI, NEGB,
  NEGI, NOP  , NOT , POP, PUSH, OR  , ROL , ROLC,
  ROR , RORC , RPTS, STF, STFI, STIK, STI , STII, SUBB, SUBC, SUBI,
  SUBRB,SUBRI, TSTB, XOR, IACK,
  LDI<cond> , LDA , FRIEEE
   ---------------------------------------------------------------------- */

DFORM_PROTOTYPE(DForm1)
{
  char src[80], dst[80], tmp[80];
  ushort f_src_src2_disp;    //  8 bits,  0- 7
  ushort f_src_src2_ARn ;    //  3 bits,  8-10
  ushort f_src_src2_modn;    //  5 bits, 11-15
  ushort f_src_src1     ;    // 16 bits,  0-15
  ushort f_dst          ;    //  5 bits, 16-20  destination
  ushort f_g            ;    //  2 bits, 21-22  t switch
//ushort f_code         ;    //  9 bits, 23-31  opcode
#ifdef UTSIM3X
  unsigned long *swap = 0L;
#endif

  f_src_src2_disp = (instr      ) & 0x000FFL;
  f_src_src2_ARn  = (instr >>  8) & 0x00007L;
  f_src_src2_modn = (instr >> 11) & 0x0001FL;
  f_src_src1      = (instr      ) & 0x0FFFFL;
  f_dst           = (instr >> 16) & 0x0001FL;
  f_g             = (instr >> 21) & 0x00003L;
//f_code          = (instr >> 23) & 0x001FFL;


//check to make sure that f_dst < 27 for most of integer instructions
#ifdef UTSIM3X
  switch (Instr[n].en)
  {
        case __LDP:
        case __STIK:
        case __RPTS: break;
        case __STF:
        case __STFI:
        case __FLOAT: C30SIM_CHECK_FLOAT_REG(f_dst); break;
        default:      C30SIM_CHECK_INT_REG(f_dst); break;
  }
#endif

  if(C3Xmode)                      // All registers valid for C40
    if (f_dst >= MAXREG) return 1;

  /*
  switch(instr >> 28)                // Test for LDFcnd / LDIcnd
  {
    case 0x4:
    case 0x5: if((instr >> 16) != 0x5070)  break;  // Exclude LDI x,DP
              else strcpy(buffer,Instr[n].instr); break;
    default : strcpy(buffer,Instr[n].instr); break;
  }
*/

  strcpy(buffer,Instr[n].instr);
  strcpy(dst,C30Reg[f_dst].s);

#ifdef UTSIM3X
  switch(Instr[n].en)
  {
  	 case __PUSH :
    case __TSTB :
    case __CMPI : C30SIM_SAVE_REG(pipe->source2,pipe->regs[f_dst]);
                  C30SIM_REG_INTERLOCK(pipe->source2,st,pipe);
                  break;
    case __ABSI :
    case __NEGB :
    case __NEGI :
    case __FLOAT:
    case __NOT  :
    case __FIX  :
    case __LDI  :
	 case __LDIc :
    case __LDII :
    case __POP  : C30SIM_SAVE_REG(pipe->dest1,pipe->regs[f_dst]);
    					C30SIM_REG_INTERLOCK(pipe->dest1,st,pipe);
                  break;
    case __LDP  : C30SIM_SAVE_REG(pipe->dest1,pipe->regs[16]); /* pipe->regs[16] = &st->dp */
    					C30SIM_REG_INTERLOCK(pipe->dest1,st,pipe);
    					break;
    default     : C30SIM_SAVE_REG2(pipe->source2,pipe->dest1,pipe->regs[f_dst]);
    					C30SIM_REG_INTERLOCK(pipe->source2,st,pipe);
                  break;
  }
#endif
  switch ( f_g )
  {
   // Register
   case 0 :
   if(C3Xmode) {if(Instr[n].en == __STIK) return 1;} // STIK exception!
   else        {if(Instr[n].en == __STIK) break;   }

            if(f_src_src1 >= MAXREG) return 1;
            strcpy(src,C30Reg[f_src_src1].s);
            C30SIM_SAVE_REG(pipe->source1, pipe->regs[f_src_src1]);
            C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
            break;

   // Direct
   case 1 :
            *src='@';
            C30SIM_MEMORY_ACCESS(pipe, pipe->source1, st,
                   (((unsigned long)(st->dp<<16) | (f_src_src1))&0x00ffffffL));
            if(get_label(src+1,(CURRENT_DP << 16) | f_src_src1,0)) break;
            sprintf( src, "@0%04xH",f_src_src1);
            break;
   // Indirect
   case 2 : if( f_src_src2_modn>MAX_MOD ) return 1;
            if( f_src_src2_modn < 8 ) {
               sprintf( src, Mod[f_src_src2_modn], f_src_src2_ARn, f_src_src2_disp);
               C30SIM_ADDRESSING_MODE(0, pipe, f_src_src2_modn,
                                      st, f_src_src2_ARn, f_src_src2_disp,
                                      &pipe->source1);
               C30SIM_UPDATE_saveArn;
            }
            else
            {
              if(f_src_src2_disp) return 1;
              sprintf( src, Mod[f_src_src2_modn], f_src_src2_ARn);
              C30SIM_ADDRESSING_MODE(0, pipe, f_src_src2_modn,
                                     st, f_src_src2_ARn, 0, &pipe->source1);
              C30SIM_UPDATE_saveArn;
            }
            break;
   // Immediate
   case 3 :
#ifdef UTSIM3X
            switch(Instr[n].en)
            {
              case __AND:
              case __ANDN:
              case __NOT:
              case __OR:
              case __XOR: C30SIM_SAVE_REG(pipe->hold, f_src_src1);
                          break;
              default:    C30SIM_SAVE_REG(pipe->hold,
                              (f_src_src1 & 0x00008000) ?
                                (f_src_src1 | 0xffff0000L) : f_src_src1);
            }
            C30SIM_SAVE_REG(pipe->source1, &pipe->hold);
            C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
#endif
            switch(Instr[n].en)
            {
              case __FLOAT : C30SIM_CHECK_FLOAT_REG(f_dst);     
                             break;
              case __ABSI:  // Integer opcodes that display decimal (not hex)
              case __ADDC:
              case __ASH :
              case __LSH :
              case __NEGB:
              case __SUBRB:
              case __SUBB:
              case __SUBC:
              case __CMPI:
              case __ADDI:
              case __MPYI:
              case __SUBRI:
              case __SUBI:
              case __IACK:
              case __NEGI:
              case __LDI :
              case __LDIc :
              case __STIK:
              case __LDII:  sprintf( src, "%d",(int) ((f_src_src1 << 16) >>16) );
                            break;
              case __RPTS : sprintf( src, "%u",(int) f_src_src1);
                            break;
            //case __FRIEEE:
            //               sprintf( src, "%8g",Short_Float(f_src_src1));
            //               break;
        		//    AND, ANDN, LDP
        		//    NOP, NOT, OR, POP, PUSH, STF, ROL, ROLC,
        		//    TSTB, XOR     // opcodes that bit field displays are better
              default:       sprintf( src, "0%04xh",(int) f_src_src1);
                             break;
            }
            break;
    default:return 1;
  }
  /* -------- exceptions relative to destination and flag operands ---------*/
  if((instr >> 16) == 0x5070)  // LDP
#ifdef DASMTEST
    sprintf(src,"@0%04x0000h",(uint)(instr & 0xFFFF));
#else
    sprintf(src,"0%04xh",(uint)(instr & 0xFFFF));
#endif
  switch(Instr[n].en) // ( f_code )
  {
    case __LDII:
    case __SIGI:if((f_g == 0) || (f_g == 3) ) return 1;
                break;

    case __NOP: *dst = 0;
                C30SIM_SAVE_REG(pipe->dest1, 0);
                if ((f_g ==1) || (f_g == 3) ) return 1;
                if ( f_g == 0 ) *src=0;
                break;

    case __LDA: if(C3Xmode) return 1;         // Enable only for C4x
                if(f_dst <  0x08) return 1;  // dst = R0-R7 not allowed
                if(f_dst <  0x13) break;     // AR0-AR7,DP,IR0,IR1 valid
                if(f_dst == 0x14) break;
                return 1;
 
    case __FRIEEE:
                if(C3Xmode) return 1;         // Enable only for C4x
                if((f_dst > 0x7) && (f_dst < 0x1C))  return 1;
                if((f_g == 0) || (f_g == 3) ) return 1;
                break;
//  case __POP:
//  case __PUSH: strcpy(src,dst);
//               *dst = 0;
//               break;
    case __ROL :
    case __ROLC:
    case __ROR :
    case __RORC:if (f_g != 3) return 1;
    case __POP:
    case __PUSH:strcpy(src,dst);
                *dst = 0;
                break;
    case __RPTS:
                if ( f_dst != 0x1B ) return 1;
                *dst = 0;
                break;
    case __NORM:
             // if((f_dst > 0x07) && (f_dst < 0x1C)) return 1; //C40
             // FIXME: This is in Keith's version, but is it necessary?
                if(f_dst > 0x07)                      return 1; //C30
                break;
    case __IACK:
                if (( (f_g != 1) && (f_g != 2)) ) return 1;
                *dst=0;
                break;
//  case __LDEP: if(f_src_src1 & 0xFFFE) return 1; // Only ITVP, TVTP allowed
//  /* LDEP */  if(f_src_src1) strcpy(src,"TVTP"); strcpy(src,"IVTP");
//              break;
 
//  case __LDEP: if(f_dst & 0x1E) return 1; // Only ITVP, TVTP allowed
//  /* LDPE */  if(f_dst ) strcpy(dst,"TVTP"); strcpy(dst,"IVTP");
//              break;
    case __STFI:
    case __STF:
    case __TOIEEE:
             // if((f_dst > 0x07) && (f_dst < 0x1C)) return 1; //C40
                if(f_dst > 0x07)                      return 1; //C30

    case __STI:
    case __STIK:
    case __STII:
                C30SIM_SAVE_REG(swap, pipe->dest1);
                C30SIM_SAVE_REG(pipe->dest1, pipe->source1);
                C30SIM_SAVE_REG(pipe->source1, swap);
                C30SIM_SAVE_REG(pipe->source2, 0);

                if(Instr[n].en == __STIK)
                {
                  switch (f_g)  // STIK exceptions only
                  {
                    case 0 : *src='@';
                       if(get_label(src+1,(CURRENT_DP<<16) | f_src_src1,0))
                             break;
                             sprintf( src, "@0%04xH",f_src_src1);
                             break;
                    case 3 : if( f_src_src2_modn>MAX_MOD ) return 1;
                             if( f_src_src2_modn < 8 )
                               sprintf(src,
                                       Mod[f_src_src2_modn],
                                       f_src_src2_ARn,
                                       f_src_src2_disp);
                             else
                             {
                               if(f_src_src2_disp) return 1;
                               sprintf(src,
                               Mod[f_src_src2_modn], f_src_src2_ARn);
                             }
                             break;
                    default: break;
                  }
                }
                strcpy(tmp,src); strcpy(src,dst), strcpy(dst,tmp);
                if ((f_g == 0) || (f_g == 3))
                {
                   if(Instr[n].en==__STIK)
                //  if(f_code == 0x2A)  /* STIK - C40 ONLY */
                     sprintf(src,"%d",(((int)f_dst) << 11) >> 11);
                   else
                     return 1; // if C30
                }
                break;
    case __CMPI: C30SIM_SAVE_REG(pipe->dest1, 0);
                 break;
    case __LDIc: C30SIM_LDI_COND(instr, st->cond[st->saveCond].val); 
                 C30SIM_UPDATE_COND;
    default:     break;
  }
  Concat2( buffer, src, dst );
  C30SIM_SAVE_REG2(pipe->source3, pipe->source4, 0);

  //
  // Special case for LDP when using dasm_assm
  //
  if(dasm_assm_on) 
    if((instr & 0xFFFFFF00L) == 0x08700000L)
      sprintf(buffer,"LDP 0%06lxh,DP",(instr & 0xFF)<<16);
  return 0;
}

/* ----------------------------------------------------------------------
              Decoding for Parallel Addressing Modes
     MPYF3 || ADDF3,  MPYF3 || SUBF3,  MPYI3 || ADDI3,  MPYI3 || SUBI3
   ---------------------------------------------------------------------- */
DFORM_PROTOTYPE(DForm3)
{
  char srcA[80], srcB[80], srcC[80], srcD[80], tmp[80];
  ushort f_ARn          ;    //  3 bits,  0- 2
  ushort f_modn         ;    //  5 bits,  3- 7
  ushort f_ARm          ;    //  3 bits,  8-10
  ushort f_modm         ;    //  5 bits, 11-15
  ushort f_src2         ;    //  3 bits, 16-18
  ushort f_src1         ;    //  3 bits, 19-21
  ushort f_d2           ;    //  1 bits, 22
  ushort f_d1           ;    //  1 bits, 23     destination
  ushort f_p            ;    //  2 bits, 24-25  t switch
//ushort f_code         ;    //  6 bits, 26-31  opcode
 
  f_ARn           = (instr      ) & 0x00007L;
  f_modn          = (instr >>  3) & 0x0001FL;
  f_ARm           = (instr >>  8) & 0x00007L;
  f_modm          = (instr >> 11) & 0x0001FL;
  f_src2          = (instr >> 16) & 0x00007L;
  f_src1          = (instr >> 19) & 0x00007L;
  f_d2            = (instr >> 22) & 0x00001L;
  f_d1            = (instr >> 23) & 0x00001L;
  f_p             = (instr >> 24) & 0x00003L;
//f_code          = (instr >> 26) & 0x0003FL;

  strcat(buffer,Instr[n].instr);
//------------------------------------------------
  if((instr & 0xE0E0L)==0xE0E0) return 1;
  if ( (f_modm > MAX_MOD) || (f_modn > MAX_MOD) )
  {
    if(Enhanced_Enable == 0)   return 1;
    if(((f_modm & 0x1C)!=0x1C) && (f_modm > MAX_MOD)) return 1;
    if(((f_modn & 0x1C)!=0x1C) && (f_modn > MAX_MOD)) return 1;
  }
  //------------------------------------------------
  if(Enhanced_Enable)
  {
    if ( f_modm < 8 ) sprintf( srcA, Mod[f_modm], f_ARm, 1);
    else
    {
      if((f_modm & 0x1C) != 0x1C)
        sprintf( srcA, Mod[f_modm], f_ARm);
      else // Enhanced mode...
      {
        int reg = (int)((instr>>8) & 0x1F);
        if(reg>MAXREG-1) return 1;         // All regs are legal
        strcpy(srcA, C30Reg[reg].s);
      }
    }
    //----------------------------------------------------------
    if ( f_modn < 8 ) sprintf( srcB, Mod[f_modn], f_ARn, 1);
    else
    {
      if((f_modn & 0x1C) != 0x1C)
        sprintf( srcB, Mod[f_modn], f_ARn);
      else // Enhanced mode
      {
        int reg = (int)(instr & 0x1F);
        if(reg>MAXREG-1) return 1;  // All regs are legal
        strcpy( srcB, C30Reg[reg].s);
      }
    }
  }
  else  //---- Old version of DASM ----------------
  {
    if (f_modn>7) sprintf(srcB,Mod[f_modn],f_ARn  );
    else          sprintf(srcB,Mod[f_modn],f_ARn,1);
    if (f_modm>7) sprintf(srcA,Mod[f_modm],f_ARm  );
    else          sprintf(srcA,Mod[f_modm],f_ARm,1);
  }
  //----------------------------------------------------------
  strcpy(srcD, C30Reg[f_src1].s);
  strcpy(srcC, C30Reg[f_src2].s);
  switch ( f_p )
  {
     case 0 : strcpy(tmp,srcB); strcpy(srcB,srcA); strcpy(srcA,tmp);
              C30SIM_ADDRESSING_MODE(0, pipe, f_modn, st, f_ARn,
                                     (f_modn > 7) ? 0 : 1, &pipe->source2);
              C30SIM_ADDRESSING_MODE(1, pipe, f_modm, st, f_ARm,
                                     (f_modm > 7) ? 0 : 1, &pipe->source1);
              C30SIM_UPDATE_saveArn;
              C30SIM_SAVE_REG(pipe->source3, pipe->regs[f_src1]);
              C30SIM_REG_INTERLOCK(pipe->source3,st,pipe);
              C30SIM_SAVE_REG(pipe->source4, pipe->regs[f_src2]);
              C30SIM_REG_INTERLOCK(pipe->source4,st,pipe);
              break;
     case 1 : /*
              strcpy(tmp,srcB); strcpy(srcB,srcC); strcpy(srcC,tmp);
              strcpy(tmp,srcC); strcpy(srcC,srcD); strcpy(srcD,tmp);
              strcpy(tmp,srcB); strcpy(srcB,srcC); strcpy(srcC,tmp);
              */
              strcpy(tmp,srcB); strcpy(srcB,srcD); strcpy(srcD,tmp);
              C30SIM_ADDRESSING_MODE(0, pipe, f_modn, st, f_ARn,
                                     (f_modn > 7) ? 0 : 1, &pipe->source3);
              C30SIM_ADDRESSING_MODE(1, pipe, f_modm, st, f_ARm,
                                     (f_modm > 7) ? 0 : 1, &pipe->source1);
              C30SIM_UPDATE_saveArn;
              C30SIM_SAVE_REG(pipe->source2, pipe->regs[f_src1]);
              C30SIM_REG_INTERLOCK(pipe->source2,st,pipe);
              C30SIM_SAVE_REG(pipe->source4, pipe->regs[f_src2]);
              C30SIM_REG_INTERLOCK(pipe->source4,st,pipe);
              break;
     case 2 : strcpy(tmp,srcD); strcpy(srcD,srcA); strcpy(srcA,tmp);
              strcpy(tmp,srcC); strcpy(srcC,srcB); strcpy(srcB,tmp);
              strcpy(tmp,srcA); strcpy(srcA,srcB); strcpy(srcB,tmp);
              C30SIM_ADDRESSING_MODE(0, pipe, f_modn, st, f_ARn,
                                     (f_modn > 7) ? 0 : 1, &pipe->source4);
              C30SIM_ADDRESSING_MODE(1, pipe, f_modm, st, f_ARm,
                                     (f_modm > 7) ? 0 : 1, &pipe->source3);
              C30SIM_UPDATE_saveArn;
              C30SIM_SAVE_REG(pipe->source1, pipe->regs[f_src1]);
              C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
              C30SIM_SAVE_REG(pipe->source2, pipe->regs[f_src2]);
              C30SIM_REG_INTERLOCK(pipe->source2,st,pipe);
              break;
     case 3 : strcpy(tmp,srcC); strcpy(srcC,srcB); strcpy(srcB,tmp);
              strcpy(tmp,srcD); strcpy(srcD,srcB); strcpy(srcB,tmp);
              C30SIM_ADDRESSING_MODE(0, pipe, f_modn, st, f_ARn,
                                     (f_modn > 7) ? 0 : 1, &pipe->source4);
              C30SIM_ADDRESSING_MODE(1, pipe, f_modm, st, f_ARm,
                                     (f_modm > 7) ? 0 : 1, &pipe->source1);
              C30SIM_UPDATE_saveArn;
              C30SIM_SAVE_REG(pipe->source2, pipe->regs[f_src1]);
              C30SIM_REG_INTERLOCK(pipe->source2,st,pipe);
              C30SIM_SAVE_REG(pipe->source3, pipe->regs[f_src2]);
              C30SIM_REG_INTERLOCK(pipe->source3,st,pipe);
              break;
    default : return 1;
  }
  Extract2(buffer, buffer, tmp, "||");
  Concat3( buffer, srcA, srcB, C30Reg[f_d1].s );
  Concat3( tmp, srcC, srcD, C30Reg[f_d2+2].s ); 
  C30SIM_SAVE_REG(pipe->dest1, pipe->regs[f_d1]);
  C30SIM_REG_INTERLOCK(pipe->dest1,st,pipe);
  C30SIM_SAVE_REG(pipe->dest2, pipe->regs[f_d2+2]);
  C30SIM_REG_INTERLOCK(pipe->dest2,st,pipe);
  strcat(buffer,tmp);

  return 0;
}

/* ----------------------------------------------------------------------
                 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
   ---------------------------------------------------------------------- */
DFORM_PROTOTYPE(DForm4)
{
  char src1[80], src2[80], src3[80], dst1[80], dst2[80], tmp[80];
  ushort f_ARn          ;    //  3 bits,  0- 2
  ushort f_modn         ;    //  5 bits,  3- 7
  ushort f_ARm          ;    //  3 bits,  8-10
  ushort f_modm         ;    //  5 bits, 11-15
  ushort f_C            ;    //  3 bits, 16-18
  ushort f_B            ;    //  3 bits, 19-21
  ushort f_A            ;    //  3 bits, 22-24
//ushort f_code         ;    //  7 bits, 25-31  opcode
  f_ARn           = (instr      ) & 0x00007L;
  f_modn          = (instr >>  3) & 0x0001FL;
  f_ARm           = (instr >>  8) & 0x00007L;
  f_modm          = (instr >> 11) & 0x0001FL;
  f_C             = (instr >> 16) & 0x00007L;
  f_B             = (instr >> 19) & 0x00007L;
  f_A             = (instr >> 22) & 0x00007L;
//f_code          = (instr >> 25) & 0x0007FL;

//if ( f_code > 0x78 ) // ???
//  return 1;
//if ( (f_modn > MAX_MOD) || (f_modm > MAX_MOD) ) return 1;
//------------------------------------------------
  if((instr & 0xE0E0L)==0xE0E0) return 1;
  if ( (f_modm > MAX_MOD) || (f_modn > MAX_MOD) )
  {
    if(Enhanced_Enable == 0)   return 1;
    if(((f_modm & 0x1C)!=0x1C) && (f_modm > MAX_MOD)) return 1;
    if(((f_modn & 0x1C)!=0x1C) && (f_modn > MAX_MOD)) return 1;
  }
  //------------------------------------------------
  if(Enhanced_Enable)
  {
    if((instr & 0xE000L) == 0xE000L) return 1;
    if ( f_modm < 8 ) sprintf( dst2, Mod[f_modm], f_ARm, 1);
    else
    {
      if((f_modm & 0x1C) != 0x1C)
        sprintf( dst2, Mod[f_modm], f_ARm);
      else // Enhanced mode...
      {
        int reg = (int)((instr>>8) & 0x1F);
        if(reg>MAXREG-1) return 1;  // All regs are legal
        strcpy( dst2, C30Reg[reg].s);
      }
    }
    //----------------------------------------------------------
    if ( f_modn < 8 ) sprintf( dst1, Mod[f_modn], f_ARn, 1);
    else
    {
      if((f_modn & 0x1C) != 0x1C)
        sprintf( dst1, Mod[f_modn], f_ARn);
      else // Enhanced mode
      {
        int reg = (int)(instr & 0x1F);
        if(reg>MAXREG-1) return 1;  // All regs are legal
        strcpy( dst1, C30Reg[reg].s);
      }
    }
  }
  else  //---- Old version of DASM ----------------
  {
    if (f_modn>7) sprintf(dst1,Mod[f_modn],f_ARn  );
    else           sprintf(dst1,Mod[f_modn],f_ARn,1);
    if (f_modm>7) sprintf(dst2,Mod[f_modm],f_ARm  );
    else           sprintf(dst2,Mod[f_modm],f_ARm,1);
  }
  //------------------------------------------------

  strcpy(buffer,Instr[n].instr);
  *src1 = '#';
  switch ( Instr[n].en) // switch( f_code )
  {
    case __STF_STF:
    case __STI_STI: //if ( f_B ) return 1;
                    *src1=0;
                    strcpy(src2,C30Reg[f_A].s);
                    strcpy(src3,C30Reg[f_C].s);
                    C30SIM_ADDRESSING_MODE(0, pipe, f_modn, st, f_ARn,
                                           (f_modn > 7) ? 0 : 1, &pipe->dest2);
                    C30SIM_ADDRESSING_MODE(1, pipe, f_modm, st, f_ARm,
                                           (f_modm > 7) ? 0 : 1, &pipe->dest1);
                    C30SIM_UPDATE_saveArn;
                    C30SIM_SAVE_REG(pipe->source1, pipe->regs[f_C]);
                    C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
                    C30SIM_SAVE_REG(pipe->source3, pipe->regs[f_A]);
                    C30SIM_REG_INTERLOCK(pipe->source3,st,pipe);
                    break;
    case __LDF_LDF:
    case __LDI_LDI: //if ( f_C ) return 1;
                    *src1 = 0;
                    strcpy(src2,dst1);
                    strcpy(dst1,C30Reg[f_A].s);
                    strcpy(src3,dst2);
                    strcpy(dst2,C30Reg[f_B].s);
                    C30SIM_ADDRESSING_MODE(0, pipe, f_modn, st, f_ARn,
                                      (f_modn > 7) ? 0 : 1, &pipe->source3);
                    C30SIM_ADDRESSING_MODE(1, pipe, f_modm, st, f_ARm,
                                      (f_modm > 7) ? 0 : 1, &pipe->source1);
                    C30SIM_UPDATE_saveArn;
                    C30SIM_SAVE_REG(pipe->dest2, pipe->regs[f_A]);
                    C30SIM_REG_INTERLOCK(pipe->dest2,st,pipe);
                    C30SIM_SAVE_REG(pipe->dest1, pipe->regs[f_B]);
                    C30SIM_REG_INTERLOCK(pipe->dest1,st,pipe);
                break;
    case __ABSF_STF:
    case __ABSI_STI:
    case __FIX_STI :
    case __FLOAT_STF:
    case __LDF_STF  :
    case __LDI_STI  :
    case __NEGF_STF :
    case __NEGI_STI :
    case __NOT_STI  :
//  case __TOIEEE_STF:
//  case __FRIEEE_STF:
                       if ( f_B ) return 1;
                       strcpy(src2,dst1);
                       strcpy(dst1,C30Reg[f_A].s);
                       strcpy(src3,C30Reg[f_C].s);
                       if (*src1) strcpy(src1,C30Reg[f_B].s);
                       C30SIM_ADDRESSING_MODE(0, pipe, f_modn, st, f_ARn,
                                        (f_modn > 7) ? 0 : 1, &pipe->source1);  //Evans had source3
                       C30SIM_ADDRESSING_MODE(1, pipe, f_modm, st, f_ARm,
                                        (f_modm > 7) ? 0 : 1, &pipe->dest2);
                       C30SIM_UPDATE_saveArn;
                       C30SIM_SAVE_REG(pipe->dest1, pipe->regs[f_A]);
                       C30SIM_REG_INTERLOCK(pipe->dest1,st,pipe);
                       C30SIM_SAVE_REG(pipe->source3, pipe->regs[f_C]);
                       C30SIM_REG_INTERLOCK(pipe->source3,st,pipe);
                       break;
//  case 0x6F : /* MPYF3 || STF */
                       *src1 = 0;
    default :          strcpy(src2,dst1);
                       strcpy(dst1,C30Reg[f_A].s);
                       strcpy(src3,C30Reg[f_C].s);
                       if (*src1) strcpy(src1,C30Reg[f_B].s);
                       C30SIM_ADDRESSING_MODE(0, pipe, f_modn, st, f_ARn,
                                        (f_modn > 7) ? 0 : 1, &pipe->source2);  //Evans had source3
                       C30SIM_ADDRESSING_MODE(1, pipe, f_modm, st, f_ARm,
                                        (f_modm > 7) ? 0 : 1, &pipe->dest2);
                       C30SIM_UPDATE_saveArn;
                       C30SIM_SAVE_REG(pipe->dest1, pipe->regs[f_A]);  //Evans left this line out when he last updated this file.
                       C30SIM_REG_INTERLOCK(pipe->dest1,st,pipe);
                       C30SIM_SAVE_REG(pipe->source1, pipe->regs[f_B]);
                       C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
                       C30SIM_SAVE_REG(pipe->source3, pipe->regs[f_C]);
                       C30SIM_REG_INTERLOCK(pipe->source3,st,pipe);
                       break;
  }
  Extract2(buffer, buffer, tmp, "||");
  if (*src1) Concat3(buffer, src1, src2, dst1);
  else Concat2(buffer, src2, dst1);
  Concat2(tmp, src3, dst2);
  strcat(buffer,tmp);

  return 0;
}

/* ----------------------------------------------------------------------
           Type 1 Integer Three-Operand Addressing Modes
              ADDC3, ADDI3, AND3, ANDN3, ASH3, CMPI3,
            LSH3, MPYI3, OR3, SUBB3, SUBI3, TSTB3, XOR3
   ---------------------------------------------------------------------- */
DFORM_PROTOTYPE(DForm5)
{
  char src1[20], src2[20], dst[20];
  ushort f_src2;    // 8 bits,  0- 7  source 2
  ushort f_src1;    // 8 bits,  8-15  source 1
  ushort f_dst ;    // 5 bits, 16-20  destination
  ushort f_t   ;    // 2 bits, 21-22  t switch
//ushort f_code;    // 9 bits, 23-31  opcode
  f_src2 = (instr      ) & 0x00FF;
  f_src1 = (instr >>  8) & 0x00FF;
  f_dst  = (instr >> 16) & 0x001F;
  f_t    = (instr >> 21) & 0x0003;
//f_code = (instr >> 23) & 0x01FF;
/*
  f_src2 = (instr & 0x000000FFL)      ;
  f_src1 = (instr & 0x0000FF00L) >>  8;
  f_dst  = (instr & 0x001F0000L) >> 16;
  f_t    = (instr & 0x00600000L) >> 21;
  f_code = (instr & 0xFF800000L) >> 23;
  */
  strcat(buffer,Instr[n].instr);

  if(f_dst >= MAXREG)
    return 1;

  strcpy(dst,C30Reg[f_dst].s);
  C30SIM_SAVE_REG(pipe->dest1, pipe->regs[f_dst]);
  C30SIM_REG_INTERLOCK(pipe->dest1,st,pipe);
  switch( f_t)
  {
    case 0:  // Reg , Reg
             if((f_src1 >= MAXREG) || (f_src2 >= MAXREG)) return 1;
             strcpy(src1,C30Reg[f_src1].s);
             strcpy(src2,C30Reg[f_src2].s);
/* change the order of pipe->source1 and pipe->source2 in order to
   execute the 3-operand instruction by calling the 2-operand instruction */
             C30SIM_SAVE_REG(pipe->source1, pipe->regs[f_src2]);
             C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
             C30SIM_SAVE_REG(pipe->source2, pipe->regs[f_src1]);
             C30SIM_REG_INTERLOCK(pipe->source2,st,pipe);
             break;

    case 1:  // Ind, Reg
             if((f_src1 >> 3) < 8) {
               sprintf(src1, Mod[f_src1 >> 3], f_src1 & 0x7, 1 );
               C30SIM_ADDRESSING_MODE(0, pipe, f_src1 >> 3,
                                      st, f_src1&0x7, 1, &pipe->source1);
               C30SIM_UPDATE_saveArn;
             }
             else
             { if((f_src1 >> 3) > MAX_MOD) return 1;
               sprintf(src1, Mod[f_src1 >> 3], f_src1 & 0x7);
               C30SIM_ADDRESSING_MODE(0, pipe, f_src1 >> 3,
                                      st, f_src1&0x7, 0, &pipe->source1);
               C30SIM_UPDATE_saveArn;
             }
             if(f_src2 >= MAXREG) return 1;
             strcpy(src2,C30Reg[f_src2].s);
             C30SIM_SAVE_REG(pipe->source2, pipe->regs[f_src2]);
             C30SIM_REG_INTERLOCK(pipe->source2,st,pipe);
             break;

    case 2:  // Reg, Ind
             if(f_src1 >= MAXREG) return 1;
             strcpy(src1,C30Reg[f_src1].s);
             C30SIM_SAVE_REG(pipe->source1, pipe->regs[f_src1]);
             C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
             if((f_src2 >> 3) < 8) {
               sprintf(src2, Mod[f_src2 >> 3], f_src2 & 0x7, 1 );
               C30SIM_ADDRESSING_MODE(0, pipe, f_src2 >> 3,
                                      st, f_src2&0x7, 1, &pipe->source2);
               C30SIM_UPDATE_saveArn;
             }
             else
             { if((f_src2 >> 3) > MAX_MOD) return 1;
               sprintf(src2, Mod[f_src2 >> 3], f_src2 & 0x7);
               C30SIM_ADDRESSING_MODE(0, pipe, f_src2 >> 3,
                                      st, f_src2&0x7, 0, &pipe->source2);
               C30SIM_UPDATE_saveArn;
             }
             break;

    case 3:  // Ind, Ind
             if((f_src1 >> 3) > 25) return 1;
             if((f_src2 >> 3) > 25) return 1;
             if((f_src1 >> 3) < 8)  {
               sprintf(src1, Mod[f_src1 >> 3], f_src1 & 0x7, 1 );
               C30SIM_ADDRESSING_MODE(0, pipe, f_src1 >> 3,
                                      st, f_src1&0x7, 1, &pipe->source1);
               C30SIM_UPDATE_saveArn;
             }
             else
             { if((f_src1 >> 3) > MAX_MOD) return 1;
               sprintf(src1, Mod[f_src1 >> 3], f_src1 & 0x7);
               C30SIM_ADDRESSING_MODE(0, pipe, f_src1 >> 3,
                                      st, f_src1&0x7, 0, &pipe->source1);
               C30SIM_UPDATE_saveArn;
             }
             if((f_src2 >> 3) < 8) {
                sprintf(src2, Mod[f_src2 >> 3], f_src2 & 0x7, 1 );
                C30SIM_ADDRESSING_MODE(0, pipe, f_src2 >> 3,
                                       st, f_src2&0x7, 1, &pipe->source2);
                C30SIM_UPDATE_saveArn;
             }
             else
             { if((f_src2 >> 3) > MAX_MOD) return 1;
               sprintf(src2, Mod[f_src2 >> 3], f_src2 & 0x7); }
             break;
    default: break;
  }

//if((f_code == 0x47) || (f_code == 0x4F)) *dst = 0; // CMPI3 TSTB3
  if((Instr[n].en == __CMPI3)||(Instr[n].en == __TSTB3)) {
     *dst = 0;
     C30SIM_SAVE_REG(pipe->dest1, 0);
  }

  C30SIM_SAVE_REG(pipe->dest2, 0);
  Concat3(buffer, src2, src1, dst);
  return 0;
}
/* ----------------------------------------------------------------------
       Type 1 Float, Decoding Three-Operand Addressing Modes
                    ADDF3, CMPF3, MPYF3, SUBF3
   ---------------------------------------------------------------------- */
DFORM_PROTOTYPE(DForm5b)
{
  char src1[20], src2[20], dst[20];
 
  ushort f_src2;    // 8 bits,  0- 7  source 2
  ushort f_src1;    // 8 bits,  8-15  source 1
  ushort f_dst ;    // 5 bits, 16-20  destination
  ushort f_t   ;    // 2 bits, 21-22  t switch
//ushort f_code;    // 9 bits, 23-31  opcode
 
  f_src2 = (instr      ) & 0x00FF;
  f_src1 = (instr >>  8) & 0x00FF;
  f_dst  = (instr >> 16) & 0x001F;
  f_t    = (instr >> 21) & 0x0003;
//f_code = (instr >> 23) & 0x01FF;

  strcat(buffer,Instr[n].instr);
  strcpy(dst,C30Reg[f_dst].s);
  C30SIM_SAVE_REG(pipe->dest1, pipe->regs[f_dst]);
  C30SIM_REG_INTERLOCK(pipe->dest1,st,pipe);
//if((f_dst > 0x7) && (f_dst < 0x1C)) return 1; // C40 float regs
  if(f_dst > 0x7)                      return 1; // C30

  switch( f_t)
  {
    case 0:  // Reg , Reg
             if((f_src1 >= MAXREG) || (f_src2 >= MAXREG)) return 1;
             if((f_src1 > 0x7) && (f_src1 < 0x1C)) return 1; // R0-R11 regs only
             if((f_src2 > 0x7) && (f_src2 < 0x1C)) return 1; // R0-R11 regs only
             strcpy(src1,C30Reg[f_src1].s);
             strcpy(src2,C30Reg[f_src2].s);
             C30SIM_SAVE_REG(pipe->source1, pipe->regs[f_src2]);
             C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
             C30SIM_SAVE_REG(pipe->source2, pipe->regs[f_src1]);
             C30SIM_REG_INTERLOCK(pipe->source2,st,pipe);
             break;
    case 1:  // Ind, Reg
             if((f_src1 >> 3) < 8) {
               sprintf(src1, Mod[f_src1 >> 3], f_src1 & 0x7, 1 );
               C30SIM_ADDRESSING_MODE(0, pipe, f_src1 >> 3,
                                      st, f_src1&0x7, 1, &pipe->source1);
               C30SIM_UPDATE_saveArn;
             }
             else
             { if((f_src1 >> 3) > MAX_MOD) return 1;
               sprintf(src1, Mod[f_src1 >> 3], f_src1 & 0x7);
               C30SIM_ADDRESSING_MODE(0, pipe, f_src1 >> 3,
                                      st, f_src1&0x7, 0, &pipe->source1);
               C30SIM_UPDATE_saveArn;
             }
             if(f_src2 >= MAXREG) return 1;
             if((f_src2 > 0x7) && (f_src2 < 0x1C)) return 1; // R0-R11 regs only
             strcpy(src2,C30Reg[f_src2].s);
             C30SIM_SAVE_REG(pipe->source2, pipe->regs[f_src2]);
             C30SIM_REG_INTERLOCK(pipe->source2,st,pipe);
             break;

    case 2:  // Reg, Ind
             if(f_src1 >= MAXREG) return 1;
             if((f_src1 > 0x7) && (f_src1 < 0x1C)) return 1; // R0-R11 regs only
             strcpy(src1,C30Reg[f_src1].s);
             C30SIM_SAVE_REG(pipe->source1, pipe->regs[f_src1]);
             C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
             if((f_src2 >> 3) < 8)   {
               sprintf(src2, Mod[f_src2 >> 3], f_src2 & 0x7, 1 );
               C30SIM_ADDRESSING_MODE(0, pipe, f_src2 >> 3,
                                      st, f_src2&0x7, 1, &pipe->source2);
               C30SIM_UPDATE_saveArn;
             }
             else
             { if((f_src2 >> 3) > MAX_MOD) return 1;
               sprintf(src2, Mod[f_src2 >> 3], f_src2 & 0x7);
               C30SIM_ADDRESSING_MODE(0, pipe, f_src2 >> 3,
                                      st, f_src2&0x7, 0, &pipe->source2);
               C30SIM_UPDATE_saveArn;
             }
             break;

    case 3:  // Ind, Ind
             if((f_src1 >> 3) < 8) {
               sprintf(src1, Mod[f_src1 >> 3], f_src1 & 0x7, 1 );
               C30SIM_ADDRESSING_MODE(0, pipe, f_src1 >> 3,
                                      st, f_src1&0x7, 1, &pipe->source1);
               C30SIM_UPDATE_saveArn;
             }
             else
             { if((f_src1 >> 3) > MAX_MOD) return 1;
               sprintf(src1, Mod[f_src1 >> 3], f_src1 & 0x7);
               C30SIM_ADDRESSING_MODE(0, pipe, f_src1 >> 3,
                                      st, f_src1&0x7, 0, &pipe->source1);
               C30SIM_UPDATE_saveArn;
             }
             if((f_src2 >> 3) < 8)  {
                sprintf(src2, Mod[f_src2 >> 3], f_src2 & 0x7, 1 );
                C30SIM_ADDRESSING_MODE(0, pipe, f_src2 >> 3,
                                       st, f_src2&0x7, 1, &pipe->source2);
                C30SIM_UPDATE_saveArn;
             }
             else
             { if((f_src2 >> 3) > MAX_MOD) return 1;
               sprintf(src2, Mod[f_src2 >> 3], f_src2 & 0x7);
               C30SIM_ADDRESSING_MODE(0, pipe, f_src2 >> 3,
                                      st, f_src2&0x7, 0, &pipe->source2);
               C30SIM_UPDATE_saveArn;
             }
             break;
    default: break;
  }

//if(f_code == 0x46) *dst = 0;  // CMPF3
  if(Instr[n].en == __CMPF3) {
     *dst = 0;
     C30SIM_SAVE_REG(pipe->dest1, 0);
  }

  C30SIM_SAVE_REG(pipe->dest2, 0);                
  switch(Instr[n].en) {
        case __CMPF3 :
        case __ADDF3 :
        case __SUBF3 :
        case __MPYF3 : C30SIM_CHECK_FLOAT_REG(f_dst);
        default      : break;
  }

  Concat3(buffer, src2, src1, dst);
  C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
  C30SIM_REG_INTERLOCK(pipe->source2,st,pipe);
  C30SIM_REG_INTERLOCK(pipe->dest1,st,pipe);
  return 0;
}

/* ----------------------------------------------------------------------
               Conditional-Branch Addressing Modes
         DB<cond>,  DB<cond>D, B<cond>, B<cond>D, B_AT, CALL<cond>, 
                      RETS<cond>, RETI<cond>
   ---------------------------------------------------------------------- */
DFORM_PROTOTYPE(DForm7)
{
  char src[80], dst[80];
  long d_addr, r_addr;
 
  ushort f_src   ;    // 16 bits,  0-15  source 2
  ushort f_cond  ;    //  5 bits, 16-20  source 1
  ushort f_delay ;    //  1 bits, 21-21  destination
  ushort f_ARn   ;    //  3 bits, 22-24  t switch
  ushort f_branch;    //  1 bits, 25-25  t switch
//ushort f_code  ;    //  6 bits, 26-31  opcode
 
  f_src   = (instr      ) & 0x0FFFFL;
  f_cond  = (instr >> 16) & 0x0001FL;
  f_delay = (instr >> 21) & 0x00001L;
  f_ARn   = (instr >> 22) & 0x00007L;
  f_branch= (instr >> 25) & 0x00001L;
//f_code  = (instr >> 26) & 0x0003FL;

  strcat(buffer,Instr[n].instr);
  *src=0;
  *dst=0;
// __DBc, __DBDc,
// __Bc , __BDc , __LDIc, __LDFc,

  if( (f_cond > MAX_COND) || (f_cond == 0xB)) return 1;
  C30SIM_SAVE_REG(st->cond[st->saveCond].val, f_cond);     
  C30SIM_UPDATE_COND;
  switch(Instr[n].en)
  {
    case __Bc   :
    case __BDc  :
    case __DBc  :
    case __DBDc :
    case __RETIc:
    case __CALLc:
    case __RETSc: break;
    default :     strcat(buffer,Cond_tab[f_cond]); break;
  }

  /*
  if( f_delay )
  {
    strcat(buffer,"D");
//  PC_Address += 2L;
  }
  */
  if(( f_branch ) != 0)
  {
    /* Add symbol search here */
     if(f_delay) r_addr = 3;
     else r_addr = 1;
  // r_addr = 1;
     r_addr =  r_addr + (long)(int)f_src;
     d_addr = PC_Address + r_addr;
     C30SIM_SAVE_REG(pipe->hold, 
                     (f_src & 0x00008000) ? (f_src | 0xffff0000L) : f_src);
     C30SIM_SAVE_REG(pipe->hold, pipe->pc + pipe->hold);
     C30SIM_SAVE_REG(pipe->source1, &pipe->hold);
     C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
     get_label(dst,d_addr, 1); // Add 1 leading WS to symbol before print
     if(*dst==0) sprintf(dst," $%+ld",r_addr); // numeric value if !found
  }
  if(( f_branch ) == 0)
  {
    C30SIM_SAVE_REG(pipe->hold, f_src);
    C30SIM_SAVE_REG(pipe->source1, &pipe->hold);
    C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
    switch(Instr[n].en)
    {
      case __RETSc:
      case __RETIc: break;
      default:      if( f_src >= MAXREG) return 1;
                    strcpy(dst,"  ");
                    strcat(dst,C30Reg[f_src].s);
                    break;
    }
  }
  switch ( Instr[n].en )
  {
    case __RETIc :
    case __BDc   :
    case __RETSc : break;
    case __DBDc  :
    case __DBc   : strcpy(src,C30Reg[f_ARn+8].s);
    // For CALLc and _Bc if the ARx fields are set, DASM output should
    // be a .word.  __CALLc should also not have the delay bit set
                   C30SIM_SAVE_REG(pipe->dest1, (&st->ar0 + f_ARn));
                   C30SIM_REG_INTERLOCK(pipe->dest1,st,pipe);
                   break; // DB<cond>
    case __CALLc : if( f_delay)return 1;               // CALL<cond>
    case __Bc    : if( f_ARn ) return 1;        break; // B<cond>
    default      : return 1;
  }
  if(*src ) Concat2(buffer,src,dst);
  else strcat(buffer,dst);
  C30SIM_SAVE_REG(pipe->dest2, 0);
  return 0;
}


/* ----------------------------------------------------------------------
        Particular Conditional-Branch Addressing Mode ( form 2 )
                           TRAP<cond> <n>
   ---------------------------------------------------------------------- */
DFORM_PROTOTYPE(DForm9)
{
  ushort f_n     ;    //  5 bits,  0- 4  source 2
//ushort f_z     ;    // 11 bits,  5-15  source 1
  ushort f_cond  ;    //  5 bits, 16-20  destination
//ushort f_code  ;    // 11 bits, 21-31  opcode
  f_n     = (instr      ) & 0x0001FL;
//f_z     = (instr >>  5) & 0x007FFL;
  f_cond  = (instr >> 16) & 0x0001FL;
//f_code  = (instr >> 21) & 0x007FFL;
 
  char tmp[80];
  strcat(buffer,Instr[n].instr);
  if(f_cond > MAX_COND) return 1;

  switch(Instr[n].en)
  {
    case __TRAP4x: if(f_cond == 0)  // If TRAP - Add U
                   sprintf(tmp, "%s %d",Cond_tab[f_cond],(int)instr&0x1FF);
                   else
                   sprintf(tmp, " %d",(int)instr&0x1FF);
                   break;
    case __TRAP  : if(f_cond == 0)  // If TRAP - Add U
                   sprintf(tmp, "%s %d",Cond_tab[f_cond],(int)f_n);
                   else
                   sprintf(tmp, " %d",(int)f_n);
                   break;
  }
  strcat(buffer,tmp);

  C30SIM_SAVE_REG(pipe->hold, f_n);
  C30SIM_SAVE_REG(pipe->source1, &pipe->hold);
  C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
  C30SIM_SAVE_REG(pipe->dest2, 0);
  C30SIM_SAVE_REG(st->cond[st->saveCond].val, f_cond);
  C30SIM_UPDATE_COND;
  return 0;
  /*
  typedef struct
  {
    uint n    :  9; // trap #
    uint z    :  7; // opcode field all 0's
    uint cond :  5;
    uint code : 11; // TRAPcond
  } FORM9;
  FORM9 *f;
  char tmp[15];
  f = (FORM9 *) &instr;
  strcat(buffer,Instr[n].instr);
  if(f->cond > MAX_COND) return 1;
  sprintf(tmp, "%s %d",Cond_tab[f->cond],f->n);
  strcat(buffer,tmp);
  return 0;
  */
}

/* ----------------------------------------------------------------------
                        Particular Instructions
                           SWI, IDLE, SIGI
   ---------------------------------------------------------------------- */
DFORM_PROTOTYPE(DFormA)
{
  if(instr==0) return 0;  // Dummy return to prevent C warnings
  strcat(buffer,Instr[n].instr);
  C30SIM_SAVE_REG2(pipe->dest1, pipe->dest2, 0);
  return 0;
}
/* ----------------------------------------------------------------------
              Decoding Long Immediate Addressing Modes
                  RPTB,RPTBD, BR, BRD, CALL, LAJ
   ---------------------------------------------------------------------- */
DFORM_PROTOTYPE(DFormB)
{
  /*
  typedef struct
  {
    uint srcl: 16;
    uint srch:  8;
    uint code:  8;  // always 0x64
  } FORMB;
  FORMB *f;
  */
  long d_addr; //, r_addr;
  char tmp[80];
//f = (FORMB *) &instr;
  strcat( buffer, Instr[n].instr);
//  r_addr = 1;
 
  // C4x operands use PC relative call and jumps
  // for the C3x, each address of this form is absolute
  /*
  switch( f->code)
  {
    case 0x63:            // LAJ   24 bit +4
    case 0x61:            // BRD   24 bit +3
    case 0x65:            // RPTBD 24 bit +3
    case 0x60:            // BR    24 bit
    case 0x62:            // CALL  24 bit
    case 0x64:            // RPTB  24 bit
 
    if(f->code == 0x63)                        r_addr = 3;
    if((f->code == 0x61) || (f->code == 0x65)) r_addr = 3;
 
                r_addr = r_addr + (((long)instr << 8) >> 8) ;
                d_addr = PC_Address + r_addr;
                for(int j=0; j<MAX_SYMBOLS; j++)
                {
                  if(*DASM_Symbols[j].name == 0)
                  {
                 // sprintf(tmp," 0%06lxH", d_addr);
                    sprintf(tmp," $%+ld",   r_addr);
#ifdef DASMTEST
                    if(r_addr < 0) return 1;         // TEST ONLY
#endif
                    break;
                  }
                  if(DASM_Symbols[j].address == d_addr)
                  {
                    sprintf(tmp," %.12s",DASM_Symbols[j].name);
                    break;
                  }
                }
                break;
    case 0x79: // RPTB  register mode - Both normal and delayed
                sprintf(tmp," %s",C30Reg[f->srcl]);
                break;
    default  : return 1;
  }
  */
  // C3x version of these codes - all are 24 bit absolute addressed

//  if(C3Xmode)
  {
    d_addr = instr & 0xFFFFFFL;
    C30SIM_SAVE_REG(pipe->hold, d_addr);
    C30SIM_SAVE_REG(pipe->source1, &pipe->hold);
    C30SIM_REG_INTERLOCK(pipe->source1,st,pipe);
    get_label(tmp,d_addr, 1); // Add 1 leading WS to symbol before print
    if(*tmp==0) sprintf(tmp," 0%lxh",d_addr); // numeric value if !found
  }
  strcat(buffer,tmp);
  C30SIM_SAVE_REG(pipe->dest2, 0);
  return 0;
}

/*-----------------------------------------------------------------
  Main function which returns the string to be displayed in <buffer>
  ----------------------------------------------------------------- */
/*  Set aside a N bit hash table for fast lookup of codes
    The upper HASH_TABLE_SIZE bits (in this case 9) are used after
    shifting FLSH bits to the right.

    If N=9 (512 entries), the shift value is 32-9=23

*/
#define HASH_TABLE_SIZE           512 /* 2^9 table size             */
#define HASH_TABLE_SHIFT           23 /* 32-9                       */
#define HASH_TABLE_MASK   0xFF800000L /* Mask upper 9 bits of instr */
#define HASH_TABLE_MASK2  0x007FFFFFL /* Mask upper 9 bits of instr */
#define FULL_TABLE_LOOKUP          -1 /* Flag for no match found    */
static int FastLook[HASH_TABLE_SIZE];

long Hash_hit=0;
long Hash_miss=0;
inline int Lookup(ulong c)
{
  int i = FastLook[(int)(c >> HASH_TABLE_SHIFT)];
  if(i!=FULL_TABLE_LOOKUP) {Hash_hit++; return i;}
  Hash_miss++;
  //-------------------------------------------
//if((c & Instr[i].mask) != Instr[i].pattern)
//{
    for(i=0;;i++)
    {
      if(Instr[i].pattern == (c & Instr[i].mask)) break;
  /*  if(Instr[i].en == __word) break; */ /* Never executes */
    }
//}
  return i;
}

int isC4code(int x)
{
  switch(Instr[x].en)
  {
    case __TRAP4x:           /* C4x specific codes   */
    case __STIK  :
    case __LDA   :
    case __FRIEEE:
    case __TOIEEE: return 1;
    default      : return 0; /* Bypass for C3x codes */
  }
}

/*---------------------------------------------------*/
/* Disassembles instr and address into a string      */
/*---------------------------------------------------*/
#ifdef UTSIM3X
int Disasm(ulong instr, char *buffer, pipeline *pipe, state *st)
#else
int Disasm(ulong address, ulong instr, char *buffer)
#endif
{
  int x, y;
  *buffer=0;
  x = Lookup(instr);
  /*---------------------------------------------------*/
  /* Include this next section (old method) to detect  */
  /* any differences in the returned opcodes           */
  /*---------------------------------------------------*/
  if(Instr[x].mask == 0x0L)
  { sprintf( buffer, ".word 0%08lxh", instr );
    C30SIM_SAVE_REG2(pipe->dest1, pipe->dest2, 0);
    
    return 1;
  }
  /*------------------------------------------------------*/
  /* In C3xmode return C4x opcodes as .word values        */
  /* This section needs to hash tabled or to use a global */
  /* global enable flag for speed during simulation       */
  if(C3Xmode)
  {
    if(isC4code(x))
    { sprintf( buffer, ".word 0%08lxh", instr );
      return 1;
    }
  }
#ifndef UTSIM3X
  PC_Address = address;
#endif

#ifdef UTSIM3X
  y = Instr[x].dform(x, instr, buffer, pipe, st);
#else
  y = Instr[x].dform(x, instr, buffer);
#endif

  if (y) {
    sprintf( buffer, ".word 0%08lxh", instr );
    C30SIM_SAVE_REG2(pipe->dest1, pipe->dest2, 0);

    return y;
  }
  C30SIM_PREVENT_WRITES_TO_ROM(pipe, Instr[x].sform, st);

  return 0;
}
/*----------------------------------------------------------
   Calling this function builds the fast lookup table
 
   - If the upper 8 bits of the code are unique, the offset into the
     table is returned for that code.  In this case the number of found
     matches is 2.  Once for the found code, and once for the .word
     that terminates the end of the list
 
   - If the upper 8 bits of the code match more than one opcode, the
     entire list must be searched.  In this case return FULL_TABLE_LOOKUP.
     In this case the number of found matches is >2
 
   - If the upper 8 bits of the code match no known codes, then it is
     a .word and only 1 match will be found (IE the .word itself)
  ---------------------------------------------------*/
void BuildFastLook(void)
{
  int i;
//int h0=0, h1=0, h2=0, h3=0;
  for(i=0;i<HASH_TABLE_SIZE;i++)
  {
    int x;
    int x2=FULL_TABLE_LOOKUP;
    int found = 0;
    for (x=0;;x++)
    {
      long l = (long)i << HASH_TABLE_SHIFT;
      if((l & Instr[x].mask) == (Instr[x].pattern & HASH_TABLE_MASK))
      {
         // If there are bits in the lower field that define the
         // opcode, then a match has NOT been found
         if((Instr[x].mask & HASH_TABLE_MASK2)==0) // Check LSB's
         found++;         // found match
         if(Instr[x].en == __word) break;
         x2 = x;          // remember last match that was not a .word
      }
    }
    // found=0   Should never occur since .word is a match
    // found=1   if only .word found as match
    // found=2   if 1 match found + .word
    // found=3++ if more than 1 match + .word
    //
    // The only case that is significant is if found==2
    // In all other cases, FULL_TABLE_LOOKUP is returned
    if(found==2) FastLook[i] = x2;
    else         FastLook[i] = FULL_TABLE_LOOKUP;
    /*
    switch(found)
    {
      case  0: h0++; break;
      case  1: h1++; break;
      case  2: h2++; break;
      default: h3++; break;
    }
    */
  }
//printf("\r\n%d %d %d %d\r\n",h0,h1,h2,h3);
}
