Back to index

cell-binutils  2.17cvs20070401
d10v-dis.c
Go to the documentation of this file.
00001 /* Disassemble D10V instructions.
00002    Copyright 1996, 1997, 1998, 2000, 2001, 2005 Free Software Foundation, Inc.
00003 
00004    This program is free software; you can redistribute it and/or modify
00005    it under the terms of the GNU General Public License as published by
00006    the Free Software Foundation; either version 2 of the License, or
00007    (at your option) any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012    GNU General Public License for more details.
00013 
00014    You should have received a copy of the GNU General Public License
00015    along with this program; if not, write to the Free Software
00016    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
00017    MA 02110-1301, USA.  */
00018 
00019 #include <stdio.h>
00020 
00021 #include "sysdep.h"
00022 #include "opcode/d10v.h"
00023 #include "dis-asm.h"
00024 
00025 /* The PC wraps at 18 bits, except for the segment number,
00026    so use this mask to keep the parts we want.  */
00027 #define PC_MASK      0x0303FFFF
00028 
00029 static void
00030 print_operand (struct d10v_operand *oper,
00031               unsigned long insn,
00032               struct d10v_opcode *op,
00033               bfd_vma memaddr,
00034               struct disassemble_info *info)
00035 {
00036   int num, shift;
00037 
00038   if (oper->flags == OPERAND_ATMINUS)
00039     {
00040       (*info->fprintf_func) (info->stream, "@-");
00041       return;
00042     }
00043   if (oper->flags == OPERAND_MINUS)
00044     {
00045       (*info->fprintf_func) (info->stream, "-");
00046       return;
00047     }
00048   if (oper->flags == OPERAND_PLUS)
00049     {
00050       (*info->fprintf_func) (info->stream, "+");
00051       return;
00052     }
00053   if (oper->flags == OPERAND_ATSIGN)
00054     {
00055       (*info->fprintf_func) (info->stream, "@");
00056       return;
00057     }
00058   if (oper->flags == OPERAND_ATPAR)
00059     {
00060       (*info->fprintf_func) (info->stream, "@(");
00061       return;
00062     }
00063 
00064   shift = oper->shift;
00065 
00066   /* The LONG_L format shifts registers over by 15.  */
00067   if (op->format == LONG_L && (oper->flags & OPERAND_REG))
00068     shift += 15;
00069 
00070   num = (insn >> shift) & (0x7FFFFFFF >> (31 - oper->bits));
00071 
00072   if (oper->flags & OPERAND_REG)
00073     {
00074       int i;
00075       int match = 0;
00076 
00077       num += (oper->flags
00078              & (OPERAND_GPR | OPERAND_FFLAG | OPERAND_CFLAG | OPERAND_CONTROL));
00079       if (oper->flags & (OPERAND_ACC0 | OPERAND_ACC1))
00080        num += num ? OPERAND_ACC1 : OPERAND_ACC0;
00081       for (i = 0; i < d10v_reg_name_cnt (); i++)
00082        {
00083          if (num == (d10v_predefined_registers[i].value & ~ OPERAND_SP))
00084            {
00085              if (d10v_predefined_registers[i].pname)
00086               (*info->fprintf_func) (info->stream, "%s",
00087                                    d10v_predefined_registers[i].pname);
00088              else
00089               (*info->fprintf_func) (info->stream, "%s",
00090                                    d10v_predefined_registers[i].name);
00091              match = 1;
00092              break;
00093            }
00094        }
00095       if (match == 0)
00096        {
00097          /* This would only get executed if a register was not in the
00098             register table.  */
00099          if (oper->flags & (OPERAND_ACC0 | OPERAND_ACC1))
00100            (*info->fprintf_func) (info->stream, "a");
00101          else if (oper->flags & OPERAND_CONTROL)
00102            (*info->fprintf_func) (info->stream, "cr");
00103          else if (oper->flags & OPERAND_REG)
00104            (*info->fprintf_func) (info->stream, "r");
00105          (*info->fprintf_func) (info->stream, "%d", num & REGISTER_MASK);
00106        }
00107     }
00108   else
00109     {
00110       /* Addresses are right-shifted by 2.  */
00111       if (oper->flags & OPERAND_ADDR)
00112        {
00113          long max;
00114          int neg = 0;
00115 
00116          max = (1 << (oper->bits - 1));
00117          if (num & max)
00118            {
00119              num = -num & ((1 << oper->bits) - 1);
00120              neg = 1;
00121            }
00122          num = num << 2;
00123          if (info->flags & INSN_HAS_RELOC)
00124            (*info->print_address_func) (num & PC_MASK, info);
00125          else
00126            {
00127              if (neg)
00128               (*info->print_address_func) ((memaddr - num) & PC_MASK, info);
00129              else
00130               (*info->print_address_func) ((memaddr + num) & PC_MASK, info);
00131            }
00132        }
00133       else
00134        {
00135          if (oper->flags & OPERAND_SIGNED)
00136            {
00137              int max = (1 << (oper->bits - 1));
00138              if (num & max)
00139               {
00140                 num = -num & ((1 << oper->bits) - 1);
00141                 (*info->fprintf_func) (info->stream, "-");
00142               }
00143            }
00144          (*info->fprintf_func) (info->stream, "0x%x", num);
00145        }
00146     }
00147 }
00148 
00149 static void
00150 dis_long (unsigned long insn,
00151          bfd_vma memaddr,
00152          struct disassemble_info *info)
00153 {
00154   int i;
00155   struct d10v_opcode *op = (struct d10v_opcode *) d10v_opcodes;
00156   struct d10v_operand *oper;
00157   int need_paren = 0;
00158   int match = 0;
00159 
00160   while (op->name)
00161     {
00162       if ((op->format & LONG_OPCODE)
00163          && ((op->mask & insn) == (unsigned long) op->opcode))
00164        {
00165          match = 1;
00166          (*info->fprintf_func) (info->stream, "%s\t", op->name);
00167 
00168          for (i = 0; op->operands[i]; i++)
00169            {
00170              oper = (struct d10v_operand *) &d10v_operands[op->operands[i]];
00171              if (oper->flags == OPERAND_ATPAR)
00172               need_paren = 1;
00173              print_operand (oper, insn, op, memaddr, info);
00174              if (op->operands[i + 1] && oper->bits
00175                 && d10v_operands[op->operands[i + 1]].flags != OPERAND_PLUS
00176                 && d10v_operands[op->operands[i + 1]].flags != OPERAND_MINUS)
00177               (*info->fprintf_func) (info->stream, ", ");
00178            }
00179          break;
00180        }
00181       op++;
00182     }
00183 
00184   if (!match)
00185     (*info->fprintf_func) (info->stream, ".long\t0x%08lx", insn);
00186 
00187   if (need_paren)
00188     (*info->fprintf_func) (info->stream, ")");
00189 }
00190 
00191 static void
00192 dis_2_short (unsigned long insn,
00193             bfd_vma memaddr,
00194             struct disassemble_info *info,
00195             int order)
00196 {
00197   int i, j;
00198   unsigned int ins[2];
00199   struct d10v_opcode *op;
00200   int match, num_match = 0;
00201   struct d10v_operand *oper;
00202   int need_paren = 0;
00203 
00204   ins[0] = (insn & 0x3FFFFFFF) >> 15;
00205   ins[1] = insn & 0x00007FFF;
00206 
00207   for (j = 0; j < 2; j++)
00208     {
00209       op = (struct d10v_opcode *) d10v_opcodes;
00210       match = 0;
00211       while (op->name)
00212        {
00213          if ((op->format & SHORT_OPCODE)
00214              && ((((unsigned int) op->mask) & ins[j])
00215                 == (unsigned int) op->opcode))
00216            {
00217              (*info->fprintf_func) (info->stream, "%s\t", op->name);
00218              for (i = 0; op->operands[i]; i++)
00219               {
00220                 oper = (struct d10v_operand *) &d10v_operands[op->operands[i]];
00221                 if (oper->flags == OPERAND_ATPAR)
00222                   need_paren = 1;
00223                 print_operand (oper, ins[j], op, memaddr, info);
00224                 if (op->operands[i + 1] && oper->bits
00225                     && d10v_operands[op->operands[i + 1]].flags != OPERAND_PLUS
00226                     && d10v_operands[op->operands[i + 1]].flags != OPERAND_MINUS)
00227                   (*info->fprintf_func) (info->stream, ", ");
00228               }
00229              match = 1;
00230              num_match++;
00231              break;
00232            }
00233          op++;
00234        }
00235       if (!match)
00236        (*info->fprintf_func) (info->stream, "unknown");
00237 
00238       switch (order)
00239        {
00240        case 0:
00241          (*info->fprintf_func) (info->stream, "\t->\t");
00242          order = -1;
00243          break;
00244        case 1:
00245          (*info->fprintf_func) (info->stream, "\t<-\t");
00246          order = -1;
00247          break;
00248        case 2:
00249          (*info->fprintf_func) (info->stream, "\t||\t");
00250          order = -1;
00251          break;
00252        default:
00253          break;
00254        }
00255     }
00256 
00257   if (num_match == 0)
00258     (*info->fprintf_func) (info->stream, ".long\t0x%08lx", insn);
00259 
00260   if (need_paren)
00261     (*info->fprintf_func) (info->stream, ")");
00262 }
00263 
00264 int
00265 print_insn_d10v (bfd_vma memaddr, struct disassemble_info *info)
00266 {
00267   int status;
00268   bfd_byte buffer[4];
00269   unsigned long insn;
00270 
00271   status = (*info->read_memory_func) (memaddr, buffer, 4, info);
00272   if (status != 0)
00273     {
00274       (*info->memory_error_func) (status, memaddr, info);
00275       return -1;
00276     }
00277   insn = bfd_getb32 (buffer);
00278 
00279   status = insn & FM11;
00280   switch (status)
00281     {
00282     case 0:
00283       dis_2_short (insn, memaddr, info, 2);
00284       break;
00285     case FM01:
00286       dis_2_short (insn, memaddr, info, 0);
00287       break;
00288     case FM10:
00289       dis_2_short (insn, memaddr, info, 1);
00290       break;
00291     case FM11:
00292       dis_long (insn, memaddr, info);
00293       break;
00294     }
00295   return 4;
00296 }