diff options
author | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2014-12-06 16:25:55 +0100 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2014-12-06 16:25:55 +0100 |
commit | 1945cfa59de0a6093011891e1974ac2b6d25658f (patch) | |
tree | e5ce6439d91746f66df8e2b49241690fa244d58c /opcodes/visium-dis.c | |
parent | bb5f7690917fd192b98c2fcace1884252c5f6f02 (diff) | |
download | gdb-1945cfa59de0a6093011891e1974ac2b6d25658f.zip gdb-1945cfa59de0a6093011891e1974ac2b6d25658f.tar.gz gdb-1945cfa59de0a6093011891e1974ac2b6d25658f.tar.bz2 |
Add Visium support to opcodes
include/
* dis-asm.h (print_insn_visium): Declare.
include/opcode/
* visium.h: New file.
opcodes/
* configure.ac: Add Visium support.
* configure: Regenerate.
* Makefile.am (TARGET_LIBOPCODES_CFILES): Add visium-dis.c and
visium-opc.c.
* Makefile.in: Regenerate.
* disassemble.c (ARCH_visium): Define if ARCH_all.
(disassembler): Deal with bfd_arch_visium if ARCH_visium.
* visium-dis.c: New file.
* visium-opc.c: Likewise.
* po/POTFILES.in: Regenerate.
Diffstat (limited to 'opcodes/visium-dis.c')
-rw-r--r-- | opcodes/visium-dis.c | 834 |
1 files changed, 834 insertions, 0 deletions
diff --git a/opcodes/visium-dis.c b/opcodes/visium-dis.c new file mode 100644 index 0000000..96be972 --- /dev/null +++ b/opcodes/visium-dis.c @@ -0,0 +1,834 @@ +/* Single instruction disassembler for the Visium. + + Copyright (C) 2002-2014 Free Software Foundation, Inc. + + 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 program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include "dis-asm.h" +#include "opcode/visium.h" + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <setjmp.h> + +/* Maximum length of an instruction. */ +#define MAXLEN 4 + +struct private +{ + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAXLEN]; + bfd_vma insn_start; + jmp_buf bailout; +}; + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct private *)(info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int fetch_data (struct disassemble_info *info, bfd_byte * addr); + +static int +fetch_data (struct disassemble_info *info, bfd_byte *addr) +{ + int status; + struct private *priv = (struct private *) info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, info); + if (status != 0) + { + (*info->memory_error_func) (status, start, info); + longjmp (priv->bailout, 1); + } + else + priv->max_fetched = addr; + return 1; +} + +static char *size_names[] = { "?", "b", "w", "?", "l", "?", "?", "?" }; + +static char *cc_names[] = +{ + "fa", "eq", "cs", "os", "ns", "ne", "cc", "oc", + "nc", "ge", "gt", "hi", "le", "ls", "lt", "tr" +}; + +/* Disassemble non-storage relative instructions. */ + +static int +disassem_class0 (disassemble_info *info, unsigned int ins) +{ + int opcode = (ins >> 21) & 0x000f; + + if (ins & CLASS0_UNUSED_MASK) + goto illegal_opcode; + + switch (opcode) + { + case 0: + /* BRR instruction. */ + { + unsigned cbf = (ins >> 27) & 0x000f; + int displacement = ((int) (ins << 16)) >> 16; + + if (ins == 0) + (*info->fprintf_func) (info->stream, "nop"); + else + (*info->fprintf_func) (info->stream, "brr %s,%+d", + cc_names[cbf], displacement); + } + break; + case 1: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 2: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 3: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 4: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 5: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 6: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 7: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 8: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 9: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 10: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 11: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 12: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 13: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 14: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 15: + /* Illegal opcode. */ + goto illegal_opcode; + break; + } + return 0; + +illegal_opcode: + return -1; +} + +/* Disassemble non-storage register class instructions. */ + +static int +disassem_class1 (disassemble_info *info, unsigned int ins) +{ + int opcode = (ins >> 21) & 0xf; + int source_a = (ins >> 16) & 0x1f; + int source_b = (ins >> 4) & 0x1f; + int indx = (ins >> 10) & 0x1f; + + int size = ins & 0x7; + + if (ins & CLASS1_UNUSED_MASK) + goto illegal_opcode; + + switch (opcode) + { + case 0: + /* Stop. */ + (*info->fprintf_func) (info->stream, "stop"); + break; + case 1: + /* BMI - Block Move Indirect. */ + if (ins != BMI) + goto illegal_opcode; + + (*info->fprintf_func) (info->stream, "bmi r1,r2,r3"); + break; + case 2: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 3: + /* BMD - Block Move Direct. */ + if (ins != BMD) + goto illegal_opcode; + + (*info->fprintf_func) (info->stream, "bmd r1,r2,r3"); + break; + case 4: + /* DSI - Disable Interrupts. */ + if (ins != DSI) + goto illegal_opcode; + + (*info->fprintf_func) (info->stream, "dsi"); + break; + + case 5: + /* ENI - Enable Interrupts. */ + if (ins != ENI) + goto illegal_opcode; + + (*info->fprintf_func) (info->stream, "eni"); + break; + + case 6: + /* Illegal opcode (was EUT). */ + goto illegal_opcode; + break; + case 7: + /* RFI - Return from Interrupt. */ + if (ins != RFI) + goto illegal_opcode; + + (*info->fprintf_func) (info->stream, "rfi"); + break; + case 8: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 9: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 10: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 11: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 12: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 13: + goto illegal_opcode; + break; + case 14: + goto illegal_opcode; + break; + case 15: + if (ins & EAM_SELECT_MASK) + { + /* Extension arithmetic module write */ + int fp_ins = (ins >> 27) & 0xf; + + if (size != 4) + goto illegal_opcode; + + if (ins & FP_SELECT_MASK) + { + /* Which floating point instructions don't need a fsrcB + register. */ + const int no_fsrcb[16] = { 1, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 0, 0, 1, 0, 0, 0 + }; + if (no_fsrcb[fp_ins] && source_b) + goto illegal_opcode; + + /* Check that none of the floating register register numbers + is higher than 15. (If this is fload, then srcA is a + general register. */ + if (ins & ((1 << 14) | (1 << 8)) || (fp_ins && ins & (1 << 20))) + goto illegal_opcode; + + switch (fp_ins) + { + case 0: + (*info->fprintf_func) (info->stream, "fload f%d,r%d", + indx, source_a); + break; + case 1: + (*info->fprintf_func) (info->stream, "fadd f%d,f%d,f%d", + indx, source_a, source_b); + break; + case 2: + (*info->fprintf_func) (info->stream, "fsub f%d,f%d,f%d", + indx, source_a, source_b); + break; + case 3: + (*info->fprintf_func) (info->stream, "fmult f%d,f%d,f%d", + indx, source_a, source_b); + break; + case 4: + (*info->fprintf_func) (info->stream, "fdiv f%d,f%d,f%d", + indx, source_a, source_b); + break; + case 5: + (*info->fprintf_func) (info->stream, "fsqrt f%d,f%d", + indx, source_a); + break; + case 6: + (*info->fprintf_func) (info->stream, "fneg f%d,f%d", + indx, source_a); + break; + case 7: + (*info->fprintf_func) (info->stream, "fabs f%d,f%d", + indx, source_a); + break; + case 8: + (*info->fprintf_func) (info->stream, "ftoi f%d,f%d", + indx, source_a); + break; + case 9: + (*info->fprintf_func) (info->stream, "itof f%d,f%d", + indx, source_a); + break; + case 12: + (*info->fprintf_func) (info->stream, "fmove f%d,f%d", + indx, source_a); + break; + default: + (*info->fprintf_func) (info->stream, + "fpinst %d,f%d,f%d,f%d", fp_ins, + indx, source_a, source_b); + break; + } + } + else + { + /* Which EAM operations do not need a srcB register. */ + const int no_srcb[32] = + { 0, 0, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (no_srcb[indx] && source_b) + goto illegal_opcode; + + if (fp_ins) + goto illegal_opcode; + + switch (indx) + { + case 0: + (*info->fprintf_func) (info->stream, "mults r%d,r%d", + source_a, source_b); + break; + case 1: + (*info->fprintf_func) (info->stream, "multu r%d,r%d", + source_a, source_b); + break; + case 2: + (*info->fprintf_func) (info->stream, "divs r%d", + source_a); + break; + case 3: + (*info->fprintf_func) (info->stream, "divu r%d", + source_a); + break; + case 4: + (*info->fprintf_func) (info->stream, "writemd r%d,r%d", + source_a, source_b); + break; + case 5: + (*info->fprintf_func) (info->stream, "writemdc r%d", + source_a); + break; + case 6: + (*info->fprintf_func) (info->stream, "divds r%d", + source_a); + break; + case 7: + (*info->fprintf_func) (info->stream, "divdu r%d", + source_a); + break; + case 9: + (*info->fprintf_func) (info->stream, "asrd r%d", + source_a); + break; + case 10: + (*info->fprintf_func) (info->stream, "lsrd r%d", + source_a); + break; + case 11: + (*info->fprintf_func) (info->stream, "asld r%d", + source_a); + break; + default: + (*info->fprintf_func) (info->stream, + "eamwrite %d,r%d,r%d", indx, + source_a, source_b); + break; + } + } + } + else + { + /* WRITE - write to memory. */ + (*info->fprintf_func) (info->stream, "write.%s %d(r%d),r%d", + size_names[size], indx, source_a, source_b); + } + break; + } + + return 0; + +illegal_opcode: + return -1; +} + +/* Disassemble storage immediate class instructions. */ + +static int +disassem_class2 (disassemble_info *info, unsigned int ins) +{ + int opcode = (ins >> 21) & 0xf; + int source_a = (ins >> 16) & 0x1f; + unsigned immediate = ins & 0x0000ffff; + + if (ins & CC_MASK) + goto illegal_opcode; + + switch (opcode) + { + case 0: + /* ADDI instruction. */ + (*info->fprintf_func) (info->stream, "addi r%d,%d", source_a, + immediate); + break; + case 1: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 2: + /* SUBI instruction. */ + (*info->fprintf_func) (info->stream, "subi r%d,%d", source_a, + immediate); + break; + case 3: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 4: + /* MOVIL instruction. */ + (*info->fprintf_func) (info->stream, "movil r%d,0x%04X", source_a, + immediate); + break; + case 5: + /* MOVIU instruction. */ + (*info->fprintf_func) (info->stream, "moviu r%d,0x%04X", source_a, + immediate); + break; + case 6: + /* MOVIQ instruction. */ + (*info->fprintf_func) (info->stream, "moviq r%d,%u", source_a, + immediate); + break; + case 7: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 8: + /* WRTL instruction. */ + if (source_a != 0) + goto illegal_opcode; + + (*info->fprintf_func) (info->stream, "wrtl 0x%04X", immediate); + break; + case 9: + /* WRTU instruction. */ + if (source_a != 0) + goto illegal_opcode; + + (*info->fprintf_func) (info->stream, "wrtu 0x%04X", immediate); + break; + case 10: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 11: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 12: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 13: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 14: + /* Illegal opcode. */ + goto illegal_opcode; + break; + case 15: + /* Illegal opcode. */ + goto illegal_opcode; + break; + } + + return 0; + +illegal_opcode: + return -1; +} + +/* Disassemble storage register class instructions. */ + +static int +disassem_class3 (disassemble_info *info, unsigned int ins) +{ + int opcode = (ins >> 21) & 0xf; + int source_b = (ins >> 4) & 0x1f; + int source_a = (ins >> 16) & 0x1f; + int size = ins & 0x7; + int dest = (ins >> 10) & 0x1f; + + /* Those instructions that don't have a srcB register. */ + const int no_srcb[16] = + { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0 }; + + /* These are instructions which can take an immediate srcB value. */ + const int srcb_immed[16] = + { 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 }; + + /* User opcodes should not provide a non-zero srcB register + when none is required. Only a BRA or floating point + instruction should have a non-zero condition code field. + Only a WRITE or EAMWRITE (opcode 15) should select an EAM + or floating point operation. Note that FP_SELECT_MASK is + the same bit (bit 3) as the interrupt bit which + distinguishes SYS1 from BRA and SYS2 from RFLAG. */ + if ((no_srcb[opcode] && source_b) + || (!srcb_immed[opcode] && ins & CLASS3_SOURCEB_IMMED) + || (opcode != 12 && opcode != 15 && ins & CC_MASK) + || (opcode != 15 && ins & (EAM_SELECT_MASK | FP_SELECT_MASK))) + goto illegal_opcode; + + + switch (opcode) + { + case 0: + /* ADD instruction. */ + (*info->fprintf_func) (info->stream, "add.%s r%d,r%d,r%d", + size_names[size], dest, source_a, source_b); + break; + case 1: + /* ADC instruction. */ + (*info->fprintf_func) (info->stream, "adc.%s r%d,r%d,r%d", + size_names[size], dest, source_a, source_b); + break; + case 2: + /* SUB instruction. */ + if (dest == 0) + (*info->fprintf_func) (info->stream, "cmp.%s r%d,r%d", + size_names[size], source_a, source_b); + else + (*info->fprintf_func) (info->stream, "sub.%s r%d,r%d,r%d", + size_names[size], dest, source_a, source_b); + break; + case 3: + /* SUBC instruction. */ + if (dest == 0) + (*info->fprintf_func) (info->stream, "cmpc.%s r%d,r%d", + size_names[size], source_a, source_b); + else + (*info->fprintf_func) (info->stream, "subc.%s r%d,r%d,r%d", + size_names[size], dest, source_a, source_b); + break; + case 4: + /* EXTW instruction. */ + if (size == 1) + goto illegal_opcode; + + (*info->fprintf_func) (info->stream, "extw.%s r%d,r%d", + size_names[size], dest, source_a); + break; + case 5: + /* ASR instruction. */ + if (ins & CLASS3_SOURCEB_IMMED) + (*info->fprintf_func) (info->stream, "asr.%s r%d,r%d,%d", + size_names[size], dest, source_a, source_b); + else + (*info->fprintf_func) (info->stream, "asr.%s r%d,r%d,r%d", + size_names[size], dest, source_a, source_b); + break; + case 6: + /* LSR instruction. */ + if (ins & CLASS3_SOURCEB_IMMED) + (*info->fprintf_func) (info->stream, "lsr.%s r%d,r%d,%d", + size_names[size], dest, source_a, source_b); + else + (*info->fprintf_func) (info->stream, "lsr.%s r%d,r%d,r%d", + size_names[size], dest, source_a, source_b); + break; + case 7: + /* ASL instruction. */ + if (ins & CLASS3_SOURCEB_IMMED) + (*info->fprintf_func) (info->stream, "asl.%s r%d,r%d,%d", + size_names[size], dest, source_a, source_b); + else + (*info->fprintf_func) (info->stream, "asl.%s r%d,r%d,r%d", + size_names[size], dest, source_a, source_b); + break; + case 8: + /* XOR instruction. */ + (*info->fprintf_func) (info->stream, "xor.%s r%d,r%d,r%d", + size_names[size], dest, source_a, source_b); + break; + case 9: + /* OR instruction. */ + if (source_b == 0) + (*info->fprintf_func) (info->stream, "move.%s r%d,r%d", + size_names[size], dest, source_a); + else + (*info->fprintf_func) (info->stream, "or.%s r%d,r%d,r%d", + size_names[size], dest, source_a, source_b); + break; + case 10: + /* AND instruction. */ + (*info->fprintf_func) (info->stream, "and.%s r%d,r%d,r%d", + size_names[size], dest, source_a, source_b); + break; + case 11: + /* NOT instruction. */ + (*info->fprintf_func) (info->stream, "not.%s r%d,r%d", + size_names[size], dest, source_a); + break; + case 12: + /* BRA instruction. */ + { + unsigned cbf = (ins >> 27) & 0x000f; + + if (size != 4) + goto illegal_opcode; + + (*info->fprintf_func) (info->stream, "bra %s,r%d,r%d", + cc_names[cbf], source_a, dest); + } + break; + case 13: + /* RFLAG instruction. */ + if (source_a || size != 4) + goto illegal_opcode; + + (*info->fprintf_func) (info->stream, "rflag r%d", dest); + break; + case 14: + /* EXTB instruction. */ + (*info->fprintf_func) (info->stream, "extb.%s r%d,r%d", + size_names[size], dest, source_a); + break; + case 15: + if (!(ins & CLASS3_SOURCEB_IMMED)) + goto illegal_opcode; + + if (ins & EAM_SELECT_MASK) + { + /* Extension arithmetic module read. */ + int fp_ins = (ins >> 27) & 0xf; + + if (size != 4) + goto illegal_opcode; + + if (ins & FP_SELECT_MASK) + { + /* Check fsrcA <= 15 and fsrcB <= 15. */ + if (ins & ((1 << 20) | (1 << 8))) + goto illegal_opcode; + + switch (fp_ins) + { + case 0: + if (source_b) + goto illegal_opcode; + + (*info->fprintf_func) (info->stream, "fstore r%d,f%d", + dest, source_a); + break; + case 10: + (*info->fprintf_func) (info->stream, "fcmp r%d,f%d,f%d", + dest, source_a, source_b); + break; + case 11: + (*info->fprintf_func) (info->stream, "fcmpe r%d,f%d,f%d", + dest, source_a, source_b); + break; + default: + (*info->fprintf_func) (info->stream, + "fpuread %d,r%d,f%d,f%d", fp_ins, + dest, source_a, source_b); + break; + } + } + else + { + if (fp_ins || source_a) + goto illegal_opcode; + + switch (source_b) + { + case 0: + (*info->fprintf_func) (info->stream, "readmda r%d", dest); + break; + case 1: + (*info->fprintf_func) (info->stream, "readmdb r%d", dest); + break; + case 2: + (*info->fprintf_func) (info->stream, "readmdc r%d", dest); + break; + default: + (*info->fprintf_func) (info->stream, "eamread r%d,%d", + dest, source_b); + break; + } + } + } + else + { + if (ins & FP_SELECT_MASK) + goto illegal_opcode; + + /* READ instruction. */ + (*info->fprintf_func) (info->stream, "read.%s r%d,%d(r%d)", + size_names[size], dest, source_b, source_a); + } + break; + } + + return 0; + +illegal_opcode: + return -1; + +} + +/* Print the visium instruction at address addr in debugged memory, + on info->stream. Return length of the instruction, in bytes. */ + +int +print_insn_visium (bfd_vma addr, disassemble_info *info) +{ + unsigned ins; + unsigned p1, p2; + int ans; + int i; + + /* Stuff copied from m68k-dis.c. */ + struct private priv; + bfd_byte *buffer = priv.the_buffer; + info->private_data = (PTR) & priv; + priv.max_fetched = priv.the_buffer; + priv.insn_start = addr; + if (setjmp (priv.bailout) != 0) + { + /* Error return. */ + return -1; + } + + /* We do return this info. */ + info->insn_info_valid = 1; + + /* Assume non branch insn. */ + info->insn_type = dis_nonbranch; + + /* Assume no delay. */ + info->branch_delay_insns = 0; + + /* Assume no target known. */ + info->target = 0; + + /* Get 32-bit instruction word. */ + FETCH_DATA (info, buffer + 4); + ins = buffer[0] << 24; + ins |= buffer[1] << 16; + ins |= buffer[2] << 8; + ins |= buffer[3]; + + ans = 0; + + p1 = buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3]; + p2 = 0; + for (i = 0; i < 8; i++) + { + p2 += p1 & 1; + p1 >>= 1; + } + + /* Decode the instruction. */ + if (p2 & 1) + ans = -1; + else + { + switch ((ins >> 25) & 0x3) + { + case 0: + ans = disassem_class0 (info, ins); + break; + case 1: + ans = disassem_class1 (info, ins); + break; + case 2: + ans = disassem_class2 (info, ins); + break; + case 3: + ans = disassem_class3 (info, ins); + break; + } + } + + if (ans != 0) + (*info->fprintf_func) (info->stream, "err"); + + /* Return number of bytes consumed (always 4 for the Visium). */ + return 4; +} |