diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-12-23 14:38:46 +0000 |
---|---|---|
committer | <> | 2015-05-26 15:48:41 +0000 |
commit | 5500a97a2ad1735db5b35bc51cfb825c1f4c38df (patch) | |
tree | cc6e777c26142b88456ff03a672e1cb69215fc32 /opcodes/tic54x-dis.c | |
download | binutils-tarball-master.tar.gz |
Imported from /home/lorry/working-area/delta_binutils-tarball/binutils-2.25.tar.bz2.HEADbinutils-2.25master
Diffstat (limited to 'opcodes/tic54x-dis.c')
-rw-r--r-- | opcodes/tic54x-dis.c | 595 |
1 files changed, 595 insertions, 0 deletions
diff --git a/opcodes/tic54x-dis.c b/opcodes/tic54x-dis.c new file mode 100644 index 0000000..7698384 --- /dev/null +++ b/opcodes/tic54x-dis.c @@ -0,0 +1,595 @@ +/* Disassembly routines for TMS320C54X architecture + Copyright (C) 1999-2014 Free Software Foundation, Inc. + Contributed by Timothy Wall (twall@cygnus.com) + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it 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. + + It is distributed in the hope that it 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 COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include <errno.h> +#include <math.h> +#include <stdlib.h> +#include "dis-asm.h" +#include "opcode/tic54x.h" +#include "coff/tic54x.h" + +static int has_lkaddr (unsigned short, const insn_template *); +static int get_insn_size (unsigned short, const insn_template *); +static int print_instruction (disassemble_info *, bfd_vma, + unsigned short, const char *, + const enum optype [], int, int); +static int print_parallel_instruction (disassemble_info *, bfd_vma, + unsigned short, + const insn_template *, int); +static int sprint_dual_address (disassemble_info *,char [], + unsigned short); +static int sprint_indirect_address (disassemble_info *,char [], + unsigned short); +static int sprint_direct_address (disassemble_info *,char [], + unsigned short); +static int sprint_mmr (disassemble_info *,char [],int); +static int sprint_condition (disassemble_info *,char *,unsigned short); +static int sprint_cc2 (disassemble_info *,char *,unsigned short); + +int +print_insn_tic54x (bfd_vma memaddr, disassemble_info *info) +{ + bfd_byte opbuf[2]; + unsigned short opcode; + int status, size; + const insn_template* tm; + + status = (*info->read_memory_func) (memaddr, opbuf, 2, info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + opcode = bfd_getl16 (opbuf); + tm = tic54x_get_insn (info, memaddr, opcode, &size); + + info->bytes_per_line = 2; + info->bytes_per_chunk = 2; + info->octets_per_byte = 2; + info->display_endian = BFD_ENDIAN_LITTLE; + + if (tm->flags & FL_PAR) + { + if (!print_parallel_instruction (info, memaddr, opcode, tm, size)) + return -1; + } + else + { + if (!print_instruction (info, memaddr, opcode, + (char *) tm->name, + tm->operand_types, + size, (tm->flags & FL_EXT))) + return -1; + } + + return size * 2; +} + +static int +has_lkaddr (unsigned short memdata, const insn_template *tm) +{ + return (IS_LKADDR (memdata) + && (OPTYPE (tm->operand_types[0]) == OP_Smem + || OPTYPE (tm->operand_types[1]) == OP_Smem + || OPTYPE (tm->operand_types[2]) == OP_Smem + || OPTYPE (tm->operand_types[1]) == OP_Sind + || OPTYPE (tm->operand_types[0]) == OP_Lmem + || OPTYPE (tm->operand_types[1]) == OP_Lmem)); +} + +/* always returns 1 (whether an insn template was found) since we provide an + "unknown instruction" template */ +const insn_template* +tic54x_get_insn (disassemble_info *info, bfd_vma addr, + unsigned short memdata, int *size) +{ + const insn_template *tm = NULL; + + for (tm = tic54x_optab; tm->name; tm++) + { + if (tm->opcode == (memdata & tm->mask)) + { + /* a few opcodes span two words */ + if (tm->flags & FL_EXT) + { + /* if lk addressing is used, the second half of the opcode gets + pushed one word later */ + bfd_byte opbuf[2]; + bfd_vma addr2 = addr + 1 + has_lkaddr (memdata, tm); + int status = (*info->read_memory_func) (addr2, opbuf, 2, info); + // FIXME handle errors + if (status == 0) + { + unsigned short data2 = bfd_getl16 (opbuf); + if (tm->opcode2 == (data2 & tm->mask2)) + { + if (size) *size = get_insn_size (memdata, tm); + return tm; + } + } + } + else + { + if (size) *size = get_insn_size (memdata, tm); + return tm; + } + } + } + for (tm = (insn_template *) tic54x_paroptab; tm->name; tm++) + { + if (tm->opcode == (memdata & tm->mask)) + { + if (size) *size = get_insn_size (memdata, tm); + return tm; + } + } + + if (size) *size = 1; + return &tic54x_unknown_opcode; +} + +static int +get_insn_size (unsigned short memdata, const insn_template *insn) +{ + int size; + + if (insn->flags & FL_PAR) + { + /* only non-parallel instructions support lk addressing */ + size = insn->words; + } + else + { + size = insn->words + has_lkaddr (memdata, insn); + } + + return size; +} + +int +print_instruction (disassemble_info *info, + bfd_vma memaddr, + unsigned short opcode, + const char *tm_name, + const enum optype tm_operands[], + int size, + int ext) +{ + static int n; + /* string storage for multiple operands */ + char operand[4][64] = { {0},{0},{0},{0}, }; + bfd_byte buf[2]; + unsigned long opcode2 = 0; + unsigned long lkaddr = 0; + enum optype src = OP_None; + enum optype dst = OP_None; + int i, shift; + char *comma = ""; + + info->fprintf_func (info->stream, "%-7s", tm_name); + + if (size > 1) + { + int status = (*info->read_memory_func) (memaddr + 1, buf, 2, info); + if (status != 0) + return 0; + lkaddr = opcode2 = bfd_getl16 (buf); + if (size > 2) + { + status = (*info->read_memory_func) (memaddr + 2, buf, 2, info); + if (status != 0) + return 0; + opcode2 = bfd_getl16 (buf); + } + } + + for (i = 0; i < MAX_OPERANDS && OPTYPE (tm_operands[i]) != OP_None; i++) + { + char *next_comma = ","; + int optional = (tm_operands[i] & OPT) != 0; + + switch (OPTYPE (tm_operands[i])) + { + case OP_Xmem: + sprint_dual_address (info, operand[i], XMEM (opcode)); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_Ymem: + sprint_dual_address (info, operand[i], YMEM (opcode)); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_Smem: + case OP_Sind: + case OP_Lmem: + info->fprintf_func (info->stream, "%s", comma); + if (INDIRECT (opcode)) + { + if (MOD (opcode) >= 12) + { + bfd_vma addr = lkaddr; + int arf = ARF (opcode); + int mod = MOD (opcode); + if (mod == 15) + info->fprintf_func (info->stream, "*("); + else + info->fprintf_func (info->stream, "*%sar%d(", + (mod == 13 || mod == 14 ? "+" : ""), + arf); + (*(info->print_address_func)) ((bfd_vma) addr, info); + info->fprintf_func (info->stream, ")%s", + mod == 14 ? "%" : ""); + } + else + { + sprint_indirect_address (info, operand[i], opcode); + info->fprintf_func (info->stream, "%s", operand[i]); + } + } + else + { + /* FIXME -- use labels (print_address_func) */ + /* in order to do this, we need to guess what DP is */ + sprint_direct_address (info, operand[i], opcode); + info->fprintf_func (info->stream, "%s", operand[i]); + } + break; + case OP_dmad: + info->fprintf_func (info->stream, "%s", comma); + (*(info->print_address_func)) ((bfd_vma) opcode2, info); + break; + case OP_xpmad: + /* upper 7 bits of address are in the opcode */ + opcode2 += ((unsigned long) opcode & 0x7F) << 16; + /* fall through */ + case OP_pmad: + info->fprintf_func (info->stream, "%s", comma); + (*(info->print_address_func)) ((bfd_vma) opcode2, info); + break; + case OP_MMRX: + sprint_mmr (info, operand[i], MMRX (opcode)); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_MMRY: + sprint_mmr (info, operand[i], MMRY (opcode)); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_MMR: + sprint_mmr (info, operand[i], MMR (opcode)); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_PA: + sprintf (operand[i], "pa%d", (unsigned) opcode2); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_SRC: + src = SRC (ext ? opcode2 : opcode) ? OP_B : OP_A; + sprintf (operand[i], (src == OP_B) ? "b" : "a"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_SRC1: + src = SRC1 (ext ? opcode2 : opcode) ? OP_B : OP_A; + sprintf (operand[i], (src == OP_B) ? "b" : "a"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_RND: + dst = DST (opcode) ? OP_B : OP_A; + sprintf (operand[i], (dst == OP_B) ? "a" : "b"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_DST: + dst = DST (ext ? opcode2 : opcode) ? OP_B : OP_A; + if (!optional || dst != src) + { + sprintf (operand[i], (dst == OP_B) ? "b" : "a"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + } + else + next_comma = comma; + break; + case OP_B: + sprintf (operand[i], "b"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_A: + sprintf (operand[i], "a"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_ARX: + sprintf (operand[i], "ar%d", (int) ARX (opcode)); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_SHIFT: + shift = SHIFT (ext ? opcode2 : opcode); + if (!optional || shift != 0) + { + sprintf (operand[i], "%d", shift); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + } + else + next_comma = comma; + break; + case OP_SHFT: + shift = SHFT (opcode); + if (!optional || shift != 0) + { + sprintf (operand[i], "%d", (unsigned) shift); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + } + else + next_comma = comma; + break; + case OP_lk: + sprintf (operand[i], "#%d", (int) (short) opcode2); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_T: + sprintf (operand[i], "t"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_TS: + sprintf (operand[i], "ts"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_k8: + sprintf (operand[i], "%d", (int) ((signed char) (opcode & 0xFF))); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_16: + sprintf (operand[i], "16"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_ASM: + sprintf (operand[i], "asm"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_BITC: + sprintf (operand[i], "%d", (int) (opcode & 0xF)); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_CC: + /* put all CC operands in the same operand */ + sprint_condition (info, operand[i], opcode); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + i = MAX_OPERANDS; + break; + case OP_CC2: + sprint_cc2 (info, operand[i], opcode); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_CC3: + { + const char *code[] = { "eq", "lt", "gt", "neq" }; + + /* Do not use sprintf with only two parameters as a + compiler warning could be generated in such conditions. */ + sprintf (operand[i], "%s", code[CC3 (opcode)]); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + } + case OP_123: + { + int code = (opcode >> 8) & 0x3; + sprintf (operand[i], "%d", (code == 0) ? 1 : (code == 2) ? 2 : 3); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + } + case OP_k5: + sprintf (operand[i], "#%d", + (int) (((signed char) opcode & 0x1F) << 3) >> 3); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_k8u: + sprintf (operand[i], "#%d", (unsigned) (opcode & 0xFF)); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_k3: + sprintf (operand[i], "#%d", (int) (opcode & 0x7)); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_lku: + sprintf (operand[i], "#%d", (unsigned) opcode2); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_N: + n = (opcode >> 9) & 0x1; + sprintf (operand[i], "st%d", n); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_SBIT: + { + const char *status0[] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", + "ovb", "ova", "c", "tc", "13", "14", "15" + }; + const char *status1[] = { + "0", "1", "2", "3", "4", + "cmpt", "frct", "c16", "sxm", "ovm", "10", + "intm", "hm", "xf", "cpl", "braf" + }; + sprintf (operand[i], "%s", + n ? status1[SBIT (opcode)] : status0[SBIT (opcode)]); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + } + case OP_12: + sprintf (operand[i], "%d", (int) ((opcode >> 9) & 1) + 1); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_TRN: + sprintf (operand[i], "trn"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_DP: + sprintf (operand[i], "dp"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_k9: + /* FIXME-- this is DP, print the original address? */ + sprintf (operand[i], "#%d", (int) (opcode & 0x1FF)); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_ARP: + sprintf (operand[i], "arp"); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + case OP_031: + sprintf (operand[i], "%d", (int) (opcode & 0x1F)); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + default: + sprintf (operand[i], "??? (0x%x)", tm_operands[i]); + info->fprintf_func (info->stream, "%s%s", comma, operand[i]); + break; + } + comma = next_comma; + } + return 1; +} + +static int +print_parallel_instruction (disassemble_info *info, + bfd_vma memaddr, + unsigned short opcode, + const insn_template *ptm, + int size) +{ + print_instruction (info, memaddr, opcode, + ptm->name, ptm->operand_types, size, 0); + info->fprintf_func (info->stream, " || "); + return print_instruction (info, memaddr, opcode, + ptm->parname, ptm->paroperand_types, size, 0); +} + +static int +sprint_dual_address (disassemble_info *info ATTRIBUTE_UNUSED, + char buf[], + unsigned short code) +{ + const char *formats[] = { + "*ar%d", + "*ar%d-", + "*ar%d+", + "*ar%d+0%%", + }; + return sprintf (buf, formats[XMOD (code)], XARX (code)); +} + +static int +sprint_indirect_address (disassemble_info *info ATTRIBUTE_UNUSED, + char buf[], + unsigned short opcode) +{ + const char *formats[] = { + "*ar%d", + "*ar%d-", + "*ar%d+", + "*+ar%d", + "*ar%d-0B", + "*ar%d-0", + "*ar%d+0", + "*ar%d+0B", + "*ar%d-%%", + "*ar%d-0%%", + "*ar%d+%%", + "*ar%d+0%%", + }; + return sprintf (buf, formats[MOD (opcode)], ARF (opcode)); +} + +static int +sprint_direct_address (disassemble_info *info ATTRIBUTE_UNUSED, + char buf[], + unsigned short opcode) +{ + /* FIXME -- look up relocation if available */ + return sprintf (buf, "DP+0x%02x", (int) (opcode & 0x7F)); +} + +static int +sprint_mmr (disassemble_info *info ATTRIBUTE_UNUSED, + char buf[], + int mmr) +{ + symbol *reg = (symbol *) mmregs; + while (reg->name != NULL) + { + if (mmr == reg->value) + { + sprintf (buf, "%s", (reg + 1)->name); + return 1; + } + ++reg; + } + sprintf (buf, "MMR(%d)", mmr); /* FIXME -- different targets. */ + return 0; +} + +static int +sprint_cc2 (disassemble_info *info ATTRIBUTE_UNUSED, + char *buf, + unsigned short opcode) +{ + const char *cc2[] = { + "??", "??", "ageq", "alt", "aneq", "aeq", "agt", "aleq", + "??", "??", "bgeq", "blt", "bneq", "beq", "bgt", "bleq", + }; + return sprintf (buf, "%s", cc2[opcode & 0xF]); +} + +static int +sprint_condition (disassemble_info *info ATTRIBUTE_UNUSED, + char *buf, + unsigned short opcode) +{ + char *start = buf; + const char *cmp[] = { + "??", "??", "geq", "lt", "neq", "eq", "gt", "leq" + }; + if (opcode & 0x40) + { + char acc = (opcode & 0x8) ? 'b' : 'a'; + if (opcode & 0x7) + buf += sprintf (buf, "%c%s%s", acc, cmp[(opcode & 0x7)], + (opcode & 0x20) ? ", " : ""); + if (opcode & 0x20) + buf += sprintf (buf, "%c%s", acc, (opcode & 0x10) ? "ov" : "nov"); + } + else if (opcode & 0x3F) + { + if (opcode & 0x30) + buf += sprintf (buf, "%s%s", + ((opcode & 0x30) == 0x30) ? "tc" : "ntc", + (opcode & 0x0F) ? ", " : ""); + if (opcode & 0x0C) + buf += sprintf (buf, "%s%s", + ((opcode & 0x0C) == 0x0C) ? "c" : "nc", + (opcode & 0x03) ? ", " : ""); + if (opcode & 0x03) + buf += sprintf (buf, "%s", + ((opcode & 0x03) == 0x03) ? "bio" : "nbio"); + } + else + buf += sprintf (buf, "unc"); + + return buf - start; +} |