diff options
author | Martin Hunt <hunt@redhat.com> | 1997-02-19 01:53:26 +0000 |
---|---|---|
committer | Martin Hunt <hunt@redhat.com> | 1997-02-19 01:53:26 +0000 |
commit | b2e3f8442ac20d4c63e2a474117e761be1fd93fa (patch) | |
tree | 73ec1896a47c872412aa6ff5d1eb06edcabb39fc /opcodes/d30v-dis.c | |
parent | 3acdeb5eeeb47616003ae2925e1c1e0a3a34075f (diff) | |
download | gdb-b2e3f8442ac20d4c63e2a474117e761be1fd93fa.zip gdb-b2e3f8442ac20d4c63e2a474117e761be1fd93fa.tar.gz gdb-b2e3f8442ac20d4c63e2a474117e761be1fd93fa.tar.bz2 |
Tue Feb 18 17:43:43 1997 Martin M. Hunt <hunt@pizza.cygnus.com>
* Makefile.in: Added d30v object files.
* configure: (bfd_d30v_arch) Rebuilt.
* configure.in: (bfd_d30v_arch) Added new case.
* d30v-dis.c: New file.
* d30v-opc.c: New file.
* disassemble.c (disassembler) Add entry for d30v.
Diffstat (limited to 'opcodes/d30v-dis.c')
-rw-r--r-- | opcodes/d30v-dis.c | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/opcodes/d30v-dis.c b/opcodes/d30v-dis.c new file mode 100644 index 0000000..91262ad --- /dev/null +++ b/opcodes/d30v-dis.c @@ -0,0 +1,345 @@ +/* Disassemble D30V instructions. + Copyright (C) 1997 Free Software Foundation, Inc. + +This program 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 2 of the License, or +(at your option) any later version. + +This program 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 program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include "opcode/d30v.h" +#include "dis-asm.h" + +#define PC_MASK 0xFFFFFFFF + +static int lookup_opcode PARAMS (( struct d30v_insn *insn, long num, int is_long )); +static void print_insn PARAMS (( struct disassemble_info *info, bfd_vma memaddr, long long num, + struct d30v_insn *insn, int is_long )); +static int extract_value PARAMS (( long long num, struct d30v_operand *oper, int is_long )); + +int +print_insn_d30v (memaddr, info) + bfd_vma memaddr; + struct disassemble_info *info; +{ + int status, i; + bfd_byte buffer[12]; + unsigned long in1,in2; + struct d30v_insn insn; + long long num; + + insn.form = (struct d30v_format *)NULL; + + status = (*info->read_memory_func) (memaddr, buffer, 8, info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + info->bytes_per_line = 8; + info->bytes_per_chunk = 4; + info->display_endian = BFD_ENDIAN_BIG; + in1 = bfd_getb32 (buffer); + in2 = bfd_getb32 (buffer+4); + + if (in1 & in2 & FM01) + { + /* LONG instruction */ + if (!lookup_opcode(&insn, in1, 1)) + { + (*info->fprintf_func) (info->stream, ".long\t0x%x,0x%x",in1,in2); + return 8; + } + num = (long long)in1 << 32 | in2; + print_insn(info, memaddr, num, &insn, 1); + } + else + { + num = in1; + if (!lookup_opcode(&insn, in1, 0)) + (*info->fprintf_func) (info->stream, ".long\t0x%x",in1); + else + print_insn(info, memaddr, num, &insn, 0); + + switch ( ((in1>>31)<<1) | (in2>>31) ) + { + case 0: + (*info->fprintf_func) (info->stream, "\t||\t"); + break; + case 1: + (*info->fprintf_func) (info->stream, "\t->\t"); + break; + case 2: + (*info->fprintf_func) (info->stream, "\t<-\t"); + default: + break; + } + + insn.form = (struct d30v_format *)NULL; + num = in2; + if (!lookup_opcode(&insn, in2, 0)) + (*info->fprintf_func) (info->stream, ".long\t0x%x",in2); + else + print_insn(info, memaddr, num, &insn, 0); + + } + return 8; +} + + +static int +lookup_opcode (insn, num, is_long) + struct d30v_insn *insn; + long num; + int is_long; +{ + int i=0, index; + struct d30v_format *f; + struct d30v_opcode *op = (struct d30v_opcode *)d30v_opcode_table; + int op1 = (num >> 25) & 0x7; + int op2 = (num >> 20) & 0x1f; + int mod = (num >> 18) & 0x3; + + /* find the opcode */ + do { + if ((op->op1 == op1) && (op->op2 == op2)) + break; + op++; + } while (op->name); + + if (!op || !op->name) + return 0; + + while (op->op1 == op1 && op->op2 == op2) + { + /* scan through all the formats for the opcode */ + while (index = op->format[i++]) + { + f = (struct d30v_format *)&d30v_format_table[index]; + while (f->form == index) + { + if ((!is_long || f->form >= LONG) && (f->modifier == mod)) + { + insn->form = f; + break; + } + f++; + } + if (insn->form) + break; + } + if (insn->form) + break; + op++; + i=0; + } + if (insn->form == NULL) + return 0; + + insn->op = op; + insn->ecc = (num >> 28) & 0x7; + return 1; +} + + +static void +print_insn ( info, memaddr, num, insn, is_long ) + struct disassemble_info *info; + bfd_vma memaddr; + long long num; + struct d30v_insn *insn; + int is_long; +{ + char buffer[128]; + int val, opnum, need_comma=0; + struct d30v_operand *oper; + int i, match, opind=0, need_paren=0, found_control=0; + + (*info->fprintf_func) (info->stream, "%s",insn->op->name); + + /* check for CMP or CMPU */ + if (d30v_operand_table[insn->form->operands[0]].flags & OPERAND_NAME) + { + opind++; + val = extract_value(num,(struct d30v_operand *)&d30v_operand_table[insn->form->operands[0]],is_long); + (*info->fprintf_func) (info->stream, "%s",d30v_cc_names[val]); + } + + if (insn->ecc) + (*info->fprintf_func) (info->stream, "/%s",d30v_ecc_names[insn->ecc]); + + (*info->fprintf_func) (info->stream, "\t"); + + while (opnum = insn->form->operands[opind++]) + { + oper = (struct d30v_operand *)&d30v_operand_table[opnum]; + + if (need_comma && oper->flags != OPERAND_PLUS && oper->flags != OPERAND_MINUS) + { + need_comma=0; + (*info->fprintf_func) (info->stream, ", "); + } + + if (oper->flags == OPERAND_ATMINUS) + { + (*info->fprintf_func) (info->stream, "@-"); + continue; + } + if (oper->flags == OPERAND_MINUS) + { + (*info->fprintf_func) (info->stream, "-"); + continue; + } + if (oper->flags == OPERAND_PLUS) + { + (*info->fprintf_func) (info->stream, "+"); + continue; + } + if (oper->flags == OPERAND_ATSIGN) + { + (*info->fprintf_func) (info->stream, "@"); + continue; + } + if (oper->flags == OPERAND_ATPAR) + { + (*info->fprintf_func) (info->stream, "@("); + need_paren = 1; + continue; + } + + if (oper->flags == OPERAND_SPECIAL) + continue; + + val = extract_value(num, oper, is_long); + + if (oper->flags & OPERAND_REG) + { + match = 0; + if (oper->flags & OPERAND_CONTROL) + { + struct d30v_operand *oper3 = + (struct d30v_operand *)&d30v_operand_table[insn->form->operands[2]]; + int id = extract_value (num, oper3, is_long ); + found_control = 1; + switch ( id ) + { + case 0: + val |= OPERAND_CONTROL; + break; + case 1: + case 2: + val = OPERAND_CONTROL + MAX_CONTROL_REG + id; + break; + case 3: + val |= OPERAND_FLAG; + break; + default: + fprintf(stderr,"illegal id (%d)\n",id); + } + } + else if (oper->flags & OPERAND_ACC) + val |= OPERAND_ACC; + else if (oper->flags & OPERAND_FLAG) + val |= OPERAND_FLAG; + for (i=0;i<reg_name_cnt();i++) + { + if (val == pre_defined_registers[i].value) + { + if (pre_defined_registers[i].pname) + (*info->fprintf_func) (info->stream, "%s",pre_defined_registers[i].pname); + else + (*info->fprintf_func) (info->stream, "%s",pre_defined_registers[i].name); + match=1; + break; + } + } + if (match==0) + { + /* this would only get executed if a register was not in the + register table */ + (*info->fprintf_func) (info->stream, "<unknown register %d>",val & 0x3F); + } + } + else if (insn->op->reloc_flag == RELOC_PCREL) + { + long max; + int neg=0; + max = (1 << (oper->bits - 1)); + if (val & max) + { + if (oper->bits == 32) + val = -val; + else + val = -val & ((1 << oper->bits)-1); + neg = 1; + } + if (neg) + (*info->print_address_func) ((memaddr - val) & PC_MASK, info); + else + (*info->print_address_func) ((memaddr + val) & PC_MASK, info); + } + else if (insn->op->reloc_flag == RELOC_ABS) + { + (*info->print_address_func) (val, info); + } + else + { + if (oper->flags & OPERAND_SIGNED) + { + int max = (1 << (oper->bits - 1)); + if (val & max) + { + val = -val & ((1 << oper->bits) - 1); + (*info->fprintf_func) (info->stream, "-"); + } + } + (*info->fprintf_func) (info->stream, "0x%x",val); + } + /* if there is another operand, then write a comma and space */ + if (insn->form->operands[opind] && !(found_control && opind == 2)) + need_comma = 1; + } + if (need_paren) + (*info->fprintf_func) (info->stream, ")"); +} + + + +static int +extract_value (num, oper, is_long) + long long num; + struct d30v_operand *oper; + int is_long; +{ + int val; + int shift = 12 - oper->position; + int mask = (0xFFFFFFFF >> (32 - oper->bits)); + + if (is_long) + { + if (oper->bits == 32) + { + /* piece together 32-bit constant */ + val = num & 0x3FFFF | (num & 0xFF00000) >> 2 | + (num & 0x3F00000000LL) >> 6; + } + else + val = (num >> (32 + shift)) & mask; + } + else + val = (num >> shift) & mask; + + if (oper->flags & OPERAND_SHIFT) + val <<= 3; + + return val; +} |