/*
 *      Interactive disassembler (IDA).
 *      Copyright (c) 1990-2000 by Ilfak Guilfanov.
 *      ALL RIGHTS RESERVED.
 *                              E-mail: ig@datarescue.com
 *
 */

#include "st20.hpp"

//--------------------------------------------------------------------------
// ST20/C2-C4
static const ushort primary4[] =
{
/* 00 */ ST20_j,
/* 01 */ ST20_ldlp,
/* 02 */ ST20_pfix,
/* 03 */ ST20_ldnl,
/* 04 */ ST20_ldc,
/* 05 */ ST20_ldnlp,
/* 06 */ ST20_nfix,
/* 07 */ ST20_ldl,
/* 08 */ ST20_adc,
/* 09 */ ST20_call,
/* 0A */ ST20_cj,
/* 0B */ ST20_ajw,
/* 0C */ ST20_eqc,
/* 0D */ ST20_stl,
/* 0E */ ST20_stnl,
/* 0F */ ST20_opr,
};

static const ushort secondary4_negative[] =
{
/*~00 */ ST20_swapqueue,        // swap scheduler queue
/*~01 */ ST20_swaptimer,        // swap timer queue
/*~02 */ ST20_insertqueue,      // insert at front of scheduler queue
/*~03 */ ST20_timeslice,        // timeslice
/*~04 */ ST20_signal,           // signal
/*~05 */ ST20_wait,             // wait
/*~06 */ ST20_trapdis,          // trap disable
/*~07 */ ST20_trapenb,          // trap enable
/*~08 */ ST20_null,
/*~09 */ ST20_null,
/*~0A */ ST20_null,
/*~0B */ ST20_tret,             // trap return
/*~0C */ ST20_ldshadow,         // load shadow registers
/*~0D */ ST20_stshadow,         // store shadow registers
/*~0E */ ST20_null,
/*~0F */ ST20_null,
/*~10 */ ST20_null,
/*~11 */ ST20_null,
/*~12 */ ST20_null,
/*~13 */ ST20_null,
/*~14 */ ST20_null,
/*~15 */ ST20_null,
/*~16 */ ST20_null,
/*~17 */ ST20_null,
/*~18 */ ST20_null,
/*~19 */ ST20_null,
/*~1A */ ST20_null,
/*~1B */ ST20_null,
/*~1C */ ST20_null,
/*~1D */ ST20_null,
/*~1E */ ST20_null,
/*~1F */ ST20_iret,             // interrupt return
/*~20 */ ST20_null,
/*~21 */ ST20_null,
/*~22 */ ST20_null,
/*~23 */ ST20_null,
/*~24 */ ST20_devmove,          // device move
/*~25 */ ST20_null,
/*~26 */ ST20_null,
/*~27 */ ST20_null,
/*~28 */ ST20_null,
/*~29 */ ST20_null,
/*~2A */ ST20_null,
/*~2B */ ST20_null,
/*~2C */ ST20_null,
/*~2D */ ST20_null,
/*~2E */ ST20_restart,          // restart
/*~2F */ ST20_causeerror,       // cause error
/*~30 */ ST20_nop,              // no operation
/*~31 */ ST20_null,
/*~32 */ ST20_null,
/*~33 */ ST20_null,
/*~34 */ ST20_null,
/*~35 */ ST20_null,
/*~36 */ ST20_null,
/*~37 */ ST20_null,
/*~38 */ ST20_null,
/*~39 */ ST20_null,
/*~3A */ ST20_null,
/*~3B */ ST20_null,
/*~3C */ ST20_null,
/*~3D */ ST20_null,
/*~3E */ ST20_null,
/*~3F */ ST20_null,
/*~40 */ ST20_null,
/*~41 */ ST20_null,
/*~42 */ ST20_null,
/*~43 */ ST20_null,
/*~44 */ ST20_null,
/*~45 */ ST20_null,
/*~46 */ ST20_null,
/*~47 */ ST20_null,
/*~48 */ ST20_null,
/*~49 */ ST20_null,
/*~4A */ ST20_null,
/*~4B */ ST20_null,
/*~4C */ ST20_stclock,          // store clock register
/*~4D */ ST20_ldclock,          // load clock
/*~4E */ ST20_clockdis,         // clock disable
/*~4F */ ST20_clockenb,         // clock enable
/*~50 */ ST20_null,
/*~51 */ ST20_null,
/*~52 */ ST20_null,
/*~53 */ ST20_null,
/*~54 */ ST20_null,
/*~55 */ ST20_null,
/*~56 */ ST20_null,
/*~57 */ ST20_null,
/*~58 */ ST20_null,
/*~59 */ ST20_null,
/*~5A */ ST20_null,
/*~5B */ ST20_null,
/*~5C */ ST20_null,
/*~5D */ ST20_null,
/*~5E */ ST20_null,
/*~5F */ ST20_null,
/*~60 */ ST20_null,
/*~61 */ ST20_null,
/*~62 */ ST20_null,
/*~63 */ ST20_null,
/*~64 */ ST20_null,
/*~65 */ ST20_null,
/*~66 */ ST20_null,
/*~67 */ ST20_null,
/*~68 */ ST20_null,
/*~69 */ ST20_null,
/*~6A */ ST20_null,
/*~6B */ ST20_null,
/*~6C */ ST20_null,
/*~6D */ ST20_null,
/*~6E */ ST20_null,
/*~6F */ ST20_null,
/*~70 */ ST20_null,
/*~71 */ ST20_null,
/*~72 */ ST20_null,
/*~73 */ ST20_null,
/*~74 */ ST20_null,
/*~75 */ ST20_null,
/*~76 */ ST20_null,
/*~77 */ ST20_null,
/*~78 */ ST20_null,
/*~79 */ ST20_null,
/*~7A */ ST20_null,
/*~7B */ ST20_null,
/*~7C */ ST20_null,
/*~7D */ ST20_null,
/*~7E */ ST20_null,
/*~7F */ ST20_null,
/*~80 */ ST20_null,
/*~81 */ ST20_null,
/*~82 */ ST20_null,
/*~83 */ ST20_null,
/*~84 */ ST20_null,
/*~85 */ ST20_null,
/*~86 */ ST20_null,
/*~87 */ ST20_null,
/*~88 */ ST20_null,
/*~89 */ ST20_null,
/*~8A */ ST20_null,
/*~8B */ ST20_null,
/*~8C */ ST20_ldprodid,         // load product identity
/*~8D */ ST20_reboot,           // reboot
/*~8E */ ST20_null,
/*~8F */ ST20_null,
};

