/* Opcode table header for Visium.

  Copyright (C) 2003-2024 Free Software Foundation, Inc.

  This file is part of GDB, GAS, and GNU binutils.

  GDB, GAS and the GNU binutils are free software; you can redistribute
  them and/or modify them under the terms of the GNU General Public
  License as published by the Free Software Foundation; either version 3,
  or (at your option) any later version.

  GDB, GAS, and the GNU binutils are distributed in the hope that they
  will be useful, but WITHOUT ANY WARRANTY; without even the implied
  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  the GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this file; see the file COPYING3.  If not, write to the Free
  Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
  MA 02110-1301, USA.  */

enum visium_opcode_arch_val
{
 VISIUM_OPCODE_ARCH_DEF = 0,
 VISIUM_OPCODE_ARCH_GR5,
 VISIUM_OPCODE_ARCH_GR6,
 VISIUM_OPCODE_ARCH_BAD
};

/* The highest architecture in the table.  */
#define VISIUM_OPCODE_ARCH_MAX (VISIUM_OPCODE_ARCH_BAD - 1)

/* Given an enum visium_opcode_arch_val, return the bitmask to use in
  insn encoding/decoding.  */
#define VISIUM_OPCODE_ARCH_MASK(arch) (1 << (arch))

/* Some defines to make life easy.  */
#define MASK_DEF VISIUM_OPCODE_ARCH_MASK (VISIUM_OPCODE_ARCH_DEF)
#define MASK_GR5 VISIUM_OPCODE_ARCH_MASK (VISIUM_OPCODE_ARCH_GR5)
#define MASK_GR6 VISIUM_OPCODE_ARCH_MASK (VISIUM_OPCODE_ARCH_GR6)

/* Bit masks of architectures supporting the insn.  */
#define def (MASK_DEF | MASK_GR5 | MASK_GR6)
#define gr5 (MASK_GR5 | MASK_GR6)
#define gr6 (MASK_GR6)

/* The condition code field is not used (zero) for most instructions.
  BRR and BRA make normal use of it. Floating point instructions use
  it as a sub-opcode.  */
#define CC_MASK (0xf << 27)

/* It seems a shame not to use these bits in a class 0 instruction,
  since they could be used to extend the range of the branch.  */
#define CLASS0_UNUSED_MASK (0x1f << 16)

/* For class 1 instructions the following bit is unused.  */
#define CLASS1_UNUSED_MASK (1 << 9)

/* For class 1 instructions this field gives the index for a write
  instruction, the specific operation for an EAM instruction, or
  the floating point destination register for a floating point
  instruction.  */
#define CLASS1_INDEX_MASK (0x1f << 10)

/* For class 3 instructions the following field gives the destination
  general register.  */
#define CLASS3_DEST_MASK (0x1f << 10)

/* For class 1 and class 3 instructions the following bit selects an
  EAM write/read rather than a memory write/read.  */
#define EAM_SELECT_MASK (1 << 15)

/* Floating point instructions are distinguished from general EAM
  instructions by the following bit.  */
#define FP_SELECT_MASK (1 << 3)

/* For both class 1 and class 3 the following fields give, where
  appropriate the srcA and srcB registers whether floating point
  or general.  */
#define SRCA_MASK (0x1f << 16)
#define SRCB_MASK (0x1f << 4)

/* The class 3 interrupt bit. It turns a BRA into a SYS1, and an
  RFLAG into a SYS2. This bit should not be set in the user's
  class 3 instructions. This bit is also used in class 3
  to distinguish between floating point and other EAM operations.
  (see FP_SELECT_MASK).  */
#define CLASS3_INT (1 << 3)

/* Class 3 shift instructions use this bit to indicate that the
  srcB field is a 5 bit immediate shift count rather than a
  register number.  */
#define CLASS3_SOURCEB_IMMED (1 << 9)

#define BMD 0x02630004
#define BMI 0x82230004
#define DSI 0x82800004
#define ENI 0x02a00004
#define RFI 0x82fe01d4

struct reg_entry
{
 const char *name;
 unsigned char code;
};

