diff options
author | Svein Seldal <svein@dev.seldal.com> | 2002-11-18 09:09:35 +0000 |
---|---|---|
committer | Svein Seldal <svein@dev.seldal.com> | 2002-11-18 09:09:35 +0000 |
commit | 3375be4ad7b076dcbfff420824e40cd3e35a2bbf (patch) | |
tree | 134047c1121b2e9204d238b7bda362eadbf01cd8 /opcodes/tic4x-dis.c | |
parent | 3ecb3a9ac70192468dd757044d8a554e277ebc1d (diff) | |
download | gdb-3375be4ad7b076dcbfff420824e40cd3e35a2bbf.tar.gz |
* gas/config/tc-tic4x.c: Fixed proper commandline
parameters. Added support for new opcode-list format. General
error message fixups.
(c4x_inst_add): Reject insn not for our CPU
(md_begin): Added matrix for setting the proper opcode-level &
device-flags according to cpu type and revision. Rewrite the
opcode hasher.
(c4x_operand_parse): Fix opcode bug
(c4x_operands_match): New function argument. Added dry-run
mechanism, that is optional error generation. Added constraint 'i'
and 'j'.
(c4x_insn_check): Added new function for post-verification of the
generated insn.
(md_assemble): Check all opcodes before croaking because of an
argument mismatch. Need this to be able to fully support
ortogonally arguments.
(md_parse_options): Revised commandprompt swicthes and added new
ones.
(md_show_usage): Complete rewrite of printout.
* gas/testsuite/gas/tic4x/addressing.s: Fix bug in one insn
* gas/testsuite/gas/tic4x/addressing_c3x.d: Update thereafter
* gas/testsuite/gas/tic4x/addressing_c4x.d: Update thereafter
* gas/testsuite/gas/tic4x/allopcodes.S: Add support for new
opclass.h changes
* gas/testsuite/gas/tic4x/opclasses.h: Added testsuites for
the new enhanced opcodes.
* gas/testsuite/gas/tic4x/opcodes.s: Regenerate
* gas/testsuite/gas/tic4x/opcodes_c3x.d: Update from above
* gas/testsuite/gas/tic4x/opcodes_c4x.d: Update from above
* gas/testsuite/gas/tic4x/opcodes_new.d: Added new testsuite for
the enhanced and special insns.
* gas/testsuite/gas/tic4x/tic4x.exp: Added the opcodes_new testsuite
* include/opcode/tic4x.h: File reordering. Added enhanced opcodes.
* opcodes/tic4x-dis.c: Added support for enhanced and special
insn.
(c4x_print_op): Added insn class 'i' and 'j'
(c4x_hash_opcode_special): Add to support special insn
(c4x_hash_opcode): Update to support the new opcode-list
format. Add support for the new special insns.
(c4x_disassemble): New opcode-list support.
Diffstat (limited to 'opcodes/tic4x-dis.c')
-rw-r--r-- | opcodes/tic4x-dis.c | 158 |
1 files changed, 127 insertions, 31 deletions
diff --git a/opcodes/tic4x-dis.c b/opcodes/tic4x-dis.c index ff1770e2ad0..b9916934dc0 100644 --- a/opcodes/tic4x-dis.c +++ b/opcodes/tic4x-dis.c @@ -25,7 +25,8 @@ #define C4X_DEBUG 0 -#define C4X_HASH_SIZE 11 /* 11 and above should give unique entries. */ +#define C4X_HASH_SIZE 11 /* 11 (bits) and above should give unique entries. */ +#define C4X_SPESOP_SIZE 8 /* Max 8. ops for special instructions */ typedef enum { @@ -50,35 +51,37 @@ static int c4x_version = 0; static int c4x_dp = 0; static int c4x_pc_offset - PARAMS ((unsigned int)); + PARAMS ((unsigned int)); static int c4x_print_char - PARAMS ((struct disassemble_info *, char)); + PARAMS ((struct disassemble_info *, char)); static int c4x_print_str - PARAMS ((struct disassemble_info *, char *)); + PARAMS ((struct disassemble_info *, char *)); static int c4x_print_register - PARAMS ((struct disassemble_info *, unsigned long)); + PARAMS ((struct disassemble_info *, unsigned long)); static int c4x_print_addr - PARAMS ((struct disassemble_info *, unsigned long)); + PARAMS ((struct disassemble_info *, unsigned long)); static int c4x_print_relative - PARAMS ((struct disassemble_info *, unsigned long, long, unsigned long)); + PARAMS ((struct disassemble_info *, unsigned long, long, unsigned long)); void c4x_print_ftoa - PARAMS ((unsigned int, FILE *, fprintf_ftype)); + PARAMS ((unsigned int, FILE *, fprintf_ftype)); static int c4x_print_direct - PARAMS ((struct disassemble_info *, unsigned long)); + PARAMS ((struct disassemble_info *, unsigned long)); static int c4x_print_immed - PARAMS ((struct disassemble_info *, immed_t, unsigned long)); + PARAMS ((struct disassemble_info *, immed_t, unsigned long)); static int c4x_print_cond - PARAMS ((struct disassemble_info *, unsigned int)); + PARAMS ((struct disassemble_info *, unsigned int)); static int c4x_print_indirect - PARAMS ((struct disassemble_info *, indirect_t, unsigned long)); + PARAMS ((struct disassemble_info *, indirect_t, unsigned long)); static int c4x_print_op - PARAMS ((struct disassemble_info *, unsigned long, c4x_inst_t *, unsigned long)); + PARAMS ((struct disassemble_info *, unsigned long, c4x_inst_t *, unsigned long)); +static void c4x_hash_opcode_special + PARAMS ((c4x_inst_t **, const c4x_inst_t *)); static void c4x_hash_opcode - PARAMS ((c4x_inst_t **, const c4x_inst_t *)); + PARAMS ((c4x_inst_t **, c4x_inst_t **, const c4x_inst_t *, unsigned long)); static int c4x_disassemble - PARAMS ((unsigned long, unsigned long, struct disassemble_info *)); + PARAMS ((unsigned long, unsigned long, struct disassemble_info *)); int print_insn_tic4x - PARAMS ((bfd_vma, struct disassemble_info *)); + PARAMS ((bfd_vma, struct disassemble_info *)); static int @@ -489,12 +492,29 @@ c4x_print_op (info, instruction, p, pc) EXTRU (instruction, 15, 0)); break; + case 'i': /* Extended indirect 0--7 */ + if ( EXTRU (instruction, 7, 5) == 7 ) + { + if( !c4x_print_register (info, EXTRU (instruction, 4, 0)) ) + return 0; + break; + } + /* Fallthrough */ + case 'I': /* indirect (short) 0--7 */ if (! c4x_print_indirect (info, INDIRECT_SHORT, EXTRU (instruction, 7, 0))) return 0; break; + case 'j': /* Extended indirect 8--15 */ + if ( EXTRU (instruction, 15, 13) == 7 ) + { + if( !c4x_print_register (info, EXTRU (instruction, 12, 8)) ) + return 0; + break; + } + case 'J': /* indirect (short) 8--15 */ if (! c4x_print_indirect (info, INDIRECT_SHORT, EXTRU (instruction, 15, 8))) @@ -629,9 +649,43 @@ c4x_print_op (info, instruction, p, pc) } static void -c4x_hash_opcode (optable, inst) +c4x_hash_opcode_special (optable_special, inst) + c4x_inst_t **optable_special; + const c4x_inst_t *inst; +{ + int i; + + for( i=0; i<C4X_SPESOP_SIZE; i++ ) + if( optable_special[i] != NULL + && optable_special[i]->opcode == inst->opcode ) + { + /* Collision (we have it already) - overwrite */ + optable_special[i] = (void *)inst; + return; + } + + for( i=0; i<C4X_SPESOP_SIZE; i++ ) + if( optable_special[i] == NULL ) + { + /* Add the new opcode */ + optable_special[i] = (void *)inst; + return; + } + + /* This should never occur. This happens if the number of special + instructions exceeds C4X_SPESOP_SIZE. Please increase the variable + of this variable */ +#if C4X_DEBUG + printf("optable_special[] is full, please increase C4X_SPESOP_SIZE!\n"); +#endif +} + +static void +c4x_hash_opcode (optable, optable_special, inst, c4x_oplevel) c4x_inst_t **optable; + c4x_inst_t **optable_special; const c4x_inst_t *inst; + const unsigned long c4x_oplevel; { int j; int opcode = inst->opcode >> (32 - C4X_HASH_SIZE); @@ -641,7 +695,8 @@ c4x_hash_opcode (optable, inst) have unique entries so there's no point having a linked list for each entry? */ for (j = opcode; j < opmask; j++) - if ((j & opmask) == opcode) + if ( (j & opmask) == opcode + && inst->oplevel & c4x_oplevel ) { #if C4X_DEBUG /* We should only have collisions for synonyms like @@ -650,7 +705,21 @@ c4x_hash_opcode (optable, inst) printf("Collision at index %d, %s and %s\n", j, optable[j]->name, inst->name); #endif - optable[j] = (void *)inst; + /* Catch those ops that collide with others already inside the + hash, and have a opmask greater than the one we use in the + hash. Store them in a special-list, that will handle full + 32-bit INSN, not only the first 11-bit (or so). */ + if ( optable[j] != NULL + && inst->opmask & ~(opmask << (32 - C4X_HASH_SIZE)) ) + { + /* Add the instruction already on the list */ + c4x_hash_opcode_special(optable_special, optable[j]); + + /* Add the new instruction */ + c4x_hash_opcode_special(optable_special, inst); + } + + optable[j] = (void *)inst; } } @@ -667,36 +736,63 @@ c4x_disassemble (pc, instruction, info) struct disassemble_info *info; { static c4x_inst_t **optable = NULL; + static c4x_inst_t **optable_special = NULL; c4x_inst_t *p; int i; + unsigned long c4x_oplevel; c4x_version = info->mach; + + c4x_oplevel = (IS_CPU_C4X (c4x_version)) ? OP_C4X : 0; + c4x_oplevel |= OP_C3X|OP_LPWR|OP_IDLE2|OP_ENH; if (optable == NULL) { optable = (c4x_inst_t **) xcalloc (sizeof (c4x_inst_t *), (1 << C4X_HASH_SIZE)); + + optable_special = (c4x_inst_t **) + xcalloc (sizeof (c4x_inst_t *), C4X_SPESOP_SIZE ); + /* Install opcodes in reverse order so that preferred forms overwrite synonyms. */ - for (i = c3x_num_insts - 1; i >= 0; i--) - c4x_hash_opcode (optable, &c3x_insts[i]); - if (IS_CPU_C4X (c4x_version)) - { - for (i = c4x_num_insts - 1; i >= 0; i--) - c4x_hash_opcode (optable, &c4x_insts[i]); - } + for (i = c4x_num_insts - 1; i >= 0; i--) + c4x_hash_opcode (optable, optable_special, &c4x_insts[i], c4x_oplevel); + + /* We now need to remove the insn that are special from the + "normal" optable, to make the disasm search this extra list + for them. + */ + for (i=0; i<C4X_SPESOP_SIZE; i++) + if ( optable_special[i] != NULL ) + optable[optable_special[i]->opcode >> (32 - C4X_HASH_SIZE)] = NULL; } /* See if we can pick up any loading of the DP register... */ if ((instruction >> 16) == 0x5070 || (instruction >> 16) == 0x1f70) c4x_dp = EXTRU (instruction, 15, 0); - + p = optable[instruction >> (32 - C4X_HASH_SIZE)]; - if (p != NULL && ((instruction & p->opmask) == p->opcode) - && c4x_print_op (NULL, instruction, p, pc)) - c4x_print_op (info, instruction, p, pc); + if ( p != NULL ) + { + if ( ((instruction & p->opmask) == p->opcode) + && c4x_print_op (NULL, instruction, p, pc) ) + c4x_print_op (info, instruction, p, pc); + else + (*info->fprintf_func) (info->stream, "%08x", instruction); + } else - (*info->fprintf_func) (info->stream, "%08x", instruction); + { + for (i = 0; i<C4X_SPESOP_SIZE; i++) + if (optable_special[i] != NULL + && optable_special[i]->opcode == instruction ) + { + (*info->fprintf_func)(info->stream, "%s", optable_special[i]->name); + break; + } + if (i==C4X_SPESOP_SIZE) + (*info->fprintf_func) (info->stream, "%08x", instruction); + } /* Return size of insn in words. */ return 1; |