Index: opcodes/tic6x-dis.c |
diff --git a/opcodes/tic6x-dis.c b/opcodes/tic6x-dis.c |
index 05626df2275ff4d8d590c72daf5711542d53bc27..68a65eee9ceca8ffd493dc2f08ba7004ed99390f 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 2010-2013 Free Software Foundation, Inc. |
Contributed by Joseph Myers <joseph@codesourcery.com> |
Bernd Schmidt <bernds@codesourcery.com> |
@@ -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. */ |
@@ -119,12 +171,19 @@ tic6x_extract_32 (unsigned char *p, struct disassemble_info *info) |
/* 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] |
@@ -225,9 +296,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); |
@@ -246,6 +317,7 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) |
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 +330,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 +365,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 +377,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 +443,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 +495,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. */ |
@@ -402,22 +540,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 +578,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 +608,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 +638,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 +664,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,9 +683,14 @@ 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 (); |
} |
+ if (opc->flags & TIC6X_FLAG_INSN16_BSIDE && func_unit_side == 1) |
+ func_unit_cross = 1; |
+ |
snprintf (func_unit_buf, 7, " .%c%u%s%s", func_unit_char, |
func_unit_side, (func_unit_cross ? "X" : ""), data_str); |
func_unit = func_unit_buf; |
@@ -540,6 +724,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 +754,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 +804,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 +842,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 +852,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 +883,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 +894,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", |
+ 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", |
- (((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_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 +1021,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 +1064,33 @@ 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; |
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 +1181,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 +1215,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 +1242,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 +1287,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 +1322,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 +1333,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 +1404,7 @@ print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) |
break; |
default: |
+ printf ("*** unknown mem_mode : %d \n", mem_mode); |
abort (); |
} |
} |
@@ -1036,12 +1415,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 +1458,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 ? ' ' : ',')); |