static const ushort secondary4[] =
{
/* 00 */ ST20_rev,              // ---------------------------------------------
/* 01 */ ST20_lb,               // load byte
/* 02 */ ST20_bsub,             // byte subscript
/* 03 */ ST20_endp,             // end process
/* 04 */ ST20_diff,             // difference
/* 05 */ ST20_add,
/* 06 */ ST20_gcall,            // general call
/* 07 */ ST20_in,               // input message
/* 08 */ ST20_prod,             // product
/* 09 */ ST20_gt,               // greater than
/* 0A */ ST20_wsub,             // word subscript
/* 0B */ ST20_out,              // output message
/* 0C */ ST20_sub,              // subtract
/* 0D */ ST20_startp,           // start process
/* 0E */ ST20_outbyte,          // output byte
/* 0F */ ST20_outword,          // output word
/* 10 */ ST20_seterr,           // set error flags
/* 11 */ ST20_null,
/* 12 */ ST20_resetch,          // reset channel
/* 13 */ ST20_csub0,            // check subscript from 0
/* 14 */ ST20_null,
/* 15 */ ST20_stopp,            // stop process
/* 16 */ ST20_ladd,             // long add
/* 17 */ ST20_stlb,             // store low priority back pointer
/* 18 */ ST20_sthf,             // store high priority front pointer
/* 19 */ ST20_norm,             // normalize
/* 1A */ ST20_ldiv,             // long divide
/* 1B */ ST20_ldpi,             // load pointer to instruction
/* 1C */ ST20_stlf,             // store low priority front pointer
/* 1D */ ST20_xdble,            // extend to double
/* 1E */ ST20_ldpri,            // load current priority
/* 1F */ ST20_rem,              // remainder
/* 20 */ ST20_ret,              // return
/* 21 */ ST20_lend,             // loop end
/* 22 */ ST20_ldtimer,          // load timer
/* 23 */ ST20_null,
/* 24 */ ST20_null,
/* 25 */ ST20_null,
/* 26 */ ST20_null,
/* 27 */ ST20_null,
/* 28 */ ST20_null,
/* 29 */ ST20_testerr,          // test error flag
/* 2A */ ST20_testpranal,       // test processor analysing
/* 2B */ ST20_tin,              // timer input
/* 2C */ ST20_div,              // divide
/* 2D */ ST20_null,
/* 2E */ ST20_dist,             // disable timer
/* 2F */ ST20_disc,             // disable channel
/* 30 */ ST20_diss,             // disable skip
/* 31 */ ST20_lmul,             // long multiply
/* 32 */ ST20_not,              // not
/* 33 */ ST20_xor,              // exclusize or
/* 34 */ ST20_bcnt,             // byte count
/* 35 */ ST20_lshr,             // long shift right
/* 36 */ ST20_lshl,             // long shift left
/* 37 */ ST20_lsum,             // long sum
/* 38 */ ST20_lsub,             // long subtract
/* 39 */ ST20_runp,             // run process
/* 3A */ ST20_xword,            // extend word
/* 3B */ ST20_sb,               // store byte
/* 3C */ ST20_gajw,             // general adjust workspace
/* 3D */ ST20_savel,            // save low priority queue registers
/* 3E */ ST20_saveh,            // save high priority queue registers
/* 3F */ ST20_wcnt,             // word count
/* 40 */ ST20_shr,              // shift right
/* 41 */ ST20_shl,              // shift left
/* 42 */ ST20_mint,             // minimum integer
/* 43 */ ST20_alt,              // alt start
/* 44 */ ST20_altwt,            // alt wait
/* 45 */ ST20_altend,           // alt end
/* 46 */ ST20_and,
/* 47 */ ST20_enbt,             // enable timer
/* 48 */ ST20_enbc,             // enable channel
/* 49 */ ST20_enbs,             // enable skip
/* 4A */ ST20_move,             // move message
/* 4B */ ST20_or,               // or
/* 4C */ ST20_csngl,            // check single
/* 4D */ ST20_ccnt1,            // check count from 1
/* 4E */ ST20_talt,             // timer alt start
/* 4F */ ST20_ldiff,            // long diff
/* 50 */ ST20_sthb,             // store high priority back pointer
/* 51 */ ST20_taltwt,           // timer alt wait
/* 52 */ ST20_sum,              // sum
/* 53 */ ST20_mul,              // multiply
/* 54 */ ST20_sttimer,          // store timer
/* 55 */ ST20_stoperr,          // stop on error
/* 56 */ ST20_cword,            // check word
/* 57 */ ST20_clrhalterr,       // clear halt-on error flag
/* 58 */ ST20_sethalterr,       // set halt-on error flag
/* 59 */ ST20_testhalterr,      // test halt-on error flag
/* 5A */ ST20_dup,              // duplicate top of stack
/* 5B */ ST20_move2dinit,       // initialize data for 2D block move
/* 5C */ ST20_move2dall,        // 2D block copy
/* 5D */ ST20_move2dnonzero,    // 2D block copy non-zero bytes
/* 5E */ ST20_move2dzero,       // 2D block copy zero bytes
/* 5F */ ST20_gtu,              // greater than unsigned
/* 60 */ ST20_null,
/* 61 */ ST20_null,
/* 62 */ ST20_null,
/* 63 */ ST20_unpacksn,         // unpack single length fp number
/* 64 */ ST20_slmul,            // signed long multiply
/* 65 */ ST20_sulmul,           // signed timer unsigned long multiply
/* 66 */ ST20_null,
/* 67 */ ST20_null,
/* 68 */ ST20_satadd,           // saturating add
/* 69 */ ST20_satsub,           // saturating subtract
/* 6A */ ST20_satmul,           // saturating multiply
/* 6B */ ST20_null,
/* 6C */ ST20_postnormsn,       // post-normalize correction of single length fp number
/* 6D */ ST20_roundsn,          // round single length floating point number
/* 6E */ ST20_ldtraph,          // load trap handler
/* 6F */ ST20_sttraph,          // store trap handler
/* 70 */ ST20_null,
/* 71 */ ST20_ldinf,            // load infinity
/* 72 */ ST20_fmul,             // fractional multiply
/* 73 */ ST20_cflerr,           // check floating point error
/* 74 */ ST20_crcword,          // calculate CRC on word
/* 75 */ ST20_crcbyte,          // calculate CRC on byte
/* 76 */ ST20_bitcnt,           // count bits set in word
/* 77 */ ST20_bitrevword,       // reverse bits in word
/* 78 */ ST20_bitrevnbits,      // reverse bottom n bits in word
/* 79 */ ST20_pop,              // pop processor stack
/* 7A */ ST20_null,
/* 7B */ ST20_null,
/* 7C */ ST20_null,
/* 7D */ ST20_null,
/* 7E */ ST20_ldmemstartval,    // load value of MemStart address
/* 7F */ ST20_null,
/* 80 */ ST20_null,
/* 81 */ ST20_wsubdb,           // form double word subscript
/* 82 */ ST20_null,
/* 83 */ ST20_null,
/* 84 */ ST20_null,
/* 85 */ ST20_null,
/* 86 */ ST20_null,
/* 87 */ ST20_null,
/* 88 */ ST20_null,
/* 89 */ ST20_null,
/* 8A */ ST20_null,
/* 8B */ ST20_null,
/* 8C */ ST20_null,
/* 8D */ ST20_null,
/* 8E */ ST20_null,
/* 8F */ ST20_null,
/* 90 */ ST20_null,
/* 91 */ ST20_null,
/* 92 */ ST20_null,
/* 93 */ ST20_null,
/* 94 */ ST20_null,
/* 95 */ ST20_null,
/* 96 */ ST20_null,
/* 97 */ ST20_null,
/* 98 */ ST20_null,
/* 99 */ ST20_null,
/* 9A */ ST20_null,
/* 9B */ ST20_null,
/* 9C */ ST20_fptesterr,        // test for FPU error
/* 9D */ ST20_null,
/* 9E */ ST20_null,
/* 9F */ ST20_null,
/* A0 */ ST20_null,
/* A1 */ ST20_null,
/* A2 */ ST20_null,
/* A3 */ ST20_null,
/* A4 */ ST20_null,
/* A5 */ ST20_null,
/* A6 */ ST20_null,
/* A7 */ ST20_null,
/* A8 */ ST20_null,
/* A9 */ ST20_null,
/* AA */ ST20_null,
/* AB */ ST20_null,
/* AC */ ST20_null,
/* AD */ ST20_null,
/* AE */ ST20_null,
/* AF */ ST20_null,
/* B0 */ ST20_settimeslice,     // set timeslicing status
/* B1 */ ST20_null,
/* B2 */ ST20_null,
/* B3 */ ST20_null,
/* B4 */ ST20_null,
/* B5 */ ST20_null,
/* B6 */ ST20_null,
/* B7 */ ST20_null,
/* B8 */ ST20_xbword,           // sign extend byte to word
/* B9 */ ST20_lbx,              // load byte and sign extend
/* BA */ ST20_cb,               // check byte
/* BB */ ST20_cbu,              // check byte unsigned
/* BC */ ST20_null,
/* BD */ ST20_null,
/* BE */ ST20_null,
/* BF */ ST20_null,
/* C0 */ ST20_null,
/* C1 */ ST20_ssub,             // sixteen subscript
/* C2 */ ST20_null,
/* C3 */ ST20_null,
/* C4 */ ST20_intdis,           // (localised) interrupt disable
/* C5 */ ST20_intenb,           // (localised) interrupt enable
/* C6 */ ST20_ldtrapped,        // load trapped process status
/* C7 */ ST20_cir,              // check in range
/* C8 */ ST20_ss,               // store sixteen
/* C9 */ ST20_null,
/* CA */ ST20_ls,               // load sixteen
/* CB */ ST20_sttrapped,        // store trapped process
/* CC */ ST20_ciru,             // check in range unsigned
/* CD */ ST20_gintdis,          // general interrupt disable
/* CE */ ST20_gintenb,          // general interrupt enable
/* CF */ ST20_null,
/* D0 */ ST20_null,
/* D1 */ ST20_null,
/* D2 */ ST20_null,
/* D3 */ ST20_null,
/* D4 */ ST20_null,
/* D5 */ ST20_null,
/* D6 */ ST20_null,
/* D7 */ ST20_null,
/* D8 */ ST20_null,
/* D9 */ ST20_null,
/* DA */ ST20_null,
/* DB */ ST20_null,
/* DC */ ST20_null,
/* DD */ ST20_null,
/* DE */ ST20_null,
/* DF */ ST20_null,
/* E0 */ ST20_null,
/* E1 */ ST20_null,
/* E2 */ ST20_null,
/* E3 */ ST20_null,
/* E4 */ ST20_null,
/* E5 */ ST20_null,
/* E6 */ ST20_null,
/* E7 */ ST20_null,
/* E8 */ ST20_null,
/* E9 */ ST20_null,
/* EA */ ST20_null,
/* EB */ ST20_null,
/* EC */ ST20_null,
/* ED */ ST20_null,
/* EE */ ST20_null,
/* EF */ ST20_null,
/* F0 */ ST20_devlb,            // device load byte
/* F1 */ ST20_devsb,            // device store byte
/* F2 */ ST20_devls,            // device load sixteen
/* F3 */ ST20_devss,            // device store sixteen
/* F4 */ ST20_devlw,            // device load word
/* F5 */ ST20_devsw,            // device store word
/* F6 */ ST20_null,
/* F7 */ ST20_null,
/* F8 */ ST20_xsword,           // sign extend sixteen to word
/* F9 */ ST20_lsx,              // load sixteen and sign extend
/* FA */ ST20_cs,               // check sixteen
/* FB */ ST20_csu,              // check sixteen unsigned
/* FC */ ST20_null,
/* FD */ ST20_null,
/* FE */ ST20_null,
/* FF */ ST20_null,
};