static const struct reg_entry gen_reg_table[] ATTRIBUTE_UNUSED =
{
 {"fp", 0x16},
 {"r0", 0x0},
 {"r1", 0x1},
 {"r10", 0xA},
 {"r11", 0xB},
 {"r12", 0xC},
 {"r13", 0xD},
 {"r14", 0xE},
 {"r15", 0xF},
 {"r16", 0x10},
 {"r17", 0x11},
 {"r18", 0x12},
 {"r19", 0x13},
 {"r2", 0x2},
 {"r20", 0x14},
 {"r21", 0x15},
 {"r22", 0x16},
 {"r23", 0x17},
 {"r24", 0x18},
 {"r25", 0x19},
 {"r26", 0x1a},
 {"r27", 0x1b},
 {"r28", 0x1c},
 {"r29", 0x1d},
 {"r3", 0x3},
 {"r30", 0x1e},
 {"r31", 0x1f},
 {"r4", 0x4},
 {"r5", 0x5},
 {"r6", 0x6},
 {"r7", 0x7},
 {"r8", 0x8},
 {"r9", 0x9},
 {"sp", 0x17},
};

static const struct reg_entry fp_reg_table[] ATTRIBUTE_UNUSED =
{
 {"f0", 0x0},
 {"f1", 0x1},
 {"f10", 0xa},
 {"f11", 0xb},
 {"f12", 0xc},
 {"f13", 0xd},
 {"f14", 0xe},
 {"f15", 0xf},
 {"f2", 0x2},
 {"f3", 0x3},
 {"f4", 0x4},
 {"f5", 0x5},
 {"f6", 0x6},
 {"f7", 0x7},
 {"f8", 0x8},
 {"f9", 0x9},
};

static const struct cc_entry
{
 const char *name;
 int code;
} cc_table [] ATTRIBUTE_UNUSED =
{
 {"cc", 6},
 {"cs", 2},
 {"eq", 1},
 {"fa", 0},
 {"ge", 9},
 {"gt", 10},
 {"hi", 11},
 {"le", 12},
 {"ls", 13},
 {"lt", 14},
 {"nc", 8},
 {"ne", 5},
 {"ns", 4},
 {"oc", 7},
 {"os", 3},
 {"tr", 15},
};

enum addressing_mode
{
 mode_d,       /* register := */
 mode_a,       /* op= register */
 mode_da,      /* register := register */
 mode_ab,      /* register * register */
 mode_dab,     /* register := register * register */
 mode_iab,     /* 5-bit immediate * register * register */
 mode_0ab,     /* zero * register * register */
 mode_da0,     /* register := register * zero */
 mode_cad,     /* condition * register * register */
 mode_das,     /* register := register * 5-bit immed/register shift count */
 mode_di,      /* register := 5-bit immediate */
 mode_ir,      /* 5-bit immediate * register */
 mode_ai,      /* register 16-bit unsigned immediate */
 mode_i,       /* 16-bit unsigned immediate */
 mode_bax,     /* register * register * 5-bit immediate */
 mode_dax,     /* register := register * 5-bit immediate */
 mode_s,       /* special mode */
 mode_sr,      /* special mode with register */
 mode_ci,      /* condition * 16-bit signed word displacement */
 mode_fdab,    /* float := float * float */
 mode_ifdab,   /* fpinst: 4-bit immediate * float * float * float */
 mode_idfab,   /* fpuread: 4-bit immediate * register * float * float */
 mode_fda,     /* float := float */
 mode_fdra,    /* float := register */
 mode_rdfab,   /* register := float * float */
 mode_rdfa,    /* register := float */
 mode_rrr,     /* 3 register sources and destinations (block move) */
};

#define class0 (0<<25)
#define class1 (1<<25)
#define class2 (2<<25)
#define class3 (3<<25)

