2004-07-07 19:28:53 +02:00
|
|
|
/* Disassembler code for CRX.
|
2020-01-01 08:57:01 +01:00
|
|
|
Copyright (C) 2004-2020 Free Software Foundation, Inc.
|
2004-07-07 19:28:53 +02:00
|
|
|
Contributed by Tomer Levi, NSC, Israel.
|
|
|
|
Written by Tomer Levi.
|
|
|
|
|
2007-07-05 11:49:03 +02:00
|
|
|
This file is part of the GNU opcodes library.
|
2004-07-07 19:28:53 +02:00
|
|
|
|
2007-07-05 11:49:03 +02:00
|
|
|
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)
|
2004-07-07 19:28:53 +02:00
|
|
|
any later version.
|
|
|
|
|
2007-07-05 11:49:03 +02:00
|
|
|
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.
|
2004-07-07 19:28:53 +02:00
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
2007-07-05 11:49:03 +02:00
|
|
|
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
|
|
MA 02110-1301, USA. */
|
2004-07-07 19:28:53 +02:00
|
|
|
|
|
|
|
#include "sysdep.h"
|
Move print_insn_XXX to an opcodes internal header
With the changes done in previous patches, print_insn_XXX functions
don't have to be external visible out of opcodes, because both gdb
and objdump select disassemblers through a single interface.
This patch moves these print_insn_XXX declarations from
include/dis-asm.h to opcodes/disassemble.h, which is a new header
added by this patch.
include:
2017-05-24 Yao Qi <yao.qi@linaro.org>
* dis-asm.h: Move some function declarations to
opcodes/disassemble.h.
opcodes:
2017-05-24 Yao Qi <yao.qi@linaro.org>
* alpha-dis.c: Include disassemble.h, don't include
dis-asm.h.
* avr-dis.c, bfin-dis.c, cr16-dis.c: Likewise.
* crx-dis.c, d10v-dis.c, d30v-dis.c: Likewise.
* disassemble.c, dlx-dis.c, epiphany-dis.c: Likewise.
* fr30-dis.c, ft32-dis.c, h8300-dis.c, h8500-dis.c: Likewise.
* hppa-dis.c, i370-dis.c, i386-dis.c: Likewise.
* i860-dis.c, i960-dis.c, ip2k-dis.c: Likewise.
* iq2000-dis.c, lm32-dis.c, m10200-dis.c: Likewise.
* m10300-dis.c, m32r-dis.c, m68hc11-dis.c: Likewise.
* m68k-dis.c, m88k-dis.c, mcore-dis.c: Likewise.
* metag-dis.c, microblaze-dis.c, mmix-dis.c: Likewise.
* moxie-dis.c, msp430-dis.c, mt-dis.c:
* nds32-dis.c, nios2-dis.c, ns32k-dis.c: Likewise.
* or1k-dis.c, pdp11-dis.c, pj-dis.c: Likewise.
* ppc-dis.c, pru-dis.c, riscv-dis.c: Likewise.
* rl78-dis.c, s390-dis.c, score-dis.c: Likewise.
* sh-dis.c, sh64-dis.c, tic30-dis.c: Likewise.
* tic4x-dis.c, tic54x-dis.c, tic6x-dis.c: Likewise.
* tic80-dis.c, tilegx-dis.c, tilepro-dis.c: Likewise.
* v850-dis.c, vax-dis.c, visium-dis.c: Likewise.
* w65-dis.c, wasm32-dis.c, xc16x-dis.c: Likewise.
* xgate-dis.c, xstormy16-dis.c, xtensa-dis.c: Likewise.
* z80-dis.c, z8k-dis.c: Likewise.
* disassemble.h: New file.
2017-05-24 18:23:52 +02:00
|
|
|
#include "disassemble.h"
|
2004-07-07 19:28:53 +02:00
|
|
|
#include "opcode/crx.h"
|
|
|
|
|
|
|
|
/* String to print when opcode was not matched. */
|
|
|
|
#define ILLEGAL "illegal"
|
|
|
|
/* Escape to 16-bit immediate. */
|
|
|
|
#define ESCAPE_16_BIT 0xE
|
|
|
|
|
|
|
|
/* Extract 'n_bits' from 'a' starting from offset 'offs'. */
|
|
|
|
#define EXTRACT(a, offs, n_bits) \
|
ubsan: crx: left shift cannot be represented in type 'int'
The ubsan complaint is fixed by the SBM change, with similar possible
complaints fixed by the EXTRACT change. The rest is just cleanup.
include/
* opcode/crx.h (inst <match>): Make unsigned int.
opcodes/
* crx-dis.c (EXTRACT, SBM): Avoid signed overflow.
(get_number_of_operands, getargtype, getbits, getregname),
(getcopregname, getprocregname, gettrapstring, getcinvstring),
(getregliststring, get_word_at_PC, get_words_at_PC, build_mask),
(powerof2, match_opcode, make_instruction, print_arguments),
(print_arg): Delete forward declarations, moving static to..
(getregname, getcopregname, getregliststring): ..these definitions.
(build_mask): Return unsigned int mask.
(match_opcode): Use unsigned int vars.
2019-12-16 00:28:09 +01:00
|
|
|
(((a) >> (offs)) & ((2ull << (n_bits - 1)) - 1))
|
2004-07-07 19:28:53 +02:00
|
|
|
|
|
|
|
/* Set Bit Mask - a mask to set all bits starting from offset 'offs'. */
|
ubsan: crx: left shift cannot be represented in type 'int'
The ubsan complaint is fixed by the SBM change, with similar possible
complaints fixed by the EXTRACT change. The rest is just cleanup.
include/
* opcode/crx.h (inst <match>): Make unsigned int.
opcodes/
* crx-dis.c (EXTRACT, SBM): Avoid signed overflow.
(get_number_of_operands, getargtype, getbits, getregname),
(getcopregname, getprocregname, gettrapstring, getcinvstring),
(getregliststring, get_word_at_PC, get_words_at_PC, build_mask),
(powerof2, match_opcode, make_instruction, print_arguments),
(print_arg): Delete forward declarations, moving static to..
(getregname, getcopregname, getregliststring): ..these definitions.
(build_mask): Return unsigned int mask.
(match_opcode): Use unsigned int vars.
2019-12-16 00:28:09 +01:00
|
|
|
#define SBM(offs) ((-1u << (offs)) & 0xffffffff)
|
2004-07-07 19:28:53 +02:00
|
|
|
|
|
|
|
typedef unsigned long dwordU;
|
|
|
|
typedef unsigned short wordU;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
dwordU val;
|
|
|
|
int nbits;
|
|
|
|
} parameter;
|
|
|
|
|
|
|
|
/* Structure to hold valid 'cinv' instruction options. */
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
/* Cinv printed string. */
|
|
|
|
char *str;
|
|
|
|
/* Value corresponding to the string. */
|
|
|
|
unsigned int value;
|
|
|
|
}
|
|
|
|
cinv_entry;
|
|
|
|
|
|
|
|
/* CRX 'cinv' options. */
|
PR22348, conflicting global vars in crx and cr16
include/
PR 22348
* opcode/cr16.h (instruction): Delete.
(cr16_words, cr16_allWords, cr16_currInsn): Delete.
* opcode/crx.h (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
(instruction): Delete.
opcodes/
PR 22348
* cr16-dis.c (cr16_cinvs, instruction, cr16_currInsn): Make static.
(cr16_words, cr16_allWords, processing_argument_number): Likewise.
(imm4flag, size_changed): Likewise.
* crx-dis.c (crx_cinvs, NUMCINVS, instruction, currInsn): Likewise.
(words, allWords, processing_argument_number): Likewise.
(cst4flag, size_changed): Likewise.
* crx-opc.c (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
gas/
PR 22348
* config/tc-crx.c (instruction, output_opcode): Make static.
(relocatable, ins_parse, cur_arg_num): Likewise.
(parse_insn): Adjust for renamed opcodes globals.
(check_range): Likewise
2017-10-25 13:29:14 +02:00
|
|
|
static const cinv_entry crx_cinvs[] =
|
2004-07-07 19:28:53 +02:00
|
|
|
{
|
2015-08-12 13:45:07 +02:00
|
|
|
{"[i]", 2}, {"[i,u]", 3}, {"[d]", 4}, {"[d,u]", 5},
|
|
|
|
{"[d,i]", 6}, {"[d,i,u]", 7}, {"[b]", 8},
|
|
|
|
{"[b,i]", 10}, {"[b,i,u]", 11}, {"[b,d]", 12},
|
2004-10-07 16:18:17 +02:00
|
|
|
{"[b,d,u]", 13}, {"[b,d,i]", 14}, {"[b,d,i,u]", 15}
|
2004-07-07 19:28:53 +02:00
|
|
|
};
|
|
|
|
|
2004-10-27 12:24:01 +02:00
|
|
|
/* Enum to distinguish different registers argument types. */
|
|
|
|
typedef enum REG_ARG_TYPE
|
2004-10-07 16:18:17 +02:00
|
|
|
{
|
2004-10-27 12:24:01 +02:00
|
|
|
/* General purpose register (r<N>). */
|
|
|
|
REG_ARG = 0,
|
|
|
|
/* User register (u<N>). */
|
|
|
|
USER_REG_ARG,
|
|
|
|
/* CO-Processor register (c<N>). */
|
2004-10-07 16:18:17 +02:00
|
|
|
COP_ARG,
|
2004-10-27 12:24:01 +02:00
|
|
|
/* CO-Processor special register (cs<N>). */
|
2015-08-12 13:45:07 +02:00
|
|
|
COPS_ARG
|
2004-10-07 16:18:17 +02:00
|
|
|
}
|
2004-10-27 12:24:01 +02:00
|
|
|
REG_ARG_TYPE;
|
2004-10-07 16:18:17 +02:00
|
|
|
|
2004-07-07 19:28:53 +02:00
|
|
|
/* Number of valid 'cinv' instruction options. */
|
PR22348, conflicting global vars in crx and cr16
include/
PR 22348
* opcode/cr16.h (instruction): Delete.
(cr16_words, cr16_allWords, cr16_currInsn): Delete.
* opcode/crx.h (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
(instruction): Delete.
opcodes/
PR 22348
* cr16-dis.c (cr16_cinvs, instruction, cr16_currInsn): Make static.
(cr16_words, cr16_allWords, processing_argument_number): Likewise.
(imm4flag, size_changed): Likewise.
* crx-dis.c (crx_cinvs, NUMCINVS, instruction, currInsn): Likewise.
(words, allWords, processing_argument_number): Likewise.
(cst4flag, size_changed): Likewise.
* crx-opc.c (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
gas/
PR 22348
* config/tc-crx.c (instruction, output_opcode): Make static.
(relocatable, ins_parse, cur_arg_num): Likewise.
(parse_insn): Adjust for renamed opcodes globals.
(check_range): Likewise
2017-10-25 13:29:14 +02:00
|
|
|
static int NUMCINVS = ((sizeof crx_cinvs)/(sizeof crx_cinvs[0]));
|
2004-07-07 19:28:53 +02:00
|
|
|
/* Current opcode table entry we're disassembling. */
|
PR22348, conflicting global vars in crx and cr16
include/
PR 22348
* opcode/cr16.h (instruction): Delete.
(cr16_words, cr16_allWords, cr16_currInsn): Delete.
* opcode/crx.h (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
(instruction): Delete.
opcodes/
PR 22348
* cr16-dis.c (cr16_cinvs, instruction, cr16_currInsn): Make static.
(cr16_words, cr16_allWords, processing_argument_number): Likewise.
(imm4flag, size_changed): Likewise.
* crx-dis.c (crx_cinvs, NUMCINVS, instruction, currInsn): Likewise.
(words, allWords, processing_argument_number): Likewise.
(cst4flag, size_changed): Likewise.
* crx-opc.c (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
gas/
PR 22348
* config/tc-crx.c (instruction, output_opcode): Make static.
(relocatable, ins_parse, cur_arg_num): Likewise.
(parse_insn): Adjust for renamed opcodes globals.
(check_range): Likewise
2017-10-25 13:29:14 +02:00
|
|
|
static const inst *instruction;
|
2004-07-07 19:28:53 +02:00
|
|
|
/* Current instruction we're disassembling. */
|
PR22348, conflicting global vars in crx and cr16
include/
PR 22348
* opcode/cr16.h (instruction): Delete.
(cr16_words, cr16_allWords, cr16_currInsn): Delete.
* opcode/crx.h (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
(instruction): Delete.
opcodes/
PR 22348
* cr16-dis.c (cr16_cinvs, instruction, cr16_currInsn): Make static.
(cr16_words, cr16_allWords, processing_argument_number): Likewise.
(imm4flag, size_changed): Likewise.
* crx-dis.c (crx_cinvs, NUMCINVS, instruction, currInsn): Likewise.
(words, allWords, processing_argument_number): Likewise.
(cst4flag, size_changed): Likewise.
* crx-opc.c (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
gas/
PR 22348
* config/tc-crx.c (instruction, output_opcode): Make static.
(relocatable, ins_parse, cur_arg_num): Likewise.
(parse_insn): Adjust for renamed opcodes globals.
(check_range): Likewise
2017-10-25 13:29:14 +02:00
|
|
|
static ins currInsn;
|
2004-07-07 19:28:53 +02:00
|
|
|
/* The current instruction is read into 3 consecutive words. */
|
PR22348, conflicting global vars in crx and cr16
include/
PR 22348
* opcode/cr16.h (instruction): Delete.
(cr16_words, cr16_allWords, cr16_currInsn): Delete.
* opcode/crx.h (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
(instruction): Delete.
opcodes/
PR 22348
* cr16-dis.c (cr16_cinvs, instruction, cr16_currInsn): Make static.
(cr16_words, cr16_allWords, processing_argument_number): Likewise.
(imm4flag, size_changed): Likewise.
* crx-dis.c (crx_cinvs, NUMCINVS, instruction, currInsn): Likewise.
(words, allWords, processing_argument_number): Likewise.
(cst4flag, size_changed): Likewise.
* crx-opc.c (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
gas/
PR 22348
* config/tc-crx.c (instruction, output_opcode): Make static.
(relocatable, ins_parse, cur_arg_num): Likewise.
(parse_insn): Adjust for renamed opcodes globals.
(check_range): Likewise
2017-10-25 13:29:14 +02:00
|
|
|
static wordU words[3];
|
2004-07-07 19:28:53 +02:00
|
|
|
/* Contains all words in appropriate order. */
|
PR22348, conflicting global vars in crx and cr16
include/
PR 22348
* opcode/cr16.h (instruction): Delete.
(cr16_words, cr16_allWords, cr16_currInsn): Delete.
* opcode/crx.h (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
(instruction): Delete.
opcodes/
PR 22348
* cr16-dis.c (cr16_cinvs, instruction, cr16_currInsn): Make static.
(cr16_words, cr16_allWords, processing_argument_number): Likewise.
(imm4flag, size_changed): Likewise.
* crx-dis.c (crx_cinvs, NUMCINVS, instruction, currInsn): Likewise.
(words, allWords, processing_argument_number): Likewise.
(cst4flag, size_changed): Likewise.
* crx-opc.c (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
gas/
PR 22348
* config/tc-crx.c (instruction, output_opcode): Make static.
(relocatable, ins_parse, cur_arg_num): Likewise.
(parse_insn): Adjust for renamed opcodes globals.
(check_range): Likewise
2017-10-25 13:29:14 +02:00
|
|
|
static ULONGLONG allWords;
|
2004-07-07 19:28:53 +02:00
|
|
|
/* Holds the current processed argument number. */
|
PR22348, conflicting global vars in crx and cr16
include/
PR 22348
* opcode/cr16.h (instruction): Delete.
(cr16_words, cr16_allWords, cr16_currInsn): Delete.
* opcode/crx.h (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
(instruction): Delete.
opcodes/
PR 22348
* cr16-dis.c (cr16_cinvs, instruction, cr16_currInsn): Make static.
(cr16_words, cr16_allWords, processing_argument_number): Likewise.
(imm4flag, size_changed): Likewise.
* crx-dis.c (crx_cinvs, NUMCINVS, instruction, currInsn): Likewise.
(words, allWords, processing_argument_number): Likewise.
(cst4flag, size_changed): Likewise.
* crx-opc.c (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
gas/
PR 22348
* config/tc-crx.c (instruction, output_opcode): Make static.
(relocatable, ins_parse, cur_arg_num): Likewise.
(parse_insn): Adjust for renamed opcodes globals.
(check_range): Likewise
2017-10-25 13:29:14 +02:00
|
|
|
static int processing_argument_number;
|
2004-07-07 19:28:53 +02:00
|
|
|
/* Nonzero means a CST4 instruction. */
|
PR22348, conflicting global vars in crx and cr16
include/
PR 22348
* opcode/cr16.h (instruction): Delete.
(cr16_words, cr16_allWords, cr16_currInsn): Delete.
* opcode/crx.h (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
(instruction): Delete.
opcodes/
PR 22348
* cr16-dis.c (cr16_cinvs, instruction, cr16_currInsn): Make static.
(cr16_words, cr16_allWords, processing_argument_number): Likewise.
(imm4flag, size_changed): Likewise.
* crx-dis.c (crx_cinvs, NUMCINVS, instruction, currInsn): Likewise.
(words, allWords, processing_argument_number): Likewise.
(cst4flag, size_changed): Likewise.
* crx-opc.c (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
gas/
PR 22348
* config/tc-crx.c (instruction, output_opcode): Make static.
(relocatable, ins_parse, cur_arg_num): Likewise.
(parse_insn): Adjust for renamed opcodes globals.
(check_range): Likewise
2017-10-25 13:29:14 +02:00
|
|
|
static int cst4flag;
|
2004-07-07 19:28:53 +02:00
|
|
|
/* Nonzero means the instruction's original size is
|
|
|
|
incremented (escape sequence is used). */
|
PR22348, conflicting global vars in crx and cr16
include/
PR 22348
* opcode/cr16.h (instruction): Delete.
(cr16_words, cr16_allWords, cr16_currInsn): Delete.
* opcode/crx.h (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
(instruction): Delete.
opcodes/
PR 22348
* cr16-dis.c (cr16_cinvs, instruction, cr16_currInsn): Make static.
(cr16_words, cr16_allWords, processing_argument_number): Likewise.
(imm4flag, size_changed): Likewise.
* crx-dis.c (crx_cinvs, NUMCINVS, instruction, currInsn): Likewise.
(words, allWords, processing_argument_number): Likewise.
(cst4flag, size_changed): Likewise.
* crx-opc.c (crx_cst4_map): Rename from cst4_map.
(crx_cst4_maps): Rename from cst4_maps.
(crx_no_op_insn): Rename from no_op_insn.
gas/
PR 22348
* config/tc-crx.c (instruction, output_opcode): Make static.
(relocatable, ins_parse, cur_arg_num): Likewise.
(parse_insn): Adjust for renamed opcodes globals.
(check_range): Likewise
2017-10-25 13:29:14 +02:00
|
|
|
static int size_changed;
|
2004-07-07 19:28:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* Retrieve the number of operands for the current assembled instruction. */
|
|
|
|
|
|
|
|
static int
|
|
|
|
get_number_of_operands (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2019-12-26 06:34:20 +01:00
|
|
|
for (i = 0; i < MAX_OPERANDS && instruction->operands[i].op_type; i++)
|
2004-07-07 19:28:53 +02:00
|
|
|
;
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the bit size for a given operand. */
|
|
|
|
|
|
|
|
static int
|
|
|
|
getbits (operand_type op)
|
|
|
|
{
|
|
|
|
if (op < MAX_OPRD)
|
|
|
|
return crx_optab[op].bit_size;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the argument type of a given operand. */
|
|
|
|
|
|
|
|
static argtype
|
|
|
|
getargtype (operand_type op)
|
|
|
|
{
|
|
|
|
if (op < MAX_OPRD)
|
|
|
|
return crx_optab[op].arg_type;
|
|
|
|
else
|
|
|
|
return nullargs;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given the trap index in dispatch table, return its name.
|
|
|
|
This routine is used when disassembling the 'excp' instruction. */
|
|
|
|
|
|
|
|
static char *
|
2009-12-11 14:42:17 +01:00
|
|
|
gettrapstring (unsigned int trap_index)
|
2004-07-07 19:28:53 +02:00
|
|
|
{
|
|
|
|
const trap_entry *trap;
|
|
|
|
|
|
|
|
for (trap = crx_traps; trap < crx_traps + NUMTRAPS; trap++)
|
2009-12-11 14:42:17 +01:00
|
|
|
if (trap->entry == trap_index)
|
2004-07-07 19:28:53 +02:00
|
|
|
return trap->name;
|
|
|
|
|
|
|
|
return ILLEGAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given a 'cinv' instruction constant operand, return its corresponding string.
|
|
|
|
This routine is used when disassembling the 'cinv' instruction. */
|
|
|
|
|
|
|
|
static char *
|
|
|
|
getcinvstring (unsigned int num)
|
|
|
|
{
|
|
|
|
const cinv_entry *cinv;
|
|
|
|
|
|
|
|
for (cinv = crx_cinvs; cinv < (crx_cinvs + NUMCINVS); cinv++)
|
|
|
|
if (cinv->value == num)
|
|
|
|
return cinv->str;
|
|
|
|
|
|
|
|
return ILLEGAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given a register enum value, retrieve its name. */
|
|
|
|
|
ubsan: crx: left shift cannot be represented in type 'int'
The ubsan complaint is fixed by the SBM change, with similar possible
complaints fixed by the EXTRACT change. The rest is just cleanup.
include/
* opcode/crx.h (inst <match>): Make unsigned int.
opcodes/
* crx-dis.c (EXTRACT, SBM): Avoid signed overflow.
(get_number_of_operands, getargtype, getbits, getregname),
(getcopregname, getprocregname, gettrapstring, getcinvstring),
(getregliststring, get_word_at_PC, get_words_at_PC, build_mask),
(powerof2, match_opcode, make_instruction, print_arguments),
(print_arg): Delete forward declarations, moving static to..
(getregname, getcopregname, getregliststring): ..these definitions.
(build_mask): Return unsigned int mask.
(match_opcode): Use unsigned int vars.
2019-12-16 00:28:09 +01:00
|
|
|
static char *
|
2004-07-07 19:28:53 +02:00
|
|
|
getregname (reg r)
|
|
|
|
{
|
2009-12-11 14:42:17 +01:00
|
|
|
const reg_entry * regentry = &crx_regtab[r];
|
2004-07-07 19:28:53 +02:00
|
|
|
|
2009-12-11 14:42:17 +01:00
|
|
|
if (regentry->type != CRX_R_REGTYPE)
|
2004-07-07 19:28:53 +02:00
|
|
|
return ILLEGAL;
|
|
|
|
else
|
2009-12-11 14:42:17 +01:00
|
|
|
return regentry->name;
|
2004-07-07 19:28:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Given a coprocessor register enum value, retrieve its name. */
|
|
|
|
|
ubsan: crx: left shift cannot be represented in type 'int'
The ubsan complaint is fixed by the SBM change, with similar possible
complaints fixed by the EXTRACT change. The rest is just cleanup.
include/
* opcode/crx.h (inst <match>): Make unsigned int.
opcodes/
* crx-dis.c (EXTRACT, SBM): Avoid signed overflow.
(get_number_of_operands, getargtype, getbits, getregname),
(getcopregname, getprocregname, gettrapstring, getcinvstring),
(getregliststring, get_word_at_PC, get_words_at_PC, build_mask),
(powerof2, match_opcode, make_instruction, print_arguments),
(print_arg): Delete forward declarations, moving static to..
(getregname, getcopregname, getregliststring): ..these definitions.
(build_mask): Return unsigned int mask.
(match_opcode): Use unsigned int vars.
2019-12-16 00:28:09 +01:00
|
|
|
static char *
|
2004-07-07 19:28:53 +02:00
|
|
|
getcopregname (copreg r, reg_type type)
|
|
|
|
{
|
2009-12-11 14:42:17 +01:00
|
|
|
const reg_entry * regentry;
|
2004-07-07 19:28:53 +02:00
|
|
|
|
|
|
|
if (type == CRX_C_REGTYPE)
|
2009-12-11 14:42:17 +01:00
|
|
|
regentry = &crx_copregtab[r];
|
2004-07-07 19:28:53 +02:00
|
|
|
else if (type == CRX_CS_REGTYPE)
|
2009-12-11 14:42:17 +01:00
|
|
|
regentry = &crx_copregtab[r+(cs0-c0)];
|
2004-07-07 19:28:53 +02:00
|
|
|
else
|
|
|
|
return ILLEGAL;
|
|
|
|
|
2009-12-11 14:42:17 +01:00
|
|
|
return regentry->name;
|
2004-07-07 19:28:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Getting a processor register name. */
|
|
|
|
|
|
|
|
static char *
|
2009-12-11 14:42:17 +01:00
|
|
|
getprocregname (int reg_index)
|
2004-07-07 19:28:53 +02:00
|
|
|
{
|
|
|
|
const reg_entry *r;
|
|
|
|
|
|
|
|
for (r = crx_regtab; r < crx_regtab + NUMREGS; r++)
|
2009-12-11 14:42:17 +01:00
|
|
|
if (r->image == reg_index)
|
2004-07-07 19:28:53 +02:00
|
|
|
return r->name;
|
|
|
|
|
|
|
|
return "ILLEGAL REGISTER";
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the power of two for a given integer. */
|
|
|
|
|
|
|
|
static int
|
|
|
|
powerof2 (int x)
|
|
|
|
{
|
|
|
|
int product, i;
|
|
|
|
|
|
|
|
for (i = 0, product = 1; i < x; i++)
|
|
|
|
product *= 2;
|
|
|
|
|
|
|
|
return product;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Transform a register bit mask to a register list. */
|
|
|
|
|
ubsan: crx: left shift cannot be represented in type 'int'
The ubsan complaint is fixed by the SBM change, with similar possible
complaints fixed by the EXTRACT change. The rest is just cleanup.
include/
* opcode/crx.h (inst <match>): Make unsigned int.
opcodes/
* crx-dis.c (EXTRACT, SBM): Avoid signed overflow.
(get_number_of_operands, getargtype, getbits, getregname),
(getcopregname, getprocregname, gettrapstring, getcinvstring),
(getregliststring, get_word_at_PC, get_words_at_PC, build_mask),
(powerof2, match_opcode, make_instruction, print_arguments),
(print_arg): Delete forward declarations, moving static to..
(getregname, getcopregname, getregliststring): ..these definitions.
(build_mask): Return unsigned int mask.
(match_opcode): Use unsigned int vars.
2019-12-16 00:28:09 +01:00
|
|
|
static void
|
2004-10-27 12:24:01 +02:00
|
|
|
getregliststring (int mask, char *string, enum REG_ARG_TYPE core_cop)
|
2004-07-07 19:28:53 +02:00
|
|
|
{
|
2018-02-24 01:03:33 +01:00
|
|
|
char temp_string[16];
|
2004-07-07 19:28:53 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
string[0] = '{';
|
|
|
|
string[1] = '\0';
|
|
|
|
|
2004-10-27 12:24:01 +02:00
|
|
|
|
|
|
|
/* A zero mask means HI/LO registers. */
|
|
|
|
if (mask == 0)
|
|
|
|
{
|
|
|
|
if (core_cop == USER_REG_ARG)
|
|
|
|
strcat (string, "ulo,uhi");
|
|
|
|
else
|
|
|
|
strcat (string, "lo,hi");
|
|
|
|
}
|
|
|
|
else
|
2004-07-07 19:28:53 +02:00
|
|
|
{
|
2004-10-27 12:24:01 +02:00
|
|
|
for (i = 0; i < 16; i++)
|
2004-10-07 16:18:17 +02:00
|
|
|
{
|
2004-10-27 12:24:01 +02:00
|
|
|
if (mask & 0x1)
|
2004-10-07 16:18:17 +02:00
|
|
|
{
|
2004-10-27 12:24:01 +02:00
|
|
|
switch (core_cop)
|
|
|
|
{
|
|
|
|
case REG_ARG:
|
|
|
|
sprintf (temp_string, "r%d", i);
|
|
|
|
break;
|
|
|
|
case USER_REG_ARG:
|
|
|
|
sprintf (temp_string, "u%d", i);
|
|
|
|
break;
|
|
|
|
case COP_ARG:
|
|
|
|
sprintf (temp_string, "c%d", i);
|
|
|
|
break;
|
|
|
|
case COPS_ARG:
|
|
|
|
sprintf (temp_string, "cs%d", i);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
strcat (string, temp_string);
|
|
|
|
if (mask & 0xfffe)
|
|
|
|
strcat (string, ",");
|
2004-10-07 16:18:17 +02:00
|
|
|
}
|
2004-10-27 12:24:01 +02:00
|
|
|
mask >>= 1;
|
|
|
|
}
|
2004-07-07 19:28:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
strcat (string, "}");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* START and END are relating 'allWords' struct, which is 48 bits size.
|
|
|
|
|
|
|
|
START|--------|END
|
|
|
|
+---------+---------+---------+---------+
|
|
|
|
| | V | A | L |
|
|
|
|
+---------+---------+---------+---------+
|
|
|
|
0 16 32 48
|
|
|
|
words [0] [1] [2] */
|
|
|
|
|
|
|
|
static parameter
|
|
|
|
makelongparameter (ULONGLONG val, int start, int end)
|
|
|
|
{
|
|
|
|
parameter p;
|
|
|
|
|
|
|
|
p.val = (dwordU) EXTRACT(val, 48 - end, end - start);
|
|
|
|
p.nbits = end - start;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build a mask of the instruction's 'constant' opcode,
|
|
|
|
based on the instruction's printing flags. */
|
|
|
|
|
ubsan: crx: left shift cannot be represented in type 'int'
The ubsan complaint is fixed by the SBM change, with similar possible
complaints fixed by the EXTRACT change. The rest is just cleanup.
include/
* opcode/crx.h (inst <match>): Make unsigned int.
opcodes/
* crx-dis.c (EXTRACT, SBM): Avoid signed overflow.
(get_number_of_operands, getargtype, getbits, getregname),
(getcopregname, getprocregname, gettrapstring, getcinvstring),
(getregliststring, get_word_at_PC, get_words_at_PC, build_mask),
(powerof2, match_opcode, make_instruction, print_arguments),
(print_arg): Delete forward declarations, moving static to..
(getregname, getcopregname, getregliststring): ..these definitions.
(build_mask): Return unsigned int mask.
(match_opcode): Use unsigned int vars.
2019-12-16 00:28:09 +01:00
|
|
|
static unsigned int
|
2004-07-07 19:28:53 +02:00
|
|
|
build_mask (void)
|
|
|
|
{
|
|
|
|
unsigned int print_flags;
|
ubsan: crx: left shift cannot be represented in type 'int'
The ubsan complaint is fixed by the SBM change, with similar possible
complaints fixed by the EXTRACT change. The rest is just cleanup.
include/
* opcode/crx.h (inst <match>): Make unsigned int.
opcodes/
* crx-dis.c (EXTRACT, SBM): Avoid signed overflow.
(get_number_of_operands, getargtype, getbits, getregname),
(getcopregname, getprocregname, gettrapstring, getcinvstring),
(getregliststring, get_word_at_PC, get_words_at_PC, build_mask),
(powerof2, match_opcode, make_instruction, print_arguments),
(print_arg): Delete forward declarations, moving static to..
(getregname, getcopregname, getregliststring): ..these definitions.
(build_mask): Return unsigned int mask.
(match_opcode): Use unsigned int vars.
2019-12-16 00:28:09 +01:00
|
|
|
unsigned int mask;
|
2004-07-07 19:28:53 +02:00
|
|
|
|
|
|
|
print_flags = instruction->flags & FMT_CRX;
|
|
|
|
switch (print_flags)
|
|
|
|
{
|
|
|
|
case FMT_1:
|
|
|
|
mask = 0xF0F00000;
|
|
|
|
break;
|
|
|
|
case FMT_2:
|
|
|
|
mask = 0xFFF0FF00;
|
|
|
|
break;
|
|
|
|
case FMT_3:
|
|
|
|
mask = 0xFFF00F00;
|
|
|
|
break;
|
|
|
|
case FMT_4:
|
|
|
|
mask = 0xFFF0F000;
|
|
|
|
break;
|
|
|
|
case FMT_5:
|
|
|
|
mask = 0xFFF0FFF0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mask = SBM(instruction->match_bits);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Search for a matching opcode. Return 1 for success, 0 for failure. */
|
|
|
|
|
|
|
|
static int
|
|
|
|
match_opcode (void)
|
|
|
|
{
|
ubsan: crx: left shift cannot be represented in type 'int'
The ubsan complaint is fixed by the SBM change, with similar possible
complaints fixed by the EXTRACT change. The rest is just cleanup.
include/
* opcode/crx.h (inst <match>): Make unsigned int.
opcodes/
* crx-dis.c (EXTRACT, SBM): Avoid signed overflow.
(get_number_of_operands, getargtype, getbits, getregname),
(getcopregname, getprocregname, gettrapstring, getcinvstring),
(getregliststring, get_word_at_PC, get_words_at_PC, build_mask),
(powerof2, match_opcode, make_instruction, print_arguments),
(print_arg): Delete forward declarations, moving static to..
(getregname, getcopregname, getregliststring): ..these definitions.
(build_mask): Return unsigned int mask.
(match_opcode): Use unsigned int vars.
2019-12-16 00:28:09 +01:00
|
|
|
unsigned int mask;
|
2004-07-07 19:28:53 +02:00
|
|
|
|
|
|
|
/* The instruction 'constant' opcode doewsn't exceed 32 bits. */
|
2020-01-02 21:37:17 +01:00
|
|
|
unsigned int doubleWord = words[1] + ((unsigned) words[0] << 16);
|
2004-07-07 19:28:53 +02:00
|
|
|
|
|
|
|
/* Start searching from end of instruction table. */
|
|
|
|
instruction = &crx_instruction[NUMOPCODES - 2];
|
|
|
|
|
|
|
|
/* Loop over instruction table until a full match is found. */
|
|
|
|
while (instruction >= crx_instruction)
|
|
|
|
{
|
|
|
|
mask = build_mask ();
|
|
|
|
if ((doubleWord & mask) == BIN(instruction->match, instruction->match_bits))
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
instruction--;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the proper parameter value for different type of arguments. */
|
|
|
|
|
|
|
|
static void
|
|
|
|
make_argument (argument * a, int start_bits)
|
|
|
|
{
|
|
|
|
int inst_bit_size, total_size;
|
|
|
|
parameter p;
|
|
|
|
|
|
|
|
if ((instruction->size == 3) && a->size >= 16)
|
|
|
|
inst_bit_size = 48;
|
|
|
|
else
|
|
|
|
inst_bit_size = 32;
|
|
|
|
|
|
|
|
switch (a->type)
|
|
|
|
{
|
|
|
|
case arg_copr:
|
|
|
|
case arg_copsr:
|
|
|
|
p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
|
|
|
|
inst_bit_size - start_bits);
|
|
|
|
a->cr = p.val;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case arg_r:
|
|
|
|
p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
|
|
|
|
inst_bit_size - start_bits);
|
|
|
|
a->r = p.val;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case arg_ic:
|
|
|
|
p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
|
|
|
|
inst_bit_size - start_bits);
|
|
|
|
|
|
|
|
if ((p.nbits == 4) && cst4flag)
|
|
|
|
{
|
|
|
|
if (IS_INSN_TYPE (CMPBR_INS) && (p.val == ESCAPE_16_BIT))
|
|
|
|
{
|
|
|
|
/* A special case, where the value is actually stored
|
|
|
|
in the last 4 bits. */
|
|
|
|
p = makelongparameter (allWords, 44, 48);
|
|
|
|
/* The size of the instruction should be incremented. */
|
|
|
|
size_changed = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p.val == 6)
|
|
|
|
p.val = -1;
|
|
|
|
else if (p.val == 13)
|
|
|
|
p.val = 48;
|
|
|
|
else if (p.val == 5)
|
|
|
|
p.val = -4;
|
|
|
|
else if (p.val == 10)
|
|
|
|
p.val = 32;
|
|
|
|
else if (p.val == 11)
|
|
|
|
p.val = 20;
|
|
|
|
else if (p.val == 9)
|
|
|
|
p.val = 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
a->constant = p.val;
|
|
|
|
break;
|
|
|
|
|
2004-11-05 12:01:00 +01:00
|
|
|
case arg_idxr:
|
2004-07-07 19:28:53 +02:00
|
|
|
a->scale = 0;
|
|
|
|
total_size = a->size + 10; /* sizeof(rbase + ridx + scl2) = 10. */
|
|
|
|
p = makelongparameter (allWords, inst_bit_size - total_size,
|
|
|
|
inst_bit_size - (total_size - 4));
|
|
|
|
a->r = p.val;
|
|
|
|
p = makelongparameter (allWords, inst_bit_size - (total_size - 4),
|
|
|
|
inst_bit_size - (total_size - 8));
|
|
|
|
a->i_r = p.val;
|
|
|
|
p = makelongparameter (allWords, inst_bit_size - (total_size - 8),
|
|
|
|
inst_bit_size - (total_size - 10));
|
|
|
|
a->scale = p.val;
|
|
|
|
p = makelongparameter (allWords, inst_bit_size - (total_size - 10),
|
|
|
|
inst_bit_size);
|
|
|
|
a->constant = p.val;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case arg_rbase:
|
|
|
|
p = makelongparameter (allWords, inst_bit_size - (start_bits + 4),
|
|
|
|
inst_bit_size - start_bits);
|
|
|
|
a->r = p.val;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case arg_cr:
|
|
|
|
if (a->size <= 8)
|
|
|
|
{
|
|
|
|
p = makelongparameter (allWords, inst_bit_size - (start_bits + 4),
|
|
|
|
inst_bit_size - start_bits);
|
|
|
|
a->r = p.val;
|
|
|
|
/* Case for opc4 r dispu rbase. */
|
|
|
|
p = makelongparameter (allWords, inst_bit_size - (start_bits + 8),
|
|
|
|
inst_bit_size - (start_bits + 4));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* The 'rbase' start_bits is always relative to a 32-bit data type. */
|
|
|
|
p = makelongparameter (allWords, 32 - (start_bits + 4),
|
|
|
|
32 - start_bits);
|
|
|
|
a->r = p.val;
|
|
|
|
p = makelongparameter (allWords, 32 - start_bits,
|
|
|
|
inst_bit_size);
|
|
|
|
}
|
|
|
|
if ((p.nbits == 4) && cst4flag)
|
|
|
|
{
|
|
|
|
if (instruction->flags & DISPUW4)
|
|
|
|
p.val *= 2;
|
|
|
|
else if (instruction->flags & DISPUD4)
|
|
|
|
p.val *= 4;
|
|
|
|
}
|
|
|
|
a->constant = p.val;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case arg_c:
|
|
|
|
p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
|
|
|
|
inst_bit_size - start_bits);
|
|
|
|
a->constant = p.val;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print a single argument. */
|
|
|
|
|
|
|
|
static void
|
2004-12-05 13:26:49 +01:00
|
|
|
print_arg (argument *a, bfd_vma memaddr, struct disassemble_info *info)
|
2004-07-07 19:28:53 +02:00
|
|
|
{
|
|
|
|
LONGLONG longdisp, mask;
|
2004-12-05 13:26:49 +01:00
|
|
|
int sign_flag = 0;
|
|
|
|
int relative = 0;
|
|
|
|
bfd_vma number;
|
2004-07-07 19:28:53 +02:00
|
|
|
int op_index = 0;
|
|
|
|
char string[200];
|
|
|
|
PTR stream = info->stream;
|
|
|
|
fprintf_ftype func = info->fprintf_func;
|
|
|
|
|
|
|
|
switch (a->type)
|
|
|
|
{
|
|
|
|
case arg_copr:
|
|
|
|
func (stream, "%s", getcopregname (a->cr, CRX_C_REGTYPE));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case arg_copsr:
|
|
|
|
func (stream, "%s", getcopregname (a->cr, CRX_CS_REGTYPE));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case arg_r:
|
|
|
|
if (IS_INSN_MNEMONIC ("mtpr") || IS_INSN_MNEMONIC ("mfpr"))
|
|
|
|
func (stream, "%s", getprocregname (a->r));
|
|
|
|
else
|
|
|
|
func (stream, "%s", getregname (a->r));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case arg_ic:
|
|
|
|
if (IS_INSN_MNEMONIC ("excp"))
|
|
|
|
func (stream, "%s", gettrapstring (a->constant));
|
|
|
|
|
|
|
|
else if (IS_INSN_MNEMONIC ("cinv"))
|
|
|
|
func (stream, "%s", getcinvstring (a->constant));
|
|
|
|
|
|
|
|
else if (INST_HAS_REG_LIST)
|
|
|
|
{
|
2015-08-12 13:45:07 +02:00
|
|
|
REG_ARG_TYPE reg_arg_type = IS_INSN_TYPE (COP_REG_INS) ?
|
|
|
|
COP_ARG : IS_INSN_TYPE (COPS_REG_INS) ?
|
2004-10-27 12:24:01 +02:00
|
|
|
COPS_ARG : (instruction->flags & USER_REG) ?
|
|
|
|
USER_REG_ARG : REG_ARG;
|
2004-10-07 16:18:17 +02:00
|
|
|
|
2004-10-27 12:24:01 +02:00
|
|
|
if ((reg_arg_type == COP_ARG) || (reg_arg_type == COPS_ARG))
|
2004-10-07 16:18:17 +02:00
|
|
|
{
|
2004-10-27 12:24:01 +02:00
|
|
|
/* Check for proper argument number. */
|
|
|
|
if (processing_argument_number == 2)
|
|
|
|
{
|
|
|
|
getregliststring (a->constant, string, reg_arg_type);
|
|
|
|
func (stream, "%s", string);
|
|
|
|
}
|
|
|
|
else
|
2012-02-27 07:37:40 +01:00
|
|
|
func (stream, "$0x%lx", a->constant & 0xffffffff);
|
2004-10-07 16:18:17 +02:00
|
|
|
}
|
|
|
|
else
|
2004-07-07 19:28:53 +02:00
|
|
|
{
|
2004-10-27 12:24:01 +02:00
|
|
|
getregliststring (a->constant, string, reg_arg_type);
|
2004-07-07 19:28:53 +02:00
|
|
|
func (stream, "%s", string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2012-02-27 07:37:40 +01:00
|
|
|
func (stream, "$0x%lx", a->constant & 0xffffffff);
|
2004-07-07 19:28:53 +02:00
|
|
|
break;
|
|
|
|
|
2004-11-05 12:01:00 +01:00
|
|
|
case arg_idxr:
|
2012-02-27 07:37:40 +01:00
|
|
|
func (stream, "0x%lx(%s,%s,%d)", a->constant & 0xffffffff,
|
|
|
|
getregname (a->r), getregname (a->i_r), powerof2 (a->scale));
|
2004-07-07 19:28:53 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case arg_rbase:
|
|
|
|
func (stream, "(%s)", getregname (a->r));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case arg_cr:
|
2012-02-27 07:37:40 +01:00
|
|
|
func (stream, "0x%lx(%s)", a->constant & 0xffffffff, getregname (a->r));
|
2004-07-07 19:28:53 +02:00
|
|
|
|
|
|
|
if (IS_INSN_TYPE (LD_STOR_INS_INC))
|
|
|
|
func (stream, "+");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case arg_c:
|
|
|
|
/* Removed the *2 part as because implicit zeros are no more required.
|
|
|
|
Have to fix this as this needs a bit of extension in terms of branchins.
|
|
|
|
Have to add support for cmp and branch instructions. */
|
|
|
|
if (IS_INSN_TYPE (BRANCH_INS) || IS_INSN_MNEMONIC ("bal")
|
|
|
|
|| IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (DCR_BRANCH_INS)
|
|
|
|
|| IS_INSN_TYPE (COP_BRANCH_INS))
|
|
|
|
{
|
2004-12-05 13:26:49 +01:00
|
|
|
relative = 1;
|
2004-07-07 19:28:53 +02:00
|
|
|
longdisp = a->constant;
|
|
|
|
longdisp <<= 1;
|
|
|
|
|
|
|
|
switch (a->size)
|
|
|
|
{
|
|
|
|
case 8:
|
|
|
|
case 16:
|
|
|
|
case 24:
|
|
|
|
case 32:
|
|
|
|
mask = ((LONGLONG)1 << a->size) - 1;
|
|
|
|
if (longdisp & ((LONGLONG)1 << a->size))
|
|
|
|
{
|
2004-12-05 13:26:49 +01:00
|
|
|
sign_flag = 1;
|
2004-07-07 19:28:53 +02:00
|
|
|
longdisp = ~(longdisp) + 1;
|
|
|
|
}
|
|
|
|
a->constant = (unsigned long int) (longdisp & mask);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
func (stream,
|
|
|
|
"Wrong offset used in branch/bal instruction");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* For branch Neq instruction it is 2*offset + 2. */
|
2004-12-05 13:26:49 +01:00
|
|
|
else if (IS_INSN_TYPE (BRANCH_NEQ_INS))
|
2004-07-07 19:28:53 +02:00
|
|
|
a->constant = 2 * a->constant + 2;
|
2004-12-05 13:26:49 +01:00
|
|
|
else if (IS_INSN_TYPE (LD_STOR_INS_INC)
|
2004-07-07 19:28:53 +02:00
|
|
|
|| IS_INSN_TYPE (LD_STOR_INS)
|
|
|
|
|| IS_INSN_TYPE (STOR_IMM_INS)
|
|
|
|
|| IS_INSN_TYPE (CSTBIT_INS))
|
|
|
|
{
|
|
|
|
op_index = instruction->flags & REVERSE_MATCH ? 0 : 1;
|
|
|
|
if (instruction->operands[op_index].op_type == abs16)
|
|
|
|
a->constant |= 0xFFFF0000;
|
|
|
|
}
|
2004-12-05 13:26:49 +01:00
|
|
|
func (stream, "%s", "0x");
|
|
|
|
number = (relative ? memaddr : 0)
|
|
|
|
+ (sign_flag ? -a->constant : a->constant);
|
|
|
|
(*info->print_address_func) (number, info);
|
2004-07-07 19:28:53 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print all the arguments of CURRINSN instruction. */
|
|
|
|
|
|
|
|
static void
|
2009-12-11 14:42:17 +01:00
|
|
|
print_arguments (ins *currentInsn, bfd_vma memaddr, struct disassemble_info *info)
|
2004-07-07 19:28:53 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2009-12-11 14:42:17 +01:00
|
|
|
for (i = 0; i < currentInsn->nargs; i++)
|
2004-07-07 19:28:53 +02:00
|
|
|
{
|
|
|
|
processing_argument_number = i;
|
|
|
|
|
2009-12-11 14:42:17 +01:00
|
|
|
print_arg (¤tInsn->arg[i], memaddr, info);
|
2004-07-07 19:28:53 +02:00
|
|
|
|
2009-12-11 14:42:17 +01:00
|
|
|
if (i != currentInsn->nargs - 1)
|
2004-07-07 19:28:53 +02:00
|
|
|
info->fprintf_func (info->stream, ", ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build the instruction's arguments. */
|
|
|
|
|
|
|
|
static void
|
|
|
|
make_instruction (void)
|
|
|
|
{
|
|
|
|
int i;
|
2004-11-29 17:34:35 +01:00
|
|
|
unsigned int shift;
|
2004-07-07 19:28:53 +02:00
|
|
|
|
|
|
|
for (i = 0; i < currInsn.nargs; i++)
|
|
|
|
{
|
2005-02-24 14:38:01 +01:00
|
|
|
argument a;
|
2005-02-23 12:53:31 +01:00
|
|
|
|
2005-02-24 14:38:01 +01:00
|
|
|
memset (&a, 0, sizeof (a));
|
2004-07-07 19:28:53 +02:00
|
|
|
a.type = getargtype (instruction->operands[i].op_type);
|
|
|
|
if (instruction->operands[i].op_type == cst4
|
2004-11-29 17:34:35 +01:00
|
|
|
|| instruction->operands[i].op_type == rbase_dispu4)
|
2004-07-07 19:28:53 +02:00
|
|
|
cst4flag = 1;
|
|
|
|
a.size = getbits (instruction->operands[i].op_type);
|
|
|
|
shift = instruction->operands[i].shift;
|
|
|
|
|
|
|
|
make_argument (&a, shift);
|
|
|
|
currInsn.arg[i] = a;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate instruction size (in bytes). */
|
|
|
|
currInsn.size = instruction->size + (size_changed ? 1 : 0);
|
2004-11-29 17:34:35 +01:00
|
|
|
/* Now in bits. */
|
2004-07-07 19:28:53 +02:00
|
|
|
currInsn.size *= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Retrieve a single word from a given memory address. */
|
|
|
|
|
|
|
|
static wordU
|
|
|
|
get_word_at_PC (bfd_vma memaddr, struct disassemble_info *info)
|
|
|
|
{
|
|
|
|
bfd_byte buffer[4];
|
|
|
|
int status;
|
|
|
|
wordU insn = 0;
|
|
|
|
|
|
|
|
status = info->read_memory_func (memaddr, buffer, 2, info);
|
|
|
|
|
|
|
|
if (status == 0)
|
|
|
|
insn = (wordU) bfd_getl16 (buffer);
|
|
|
|
|
|
|
|
return insn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Retrieve multiple words (3) from a given memory address. */
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_words_at_PC (bfd_vma memaddr, struct disassemble_info *info)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
bfd_vma mem;
|
|
|
|
|
|
|
|
for (i = 0, mem = memaddr; i < 3; i++, mem += 2)
|
|
|
|
words[i] = get_word_at_PC (mem, info);
|
|
|
|
|
|
|
|
allWords =
|
|
|
|
((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) + words[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prints the instruction by calling print_arguments after proper matching. */
|
|
|
|
|
|
|
|
int
|
2016-04-14 00:30:46 +02:00
|
|
|
print_insn_crx (bfd_vma memaddr, struct disassemble_info *info)
|
2004-07-07 19:28:53 +02:00
|
|
|
{
|
|
|
|
int is_decoded; /* Nonzero means instruction has a match. */
|
|
|
|
|
|
|
|
/* Initialize global variables. */
|
|
|
|
cst4flag = 0;
|
|
|
|
size_changed = 0;
|
|
|
|
|
|
|
|
/* Retrieve the encoding from current memory location. */
|
|
|
|
get_words_at_PC (memaddr, info);
|
|
|
|
/* Find a matching opcode in table. */
|
|
|
|
is_decoded = match_opcode ();
|
|
|
|
/* If found, print the instruction's mnemonic and arguments. */
|
2016-10-05 23:38:25 +02:00
|
|
|
if (is_decoded > 0 && (words[0] != 0 || words[1] != 0))
|
2004-07-07 19:28:53 +02:00
|
|
|
{
|
|
|
|
info->fprintf_func (info->stream, "%s", instruction->mnemonic);
|
|
|
|
if ((currInsn.nargs = get_number_of_operands ()) != 0)
|
|
|
|
info->fprintf_func (info->stream, "\t");
|
|
|
|
make_instruction ();
|
2004-12-05 13:26:49 +01:00
|
|
|
print_arguments (&currInsn, memaddr, info);
|
2004-07-07 19:28:53 +02:00
|
|
|
return currInsn.size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No match found. */
|
|
|
|
info->fprintf_func (info->stream,"%s ",ILLEGAL);
|
|
|
|
return 2;
|
|
|
|
}
|