//--------------------------------------------------------------------------
// ST20/C1
static const ushort primary1[] =
{
/* 00 */ ST20_j,
/* 01 */ ST20_ldlp,
/* 02 */ ST20_pfix,
/* 03 */ ST20_ldnl,
/* 04 */ ST20_ldc,
/* 05 */ ST20_ldnlp,
/* 06 */ ST20_nfix,
/* 07 */ ST20_ldl,
/* 08 */ ST20_adc,
/* 09 */ ST20_fcall,
/* 0A */ ST20_cj,
/* 0B */ ST20_ajw,
/* 0C */ ST20_eqc,
/* 0D */ ST20_stl,
/* 0E */ ST20_stnl,
/* 0F */ ST20_opr,
};

static const ushort secondary1[] =
{
/* 00 */ ST20_rev,
/* 01 */ ST20_dup,
/* 02 */ ST20_rot,
/* 03 */ ST20_arot,
/* 04 */ ST20_add,
/* 05 */ ST20_sub,
/* 06 */ ST20_mul,
/* 07 */ ST20_wsub,
/* 08 */ ST20_not,
/* 09 */ ST20_and,
/* 0A */ ST20_or,
/* 0B */ ST20_shl,
/* 0C */ ST20_shr,
/* 0D */ ST20_jab,
/* 0E */ ST20_timeslice,
/* 0F */ ST20_breakpoint,
/* 10 */ ST20_addc,
/* 11 */ ST20_subc,
/* 12 */ ST20_mac,
/* 13 */ ST20_umac,
/* 14 */ ST20_smul,
/* 15 */ ST20_smacinit,
/* 16 */ ST20_smacloop,
/* 17 */ ST20_biquad,
/* 18 */ ST20_divstep,
/* 19 */ ST20_unsign,
/* 1A */ ST20_saturate,
/* 1B */ ST20_gt,
/* 1C */ ST20_gtu,
/* 1D */ ST20_order,
/* 1E */ ST20_orderu,
/* 1F */ ST20_ashr,
/* 20 */ ST20_xor,
/* 21 */ ST20_xbword,
/* 22 */ ST20_xsword,
/* 23 */ ST20_bitld,
/* 24 */ ST20_bitst,
/* 25 */ ST20_bitmask,
/* 26 */ ST20_statusset,
/* 27 */ ST20_statusclr,
/* 28 */ ST20_statustst,
/* 29 */ ST20_rmw,
/* 2A */ ST20_lbinc,
/* 2B */ ST20_sbinc,
/* 2C */ ST20_lsinc,
/* 2D */ ST20_lsxinc,
/* 2E */ ST20_ssinc,
/* 2F */ ST20_lwinc,
/* 30 */ ST20_swinc,
/* 31 */ ST20_ecall,
/* 32 */ ST20_eret,
/* 33 */ ST20_run,
/* 34 */ ST20_stop,
/* 35 */ ST20_signal,
/* 36 */ ST20_wait,
/* 37 */ ST20_enqueue,
/* 38 */ ST20_dequeue,
/* 39 */ ST20_ldtdesc,
/* 3A */ ST20_ldpi,
/* 3B */ ST20_gajw,
/* 3C */ ST20_ldprodid,
/* 3D */ ST20_io,
/* 3E */ ST20_swap32,
/* 3F */ ST20_nop,
};

