/*
 *      Interactive disassembler (IDA).
 *      Version 3.05
 *      Copyright (c) 1990-95 by Ilfak Guilfanov.
 *      ALL RIGHTS RESERVED.
 *                              FIDO:   2:5020/209
 *                              E-mail: ig@estar.msk.su
 *
 */

#include "tms.hpp"

//----------------------------------------------------------------------
inline ushort get_next_byte(insn_t &insn)
{
  return (ushort)get_wide_byte(insn.ea + insn.size++);
}

//----------------------------------------------------------------------
inline void op_daddr(insn_t &insn, op_t &o)    // 16-bit address data
{
  o.type = o_mem;
  o.addr = get_next_byte(insn);
  o.sib  = 1;
}

//----------------------------------------------------------------------
inline void op_paddr(insn_t &insn, op_t &o)    // 16-bit address prog
{
  o.type = o_near;
  o.addr = get_next_byte(insn);
}

//----------------------------------------------------------------------
inline void op_ioaddr(insn_t &insn, op_t &o)   // 16-bit port address
{
  o.dtype = dt_word;
  o.type  = o_imm;
  o.value = get_next_byte(insn);
  o.sib   = 1;
}

//----------------------------------------------------------------------
int tms320c5_t::op_iaa(const insn_t &insn, op_t &o) const // direct or indirect address
{
  if ( code & 0x80 )
  {
    o.type = o_phrase;
    o.phrase = (code & 0x7F);
    if ( (o.phrase & 0x70) == 0x30 )
      return 0;
  }
  else
  {
    o.type = o_mem;
    o.addr = (get_sreg(insn.ea, rDP)<<7) + (code & 0x7F);
    o.sib  = 0;
  }
  return 1;
}

//----------------------------------------------------------------------
int tms320c5_t::op_indir(op_t &o)            // direct or indirect address
{                                       // optional
  o.type = o_phrase;
  o.phrase = (code & 0x7F);
  if ( (o.phrase & 0x70) == 0x30 )
    return 0;
  if ( (o.phrase & 0x70) == 0 )
    o.clr_shown();
  return 1;
}

//----------------------------------------------------------------------
int tms320c5_t::op_maa(const insn_t &insn, op_t &o) const // memory-mapped register from code
{
  if ( !op_iaa(insn, o) )
    return 0;
  if ( o.type == o_mem )
    o.addr = (code & 0x7F);
  return 1;
}

//----------------------------------------------------------------------
inline void op_ar(op_t &o, uint16 ar)   // aux register
{
  o.type = o_reg;
  o.reg = rAr0 + ar;
}

//----------------------------------------------------------------------
inline void op_imm(insn_t &insn, op_t &o) // 16-bit immediate
{
  o.dtype = dt_word;
  o.type  = o_imm;
  o.value = get_next_byte(insn);
  o.sib   = 0;
}

//----------------------------------------------------------------------
inline void op_shift(op_t &o, int shift) // shift
{
  o.type = o_imm;
  o.value = shift;
  o.sib = 2;
  if ( o.value == 0 )
    o.clr_shown();
}

//----------------------------------------------------------------------
void tms320c5_t::op_short(op_t &o) const          // short immediate
{
  o.dtype = dt_byte;
  o.type  = o_imm;
  o.value = code & 0xFF;
  o.sib   = 0;
}

//----------------------------------------------------------------------
inline void op_cbit(op_t &o, int bit)
{
  o.type = o_bit;
  o.value = bit;
}

//----------------------------------------------------------------------
int tms320c5_t::op_cond(op_t &o) const
{
  o.type = o_cond;
  o.Cond = uint16(o.value = (code & 0x3FF));
  int mask = int(o.value>>0) & 0xF;
  int cond = int(o.value>>4) & 0xF;
  if ( ((mask>>2) & 3) == 3 ) // Z L
  {
    switch ( (cond>>2)&3 )
    {
      case 0:
      case 1:
        return 0;
    }
  }
  return 1;
}

//----------------------------------------------------------------------
void tms320c5_t::op_bit(op_t &o) const
{
  o.type = o_imm;
// strange? documentation say this way:  o.value = 15 - ((code >> 8) & 0xF);
// assembler works this way:
  o.value = (code >> 8) & 0xF;
  o.sib = 3;
}

