+/* Extract and return the value of OPERAND from the instruction whose value
+ is held in the array INSN. */
+
+static int
+extract_operand_value (const struct arc_operand *operand,
+ unsigned long long insn,
+ unsigned limm)
+{
+ int value;
+
+ /* Read the limm operand, if required. */
+ if (operand->flags & ARC_OPERAND_LIMM)
+ /* The second part of the instruction value will have been loaded as
+ part of the find_format call made earlier. */
+ value = limm;
+ else
+ {
+ if (operand->extract)
+ value = (*operand->extract) (insn, (int *) NULL);
+ else
+ {
+ if (operand->flags & ARC_OPERAND_ALIGNED32)
+ {
+ value = (insn >> operand->shift)
+ & ((1 << (operand->bits - 2)) - 1);
+ value = value << 2;
+ }
+ else
+ {
+ value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
+ }
+ if (operand->flags & ARC_OPERAND_SIGNED)
+ {
+ int signbit = 1 << (operand->bits - 1);
+ value = (value ^ signbit) - signbit;
+ }
+ }
+ }
+
+ return value;
+}
+
+/* Find the next operand, and the operands value from ITER. Return TRUE if
+ there is another operand, otherwise return FALSE. If there is an
+ operand returned then the operand is placed into OPERAND, and the value
+ into VALUE. If there is no operand returned then OPERAND and VALUE are
+ unchanged. */
+
+static bfd_boolean
+operand_iterator_next (struct arc_operand_iterator *iter,
+ const struct arc_operand **operand,
+ int *value)
+{
+ if (*iter->opidx == 0)
+ {
+ *operand = NULL;
+ return FALSE;
+ }
+
+ *operand = &arc_operands[*iter->opidx];
+ *value = extract_operand_value (*operand, iter->insn, iter->limm);
+ iter->opidx++;
+
+ return TRUE;
+}
+
+/* Helper for parsing the options. */
+
+static void
+parse_option (char *option)
+{
+ if (CONST_STRNEQ (option, "dsp"))
+ add_to_decodelist (DSP, NONE);
+
+ else if (CONST_STRNEQ (option, "spfp"))
+ add_to_decodelist (FLOAT, SPX);
+
+ else if (CONST_STRNEQ (option, "dpfp"))
+ add_to_decodelist (FLOAT, DPX);
+
+ else if (CONST_STRNEQ (option, "quarkse_em"))
+ {
+ add_to_decodelist (FLOAT, DPX);
+ add_to_decodelist (FLOAT, SPX);
+ add_to_decodelist (FLOAT, QUARKSE);
+ }
+
+ else if (CONST_STRNEQ (option, "fpuda"))
+ add_to_decodelist (FLOAT, DPA);
+
+ else if (CONST_STRNEQ (option, "fpus"))
+ {
+ add_to_decodelist (FLOAT, SP);
+ add_to_decodelist (FLOAT, CVT);
+ }
+
+ else if (CONST_STRNEQ (option, "fpud"))
+ {
+ add_to_decodelist (FLOAT, DP);
+ add_to_decodelist (FLOAT, CVT);
+ }
+ else
+ fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
+}
+
+/* Go over the options list and parse it. */
+
+static void
+parse_disassembler_options (char *options)
+{
+ if (options == NULL)
+ return;
+
+ while (*options)
+ {
+ /* Skip empty options. */
+ if (*options == ',')
+ {
+ ++ options;
+ continue;
+ }
+
+ parse_option (options);
+
+ while (*options != ',' && *options != '\0')
+ ++ options;
+ }
+}
+
+/* Return the instruction type for an instruction described by OPCODE. */
+
+static enum dis_insn_type
+arc_opcode_to_insn_type (const struct arc_opcode *opcode)
+{
+ enum dis_insn_type insn_type;
+
+ switch (opcode->insn_class)
+ {
+ case BRANCH:
+ case BBIT0:
+ case BBIT1:
+ case BI:
+ case BIH:
+ case BRCC:
+ case EI:
+ case JLI:
+ case JUMP:
+ case LOOP:
+ if (!strncmp (opcode->name, "bl", 2)
+ || !strncmp (opcode->name, "jl", 2))
+ {
+ if (opcode->subclass == COND)
+ insn_type = dis_condjsr;
+ else
+ insn_type = dis_jsr;
+ }
+ else
+ {
+ if (opcode->subclass == COND)
+ insn_type = dis_condbranch;
+ else
+ insn_type = dis_branch;
+ }
+ break;
+ case LOAD:
+ case STORE:
+ case MEMORY:
+ case ENTER:
+ case PUSH:
+ case POP:
+ insn_type = dis_dref;
+ break;
+ case LEAVE:
+ insn_type = dis_branch;
+ break;
+ default:
+ insn_type = dis_nonbranch;
+ break;
+ }
+
+ return insn_type;
+}
+