X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=opcodes%2Ftic6x-dis.c;h=51f009d36f71ebd03175d72def9101226d625e14;hb=030a2e78acf66c5c12e073ec3887a167da7a7195;hp=05626df2275ff4d8d590c72daf5711542d53bc27;hpb=c0621d88b096cc046adf6ed484baea9ba5bfe721;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/tic6x-dis.c b/opcodes/tic6x-dis.c index 05626df227..51f009d36f 100644 --- a/opcodes/tic6x-dis.c +++ b/opcodes/tic6x-dis.c @@ -1,6 +1,5 @@ /* TI C6X disassembler. - Copyright 2010 - Free Software Foundation, Inc. + Copyright (C) 2010-2020 Free Software Foundation, Inc. Contributed by Joseph Myers Bernd Schmidt @@ -22,7 +21,7 @@ MA 02110-1301, USA. */ #include "sysdep.h" -#include "dis-asm.h" +#include "disassemble.h" #include "opcode/tic6x.h" #include "libiberty.h" @@ -53,6 +52,30 @@ const tic6x_ctrl tic6x_ctrl_table[tic6x_ctrl_max] = /* Define the opcode table. */ const tic6x_opcode tic6x_opcode_table[tic6x_opcode_max] = { +#define INSNU(name, func_unit, format, type, isa, flags, fixed, ops, var) \ + { \ + STRINGX(name), \ + CONCAT2(tic6x_func_unit_,func_unit), \ + CONCAT3(tic6x_insn_format,_,format), \ + CONCAT2(tic6x_pipeline_,type), \ + CONCAT2(TIC6X_INSN_,isa), \ + flags, \ + fixed, \ + ops, \ + var \ + }, +#define INSNUE(name, e, func_unit, format, type, isa, flags, fixed, ops, var) \ + { \ + STRINGX(name), \ + CONCAT2(tic6x_func_unit_,func_unit), \ + CONCAT3(tic6x_insn_format,_,format), \ + CONCAT2(tic6x_pipeline_,type), \ + CONCAT2(TIC6X_INSN_,isa), \ + flags, \ + fixed, \ + ops, \ + var \ + }, #define INSN(name, func_unit, format, type, isa, flags, fixed, ops, var) \ { \ STRINGX(name), \ @@ -80,6 +103,8 @@ const tic6x_opcode tic6x_opcode_table[tic6x_opcode_max] = #include "opcode/tic6x-opcode-table.h" #undef INSN #undef INSNE +#undef INSNU +#undef INSNUE }; /* If instruction format FMT has a field FIELD, return a pointer to @@ -97,12 +122,39 @@ tic6x_field_from_fmt (const tic6x_insn_format *fmt, tic6x_insn_field_id field) return NULL; } +/* Extract the field width. */ + +static unsigned int +tic6x_field_width (const tic6x_insn_field *field) +{ + unsigned int i; + unsigned int width = 0; + + if (!field->num_bitfields) + return field->bitfields[0].width; + + for (i = 0 ; i < field->num_bitfields ; i++) + width += field->bitfields[i].width; + + return width; +} + /* Extract the bits corresponding to FIELD from OPCODE. */ static unsigned int tic6x_field_bits (unsigned int opcode, const tic6x_insn_field *field) { - return (opcode >> field->low_pos) & ((1u << field->width) - 1); + unsigned int i; + unsigned int val = 0; + + if (!field->num_bitfields) + return (opcode >> field->bitfields[0].low_pos) & ((1u << field->bitfields[0].width) - 1); + + for (i = 0 ; i < field->num_bitfields ; i++) + val |= ((opcode >> field->bitfields[i].low_pos) & ((1u << field->bitfields[i].width) - 1)) + << field->bitfields[i].pos; + + return val; } /* Extract a 32-bit value read from the instruction stream. */ @@ -111,20 +163,27 @@ static unsigned int tic6x_extract_32 (unsigned char *p, struct disassemble_info *info) { if (info->endian == BFD_ENDIAN_LITTLE) - return (p[0]) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); + return p[0] | (p[1] << 8) | (p[2] << 16) | ((unsigned) p[3] << 24); else - return (p[3]) | (p[2] << 8) | (p[1] << 16) | (p[0] << 24); + return p[3] | (p[2] << 8) | (p[1] << 16) | ((unsigned) p[0] << 24); } /* Extract a 16-bit value read from the instruction stream. */ static unsigned int -tic6x_extract_16 (unsigned char *p, struct disassemble_info *info) +tic6x_extract_16 (unsigned char *p, tic6x_fetch_packet_header *header, + struct disassemble_info *info) { + unsigned int op16; + if (info->endian == BFD_ENDIAN_LITTLE) - return (p[0]) | (p[1] << 8); + op16 = (p[0]) | (p[1] << 8); else - return (p[1]) | (p[0] << 8); + op16 = (p[1]) | (p[0] << 8); + op16 |= (header->sat << TIC6X_COMPACT_SAT_POS); + op16 |= (header->br << TIC6X_COMPACT_BR_POS); + op16 |= (header->dsz << TIC6X_COMPACT_DSZ_POS); + return op16; } /* FP points to a fetch packet. Return whether it is header-based; if @@ -138,8 +197,20 @@ tic6x_check_fetch_packet_header (unsigned char *fp, int i; header->header = tic6x_extract_32 (fp + 28, info); + if ((header->header & 0xf0000000) != 0xe0000000) - return FALSE; + { + header->prot = 0; + header->rs = 0; + header->dsz = 0; + header->br = 0; + header->sat = 0; + for (i = 0; i < 7; i++) + header->word_compact[i] = FALSE; + for (i = 0; i < 14; i++) + header->p_bits[i] = FALSE; + return FALSE; + } for (i = 0; i < 7; i++) header->word_compact[i] @@ -178,6 +249,9 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) fp_offset = addr & 0x1f; fp_addr = addr - fp_offset; + /* Read in a block of instructions. Since there might be a + symbol in the middle of this block, disable stop_vma. */ + info->stop_vma = 0; status = info->read_memory_func (fp_addr, fp, 32, info); if (status) { @@ -225,9 +299,9 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) pretending that the two halves of the word are in opposite locations to where they actually are. */ if (info->endian == BFD_ENDIAN_LITTLE) - opcode = tic6x_extract_16 (fp + fp_offset, info); + opcode = tic6x_extract_16 (fp + fp_offset, &header, info); else - opcode = tic6x_extract_16 (fp + (fp_offset ^ 2), info); + opcode = tic6x_extract_16 (fp + (fp_offset ^ 2), &header, info); } else opcode = tic6x_extract_32 (fp + fp_offset, info); @@ -242,10 +316,11 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) const char *parallel; const char *cond = ""; const char *func_unit; - char func_unit_buf[7]; + char func_unit_buf[8]; unsigned int func_unit_side = 0; unsigned int func_unit_data_side = 0; unsigned int func_unit_cross = 0; + unsigned int t_val = 0; /* The maximum length of the text of a non-PC-relative operand is 24 bytes (SPMASK masking all eight functional units, with separating commas and trailing NUL). */ @@ -258,6 +333,7 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) unsigned int op_num; bfd_boolean fixed_ok; bfd_boolean operands_ok; + bfd_boolean have_t = FALSE; if (opc->flags & TIC6X_FLAG_MACRO) continue; @@ -292,7 +368,10 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) table. */ z_field = tic6x_field_from_fmt (fmt, tic6x_field_z); if (!z_field) - abort (); + { + printf ("*** opcode %x: missing z field", opcode); + abort (); + } creg_value = tic6x_field_bits (opcode, creg_field); z_value = tic6x_field_bits (opcode, z_field); @@ -301,6 +380,62 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) continue; } + if (opc->flags & TIC6X_FLAG_INSN16_SPRED) + { + const tic6x_insn_field *cc_field; + unsigned int s_value = 0; + unsigned int z_value = 0; + bfd_boolean cond_known = FALSE; + static const char *const conds[2][2] = + { + { "[a0] ", "[!a0] " }, + { "[b0] ", "[!b0] " } + }; + + cc_field = tic6x_field_from_fmt (fmt, tic6x_field_cc); + + if (cc_field) + { + unsigned int cc_value; + + cc_value = tic6x_field_bits (opcode, cc_field); + s_value = (cc_value & 0x2) >> 1; + z_value = (cc_value & 0x1); + cond_known = TRUE; + } + else + { + const tic6x_insn_field *z_field; + const tic6x_insn_field *s_field; + + s_field = tic6x_field_from_fmt (fmt, tic6x_field_s); + + if (!s_field) + { + printf ("opcode %x: missing compact insn predicate register field (s field)\n", + opcode); + abort (); + } + s_value = tic6x_field_bits (opcode, s_field); + z_field = tic6x_field_from_fmt (fmt, tic6x_field_z); + if (!z_field) + { + printf ("opcode %x: missing compact insn predicate z_value (z field)\n", opcode); + abort (); + } + + z_value = tic6x_field_bits (opcode, z_field); + cond_known = TRUE; + } + + if (!cond_known) + { + printf ("opcode %x: unspecified ompact insn predicate\n", opcode); + abort (); + } + cond = conds[s_value][z_value]; + } + /* All fixed fields must have matching values; all fields with restricted ranges must have values within those ranges. */ fixed_ok = TRUE; @@ -311,7 +446,12 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) = tic6x_field_from_fmt (fmt, opc->fixed_fields[fix].field_id); if (!field) - abort (); + { + printf ("opcode %x: missing field #%d for FIX #%d\n", + opcode, opc->fixed_fields[fix].field_id, fix); + abort (); + } + field_bits = tic6x_field_bits (opcode, field); if (field_bits < opc->fixed_fields[fix].min_val || field_bits > opc->fixed_fields[fix].max_val) @@ -358,6 +498,7 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) /* Find the last instruction of the previous fetch packet. */ unsigned char fp_prev[32]; + status = info->read_memory_func (fp_addr - 32, fp_prev, 32, info); if (status) /* No previous instruction to be parallel with. */ @@ -369,8 +510,17 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) prev_header_based = tic6x_check_fetch_packet_header (fp_prev, &prev_header, info); - if (prev_header_based && prev_header.word_compact[6]) - p_bit = prev_header.p_bits[13]; + if (prev_header_based) + { + if (prev_header.word_compact[6]) + p_bit = prev_header.p_bits[13]; + else + { + unsigned int prev_opcode = tic6x_extract_32 (fp_prev + 24, + info); + p_bit = (prev_opcode & 0x1) ? TRUE : FALSE; + } + } else { unsigned int prev_opcode = tic6x_extract_32 (fp_prev + 28, @@ -402,22 +552,37 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) unsigned int fld_val; field = tic6x_field_from_fmt (fmt, enc->field_id); + if (!field) - abort (); + { + printf ("opcode %x: could not retrieve field (field_id:%d)\n", + opcode, fld_num); + abort (); + } + fld_val = tic6x_field_bits (opcode, field); + switch (enc->coding_method) { case tic6x_coding_fu: /* The side must be specified exactly once. */ if (func_unit_side) - abort (); + { + printf ("opcode %x: field #%d use tic6x_coding_fu, but func_unit_side is already set!\n", + opcode, fld_num); + abort (); + } func_unit_side = (fld_val ? 2 : 1); break; case tic6x_coding_data_fu: /* The data side must be specified exactly once. */ if (func_unit_data_side) - abort (); + { + printf ("opcode %x: field #%d use tic6x_coding_fu, but func_unit_side is already set!\n", + opcode, fld_num); + abort (); + } func_unit_data_side = (fld_val ? 2 : 1); break; @@ -425,11 +590,22 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) /* Cross path use must be specified exactly once. */ if (have_cross) - abort (); + { + printf ("opcode %x: field #%d use tic6x_coding_xpath, have_cross is already set!\n", + opcode, fld_num); + abort (); + } have_cross = TRUE; func_unit_cross = fld_val; break; + case tic6x_coding_rside: + /* If the format has a t field, use it for src/dst register side. */ + have_t = TRUE; + t_val = fld_val; + func_unit_data_side = (t_val ? 2 : 1); + break; + case tic6x_coding_areg: have_areg = TRUE; break; @@ -444,17 +620,28 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) determined either from the flags or from an instruction field. */ if (func_unit_side != 1 && func_unit_side != 2) - abort (); + { + printf ("opcode %x: func_unit_side is not encoded!\n", opcode); + abort (); + } /* Cross paths are not applicable when sides are specified for both address and data paths. */ if (func_unit_data_side && have_cross) - abort (); + { + printf ("opcode %x: xpath not applicable when side are specified both for address and data!\n", + opcode); + abort (); + } /* Separate address and data paths are only applicable for the D unit. */ if (func_unit_data_side && opc->func_unit != tic6x_func_unit_d) - abort (); + { + printf ("opcode %x: separate address and data paths only applicable for D unit!\n", + opcode); + abort (); + } /* If an address register is being used but in ADDA rather than a load or store, it uses a cross path for side-A @@ -463,7 +650,10 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) if (have_areg && !func_unit_data_side) { if (have_cross) - abort (); + { + printf ("opcode %x: illegal cross path specifier in adda opcode!\n", opcode); + abort (); + } func_unit_cross = (func_unit_side == 1 ? TRUE : FALSE); } @@ -486,6 +676,7 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) break; default: + printf ("opcode %x: illegal func_unit specifier %d\n", opcode, opc->func_unit); abort (); } @@ -504,11 +695,17 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) break; default: + printf ("opcode %x: illegal data func_unit specifier %d\n", + opcode, func_unit_data_side); abort (); } - snprintf (func_unit_buf, 7, " .%c%u%s%s", func_unit_char, - func_unit_side, (func_unit_cross ? "X" : ""), data_str); + if (opc->flags & TIC6X_FLAG_INSN16_BSIDE && func_unit_side == 1) + func_unit_cross = 1; + + snprintf (func_unit_buf, sizeof func_unit_buf, " .%c%u%s%s", + func_unit_char, func_unit_side, + (func_unit_cross ? "X" : ""), data_str); func_unit = func_unit_buf; } @@ -540,6 +737,19 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) switch (opc->operand_info[op_num].form) { + case tic6x_operand_b15reg: + /* Fully determined by the functional unit. */ + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "b15"); + continue; + + case tic6x_operand_zreg: + /* Fully determined by the functional unit. */ + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "%c0", + (func_unit_side == 2 ? 'b' : 'a')); + continue; + case tic6x_operand_retreg: /* Fully determined by the functional unit. */ operands_text[op_num] = TRUE; @@ -557,6 +767,46 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) snprintf (operands[op_num], 24, "nrp"); continue; + case tic6x_operand_ilc: + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "ilc"); + continue; + + case tic6x_operand_hw_const_minus_1: + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "-1"); + continue; + + case tic6x_operand_hw_const_0: + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "0"); + continue; + + case tic6x_operand_hw_const_1: + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "1"); + continue; + + case tic6x_operand_hw_const_5: + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "5"); + continue; + + case tic6x_operand_hw_const_16: + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "16"); + continue; + + case tic6x_operand_hw_const_24: + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "24"); + continue; + + case tic6x_operand_hw_const_31: + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "31"); + continue; + default: break; } @@ -567,16 +817,25 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) = &opc->variable_fields[fld_num]; const tic6x_insn_field *field; unsigned int fld_val; + unsigned int reg_base = 0; signed int signed_fld_val; + char reg_side = '?'; if (enc->operand_num != op_num) continue; field = tic6x_field_from_fmt (fmt, enc->field_id); if (!field) - abort (); - fld_val = tic6x_field_bits (opcode, field); + { + printf ("opcode %x: missing field (field_id:%d) in format\n", opcode, enc->field_id); + abort (); + } + fld_val = tic6x_field_bits (opcode, field); switch (enc->coding_method) { + case tic6x_coding_cst_s3i: + (fld_val == 0x00) && (fld_val = 0x10); + (fld_val == 0x07) && (fld_val = 0x08); + /* Fall through. */ case tic6x_coding_ucst: case tic6x_coding_ulcst_dpr_byte: case tic6x_coding_ulcst_dpr_half: @@ -596,6 +855,7 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) break; default: + printf ("opcode %x: illegal operand form for operand#%d\n", opcode, op_num); abort (); } break; @@ -605,11 +865,26 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) snprintf (operands[op_num], 24, "%u", fld_val << 16); break; + case tic6x_coding_scst_l3i: + operands_text[op_num] = TRUE; + if (fld_val == 0) + { + signed_fld_val = 8; + } + else + { + signed_fld_val = (signed int) fld_val; + signed_fld_val ^= (1 << (tic6x_field_width (field) - 1)); + signed_fld_val -= (1 << (tic6x_field_width (field) - 1)); + } + snprintf (operands[op_num], 24, "%d", signed_fld_val); + break; + case tic6x_coding_scst: operands_text[op_num] = TRUE; signed_fld_val = (signed int) fld_val; - signed_fld_val ^= (1 << (field->width - 1)); - signed_fld_val -= (1 << (field->width - 1)); + signed_fld_val ^= (1 << (tic6x_field_width (field) - 1)); + signed_fld_val -= (1 << (tic6x_field_width (field) - 1)); snprintf (operands[op_num], 24, "%d", signed_fld_val); break; @@ -621,8 +896,8 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) case tic6x_coding_pcrel: case tic6x_coding_pcrel_half: signed_fld_val = (signed int) fld_val; - signed_fld_val ^= (1 << (field->width - 1)); - signed_fld_val -= (1 << (field->width - 1)); + signed_fld_val ^= (1 << (tic6x_field_width (field) - 1)); + signed_fld_val -= (1 << (tic6x_field_width (field) - 1)); if (fetch_packet_header_based && enc->coding_method == tic6x_coding_pcrel_half) signed_fld_val *= 2; @@ -632,70 +907,124 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) operands_addresses[op_num] = fp_addr + signed_fld_val; break; + case tic6x_coding_regpair_msb: + if (opc->operand_info[op_num].form != tic6x_operand_regpair) + abort (); + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "%c%u:%c%u", + (func_unit_side == 2 ? 'b' : 'a'), (fld_val | 0x1), + (func_unit_side == 2 ? 'b' : 'a'), (fld_val | 0x1) - 1); + break; + + case tic6x_coding_pcrel_half_unsigned: + operands_pcrel[op_num] = TRUE; + operands_addresses[op_num] = fp_addr + 2 * fld_val; + break; + case tic6x_coding_reg_shift: fld_val <<= 1; /* Fall through. */ case tic6x_coding_reg: + if (num_bits == 16 && header.rs && !(opc->flags & TIC6X_FLAG_INSN16_NORS)) + { + reg_base = 16; + } switch (opc->operand_info[op_num].form) { + case tic6x_operand_treg: + if (!have_t) + { + printf ("opcode %x: operand treg but missing t field\n", opcode); + abort (); + } + operands_text[op_num] = TRUE; + reg_side = t_val ? 'b' : 'a'; + snprintf (operands[op_num], 24, "%c%u", reg_side, reg_base + fld_val); + break; + case tic6x_operand_reg: operands_text[op_num] = TRUE; - snprintf (operands[op_num], 24, "%c%u", - (func_unit_side == 2 ? 'b' : 'a'), fld_val); + reg_side = (func_unit_side == 2) ? 'b' : 'a'; + snprintf (operands[op_num], 24, "%c%u", reg_side, reg_base + fld_val); + break; + + case tic6x_operand_reg_nors: + operands_text[op_num] = TRUE; + reg_side = (func_unit_side == 2) ? 'b' : 'a'; + snprintf (operands[op_num], 24, "%c%u", reg_side, fld_val); + break; + + case tic6x_operand_reg_bside: + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "b%u", reg_base + fld_val); + break; + + case tic6x_operand_reg_bside_nors: + operands_text[op_num] = TRUE; + snprintf (operands[op_num], 24, "b%u", fld_val); break; case tic6x_operand_xreg: operands_text[op_num] = TRUE; - snprintf (operands[op_num], 24, "%c%u", - (((func_unit_side == 2) ^ func_unit_cross) - ? 'b' - : 'a'), fld_val); + reg_side = ((func_unit_side == 2) ^ func_unit_cross) ? 'b' : 'a'; + snprintf (operands[op_num], 24, "%c%u", reg_side, reg_base + fld_val); break; case tic6x_operand_dreg: operands_text[op_num] = TRUE; - snprintf (operands[op_num], 24, "%c%u", - (func_unit_data_side == 2 ? 'b' : 'a'), - fld_val); + reg_side = (func_unit_data_side == 2) ? 'b' : 'a'; + snprintf (operands[op_num], 24, "%c%u", reg_side, reg_base + fld_val); break; case tic6x_operand_regpair: operands_text[op_num] = TRUE; if (fld_val & 1) operands_ok = FALSE; + reg_side = (func_unit_side == 2) ? 'b' : 'a'; snprintf (operands[op_num], 24, "%c%u:%c%u", - (func_unit_side == 2 ? 'b' : 'a'), fld_val + 1, - (func_unit_side == 2 ? 'b' : 'a'), fld_val); + reg_side, reg_base + fld_val + 1, + reg_side, reg_base + fld_val); break; case tic6x_operand_xregpair: operands_text[op_num] = TRUE; if (fld_val & 1) operands_ok = FALSE; + reg_side = ((func_unit_side == 2) ^ func_unit_cross) ? 'b' : 'a'; snprintf (operands[op_num], 24, "%c%u:%c%u", - (((func_unit_side == 2) ^ func_unit_cross) - ? 'b' - : 'a'), fld_val + 1, - (((func_unit_side == 2) ^ func_unit_cross) - ? 'b' - : 'a'), fld_val); + reg_side, reg_base + fld_val + 1, + reg_side, reg_base + fld_val); + break; + + case tic6x_operand_tregpair: + if (!have_t) + { + printf ("opcode %x: operand tregpair but missing t field\n", opcode); + abort (); + } + operands_text[op_num] = TRUE; + if (fld_val & 1) + operands_ok = FALSE; + reg_side = t_val ? 'b' : 'a'; + snprintf (operands[op_num], 24, "%c%u:%c%u", + reg_side, reg_base + fld_val + 1, + reg_side, reg_base + fld_val); break; case tic6x_operand_dregpair: operands_text[op_num] = TRUE; if (fld_val & 1) operands_ok = FALSE; + reg_side = (func_unit_data_side) == 2 ? 'b' : 'a'; snprintf (operands[op_num], 24, "%c%u:%c%u", - (func_unit_data_side == 2 ? 'b' : 'a'), - fld_val + 1, - (func_unit_data_side == 2 ? 'b' : 'a'), - fld_val); + reg_side, reg_base + fld_val + 1, + reg_side, reg_base + fld_val); break; case tic6x_operand_mem_deref: operands_text[op_num] = TRUE; - snprintf (operands[op_num], 24, "*%c%u", - (func_unit_side == 2 ? 'b' : 'a'), fld_val); + reg_side = func_unit_side == 2 ? 'b' : 'a'; + snprintf (operands[op_num], 24, "*%c%u", reg_side, reg_base + fld_val); break; case tic6x_operand_mem_short: @@ -705,6 +1034,30 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) break; default: + printf ("opcode %x: unexpected operand form %d for operand #%d", + opcode, opc->operand_info[op_num].form, op_num); + abort (); + } + break; + + case tic6x_coding_reg_ptr: + switch (opc->operand_info[op_num].form) + { + case tic6x_operand_mem_short: + case tic6x_operand_mem_ndw: + if (fld_val > 0x3u) + { + printf("opcode %x: illegal field value for ptr register of operand #%d (%d)", + opcode, op_num, fld_val); + abort (); + } + mem_base_reg = 0x4 | fld_val; + mem_base_reg_known = TRUE; + break; + + default: + printf ("opcode %x: unexpected operand form %d for operand #%d", + opcode, opc->operand_info[op_num].form, op_num); abort (); } break; @@ -724,14 +1077,34 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) break; default: + printf ("opcode %x: bad operand form\n", opcode); abort (); } break; - case tic6x_coding_mem_offset: + case tic6x_coding_mem_offset_minus_one_noscale: + case tic6x_coding_mem_offset_minus_one: + fld_val += 1; + /* Fall through. */ case tic6x_coding_mem_offset_noscale: + case tic6x_coding_mem_offset: mem_offset = fld_val; mem_offset_known = TRUE; + if (num_bits == 16) + { + mem_mode_known = TRUE; + mem_mode = TIC6X_INSN16_MEM_MODE_VAL (opc->flags); + mem_scaled_known = TRUE; + mem_scaled = TRUE; + if (opc->flags & TIC6X_FLAG_INSN16_B15PTR) + { + mem_base_reg_known = TRUE; + mem_base_reg = 15; + } + if ( enc->coding_method == tic6x_coding_mem_offset_noscale + || enc->coding_method == tic6x_coding_mem_offset_noscale ) + mem_scaled = FALSE; + } break; case tic6x_coding_mem_mode: @@ -822,11 +1195,11 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) if (info->endian == BFD_ENDIAN_LITTLE) search_opcode = (tic6x_extract_16 - (search_fp + search_fp_offset, info)); + (search_fp + search_fp_offset, &header, info)); else search_opcode = (tic6x_extract_16 - (search_fp + (search_fp_offset ^ 2), + (search_fp + (search_fp_offset ^ 2), &header, info)); } else @@ -856,7 +1229,10 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) if (prev_sploop_found) { if (sploop_ii <= 0) - abort (); + { + printf ("opcode %x: sloop index not found (%d)\n", opcode, sploop_ii); + abort (); + } else if (sploop_ii <= 1) fcyc_bits = 0; else if (sploop_ii <= 2) @@ -880,8 +1256,11 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) operands_text[op_num] = TRUE; break; } - if (fcyc_bits > field->width) - abort (); + if (fcyc_bits > tic6x_field_width(field)) + { + printf ("opcode %x: illegal fcyc value (%d)\n", opcode, fcyc_bits); + abort (); + } if (enc->coding_method == tic6x_coding_fstg) { int i, t; @@ -922,18 +1301,23 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) case tic6x_coding_fu: case tic6x_coding_data_fu: case tic6x_coding_xpath: + case tic6x_coding_rside: /* Don't relate to operands, so operand number is meaningless. */ break; default: + printf ("opcode %x: illegal field encoding (%d)\n", opcode, enc->coding_method); abort (); } if (mem_base_reg_known_long && mem_offset_known_long) { if (operands_text[op_num] || operands_pcrel[op_num]) - abort (); + { + printf ("opcode %x: long access but operands already known ?\n", opcode); + abort (); + } operands_text[op_num] = TRUE; snprintf (operands[op_num], 24, "*+b%u(%u)", mem_base_reg, mem_offset * opc->operand_info[op_num].size); @@ -952,7 +1336,10 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) char offsetp[6]; if (operands_text[op_num] || operands_pcrel[op_num]) - abort (); + { + printf ("opcode %x: mem access operands already known ?\n", opcode); + abort (); + } side = func_unit_side == 2 ? 'b' : 'a'; snprintf (base, 4, "%c%u", side, mem_base_reg); @@ -960,7 +1347,12 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) offset_is_reg = ((mem_mode & 4) ? TRUE : FALSE); if (offset_is_reg) { - snprintf (offset, 4, "%c%u", side, mem_offset); + + if (num_bits == 16 && header.rs && !(opc->flags & TIC6X_FLAG_INSN16_NORS)) + { + reg_base = 16; + } + snprintf (offset, 4, "%c%u", side, reg_base + mem_offset); if (opc->operand_info[op_num].form == tic6x_operand_mem_ndw) offset_scaled = mem_scaled ? TRUE : FALSE; @@ -1026,6 +1418,7 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) break; default: + printf ("*** unknown mem_mode : %d \n", mem_mode); abort (); } } @@ -1036,12 +1429,18 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) tic6x_ctrl_id crid; if (operands_text[op_num] || operands_pcrel[op_num]) - abort (); + { + printf ("*** abort crlo crli\n"); + abort (); + } rw = opc->operand_info[op_num].rw; if (rw != tic6x_rw_read && rw != tic6x_rw_write) - abort (); + { + printf ("*** abort rw : %d\n", rw); + abort (); + } for (crid = 0; crid < tic6x_ctrl_max; crid++) { @@ -1073,26 +1472,37 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) || spmask_skip_operand) break; } + /* end for fld_num */ + if (spmask_skip_operand) { /* SPMASK operands are only valid as the single operand in the opcode table. */ if (num_operands != 1) - abort (); + { + printf ("opcode: %x, num_operands != 1 : %d\n", opcode, num_operands); + abort (); + } num_operands = 0; break; } + /* The operand must by now have been decoded. */ if (!operands_text[op_num] && !operands_pcrel[op_num]) - abort (); - } + { + printf ("opcode: %x, operand #%d not decoded\n", opcode, op_num); + abort (); + } + } + /* end for op_num */ if (!operands_ok) continue; info->bytes_per_chunk = num_bits / 8; - info->fprintf_func (info->stream, "%s%s%s%s", parallel, cond, - opc->name, func_unit); + info->fprintf_func (info->stream, "%s", parallel); + info->fprintf_func (info->stream, "%s%s%s", cond, opc->name, + func_unit); for (op_num = 0; op_num < num_operands; op_num++) { info->fprintf_func (info->stream, "%c", (op_num == 0 ? ' ' : ','));