//----------------------------------------------------------------------
int tms320c5_t::ana_c2(insn_t &insn)
{
  uchar subcode = (code >> 8) & 0xF;
  switch ( code >> 12 )
  {
// 0000 SSSS MDDD DDDD          TMS2_add
// 0001 SSSS MDDD DDDD          TMS2_sub
// 0010 SSSS MDDD DDDD          TMS2_lac
    case 0:
      insn.itype = TMS2_add;
      goto iaa_shift;
    case 1:
      insn.itype = TMS2_sub;
      goto iaa_shift;
    case 2:
      insn.itype = TMS2_lac;
iaa_shift:
      if ( !op_iaa(insn, insn.Op1) )
        return 0;
      op_shift(insn.Op2, subcode);
      break;

// 0011 0RRR MDDD DDDD          TMS2_lar
// 0011 1000 MDDD DDDD          TMS2_mpy
// 0011 1001 MDDD DDDD          TMS2_sqra
// 0011 1010 MDDD DDDD          TMS2_mpya
// 0011 1011 MDDD DDDD          TMS2_mpys
// 0011 1100 MDDD DDDD          TMS2_lt
// 0011 1101 MDDD DDDD          TMS2_lta
// 0011 1110 MDDD DDDD          TMS2_ltp
// 0011 1111 MDDD DDDD          TMS2_ltd
    case 3:
      if ( subcode < 8 )
      {
        insn.itype = TMS2_lar;
        op_ar(insn.Op1, subcode);
        if ( !op_iaa(insn, insn.Op2) )
          return 0;
      }
      else
      {
        static const uchar codes[8] =
        {
          TMS2_mpy, TMS2_sqra, TMS2_mpya, TMS2_mpys,
          TMS2_lt,  TMS2_lta,  TMS2_ltp,  TMS2_ltd
        };
        insn.itype = codes[subcode-8];
        if ( !op_iaa(insn, insn.Op1) )
          return 0;
      }
      break;

// 0100 0000 MDDD DDDD          TMS2_zalh
// 0100 0001 MDDD DDDD          TMS2_zals
// 0100 0010 MDDD DDDD          TMS2_lact
// 0100 0011 MDDD DDDD          TMS2_addc
// 0100 0100 MDDD DDDD          TMS2_subh
// 0100 0101 MDDD DDDD          TMS2_subs
// 0100 0110 MDDD DDDD          TMS2_subt
// 0100 0111 MDDD DDDD          TMS2_subc
// 0100 1000 MDDD DDDD          TMS2_addh
// 0100 1001 MDDD DDDD          TMS2_adds
// 0100 1010 MDDD DDDD          TMS2_addt
// 0100 1011 MDDD DDDD          TMS2_rpt
// 0100 1100 MDDD DDDD          TMS2_xor
// 0100 1101 MDDD DDDD          TMS2_or
// 0100 1110 MDDD DDDD          TMS2_and
// 0100 1111 MDDD DDDD          TMS2_subb
    case 4:
      {
        static const ushort codes[16] =
        {
          TMS2_zalh, TMS2_zals, TMS2_lact, TMS2_addc,
          TMS2_subh, TMS2_subs, TMS2_subt, TMS2_subc,
          TMS2_addh, TMS2_adds, TMS2_addt, TMS2_rpt,
          TMS2_xor,  TMS2_or,   TMS2_and,  TMS2_subb
        };
        insn.itype = codes[subcode];
        if ( !op_iaa(insn, insn.Op1) )
          return 0;
      }
      break;

// 0101 0000 MDDD DDDD          TMS2_lst
// 0101 0001 MDDD DDDD          TMS2_lst1
// 0101 0010 MDDD DDDD          TMS2_ldp
// 0101 0011 MDDD DDDD          TMS2_lph
// 0101 0100 MDDD DDDD          TMS2_pshd
// 0101 0101 0000 0000          TMS2_nop
// 0101 0101 1000 1RRR          TMS2_larp
// 0101 0101 MDDD DDDD          TMS2_mar
// 0101 0110 MDDD DDDD          TMS2_dmov
// 0101 0111 MDDD DDDD          TMS2_bitt
// 0101 1000 MDDD DDDD          TMS2_tblr
// 0101 1001 MDDD DDDD          TMS2_tblw
// 0101 1010 MDDD DDDD          TMS2_sqrs
// 0101 1011 MDDD DDDD          TMS2_lts
// 0101 1100 MDDD DDDD +1       TMS2_macd
// 0101 1101 MDDD DDDD +1       TMS2_mac
// 0101 1110 1DDD DDDD +1       TMS2_bc
// 0101 1111 1DDD DDDD +1       TMS2_bnc
    case 5:
      {
        static const ushort codes[16] =
        {
          TMS2_lst,  TMS2_lst1, TMS2_ldp,  TMS2_lph,
          TMS2_pshd, TMS2_mar,  TMS2_dmov, TMS2_bitt,
          TMS2_tblr, TMS2_tblw, TMS2_sqrs, TMS2_lts,
          TMS2_macd, TMS2_mac,  TMS2_bc,   TMS2_bnc
        };
        insn.itype = codes[subcode];
        if ( subcode >= 12 )
        {
          op_paddr(insn, insn.Op1);
          if ( subcode >= 14 )
          {
            if ( !op_indir(insn.Op2) )
              return 0;
          }
          else
          {
            if ( !op_iaa(insn, insn.Op2) )
              return 0;
          }
        }
        else
        {
          if ( subcode == 5 )
          {
            if ( (code & 0x80) == 0 )
            {
              insn.itype = TMS2_nop;
              insn.Op1.type = o_void;
              break;
            }
            else if ( (code & 0xF8) == 0x88 )
            {
              insn.itype = TMS2_larp;
              insn.Op1.type = o_reg;
              insn.Op1.reg = rAr0 + (code & 7);
              break;
            }
          }
          if ( !op_iaa(insn, insn.Op1) )
            return 0;
        }
      }
      break;

// 0110 0XXX MDDD DDDD          TMS2_sacl
// 0110 1XXX MDDD DDDD          TMS2_sach
    case 6:
      insn.itype = (subcode & 8) ? TMS2_sach : TMS2_sacl;
      if ( !op_iaa(insn, insn.Op1) )
        return 0;
      op_shift(insn.Op2, subcode & 7);
      break;

// 0111 0RRR MDDD DDDD          TMS2_sar
// 0111 1000 MDDD DDDD          TMS2_sst
// 0111 1001 MDDD DDDD          TMS2_sst1
// 0111 1010 MDDD DDDD          TMS2_popd
// 0111 1011 MDDD DDDD          TMS2_zalr
// 0111 1100 MDDD DDDD          TMS2_spl
// 0111 1101 MDDD DDDD          TMS2_sph
// 0111 1110 KKKK KKKK          TMS2_adrk
// 0111 1111 KKKK KKKK          TMS2_sbrk
    case 7:
      if ( subcode < 8 )
      {
        insn.itype = TMS2_sar;
        op_ar(insn.Op1, subcode);
        if ( !op_iaa(insn, insn.Op2) )
          return 0;
      }
      else
      {
        static const ushort codes[8] =
        {
          TMS2_sst, TMS2_sst1, TMS2_popd, TMS2_zalr,
          TMS2_spl, TMS2_sph,  TMS2_adrk, TMS2_sbrk
        };
        insn.itype = codes[subcode-8];
        if ( subcode >= 14 )
          op_short(insn.Op1);
        else if ( !op_iaa(insn, insn.Op1) )
          return 0;
      }
      break;

// 1000 AAAA MDDD DDDD          TMS2_in
    case 8:
      insn.itype = TMS2_in;
      if ( !op_iaa(insn, insn.Op1) )
        return 0;
      insn.Op2.value = subcode;
      insn.Op2.type  = o_imm;
      insn.Op2.sib   = 1;
      break;

// 1001 BBBB MDDD DDDD          TMS2_bit
    case 9:
      insn.itype = TMS2_bit;
      if ( !op_iaa(insn, insn.Op1) )
        return 0;
      insn.Op2.value = subcode;
      insn.Op2.type  = o_imm;
      insn.Op2.sib   = 0;
      break;

// 101K KKKK KKKK KKKK          TMS2_mpyk
    case 0xA:
    case 0xB:
      insn.itype = TMS2_mpyk;
      insn.Op1.value = code & 0x1FFF;
      if ( (insn.Op1.value & 0x1000) != 0 )
        insn.Op1.value |= ~0x1FFF; // extend sign
      insn.Op1.type  = o_imm;
      insn.Op1.sib   = 0;
      break;

// 1100 0RRR KKKK KKKK          TMS2_lark
// 1100 100K KKKK KKKK          TMS2_ldpk
// 1100 1010 0000 0000          TMS2_zac
// 1100 1010 KKKK KKKK          TMS2_lack
// 1100 1011 KKKK KKKK          TMS2_rptk
// 1100 1100 KKKK KKKK          TMS2_addk
// 1100 1101 KKKK KKKK          TMS2_subk
// 1100 1110 0000 0000          TMS2_eint
// 1100 1110 0000 0001          TMS2_dint
// 1100 1110 0000 0010          TMS2_rovm
// 1100 1110 0000 0011          TMS2_sovm
// 1100 1110 0000 0100          TMS2_cnfd
// 1100 1110 0000 0101          TMS2_cnfp
// 1100 1110 0000 0110          TMS2_rsxm
// 1100 1110 0000 0111          TMS2_ssxm
// 1100 1110 0000 10KK          TMS2_spm
// 1100 1110 0000 1100          TMS2_rxf
// 1100 1110 0000 1101          TMS2_sxf
// 1100 1110 0000 111K          TMS2_fort
// 1100 1110 0001 0100          TMS2_pac
// 1100 1110 0001 0101          TMS2_apac
// 1100 1110 0001 0110          TMS2_spac
// 1100 1110 0001 1000          TMS2_sfl
// 1100 1110 0001 1001          TMS2_sfr
// 1100 1110 0001 1011          TMS2_abs
// 1100 1110 0001 1100          TMS2_push
// 1100 1110 0001 1101          TMS2_pop
// 1100 1110 0001 1110          TMS2_trap
// 1100 1110 0001 1111          TMS2_idle
// 1100 1110 0010 0000          TMS2_rtxm
// 1100 1110 0010 0001          TMS2_stxm
// 1100 1110 0010 0011          TMS2_neg
// 1100 1110 0010 0100          TMS2_cala
// 1100 1110 0010 0101          TMS2_bacc
// 1100 1110 0010 0110          TMS2_ret
// 1100 1110 0010 0111          TMS2_cmpl
// 1100 1110 0011 0000          TMS2_rc
// 1100 1110 0011 0001          TMS2_sc
// 1100 1110 0011 0010          TMS2_rtc
// 1100 1110 0011 0011          TMS2_stc
// 1100 1110 0011 0100          TMS2_rol
// 1100 1110 0011 0101          TMS2_ror
// 1100 1110 0011 0110          TMS2_rfsm
// 1100 1110 0011 0111          TMS2_sfsm
// 1100 1110 0011 1000          TMS2_rhm
// 1100 1110 0011 1001          TMS2_shm
// 1100 1110 0011 11KK          TMS2_conf
// 1100 1110 0101 00KK          TMS2_cmpr
// 1100 1110 1AAA 0010          TMS2_norm
// 1100 1111 MDDD DDDD          TMS2_mpyu
    case 0xC:
      switch ( subcode )
      {
        default:                // 1100 0RRR KKKK KKKK          TMS2_lark
          insn.itype = TMS2_lark;
          op_ar(insn.Op1, subcode);
          op_short(insn.Op2);
          break;
        case 8:
        case 9:                 // 1100 100K KKKK KKKK          TMS2_ldpk
          insn.itype     = TMS2_ldpk;
          insn.Op1.dtype = dt_word;
          insn.Op1.value = code & 0x1FF;
          insn.Op1.type  = o_imm;
          insn.Op1.sib   = 0;
          break;
        case 0xA:
          if ( code == 0xCA00 )
          {
            insn.itype = TMS2_zac;
            break;
          }
          insn.itype = TMS2_lack;
          goto LOAD_SHORT;
        case 0xB:
          insn.itype = TMS2_rptk;
          op_short(insn.Op1);
          insn.Op1.sib = 1;
          break;
        case 0xC:
          insn.itype = TMS2_addk;
          goto LOAD_SHORT;
        case 0xD:
          insn.itype = TMS2_subk;
LOAD_SHORT:
          op_short(insn.Op1);
          break;
        case 0xE:
          switch ( (code>>4) & 0xF )
          {
                                //      0000 0000 TMS2_eint
                                //      0000 0001 TMS2_dint
                                //      0000 0010 TMS2_rovm
                                //      0000 0011 TMS2_sovm
                                //      0000 0100 TMS2_cnfd
                                //      0000 0101 TMS2_cnfp
                                //      0000 0110 TMS2_rsxm
                                //      0000 0111 TMS2_ssxm
                                //      0000 10KK TMS2_spm
                                //      0000 1100 TMS2_rxf
                                //      0000 1101 TMS2_sxf
                                //      0000 111K TMS2_fort
            case 0:
              {
                static const ushort codes[] =
                {
                  TMS2_eint, TMS2_dint, TMS2_rovm, TMS2_sovm,
                  TMS2_cnfd, TMS2_cnfp, TMS2_rsxm, TMS2_ssxm,
                  TMS2_spm,  TMS2_spm,  TMS2_spm,  TMS2_spm,
                  TMS2_rxf,  TMS2_sxf,  TMS2_fort, TMS2_fort
                };
                insn.itype = codes[code & 0xF];
                if ( insn.itype == TMS2_spm )
                {
                  insn.Op1.value = code & 3;
                  insn.Op1.type  = o_imm;
                  insn.Op1.sib   = 0;
                }
                else if ( insn.itype == TMS2_fort )
                {
                  insn.Op1.value = code & 1;
                  insn.Op1.type  = o_imm;
                  insn.Op1.sib   = 0;
                }
              }
              break;

            //      0001 0100 TMS2_pac
            //      0001 0101 TMS2_apac
            //      0001 0110 TMS2_spac
            //      0001 1000 TMS2_sfl
            //      0001 1001 TMS2_sfr
            //      0001 1011 TMS2_abs
            //      0001 1100 TMS2_push
            //      0001 1101 TMS2_pop
            //      0001 1110 TMS2_trap
            //      0001 1111 TMS2_idle
            case 1:
              {
                static const ushort codes[] =
                {
                  TMS_null,  TMS_null,  TMS_null,  TMS_null,
                  TMS2_pac,  TMS2_apac, TMS2_spac, TMS_null,
                  TMS2_sfl,  TMS2_sfr,  TMS_null,  TMS2_abs,
                  TMS2_push, TMS2_pop,  TMS2_trap, TMS2_idle
                };
                insn.itype = codes[code & 0xF];
              }
              break;

            //      0010 0000 TMS2_rtxm
            //      0010 0001 TMS2_stxm
            //      0010 0011 TMS2_neg
            //      0010 0100 TMS2_cala
            //      0010 0101 TMS2_bacc
            //      0010 0110 TMS2_ret
            //      0010 0111 TMS2_cmpl
            case 2:
              if ( (code & 0xF) < 8 )
              {
                static const ushort codes[] =
                {
                  TMS2_rtxm, TMS2_stxm, TMS_null, TMS2_neg,
                  TMS2_cala, TMS2_bacc, TMS2_ret, TMS2_cmpl
                };
                insn.itype = codes[code & 0xF];
              }
              break;

            //      0011 0000 TMS2_rc
            //      0011 0001 TMS2_sc
            //      0011 0010 TMS2_rtc
            //      0011 0011 TMS2_stc
            //      0011 0100 TMS2_rol
            //      0011 0101 TMS2_ror
            //      0011 0110 TMS2_rfsm
            //      0011 0111 TMS2_sfsm
            //      0011 1000 TMS2_rhm
            //      0011 1001 TMS2_shm
            //      0011 11KK TMS2_conf
            case 3:
              if ( (code & 0xF) >= 0xC )
              {
                insn.itype = TMS2_conf;
                insn.Op1.value = code & 3;
                insn.Op1.type  = o_imm;
                insn.Op1.sib   = 0;
              }
              else
              {
                static const ushort codes[] =
                {
                  TMS2_rc,  TMS2_sc,   TMS2_rtc,  TMS2_stc,
                  TMS2_rol, TMS2_ror,  TMS2_rfsm, TMS2_sfsm,
                  TMS2_rhm, TMS2_shm,  TMS_null,  TMS_null,
                };
                insn.itype = codes[code & 0xF];
              }
              break;

                                //      0101 00KK TMS2_cmpr
            case 5:
              if ( (code & 0xC) == 0 )
              {
                insn.itype = TMS2_cmpr;
                insn.Op1.value = code & 3;
                insn.Op1.type  = o_imm;
                insn.Op1.sib   = 0;
              }
              break;

                                //      1AAA 0010 TMS2_norm
            case 0x8:
            case 0x9:
            case 0xA:
            case 0xB:
            case 0xC:
            case 0xD:
            case 0xE:
            case 0xF:
              insn.itype = TMS2_norm;
              op_indir(insn.Op1);
              break;

            default:
              return 0;
          }
          break;
        case 0xF:       // 1100 1111 MDDD DDDD          TMS2_mpyu
          insn.itype = TMS2_mpyu;
          if ( !op_iaa(insn, insn.Op1) )
            return 0;
          break;
      }
      break;

// 1101 0RRR 0000 0000 +1       TMS2_lrlk
// 1101 SSSS 0000 0001 +1       TMS2_lalk
// 1101 SSSS 0000 0010 +1       TMS2_adlk
// 1101 SSSS 0000 0011 +1       TMS2_sblk
// 1101 SSSS 0000 0100 +1       TMS2_andk
// 1101 SSSS 0000 0101 +1       TMS2_ork
// 1101 SSSS 0000 0110 +1       TMS2_xork
    case 0xD:
      {
        uint opcode = code & 0xFF;
        if ( opcode == 0 )
        {
          if ( subcode >= 8 )
            return 0;
          insn.itype = TMS2_lrlk;
          op_ar(insn.Op1, subcode);
          op_imm(insn, insn.Op2);
        }
        else if ( opcode < 7 )
        {
          static const ushort codes[] =
          {
            0,         TMS2_lalk, TMS2_adlk, TMS2_sblk,
            TMS2_andk, TMS2_ork,  TMS2_xork,
          };
          insn.itype = codes[opcode];
          op_imm(insn, insn.Op1);
          op_shift(insn.Op2, subcode);
        }
        else
        {
          return 0;
        }
      }
      break;

// 1110 AAAA MDDD DDDD          TMS2_out
    case 0xE:
      insn.itype = TMS2_out;
      if ( !op_iaa(insn, insn.Op1) )
        return 0;
      insn.Op2.value = subcode;
      insn.Op2.type  = o_imm;
      insn.Op2.sib   = 1;
      break;

    // 1111 0000 1DDD DDDD +1       TMS2_bv
    // 1111 0001 1DDD DDDD +1       TMS2_bgz
    // 1111 0010 1DDD DDDD +1       TMS2_blez
    // 1111 0011 1DDD DDDD +1       TMS2_blz
    // 1111 0100 1DDD DDDD +1       TMS2_bgez
    // 1111 0101 1DDD DDDD +1       TMS2_bnz
    // 1111 0110 1DDD DDDD +1       TMS2_bz
    // 1111 0111 1DDD DDDD +1       TMS2_bnv
    // 1111 1000 1DDD DDDD +1       TMS2_bbz
    // 1111 1001 1DDD DDDD +1       TMS2_bbnz
    // 1111 1010 1DDD DDDD +1       TMS2_bioz
    // 1111 1011 1DDD DDDD +1       TMS2_banz
    // 1111 1100 MDDD DDDD +1       TMS2_blkp
    // 1111 1101 MDDD DDDD +1       TMS2_blkd
    // 1111 1110 1DDD DDDD +1       TMS2_call
    // 1111 1111 1DDD DDDD +1       TMS2_b
    case 0xF:
      {
        static const ushort codes[16] =
        {
          TMS2_bv,   TMS2_bgz,  TMS2_blez, TMS2_blz,
          TMS2_bgez, TMS2_bnz,  TMS2_bz,   TMS2_bnv,
          TMS2_bbz,  TMS2_bbnz, TMS2_bioz, TMS2_banz,
          TMS2_blkp, TMS2_blkd, TMS2_call, TMS2_b
        };
        insn.itype = codes[subcode];
        op_paddr(insn, insn.Op1);
        switch ( insn.itype )
        {
          case TMS2_blkd:
            insn.Op1.type = o_mem;
            insn.Op1.sib  = 1;
            [[fallthrough]];
          case TMS2_blkp:
            if ( !op_iaa(insn, insn.Op2) )
              return 0;
            break;
          default:
            if ( !op_indir(insn.Op2) )
              return 0;
            break;
        }
      }
      break;
   }
   return 1;
}