static const struct opcode_entry
{
 const char *mnem;
 enum addressing_mode mode;
 unsigned code;
 char flags;
}
opcode_table[] ATTRIBUTE_UNUSED =
{
 { "adc.b",    mode_dab,  class3|(1<<21)|(1), def },
 { "adc.l",    mode_dab,  class3|(1<<21)|(4), def },
 { "adc.w",    mode_dab,  class3|(1<<21)|(2), def },
 { "add.b",    mode_dab,  class3|(0<<21)|(1), def },
 { "add.l",    mode_dab,  class3|(0<<21)|(4), def },
 { "add.w",    mode_dab,  class3|(0<<21)|(2), def },
 { "addi",     mode_ai,   class2, def },
 { "and.b",    mode_dab,  class3|(10<<21)|(1), def},
 { "and.l",    mode_dab,  class3|(10<<21)|(4), def },
 { "and.w",    mode_dab,  class3|(10<<21)|(2), def },
 { "asl.b",    mode_das,  class3|(7<<21)|(1), def },
 { "asl.l",    mode_das,  class3|(7<<21)|(4), def },
 { "asl.w",    mode_das,  class3|(7<<21)|(2), def },
 { "asld",     mode_a,    class1|(15<<21)|(1<<15)|(11<<10)|(4), def },
 { "asr.b",    mode_das,  class3|(5<<21)|(1), def },
 { "asr.l",    mode_das,  class3|(5<<21)|(4), def },
 { "asr.w",    mode_das,  class3|(5<<21)|(2), def },
 { "asrd",     mode_a,    class1|(15<<21)|(1<<15)|(9<<10)|(4), def },
 { "bmd",      mode_rrr,  class1|(3<<21)|(3<<16)|(4), gr6 },
 { "bmi",      mode_rrr,  class1|(1<<21)|(3<<16)|(4), gr6 },
 { "bra",      mode_cad,  class3|(12<<21)|(4), def },
 { "brr",      mode_ci,   class0, def },
 { "cmp.b",    mode_0ab,  class3|(2<<21)|(1), def },
 { "cmp.l",    mode_0ab,  class3|(2<<21)|(4), def },
 { "cmp.w",    mode_0ab,  class3|(2<<21)|(2), def },
 { "cmpc.b",   mode_0ab,  class3|(3<<21)|(1), def },
 { "cmpc.l",   mode_0ab,  class3|(3<<21)|(4), def },
 { "cmpc.w",   mode_0ab,  class3|(3<<21)|(2), def },
 { "divds",    mode_a,    class1|(15<<21)|(1<<15)|(6<<10)|(4), def },
 { "divdu",    mode_a,    class1|(15<<21)|(1<<15)|(7<<10)|(4), def },
 { "divs",     mode_a,    class1|(15<<21)|(1<<15)|(2<<10)|(4), def },
 { "divu",     mode_a,    class1|(15<<21)|(1<<15)|(3<<10)|(4), def },
 { "dsi",      mode_s,    class1|(4<<21)|(4), def },
 { "eamread",  mode_di,   class3|(15<<21)|(1<<15)|(1<<9)|(4), def },
 { "eamwrite", mode_iab,  class1|(15<<21)|(1<<15)|(4), def },
 { "eni",      mode_s,    class1|(5<<21)|(4), def },
 { "extb.b",   mode_da,   class3|(14<<21)|(1), def },
 { "extb.l",   mode_da,   class3|(14<<21)|(4), def },
 { "extb.w",   mode_da,   class3|(14<<21)|(2), def },
 { "extw.l",   mode_da,   class3|(4<<21)|(4), def },
 { "extw.w",   mode_da,   class3|(4<<21)|(2), def },
 { "fabs",     mode_fda,  class1|(7<<27)|(15<<21)|(1<<15)|(1<<3)|(4), gr5 },
 { "fadd",     mode_fdab, class1|(1<<27)|(15<<21)|(1<<15)|(1<<3)|(4), gr5 },
 { "fcmp",     mode_rdfab,class3|(10<<27)|(15<<21)|(1<<15)|(1<<9)|(1<<3)|(4), gr5 },
 { "fcmpe",    mode_rdfab,class3|(11<<27)|(15<<21)|(1<<15)|(1<<9)|(1<<3)|(4), gr5 },
 { "fdiv",     mode_fdab, class1|(4<<27)|(15<<21)|(1<<15)|(1<<3)|(4), gr5 },
 { "fload",    mode_fdra, class1|(15<<21)|(1<<15)|(1<<3)|(4), gr5 },
 { "fmove",    mode_fda,  class1|(12<<27)|(15<<21)|(1<<15)|(1<<3)|(4), gr5},
 { "fmult",    mode_fdab, class1|(3<<27)|(15<<21)|(1<<15)|(1<<3)|(4), gr5 },
 { "fneg",     mode_fda,  class1|(6<<27)|(15<<21)|(1<<15)|(1<<3)|(4), gr5 },
 { "fpinst",   mode_ifdab,class1|(15<<21)|(1<<15)|(1<<3)|(4), gr5 },
 { "fpuread",  mode_idfab,class3|(15<<21)|(1<<15)|(1<<9)|(1<<3)|(4), gr5 },
 { "fsqrt",    mode_fda,  class1|(5<<27)|(15<<21)|(1<<15)|(1<<3)|(4), gr5 },
 { "fstore",   mode_rdfa, class3|(15<<21)|(1<<15)|(1<<9)|(1<<3)|(4), gr5 },
 { "fsub",     mode_fdab, class1|(2<<27)|(15<<21)|(1<<15)|(1<<3)|(4), gr5 },
 { "ftoi",     mode_fda,  class1|(8<<27)|(15<<21)|(1<<15)|(1<<3)|(4), gr5 },
 { "itof",     mode_fda,  class1|(9<<27)|(15<<21)|(1<<15)|(1<<3)|(4), gr5 },
 { "lsr.b",    mode_das,  class3|(6<<21)|(1), def },
 { "lsr.l",    mode_das,  class3|(6<<21)|(4), def },
 { "lsr.w",    mode_das,  class3|(6<<21)|(2), def },
 { "lsrd",     mode_a,    class1|(15<<21)|(1<<15)|(10<<10)|(4), def },
 { "move.b",   mode_da0,  class3|(9<<21)|(1), def },
 { "move.l",   mode_da0,  class3|(9<<21)|(4), def },
 { "move.w",   mode_da0,  class3|(9<<21)|(2), def },
 { "movil",    mode_ai,   class2|(4<<21), def },
 { "moviq",    mode_ai,   class2|(6<<21), def },
 { "moviu",    mode_ai,   class2|(5<<21), def },
 { "mults",    mode_ab,   class1|(15<<21)|(1<<15)|(0<<10)|(4), def },
 { "multu",    mode_ab,   class1|(15<<21)|(1<<15)|(1<<10)|(4), def },
 { "nop",      mode_s,    class0, def },
 { "not.b",    mode_da,   class3|(11<<21)|(1), def },
 { "not.l",    mode_da,   class3|(11<<21)|(4), def },
 { "not.w",    mode_da,   class3|(11<<21)|(2), def },
 { "or.b",     mode_dab,  class3|(9<<21)|(1), def },
 { "or.l",     mode_dab,  class3|(9<<21)|(4), def },
 { "or.w",     mode_dab,  class3|(9<<21)|(2), def },
 { "read.b",   mode_dax,  class3|(15<<21)|(1<<9)|(1), def },
 { "read.l",   mode_dax,  class3|(15<<21)|(1<<9)|(4), def },
 { "read.w",   mode_dax,  class3|(15<<21)|(1<<9)|(2), def },
 { "readmda",  mode_d,    class3|(15<<21)|(1<<15)|(1<<9)|(4), def },
 { "readmdb",  mode_d,    class3|(15<<21)|(1<<15)|(1<<9)|(1<<4)|(4), def },
 { "readmdc",  mode_d,    class3|(15<<21)|(1<<15)|(1<<9)|(2<<4)|(4), def },
 { "rfi",      mode_s,    class1|(7<<21)|(30<<16)|(29<<4)|(4), def },
 { "rflag",    mode_d,    class3|(13<<21)|(4), def },
 { "stop",     mode_ir,   class1|(0<<21)|(4), def },
 { "sub.b",    mode_dab,  class3|(2<<21)|(1), def },
 { "sub.l",    mode_dab,  class3|(2<<21)|(4), def },
 { "sub.w",    mode_dab,  class3|(2<<21)|(2), def },
 { "subc.b",   mode_dab,  class3|(3<<21)|(1), def },
 { "subc.l",   mode_dab,  class3|(3<<21)|(4), def },
 { "subc.w",   mode_dab,  class3|(3<<21)|(2), def },
 { "subi",     mode_ai,   class2|(2<<21), def },
 { "trace",    mode_ir,   class1|(13<<21), def },
 { "write.b",  mode_bax,  class1|(15<<21)|(1), def },
 { "write.l",  mode_bax,  class1|(15<<21)|(4), def },
 { "write.w",  mode_bax,  class1|(15<<21)|(2), def },
 { "writemd",  mode_ab,   class1|(15<<21)|(1<<15)|(4<<10)|(4), def },
 { "writemdc", mode_a,    class1|(15<<21)|(1<<15)|(5<<10)|(4), def },
 { "wrtl",     mode_i,    class2|(8<<21), gr6 },
 { "wrtu",     mode_i,    class2|(9<<21), gr6 },
 { "xor.b",    mode_dab,  class3|(8<<21)|(1), def },
 { "xor.l",    mode_dab,  class3|(8<<21)|(4), def },
 { "xor.w",    mode_dab,  class3|(8<<21)|(2), def },
};