struct ana_info_t
{
  const ushort *primary;
  const ushort *secondary;
  size_t sqty;
  const ushort *secondary_negative;
  size_t nsqty;
};

static const ana_info_t c1 =
{
  primary1,
  secondary1,
  qnumber(secondary1),
  nullptr,
  0
};

static const ana_info_t c4 =
{
  primary4,
  secondary4,
  qnumber(secondary4),
  secondary4_negative,
  qnumber(secondary4_negative),
};

//--------------------------------------------------------------------------
int st20_t::st20_ana(insn_t *_insn)
{
  insn_t &insn = *_insn;
  const ana_info_t &a = isc4() ? c4 : c1;
  int value = 0;
  while ( 1 )
  {
    int code = insn.get_next_byte();
    value |= (code & 15);
    insn.itype = a.primary[code>>4];
    switch ( insn.itype )
    {
      case ST20_j:
      case ST20_cj:
      case ST20_fcall:
      case ST20_call:
        insn.Op1.type = o_near;
        insn.Op1.dtype = dt_code;
        insn.Op1.addr = uint32(insn.ip + insn.size + value);
        break;
      case ST20_ldlp:
      case ST20_ldnl:
      case ST20_ldc:
      case ST20_ldnlp:
      case ST20_ldl:
      case ST20_adc:
      case ST20_ajw:
      case ST20_eqc:
      case ST20_stl:
      case ST20_stnl:
        insn.Op1.type = o_imm;
        insn.Op1.dtype = dt_dword;
        insn.Op1.value = value;
        break;
      case ST20_nfix:
        value = ~value;
        [[fallthrough]];
      case ST20_pfix:
        value <<= 4;
        continue;
      case ST20_opr:
        if ( isc4() && value == 0x17C )
        {
          insn.itype = ST20_lddevid;
          break;
        }
        if ( value < 0 )
        {
          value = (~value & ~15) | (value & 15);
          if ( value >= a.nsqty )
            return 0;
          insn.itype = a.secondary_negative[value];
        }
        else
        {
          if ( value >= a.sqty )
            return 0;
          insn.itype = a.secondary[value];
        }
        break;
    }
    break;
  }
  return insn.size;
}