//----------------------------------------------------------------------
//----------------------------------------------------------------------
int tms320c5_t::ana(insn_t *_insn)
{
  insn_t &insn = *_insn;
  code = get_next_byte(insn);
  uchar subcode = (code >> 8) & 0xF;
  uint nibble;

  if ( isC2() )
  {
    if ( !ana_c2(insn) )
      return 0;
  }
  else
  {
    switch ( code >> 12 )
    {
      case 0:
        if ( subcode < 8 )
        {
          insn.itype = TMS_lar;
          op_ar(insn.Op1, subcode);
          if ( !op_iaa(insn, insn.Op2) )
            return 0;
        }
        else
        {
          {
            static const uchar codes[8] =
            {
              TMS_lamm, TMS_smmr, TMS_subc, TMS_rpt,
              TMS_out,  TMS_ldp,  TMS_lst,  TMS_lst
            };
            insn.itype = codes[subcode-8];
          }
          if ( subcode == 0xC )
            op_ioaddr(insn, insn.Op2);
        case08_common:
          {
            int ok = (subcode == 0x8 || subcode == 0x9)
                   ? op_maa(insn, insn.Op1)
                   : op_iaa(insn, insn.Op1);
            if ( !ok )
              return 0;
          }
          if ( subcode == 0x9 )
            op_daddr(insn, insn.Op2);
          if ( subcode >= 0xE )
          {
            if ( insn.itype == TMS_sst )
              op_maa(insn, insn.Op1);
            insn.Op2 = insn.Op1;
            insn.Op2.n = 1;
            insn.Op1.type = o_imm;
            insn.Op1.value = subcode & 1;
            insn.Op1.sib = 0;
          }
        }
        break;
      case 8:
        if ( subcode < 8 )
        {
          insn.itype = TMS_sar;
          op_ar(insn.Op1, subcode);
          if ( !op_iaa(insn, insn.Op2) )
            return 0;
        }
        else
        {
          static const uchar codes[8] =
          {
            TMS_samm, TMS_lmmr, TMS_popd, TMS_mar,
            TMS_spl,  TMS_sph,  TMS_sst,  TMS_sst
          };
          insn.itype = codes[subcode-8];
          if ( subcode == 0xB && (code & 0xFF) == 0 )
          {
            insn.itype = TMS_nop;
            insn.Op1.type = o_void;
            break;
          }
          goto case08_common;
        }
        break;
      case 1:
        insn.itype = TMS_lacc;
        goto iaa_shift;
      case 2:
        insn.itype = TMS_add;
        goto iaa_shift;
      case 3:
        insn.itype = TMS_sub;
      iaa_shift:
        if ( !op_iaa(insn, insn.Op1) )
          return 0;
        op_shift(insn.Op2, subcode);
        break;
      case 4:
        insn.itype = TMS_bit;
        if ( !op_iaa(insn, insn.Op1) )
          return 0;
        op_bit(insn.Op2);
        break;
      case 5:
        {
          static const uchar codes[16] =
          {
            TMS_mpya, TMS_mpys, TMS_sqra, TMS_sqrs,
            TMS_mpy,  TMS_mpyu, TMS_null, TMS_bldp,
            TMS_xpl,  TMS_opl,  TMS_apl,  TMS_cpl,
            TMS_xpl2, TMS_opl2, TMS_apl2, TMS_cpl2
          };
          insn.itype = codes[subcode];
          if ( !op_iaa(insn, insn.Op1) )
            return 0;
          op_t *o;
          if ( subcode >= 0xC )
          {
            op_imm(insn, insn.Op1);
            o = &insn.Op2;
          }
          else
          {
            o = &insn.Op1;
          }
          if ( !op_iaa(insn, *o) )
            return 0;
        }
        break;
      case 6:
        {
          static const uchar codes[16] =
          {
            TMS_addc, TMS_add,  TMS_adds, TMS_addt,
            TMS_subb, TMS_sub,  TMS_subs, TMS_subt,
            TMS_zalr, TMS_lacl, TMS_lacc, TMS_lact,
            TMS_xor,  TMS_or,   TMS_and,  TMS_bitt
          };
          insn.itype = codes[subcode];
          if ( !op_iaa(insn, insn.Op1) )
            return 0;
          if ( insn.itype == TMS_lacc
            || insn.itype == TMS_add
            || insn.itype == TMS_sub )
          {
            op_shift(insn.Op2, 16);
          }
        }
        break;
      case 7:
        {
          static const uchar codes[16] =
          {
            TMS_lta,  TMS_ltp, TMS_ltd,   TMS_lt,
            TMS_lts,  TMS_lph, TMS_pshd,  TMS_dmov,
            TMS_adrk, TMS_b,   TMS_call,  TMS_banz,
            TMS_sbrk, TMS_bd,  TMS_calld, TMS_banzd
          };
          insn.itype = codes[subcode];
          if ( subcode < 8 )
          {
            if ( !op_iaa(insn, insn.Op1) )
              return 0;
          }
          else
          {
            if ( subcode != 8 && subcode != 0xC )
            {
              op_paddr(insn, insn.Op1);
              if ( !op_iaa(insn, insn.Op2) || insn.Op2.type != o_phrase )
                insn.itype = TMS_null;
            }
            else
            {
              op_short(insn.Op1);
            }
          }
        }
        break;
      case 9:
        insn.itype = (subcode & 8) ? TMS_sach : TMS_sacl;
        if ( !op_iaa(insn, insn.Op1) )
          return 0;
        op_shift(insn.Op2, subcode&7);
        break;
      case 0xA:
        {
          static const uchar codes[16] =
          {
            TMS_norm, TMS_null, TMS_mac,  TMS_macd,
            TMS_blpd, TMS_blpd, TMS_tblr, TMS_tblw,
            TMS_bldd, TMS_bldd, TMS_mads, TMS_madd,
            TMS_bldd, TMS_bldd, TMS_splk, TMS_in
          };
          insn.itype = codes[subcode];
          switch ( subcode )
          {
            case 0:
              if ( !op_iaa(insn, insn.Op1) )
                return 0;
              if ( (code & 0x80) == 0 )
                insn.itype = TMS_null;
              break;
            case 4:       // blpd bmar, ?
            case 0xC:     // bldd bmar, ?
              insn.Op1.type = o_reg;
              insn.Op1.reg = rBMAR;
              if ( !op_iaa(insn, insn.Op2) )
                return 0;
              break;
            case 0xD:     // bldd ?, bmar
              if ( !op_iaa(insn, insn.Op1) )
                return 0;
              insn.Op2.type = o_reg;
              insn.Op2.reg = rBMAR;
              break;
            case 2:               // mac
            case 3:               // macd
            case 5:               // blpd
              op_paddr(insn, insn.Op1);
              if ( !op_iaa(insn, insn.Op2) )
                return 0;
              break;
            case 8:
              op_daddr(insn, insn.Op1);
              if ( !op_iaa(insn, insn.Op2) )
                return 0;
              break;
            case 9:
              if ( !op_iaa(insn, insn.Op1) )
                return 0;
              op_daddr(insn, insn.Op2);
              break;
            case 0xE:
              op_imm(insn, insn.Op1);
              if ( !op_iaa(insn, insn.Op2) )
                return 0;
              break;
            case 0xF:
              if ( !op_iaa(insn, insn.Op1) )
                return 0;
              op_ioaddr(insn, insn.Op2);
              break;
            default:
              if ( !op_iaa(insn, insn.Op1) )
                return 0;
              break;
          }
        }
        break;

      case 0xB:
        switch ( subcode )
        {
          case 0: case 1: case 2: case 3:
          case 4: case 5: case 6: case 7:
            insn.itype = TMS_lar;
            op_ar(insn.Op1, subcode);
            op_short(insn.Op2);
            break;
          case 8: case 9: case 0xA: case 0xB:
          case 0xC:
            {
              static const uchar codes[] =
              {
                TMS_add, TMS_lacl, TMS_sub, TMS_rpt, TMS_ldp
              };
              insn.itype = codes[subcode-8]; //lint !e676 possibly indexing before the beginning of an allocation
              op_short(insn.Op1);
            }
            break;
          case 0xD:
            insn.itype = TMS_ldp;
            op_short(insn.Op1);
            insn.Op1.value |= 0x100;
            break;
          case 0xE:
            nibble = (code & 0xF);
            switch ( (code >> 4) & 0xF )
            {
              case 0: case 1: case 2: case 3:
                {
                  static const uchar codes[] =
                  {
                    TMS_abs,  TMS_cmpl,  TMS_neg,  TMS_pac,
                    TMS_apac, TMS_spac,  TMS_null, TMS_null,
                    TMS_null, TMS_sfl,   TMS_sfr,  TMS_null,
                    TMS_rol,  TMS_ror,   TMS_null, TMS_null,

                    TMS_addb, TMS_adcb,  TMS_andb, TMS_orb,
                    TMS_rolb, TMS_rorb,  TMS_sflb, TMS_sfrb,
                    TMS_sbb,  TMS_sbbb,  TMS_xorb, TMS_crgt,
                    TMS_crlt, TMS_exar,  TMS_sacb, TMS_lacb,

                    TMS_bacc, TMS_baccd, TMS_idle, TMS_idle2,
                    TMS_null, TMS_null,  TMS_null, TMS_null,
                    TMS_null, TMS_null,  TMS_null, TMS_null,
                    TMS_null, TMS_null,  TMS_null, TMS_null,

                    TMS_cala, TMS_null,  TMS_pop,  TMS_null,
                    TMS_null, TMS_null,  TMS_null, TMS_null,
                    TMS_reti, TMS_null,  TMS_rete, TMS_null,
                    TMS_push, TMS_calad, TMS_null, TMS_null
                  };
                  insn.itype = codes[code & 0x3F];
                }
                break;
              case 4:
                insn.itype = (code & 1) ? TMS_setc : TMS_clrc;
                op_cbit(insn.Op1, (code>>1)&7);
                break;
              case 5:
                {
                  static const uchar codes[] =
                  {
                    TMS_null, TMS_trap, TMS_nmi,  TMS_null,
                    TMS_null, TMS_null, TMS_null, TMS_null,
                    TMS_zpr,  TMS_zap,  TMS_sath, TMS_satl,
                    TMS_null, TMS_null, TMS_null, TMS_null
                  };
                  insn.itype = codes[nibble];
                }
                break;
              case 6:
              case 7:
                insn.itype = TMS_intr;
                insn.Op1.type = o_imm;
                insn.Op1.value = (code & 0x1F);
                insn.Op1.sib = 1;
                break;
              case 8:
                if ( nibble < 4 )
                {
                  static const uchar codes[] =
                  {
                    TMS_mpy, TMS_and, TMS_or, TMS_xor
                  };
                  insn.itype = codes[nibble];
                  op_imm(insn, insn.Op1);
                  if ( nibble != 0 )
                    op_shift(insn.Op2, 16);
                }
                break;
              case 9:
                if ( nibble == 0 )
                  insn.itype = TMS_estop;
                break;
              case 0xC:
                switch ( nibble )
                {
                  case 4:
                    insn.itype = TMS_rpt;
                    op_imm(insn, insn.Op1);
                    break;
                  case 5:
                    insn.itype = TMS_rptz;
                    op_imm(insn, insn.Op1);
                    break;
                  case 6:
                    insn.itype = TMS_rptb;
                    op_paddr(insn, insn.Op1);
                    break;
                }
                break;
            }
            break;
          case 0xF:
            nibble = (code & 0xF);
            switch ( (code>>4) & 0xF )
            {
              case 0:
                if ( code & 8 )
                {
                  insn.itype = TMS_lar;
                  op_ar(insn.Op1, code & 7);
                  op_imm(insn, insn.Op2);
                }
                else
                {
                  insn.itype = TMS_spm;
                  op_short(insn.Op1);
                  insn.Op1.sib = 1;
                }
                break;
              case 4:
                if ( (nibble & 0xC) == 4 )
                {
                  insn.itype = TMS_cmpr;
                  insn.Op1.type = o_imm;
                  insn.Op1.value = nibble & 3;
                  insn.Op1.sib = 1;
                }
                break;
              case 0xE:
                insn.itype = TMS_bsar;
                op_shift(insn.Op1, nibble+1);
                break;
              case 8:
              case 9:
              case 0xA:
              case 0xB:
              case 0xC:
              case 0xD:
                {
                  static const uchar codes[] =
                  {
                    TMS_lacc, TMS_add, TMS_sub, TMS_and, TMS_or, TMS_xor
                  };
                  insn.itype = codes[(code>>4) & 0x7];
                  op_imm(insn, insn.Op1);
                  op_shift(insn.Op2, nibble);
                }
                break;
            }
            break;
        }
        break;
      case 0xC:
      case 0xD:
        insn.itype = TMS_mpy;
        insn.Op1.dtype = dt_word;
        insn.Op1.type  = o_imm;
        insn.Op1.value = (code & 0x1FFF);
        if ( (insn.Op1.value & 0x1000) != 0 )
          insn.Op1.value |= ~0x1FFF; // extend sign
        insn.Op1.sib = 0;
        break;
      case 0xE:
      case 0xF:
        switch ( subcode>>2 )
        {
          case 0:
            insn.itype = (code & 0x1000) ? TMS_bcndd : TMS_bcnd;
            op_paddr(insn, insn.Op1);
            if ( !op_cond(insn.Op2) )
              return 0;
            break;
          case 1:
            insn.itype = TMS_xc;
            insn.Op1.type = o_imm;
            insn.Op1.value = (code & 0x1000) ? 2 : 1;
            insn.Op1.sib = 1;
            if ( !op_cond(insn.Op2) )
              return 0;
            break;
          case 2:
            insn.itype = (code & 0x1000) ? TMS_ccd : TMS_cc;
            op_paddr(insn, insn.Op1);
            if ( !op_cond(insn.Op2) )
              return 0;
            break;
          case 3:
            if ( (code & 0xEFFF) == 0xEF00 )
              insn.itype = (code & 0x1000) ? TMS_retd : TMS_ret;
            else
            {
              insn.itype = (code & 0x1000) ? TMS_retcd : TMS_retc;
              if ( !op_cond(insn.Op1) )
                return 0;
            }
            break;
        }
        break;
    }
  }
  if ( insn.itype == TMS_null )
    return 0;
  return insn.size;
}
