Back to index

cell-binutils  2.17cvs20070401
Classes | Defines | Typedefs | Enumerations | Functions | Variables
tc-d10v.c File Reference
#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
#include "opcode/d10v.h"
#include "elf/ppc.h"

Go to the source code of this file.

Classes

struct  d10v_fixup
struct  _fixups

Defines

#define AT_WORD_P(X)
#define AT_WORD_RIGHT_SHIFT   2
#define MAX_INSN_FIXUPS   5
#define PACK_UNSPEC   (0) /* Packing order not specified. */
#define PACK_PARALLEL   (1) /* "||" */
#define PACK_LEFT_RIGHT   (2) /* "->" */
#define PACK_RIGHT_LEFT   (3) /* "<-" */

Typedefs

typedef struct _fixups Fixups
typedef int packing_type

Enumerations

enum  options {
  OPTION_EB = OPTION_MD_BASE, OPTION_EL, OPTION_ARC5, OPTION_ARC6,
  OPTION_ARC7, OPTION_ARC8, OPTION_ARC, OPTION_ALL_OPCODES = OPTION_MD_BASE + 1,
  OPTION_NO_SKIP_BUG, OPTION_NO_WRAP, OPTION_NOWARNSWAP = OPTION_MD_BASE, OPTION_GSTABSPACKING,
  OPTION_NOGSTABSPACKING, OPTION_CPU_IP2022 = OPTION_MD_BASE, OPTION_CPU_IP2022EXT, OPTION_JSRI2BSR_ON = OPTION_MD_BASE,
  OPTION_JSRI2BSR_OFF, OPTION_SIFILTER_ON, OPTION_SIFILTER_OFF, OPTION_CPU,
  OPTION_EB, OPTION_EL, OPTION_RELAX = OPTION_MD_BASE, OPTION_BIG,
  OPTION_LITTLE, OPTION_SMALL, OPTION_DSP, OPTION_ISA,
  OPTION_RENESAS, OPTION_ALLOW_REG_PREFIX, OPTION_DUMMY, OPTION_MACH_Z80 = OPTION_MD_BASE,
  OPTION_MACH_R800, OPTION_MACH_IUD, OPTION_MACH_WUD, OPTION_MACH_FUD,
  OPTION_MACH_IUP, OPTION_MACH_WUP, OPTION_MACH_FUP
}

Functions

static int reg_name_search (char *name)
static int register_name (expressionS *expressionP)
static int check_range (unsigned long num, int bits, int flags)
void md_show_usage (FILE *stream)
int md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
symbolS * md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
char * md_atof (int type, char *litP, int *sizeP)
void md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, asection *sec ATTRIBUTE_UNUSED, fragS *fragP ATTRIBUTE_UNUSED)
valueT md_section_align (asection *seg, valueT addr)
void md_begin (void)
static int postfix (char *p)
static bfd_reloc_code_real_type get_reloc (struct d10v_operand *op)
static int get_operands (expressionS exp[])
static unsigned long d10v_insert_operand (unsigned long insn, int op_type, offsetT value, int left, fixS *fix)
static unsigned long build_insn (struct d10v_opcode *opcode, expressionS *opers, unsigned long insn)
static void write_long (unsigned long insn, Fixups *fx)
static void write_1_short (struct d10v_opcode *opcode, unsigned long insn, Fixups *fx)
static void check_resource_conflict (struct d10v_opcode *op1, unsigned long insn1, struct d10v_opcode *op2, unsigned long insn2)
static int parallel_ok (struct d10v_opcode *op1, unsigned long insn1, struct d10v_opcode *op2, unsigned long insn2, packing_type exec_type)
static int write_2_short (struct d10v_opcode *opcode1, unsigned long insn1, struct d10v_opcode *opcode2, unsigned long insn2, packing_type exec_type, Fixups *fx)
static symbolS * find_symbol_matching_register (expressionS *exp)
static struct d10v_opcodefind_opcode (struct d10v_opcode *opcode, expressionS myops[])
static unsigned long do_assemble (char *str, struct d10v_opcode **opcode)
arelenttc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
int md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED, asection *seg ATTRIBUTE_UNUSED)
long md_pcrel_from_section (fixS *fixp, segT sec)
void md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
int d10v_cleanup (void)
static void d10v_dot_word (int dummy ATTRIBUTE_UNUSED)
void md_operand (expressionS *expressionP)
bfd_boolean d10v_fix_adjustable (fixS *fixP)
void md_assemble (char *str)

Variables

const char comment_chars [] = ";"
const char line_comment_chars [] = "#"
const char line_separator_chars [] = ""
const char * md_shortopts = "O"
const char EXP_CHARS [] = "eE"
const char FLT_CHARS [] = "dD"
int Optimizing = 0
static Fixups FixUps [2]
static Fixupsfixups
static int do_not_ignore_hash = 0
static packing_type etype = PACK_UNSPEC
static bfd_boolean flag_warn_suppress_instructionswap
static bfd_boolean flag_allow_gstabs_packing = 1
size_t md_longopts_size = sizeof (md_longopts)
static struct hash_controld10v_hash
static unsigned long prev_insn
static struct d10v_opcodeprev_opcode = 0
static subsegT prev_subseg
static segT prev_seg = 0
const pseudo_typeS md_pseudo_table []

Class Documentation

struct d10v_fixup

Definition at line 46 of file tc-d10v.c.

Collaboration diagram for d10v_fixup:
Class Members
expressionS exp
int operand
int pcrel
bfd_reloc_code_real_type reloc
int size
struct _fixups

Definition at line 55 of file tc-d10v.c.

Collaboration diagram for _fixups:
Class Members
int fc
struct _fixups * next

Define Documentation

#define AT_WORD_P (   X)
Value:
((X)->X_op == O_right_shift \
                    && (X)->X_op_symbol != NULL \
                    && symbol_constant_p ((X)->X_op_symbol) \
                    && S_GET_VALUE ((X)->X_op_symbol) == AT_WORD_RIGHT_SHIFT)

Definition at line 37 of file tc-d10v.c.

#define AT_WORD_RIGHT_SHIFT   2

Definition at line 41 of file tc-d10v.c.

#define MAX_INSN_FIXUPS   5

Definition at line 44 of file tc-d10v.c.

#define PACK_LEFT_RIGHT   (2) /* "->" */

Definition at line 70 of file tc-d10v.c.

#define PACK_PARALLEL   (1) /* "||" */

Definition at line 69 of file tc-d10v.c.

#define PACK_RIGHT_LEFT   (3) /* "<-" */

Definition at line 71 of file tc-d10v.c.

#define PACK_UNSPEC   (0) /* Packing order not specified. */

Definition at line 68 of file tc-d10v.c.


Typedef Documentation

typedef int packing_type

Definition at line 67 of file tc-d10v.c.


Enumeration Type Documentation

enum options
Enumerator:
OPTION_EB 
OPTION_EL 
OPTION_ARC5 
OPTION_ARC6 
OPTION_ARC7 
OPTION_ARC8 
OPTION_ARC 
OPTION_ALL_OPCODES 
OPTION_NO_SKIP_BUG 
OPTION_NO_WRAP 
OPTION_NOWARNSWAP 
OPTION_GSTABSPACKING 
OPTION_NOGSTABSPACKING 
OPTION_CPU_IP2022 
OPTION_CPU_IP2022EXT 
OPTION_JSRI2BSR_ON 
OPTION_JSRI2BSR_OFF 
OPTION_SIFILTER_ON 
OPTION_SIFILTER_OFF 
OPTION_CPU 
OPTION_EB 
OPTION_EL 
OPTION_RELAX 
OPTION_BIG 
OPTION_LITTLE 
OPTION_SMALL 
OPTION_DSP 
OPTION_ISA 
OPTION_RENESAS 
OPTION_ALLOW_REG_PREFIX 
OPTION_DUMMY 
OPTION_MACH_Z80 
OPTION_MACH_R800 
OPTION_MACH_IUD 
OPTION_MACH_WUD 
OPTION_MACH_FUD 
OPTION_MACH_IUP 
OPTION_MACH_WUP 
OPTION_MACH_FUP 

Definition at line 84 of file tc-d10v.c.


Function Documentation

static unsigned long build_insn ( struct d10v_opcode opcode,
expressionS opers,
unsigned long  insn 
) [static]

Definition at line 549 of file tc-d10v.c.

{
  int i, bits, shift, flags, format;
  unsigned long number;

  /* The insn argument is only used for the DIVS kludge.  */
  if (insn)
    format = LONG_R;
  else
    {
      insn = opcode->opcode;
      format = opcode->format;
    }

  for (i = 0; opcode->operands[i]; i++)
    {
      flags = d10v_operands[opcode->operands[i]].flags;
      bits = d10v_operands[opcode->operands[i]].bits;
      shift = d10v_operands[opcode->operands[i]].shift;
      number = opers[i].X_add_number;

      if (flags & OPERAND_REG)
       {
         number &= REGISTER_MASK;
         if (format == LONG_L)
           shift += 15;
       }

      if (opers[i].X_op != O_register && opers[i].X_op != O_constant)
       {
         /* Now create a fixup.  */

         if (fixups->fc >= MAX_INSN_FIXUPS)
           as_fatal (_("too many fixups"));

         if (AT_WORD_P (&opers[i]))
           {
             /* Recognize XXX>>1+N aka XXX@word+N as special (AT_WORD).  */
             fixups->fix[fixups->fc].reloc = BFD_RELOC_D10V_18;
             opers[i].X_op = O_symbol;
             opers[i].X_op_symbol = NULL; /* Should free it.  */
             /* number is left shifted by AT_WORD_RIGHT_SHIFT so
                 that, it is aligned with the symbol's value.  Later,
                 BFD_RELOC_D10V_18 will right shift (symbol_value +
                 X_add_number).  */
             number <<= AT_WORD_RIGHT_SHIFT;
             opers[i].X_add_number = number;
           }
         else
           {
             fixups->fix[fixups->fc].reloc =
              get_reloc ((struct d10v_operand *) &d10v_operands[opcode->operands[i]]);

             /* Check that an immediate was passed to ops that expect one.  */
             if ((flags & OPERAND_NUM)
                && (fixups->fix[fixups->fc].reloc == 0))
              as_bad (_("operand is not an immediate"));
           }

         if (fixups->fix[fixups->fc].reloc == BFD_RELOC_16 ||
             fixups->fix[fixups->fc].reloc == BFD_RELOC_D10V_18)
           fixups->fix[fixups->fc].size = 2;
         else
           fixups->fix[fixups->fc].size = 4;

         fixups->fix[fixups->fc].exp = opers[i];
         fixups->fix[fixups->fc].operand = opcode->operands[i];
         fixups->fix[fixups->fc].pcrel =
           (flags & OPERAND_ADDR) ? TRUE : FALSE;
         (fixups->fc)++;
       }

      /* Truncate to the proper number of bits.  */
      if ((opers[i].X_op == O_constant) && check_range (number, bits, flags))
       as_bad (_("operand out of range: %lu"), number);
      number &= 0x7FFFFFFF >> (31 - bits);
      insn = insn | (number << shift);
    }

  /* kludge: for DIVS, we need to put the operands in twice on the second
     pass, format is changed to LONG_R to force the second set of operands
     to not be shifted over 15.  */
  if ((opcode->opcode == OPCODE_DIVS) && (format == LONG_L))
    insn = build_insn (opcode, opers, insn);

  return insn;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int check_range ( unsigned long  num,
int  bits,
int  flags 
) [static]

Definition at line 168 of file tc-d10v.c.

{
  long min, max;
  int retval = 0;

  /* Don't bother checking 16-bit values.  */
  if (bits == 16)
    return 0;

  if (flags & OPERAND_SHIFT)
    {
      /* All special shift operands are unsigned and <= 16.
        We allow 0 for now.  */
      if (num > 16)
       return 1;
      else
       return 0;
    }

  if (flags & OPERAND_SIGNED)
    {
      /* Signed 3-bit integers are restricted to the (-2, 3) range.  */
      if (flags & RESTRICTED_NUM3)
       {
         if ((long) num < -2 || (long) num > 3)
           retval = 1;
       }
      else
       {
         max = (1 << (bits - 1)) - 1;
         min = - (1 << (bits - 1));
         if (((long) num > max) || ((long) num < min))
           retval = 1;
       }
    }
  else
    {
      max = (1 << bits) - 1;
      min = 0;
      if (((long) num > max) || ((long) num < min))
       retval = 1;
    }
  return retval;
}

Here is the caller graph for this function:

static void check_resource_conflict ( struct d10v_opcode op1,
unsigned long  insn1,
struct d10v_opcode op2,
unsigned long  insn2 
) [static]

Definition at line 725 of file tc-d10v.c.

{
  int i, j, flags, mask, shift, regno;
  unsigned long ins, mod[2];
  struct d10v_opcode *op;

  if ((op1->exec_type & SEQ)
      || ! ((op1->exec_type & PAR) || (op1->exec_type & PARONLY)))
    {
      as_warn (_("packing conflict: %s must dispatch sequentially"),
             op1->name);
      return;
    }

  if ((op2->exec_type & SEQ)
      || ! ((op2->exec_type & PAR) || (op2->exec_type & PARONLY)))
    {
      as_warn (_("packing conflict: %s must dispatch sequentially"),
             op2->name);
      return;
    }

   /* See if both instructions write to the same resource.

      The idea here is to create two sets of bitmasks (mod and used) which
      indicate which registers are modified or used by each instruction.
      The operation can only be done in parallel if neither instruction
      modifies the same register. Accesses to control registers and memory
      are treated as accesses to a single register. So if both instructions
      write memory or if the first instruction writes memory and the second
      reads, then they cannot be done in parallel. We treat reads to the PSW
      (which includes C, F0, and F1) in isolation. So simultaneously writing
      C and F0 in two different sub-instructions is permitted.  */

  /* The bitmasks (mod and used) look like this (bit 31 = MSB).
     r0-r15     0-15
     a0-a1      16-17
     cr (not psw) 18
     psw(other)   19
     mem        20
     psw(C flag)  21
     psw(F0 flag) 22  */

  for (j = 0; j < 2; j++)
    {
      if (j == 0)
       {
         op = op1;
         ins = insn1;
       }
      else
       {
         op = op2;
         ins = insn2;
       }
      mod[j] = 0;
      if (op->exec_type & BRANCH_LINK)
       mod[j] |= 1 << 13;

      for (i = 0; op->operands[i]; i++)
       {
         flags = d10v_operands[op->operands[i]].flags;
         shift = d10v_operands[op->operands[i]].shift;
         mask = 0x7FFFFFFF >> (31 - d10v_operands[op->operands[i]].bits);
         if (flags & OPERAND_REG)
           {
             regno = (ins >> shift) & mask;
             if (flags & (OPERAND_ACC0 | OPERAND_ACC1))
              regno += 16;
             else if (flags & OPERAND_CONTROL)   /* mvtc or mvfc */
              {
                if (regno == 0)
                  regno = 19;
                else
                  regno = 18;
              }
             else if (flags & OPERAND_FFLAG)
              regno = 22;
             else if (flags & OPERAND_CFLAG)
              regno = 21;

             if (flags & OPERAND_DEST
                /* Auto inc/dec also modifies the register.  */
                || (op->operands[i + 1] != 0
                    && (d10v_operands[op->operands[i + 1]].flags
                       & (OPERAND_PLUS | OPERAND_MINUS)) != 0))
              {
                mod[j] |= 1 << regno;
                if (flags & OPERAND_EVEN)
                  mod[j] |= 1 << (regno + 1);
              }
           }
         else if (flags & OPERAND_ATMINUS)
           {
             /* SP implicitly used/modified.  */
             mod[j] |= 1 << 15;
           }
       }

      if (op->exec_type & WMEM)
       mod[j] |= 1 << 20;
      else if (op->exec_type & WF0)
       mod[j] |= 1 << 22;
      else if (op->exec_type & WCAR)
       mod[j] |= 1 << 21;
    }

  if ((mod[0] & mod[1]) == 0)
    return;
  else
    {
      unsigned long x;
      x = mod[0] & mod[1];

      for (j = 0; j <= 15; j++)
       if (x & (1 << j))
         as_warn (_("resource conflict (R%d)"), j);
      for (j = 16; j <= 17; j++)
       if (x & (1 << j))
         as_warn (_("resource conflict (A%d)"), j - 16);
      if (x & (1 << 19))
       as_warn (_("resource conflict (PSW)"));
      if (x & (1 << 21))
       as_warn (_("resource conflict (C flag)"));
      if (x & (1 << 22))
       as_warn (_("resource conflict (F flag)"));
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int d10v_cleanup ( void  )

Definition at line 1635 of file tc-d10v.c.

{
  segT seg;
  subsegT subseg;

  /* If cleanup was invoked because the assembler encountered, e.g., a
     user label, we write out the pending instruction, if any.  If it
     was invoked because the assembler is outputting a piece of line
     debugging information, though, we write out the pending
     instruction only if the --no-gstabs-packing command line switch
     has been specified.  */
  if (prev_opcode
      && etype == PACK_UNSPEC
      && (! outputting_stabs_line_debug || ! flag_allow_gstabs_packing))
    {
      seg = now_seg;
      subseg = now_subseg;

      if (prev_seg)
       subseg_set (prev_seg, prev_subseg);

      write_1_short (prev_opcode, prev_insn, fixups->next);
      subseg_set (seg, subseg);
      prev_opcode = NULL;
    }
  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void d10v_dot_word ( int dummy  ATTRIBUTE_UNUSED) [static]

Definition at line 1667 of file tc-d10v.c.

{
  expressionS exp;
  char *p;

  if (is_it_end_of_statement ())
    {
      demand_empty_rest_of_line ();
      return;
    }

  do
    {
      expression (&exp);
      if (!strncasecmp (input_line_pointer, "@word", 5))
       {
         exp.X_add_number = 0;
         input_line_pointer += 5;

         p = frag_more (2);
         fix_new_exp (frag_now, p - frag_now->fr_literal, 2,
                     &exp, 0, BFD_RELOC_D10V_18);
       }
      else
       emit_expr (&exp, 2);
    }
  while (*input_line_pointer++ == ',');

  input_line_pointer--;            /* Put terminator back into stream.  */
  demand_empty_rest_of_line ();
}

Here is the call graph for this function:

bfd_boolean d10v_fix_adjustable ( fixS *  fixP)

Definition at line 1720 of file tc-d10v.c.

{
  /* We need the symbol name for the VTABLE entries.  */
  if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
    return 0;

  return 1;
}
static unsigned long d10v_insert_operand ( unsigned long  insn,
int  op_type,
offsetT  value,
int  left,
fixS *  fix 
) [static]

Definition at line 520 of file tc-d10v.c.

{
  int shift, bits;

  shift = d10v_operands[op_type].shift;
  if (left)
    shift += 15;

  bits = d10v_operands[op_type].bits;

  /* Truncate to the proper number of bits.  */
  if (check_range (value, bits, d10v_operands[op_type].flags))
    as_bad_where (fix->fx_file, fix->fx_line,
                _("operand out of range: %ld"), (long) value);

  value &= 0x7FFFFFFF >> (31 - bits);
  insn |= (value << shift);

  return insn;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static unsigned long do_assemble ( char *  str,
struct d10v_opcode **  opcode 
) [static]

Definition at line 1436 of file tc-d10v.c.

{
  unsigned char *op_start, *op_end;
  char *save;
  char name[20];
  int nlen = 0;
  expressionS myops[6];

  /* Drop leading whitespace.  */
  while (*str == ' ')
    str++;

  /* Find the opcode end.  */
  for (op_start = op_end = (unsigned char *) str;
       *op_end && nlen < 20 && !is_end_of_line[*op_end] && *op_end != ' ';
       op_end++)
    {
      name[nlen] = TOLOWER (op_start[nlen]);
      nlen++;
    }
  name[nlen] = 0;

  if (nlen == 0)
    return -1;

  /* Find the first opcode with the proper name.  */
  *opcode = (struct d10v_opcode *) hash_find (d10v_hash, name);
  if (*opcode == NULL)
    return -1;

  save = input_line_pointer;
  input_line_pointer = (char *) op_end;
  *opcode = find_opcode (*opcode, myops);
  if (*opcode == 0)
    return -1;
  input_line_pointer = save;

  return build_insn ((*opcode), myops, 0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct d10v_opcode* find_opcode ( struct d10v_opcode opcode,
expressionS  myops[] 
) [static, read]

Definition at line 1180 of file tc-d10v.c.

{
  int i, match;
  struct d10v_opcode *next_opcode;

  /* Get all the operands and save them as expressions.  */
  get_operands (myops);

  /* Now see if the operand is a fake.  If so, find the correct size
     instruction, if possible.  */
  if (opcode->format == OPCODE_FAKE)
    {
      int opnum = opcode->operands[0];
      int flags;

      if (myops[opnum].X_op == O_register)
       {
         myops[opnum].X_op = O_symbol;
         myops[opnum].X_add_symbol =
           symbol_find_or_make ((char *) myops[opnum].X_op_symbol);
         myops[opnum].X_add_number = 0;
         myops[opnum].X_op_symbol = NULL;
       }

      next_opcode = opcode + 1;

      /* If the first operand is supposed to be a register, make sure
        we got a valid one.  */
      flags = d10v_operands[next_opcode->operands[0]].flags;
      if (flags & OPERAND_REG)
       {
         int X_op = myops[0].X_op;
         int num = myops[0].X_add_number;

         if (X_op != O_register
             || (num & ~flags
                & (OPERAND_GPR | OPERAND_ACC0 | OPERAND_ACC1
                   | OPERAND_FFLAG | OPERAND_CFLAG | OPERAND_CONTROL))
             || ((flags & OPERAND_SP) && ! (num & OPERAND_SP)))
           {
             as_bad (_("bad opcode or operands"));
             return 0;
           }
       }

      if (myops[opnum].X_op == O_constant
         || (myops[opnum].X_op == O_symbol
             && S_IS_DEFINED (myops[opnum].X_add_symbol)
             && (S_GET_SEGMENT (myops[opnum].X_add_symbol) == now_seg)))
       {
         for (i = 0; opcode->operands[i + 1]; i++)
           {
             int bits = d10v_operands[next_opcode->operands[opnum]].bits;
             int flags = d10v_operands[next_opcode->operands[opnum]].flags;
             if (flags & OPERAND_ADDR)
              bits += 2;

             if (myops[opnum].X_op == O_constant)
              {
                if (!check_range (myops[opnum].X_add_number, bits, flags))
                  break;
              }
             else
              {
                fragS *sym_frag;
                fragS *f;
                unsigned long current_position;
                unsigned long symbol_position;
                unsigned long value;
                bfd_boolean found_symbol;

                /* Calculate the address of the current instruction
                   and the address of the symbol.  Do this by summing
                   the offsets of previous frags until we reach the
                   frag containing the symbol, and the current frag.  */
                sym_frag = symbol_get_frag (myops[opnum].X_add_symbol);
                found_symbol = FALSE;

                current_position =
                  obstack_next_free (&frchain_now->frch_obstack)
                  - frag_now->fr_literal;
                symbol_position = S_GET_VALUE (myops[opnum].X_add_symbol);

                for (f = frchain_now->frch_root; f; f = f->fr_next)
                  {
                    current_position += f->fr_fix + f->fr_offset;

                    if (f == sym_frag)
                     found_symbol = TRUE;

                    if (! found_symbol)
                     symbol_position += f->fr_fix + f->fr_offset;
                  }

                value = symbol_position;

                if (flags & OPERAND_ADDR)
                  value -= current_position;

                if (AT_WORD_P (&myops[opnum]))
                  {
                    if (bits > 4)
                     {
                       bits += 2;
                       if (!check_range (value, bits, flags))
                         break;
                     }
                  }
                else if (!check_range (value, bits, flags))
                  break;
              }
             next_opcode++;
           }

         if (opcode->operands [i + 1] == 0)
           as_fatal (_("value out of range"));
         else
           opcode = next_opcode;
       }
      else
       /* Not a constant, so use a long instruction.  */
       opcode += 2;
    }

  match = 0;

  /* Now search the opcode table table for one with operands
     that matches what we've got.  */
  while (!match)
    {
      match = 1;
      for (i = 0; opcode->operands[i]; i++)
       {
         int flags = d10v_operands[opcode->operands[i]].flags;
         int X_op = myops[i].X_op;
         int num = myops[i].X_add_number;

         if (X_op == 0)
           {
             match = 0;
             break;
           }

         if (flags & OPERAND_REG)
           {
             if ((X_op != O_register)
                || (num & ~flags
                    & (OPERAND_GPR | OPERAND_ACC0 | OPERAND_ACC1
                      | OPERAND_FFLAG | OPERAND_CFLAG
                      | OPERAND_CONTROL))
                || ((flags & OPERAND_SP) && ! (num & OPERAND_SP)))
              {
                match = 0;
                break;
              }
           }

         if (((flags & OPERAND_MINUS)   && ((X_op != O_absent) || (num != OPERAND_MINUS))) ||
             ((flags & OPERAND_PLUS)    && ((X_op != O_absent) || (num != OPERAND_PLUS))) ||
             ((flags & OPERAND_ATMINUS) && ((X_op != O_absent) || (num != OPERAND_ATMINUS))) ||
             ((flags & OPERAND_ATPAR)   && ((X_op != O_absent) || (num != OPERAND_ATPAR))) ||
             ((flags & OPERAND_ATSIGN)  && ((X_op != O_absent) || ((num != OPERAND_ATSIGN) && (num != OPERAND_ATPAR)))))
           {
             match = 0;
             break;
           }

         /* Unfortunately, for the indirect operand in instructions such
            as ``ldb r1, @(c,r14)'' this function can be passed
            X_op == O_register (because 'c' is a valid register name).
            However we cannot just ignore the case when X_op == O_register
            but flags & OPERAND_REG is null, so we check to see if a symbol
            of the same name as the register exists.  If the symbol does
            exist, then the parser was unable to distinguish the two cases
            and we fix things here. (Ref: PR14826)  */

         if (!(flags & OPERAND_REG) && (X_op == O_register))
           {
             symbolS * sym;

             sym = find_symbol_matching_register (& myops[i]);

             if (sym != NULL)
              {
                myops[i].X_op = X_op = O_symbol;
                myops[i].X_add_symbol = sym;
              }
             else
              as_bad
                (_("illegal operand - register name found where none expected"));
           }
       }

      /* We're only done if the operands matched so far AND there
            are no more to check.  */
      if (match && myops[i].X_op == 0)
       break;
      else
       match = 0;

      next_opcode = opcode + 1;

      if (next_opcode->opcode == 0)
       break;

      if (strcmp (next_opcode->name, opcode->name))
       break;

      opcode = next_opcode;
    }

  if (!match)
    {
      as_bad (_("bad opcode or operands"));
      return 0;
    }

  /* Check that all registers that are required to be even are.
     Also, if any operands were marked as registers, but were really symbols,
     fix that here.  */
  for (i = 0; opcode->operands[i]; i++)
    {
      if ((d10v_operands[opcode->operands[i]].flags & OPERAND_EVEN) &&
         (myops[i].X_add_number & 1))
       as_fatal (_("Register number must be EVEN"));
      if ((d10v_operands[opcode->operands[i]].flags & OPERAND_NOSP)
         && (myops[i].X_add_number & OPERAND_SP))
       as_bad (_("Unsupported use of sp"));
      if (myops[i].X_op == O_register)
       {
         if (!(d10v_operands[opcode->operands[i]].flags & OPERAND_REG))
           {
             myops[i].X_op = O_symbol;
             myops[i].X_add_symbol =
              symbol_find_or_make ((char *) myops[i].X_op_symbol);
             myops[i].X_add_number = 0;
             myops[i].X_op_symbol = NULL;
           }
       }
      if ((d10v_operands[opcode->operands[i]].flags & OPERAND_CONTROL)
         && (myops[i].X_add_number == OPERAND_CONTROL + 4
             || myops[i].X_add_number == OPERAND_CONTROL + 5
             || myops[i].X_add_number == OPERAND_CONTROL + 6
             || myops[i].X_add_number == OPERAND_CONTROL + 12
             || myops[i].X_add_number == OPERAND_CONTROL + 13
             || myops[i].X_add_number == OPERAND_CONTROL + 15))
       as_warn (_("cr%ld is a reserved control register"),
               myops[i].X_add_number - OPERAND_CONTROL);
    }
  return opcode;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static symbolS* find_symbol_matching_register ( expressionS exp) [static]

Definition at line 1156 of file tc-d10v.c.

{
  int i;

  if (exp->X_op != O_register)
    return NULL;

  /* Find the name of the register.  */
  for (i = d10v_reg_name_cnt (); i--;)
    if (d10v_predefined_registers[i].value == exp->X_add_number)
      break;

  if (i < 0)
    abort ();

  /* Now see if a symbol has been defined with the same name.  */
  return symbol_find (d10v_predefined_registers[i].name);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int get_operands ( expressionS  exp[]) [static]

Definition at line 384 of file tc-d10v.c.

{
  char *p = input_line_pointer;
  int numops = 0;
  int post = 0;
  int uses_at = 0;

  while (*p)
    {
      while (*p == ' ' || *p == '\t' || *p == ',')
       p++;
      if (*p == 0 || *p == '\n' || *p == '\r')
       break;

      if (*p == '@')
       {
         uses_at = 1;

         p++;
         exp[numops].X_op = O_absent;
         if (*p == '(')
           {
             p++;
             exp[numops].X_add_number = OPERAND_ATPAR;
           }
         else if (*p == '-')
           {
             p++;
             exp[numops].X_add_number = OPERAND_ATMINUS;
           }
         else
           {
             exp[numops].X_add_number = OPERAND_ATSIGN;
             if (*p == '+')
              {
                numops++;
                exp[numops].X_op = O_absent;
                exp[numops].X_add_number = OPERAND_PLUS;
                p++;
              }
             post = postfix (p);
           }
         numops++;
         continue;
       }

      if (*p == ')')
       {
         /* Just skip the trailing paren.  */
         p++;
         continue;
       }

      input_line_pointer = p;

      /* Check to see if it might be a register name.  */
      if (!register_name (&exp[numops]))
       {
         /* Parse as an expression.  */
         if (uses_at)
           {
             /* Any expression that involves the indirect addressing
               cannot also involve immediate addressing.  Therefore
               the use of the hash character is illegal.  */
             int save = do_not_ignore_hash;
             do_not_ignore_hash = 1;

             expression (&exp[numops]);

             do_not_ignore_hash = save;
           }
         else
           expression (&exp[numops]);
       }

      if (strncasecmp (input_line_pointer, "@word", 5) == 0)
       {
         input_line_pointer += 5;
         if (exp[numops].X_op == O_register)
           {
             /* If it looked like a register name but was followed by
                 "@word" then it was really a symbol, so change it to
                 one.  */
             exp[numops].X_op = O_symbol;
             exp[numops].X_add_symbol =
              symbol_find_or_make ((char *) exp[numops].X_op_symbol);
           }

         /* Check for identifier@word+constant.  */
         if (*input_line_pointer == '-' || *input_line_pointer == '+')
           {
             expressionS new_exp;
             expression (&new_exp);
             exp[numops].X_add_number = new_exp.X_add_number;
           }

         /* Convert expr into a right shift by AT_WORD_RIGHT_SHIFT.  */
         {
           expressionS new_exp;
           memset (&new_exp, 0, sizeof new_exp);
           new_exp.X_add_number = AT_WORD_RIGHT_SHIFT;
           new_exp.X_op = O_constant;
           new_exp.X_unsigned = 1;
           exp[numops].X_op_symbol = make_expr_symbol (&new_exp);
           exp[numops].X_op = O_right_shift;
         }

         know (AT_WORD_P (&exp[numops]));
       }

      if (exp[numops].X_op == O_illegal)
       as_bad (_("illegal operand"));
      else if (exp[numops].X_op == O_absent)
       as_bad (_("missing operand"));

      numops++;
      p = input_line_pointer;
    }

  switch (post)
    {
    case -1:  /* Postdecrement mode.  */
      exp[numops].X_op = O_absent;
      exp[numops++].X_add_number = OPERAND_MINUS;
      break;
    case 1:   /* Postincrement mode.  */
      exp[numops].X_op = O_absent;
      exp[numops++].X_add_number = OPERAND_PLUS;
      break;
    }

  exp[numops].X_op = 0;
  return numops;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 363 of file tc-d10v.c.

{
  int bits = op->bits;

  if (bits <= 4)
    return 0;

  if (op->flags & OPERAND_ADDR)
    {
      if (bits == 8)
       return BFD_RELOC_D10V_10_PCREL_R;
      else
       return BFD_RELOC_D10V_18_PCREL;
    }

  return BFD_RELOC_16;
}

Here is the caller graph for this function:

void md_apply_fix ( fixS *  fixP,
valueT valP,
segT seg  ATTRIBUTE_UNUSED 
)

Definition at line 1523 of file tc-d10v.c.

{
  char *where;
  unsigned long insn;
  long value = *valP;
  int op_type;
  int left = 0;

  if (fixP->fx_addsy == (symbolS *) NULL)
    fixP->fx_done = 1;

  /* We don't actually support subtracting a symbol.  */
  if (fixP->fx_subsy != (symbolS *) NULL)
    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));

  op_type = fixP->fx_r_type;
  if (op_type & 2048)
    {
      op_type -= 2048;
      if (op_type & 1024)
       {
         op_type -= 1024;
         fixP->fx_r_type = BFD_RELOC_D10V_10_PCREL_L;
         left = 1;
       }
      else if (op_type & 4096)
       {
         op_type -= 4096;
         fixP->fx_r_type = BFD_RELOC_D10V_18;
       }
      else
       fixP->fx_r_type =
         get_reloc ((struct d10v_operand *) &d10v_operands[op_type]);
    }

  /* Fetch the instruction, insert the fully resolved operand
     value, and stuff the instruction back again.  */
  where = fixP->fx_frag->fr_literal + fixP->fx_where;
  insn = bfd_getb32 ((unsigned char *) where);

  switch (fixP->fx_r_type)
    {
    case BFD_RELOC_D10V_10_PCREL_L:
    case BFD_RELOC_D10V_10_PCREL_R:
    case BFD_RELOC_D10V_18_PCREL:
      /* If the fix is relative to a global symbol, not a section
        symbol, then ignore the offset.
         XXX - Do we have to worry about branches to a symbol + offset ?  */
      if (fixP->fx_addsy != NULL
         && S_IS_EXTERNAL (fixP->fx_addsy) )
        {
          segT fseg = S_GET_SEGMENT (fixP->fx_addsy);
          segment_info_type *segf = seg_info(fseg);

         if ( segf && segf->sym != fixP->fx_addsy)
           value = 0;
        }
      /* Drop through.  */
    case BFD_RELOC_D10V_18:
      /* Instruction addresses are always right-shifted by 2.  */
      value >>= AT_WORD_RIGHT_SHIFT;
      if (fixP->fx_size == 2)
       bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
      else
       {
         struct d10v_opcode *rep, *repi;

         rep = (struct d10v_opcode *) hash_find (d10v_hash, "rep");
         repi = (struct d10v_opcode *) hash_find (d10v_hash, "repi");
         if ((insn & FM11) == FM11
             && ((repi != NULL
                 && (insn & repi->mask) == (unsigned) repi->opcode)
                || (rep != NULL
                    && (insn & rep->mask) == (unsigned) rep->opcode))
             && value < 4)
           as_fatal
             (_("line %d: rep or repi must include at least 4 instructions"),
              fixP->fx_line);
         insn =
           d10v_insert_operand (insn, op_type, (offsetT) value, left, fixP);
         bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
       }
      break;
    case BFD_RELOC_32:
      bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
      break;
    case BFD_RELOC_16:
      bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
      break;

    case BFD_RELOC_VTABLE_INHERIT:
    case BFD_RELOC_VTABLE_ENTRY:
      fixP->fx_done = 0;
      return;

    default:
      as_fatal (_("line %d: unknown relocation type: 0x%x"),
              fixP->fx_line, fixP->fx_r_type);
    }
}

Here is the call graph for this function:

void md_assemble ( char *  str)

Definition at line 1738 of file tc-d10v.c.

{
  /* etype is saved extype.  For multi-line instructions.  */
  packing_type extype = PACK_UNSPEC;             /* Parallel, etc.  */
  struct d10v_opcode *opcode;
  unsigned long insn;
  char *str2;

  if (etype == PACK_UNSPEC)
    {
      /* Look for the special multiple instruction separators.  */
      str2 = strstr (str, "||");
      if (str2)
       extype = PACK_PARALLEL;
      else
       {
         str2 = strstr (str, "->");
         if (str2)
           extype = PACK_LEFT_RIGHT;
         else
           {
             str2 = strstr (str, "<-");
             if (str2)
              extype = PACK_RIGHT_LEFT;
           }
       }

      /* str2 points to the separator, if there is one.  */
      if (str2)
       {
         *str2 = 0;

         /* If two instructions are present and we already have one saved,
            then first write out the saved one.  */
         d10v_cleanup ();

         /* Assemble first instruction and save it.  */
         prev_insn = do_assemble (str, &prev_opcode);
         prev_seg = now_seg;
         prev_subseg = now_subseg;
         if (prev_insn == (unsigned long) -1)
           as_fatal (_("can't find previous opcode "));
         fixups = fixups->next;
         str = str2 + 2;
       }
    }

  insn = do_assemble (str, &opcode);
  if (insn == (unsigned long) -1)
    {
      if (extype != PACK_UNSPEC)
       etype = extype;
      else
       as_bad (_("could not assemble: %s"), str);
      return;
    }

  if (etype != PACK_UNSPEC)
    {
      extype = etype;
      etype = PACK_UNSPEC;
    }

  /* If this is a long instruction, write it and any previous short
     instruction.  */
  if (opcode->format & LONG_OPCODE)
    {
      if (extype != PACK_UNSPEC)
       as_fatal (_("Unable to mix instructions as specified"));
      d10v_cleanup ();
      write_long (insn, fixups);
      prev_opcode = NULL;
      return;
    }

  if (prev_opcode
      && prev_seg
      && ((prev_seg != now_seg) || (prev_subseg != now_subseg)))
    d10v_cleanup ();

  if (prev_opcode
      && (0 == write_2_short (prev_opcode, prev_insn, opcode, insn, extype,
                           fixups)))
    {
      /* No instructions saved.  */
      prev_opcode = NULL;
    }
  else
    {
      if (extype != PACK_UNSPEC)
       as_fatal (_("Unable to mix instructions as specified"));
      /* Save last instruction so it may be packed on next pass.  */
      prev_opcode = opcode;
      prev_insn = insn;
      prev_seg = now_seg;
      prev_subseg = now_subseg;
      fixups = fixups->next;
    }
}

Here is the call graph for this function:

char* md_atof ( int type  ,
char *  litP,
int sizeP 
)

Definition at line 260 of file tc-d10v.c.

{
  int prec;
  LITTLENUM_TYPE words[4];
  char *t;
  int i;

  switch (type)
    {
    case 'f':
      prec = 2;
      break;
    case 'd':
      prec = 4;
      break;
    default:
      *sizeP = 0;
      return _("bad call to md_atof");
    }

  t = atof_ieee (input_line_pointer, type, words);
  if (t)
    input_line_pointer = t;

  *sizeP = prec * 2;

  for (i = 0; i < prec; i++)
    {
      md_number_to_chars (litP, (valueT) words[i], 2);
      litP += 2;
    }
  return NULL;
}

Here is the call graph for this function:

void md_begin ( void  )

Definition at line 310 of file tc-d10v.c.

{
  char *prev_name = "";
  struct d10v_opcode *opcode;
  d10v_hash = hash_new ();

  /* Insert unique names into hash table.  The D10v instruction set
     has many identical opcode names that have different opcodes based
     on the operands.  This hash table then provides a quick index to
     the first opcode with a particular name in the opcode table.  */

  for (opcode = (struct d10v_opcode *) d10v_opcodes; opcode->name; opcode++)
    {
      if (strcmp (prev_name, opcode->name))
       {
         prev_name = (char *) opcode->name;
         hash_insert (d10v_hash, opcode->name, (char *) opcode);
       }
    }

  fixups = &FixUps[0];
  FixUps[0].next = &FixUps[1];
  FixUps[1].next = &FixUps[0];
}

Here is the call graph for this function:

void md_convert_frag ( bfd *abfd  ATTRIBUTE_UNUSED,
asection *sec  ATTRIBUTE_UNUSED,
fragS *fragP  ATTRIBUTE_UNUSED 
)

Definition at line 295 of file tc-d10v.c.

{
  abort ();
}
int md_estimate_size_before_relax ( fragS *fragp  ATTRIBUTE_UNUSED,
asection *seg  ATTRIBUTE_UNUSED 
)

Definition at line 1505 of file tc-d10v.c.

{
  abort ();
  return 0;
}
void md_operand ( expressionS expressionP)

Definition at line 1710 of file tc-d10v.c.

{
  if (*input_line_pointer == '#' && ! do_not_ignore_hash)
    {
      input_line_pointer++;
      expression (expressionP);
    }
}
int md_parse_option ( int c  ,
char *arg  ATTRIBUTE_UNUSED 
)

Definition at line 225 of file tc-d10v.c.

{
  switch (c)
    {
    case 'O':
      /* Optimize. Will attempt to parallelize operations.  */
      Optimizing = 1;
      break;
    case OPTION_NOWARNSWAP:
      flag_warn_suppress_instructionswap = 1;
      break;
    case OPTION_GSTABSPACKING:
      flag_allow_gstabs_packing = 1;
      break;
    case OPTION_NOGSTABSPACKING:
      flag_allow_gstabs_packing = 0;
      break;
    default:
      return 0;
    }
  return 1;
}
long md_pcrel_from_section ( fixS *  fixp,
segT sec   
)

Definition at line 1513 of file tc-d10v.c.

{
  if (fixp->fx_addsy != (symbolS *) NULL
      && (!S_IS_DEFINED (fixp->fx_addsy)
         || (S_GET_SEGMENT (fixp->fx_addsy) != sec)))
    return 0;
  return fixp->fx_frag->fr_address + fixp->fx_where;
}

Here is the call graph for this function:

Definition at line 303 of file tc-d10v.c.

{
  int align = bfd_get_section_alignment (stdoutput, seg);
  return ((addr + (1 << align) - 1) & (-1 << align));
}

Here is the call graph for this function:

void md_show_usage ( FILE *  stream)

Definition at line 214 of file tc-d10v.c.

{
  fprintf (stream, _("D10V options:\n\
-O                      Optimize.  Will do some operations in parallel.\n\
--gstabs-packing        Pack adjacent short instructions together even\n\
                        when --gstabs is specified.  On by default.\n\
--no-gstabs-packing     If --gstabs is specified, do not pack adjacent\n\
                        instructions together.\n"));
}

Here is the call graph for this function:

symbolS* md_undefined_symbol ( char *name  ATTRIBUTE_UNUSED)

Definition at line 249 of file tc-d10v.c.

{
  return 0;
}
static int parallel_ok ( struct d10v_opcode op1,
unsigned long  insn1,
struct d10v_opcode op2,
unsigned long  insn2,
packing_type  exec_type 
) [static]

Definition at line 861 of file tc-d10v.c.

{
  int i, j, flags, mask, shift, regno;
  unsigned long ins, mod[2], used[2];
  struct d10v_opcode *op;

  if ((op1->exec_type & SEQ) != 0 || (op2->exec_type & SEQ) != 0
      || (op1->exec_type & PAR) == 0 || (op2->exec_type & PAR) == 0
      || (op1->unit == BOTH) || (op2->unit == BOTH)
      || (op1->unit == IU && op2->unit == IU)
      || (op1->unit == MU && op2->unit == MU))
    return 0;

  /* If this is auto parallelization, and the first instruction is a
     branch or should not be packed, then don't parallelize.  */
  if (exec_type == PACK_UNSPEC
      && (op1->exec_type & (ALONE | BRANCH)))
    return 0;

  /* The idea here is to create two sets of bitmasks (mod and used)
     which indicate which registers are modified or used by each
     instruction.  The operation can only be done in parallel if
     instruction 1 and instruction 2 modify different registers, and
     the first instruction does not modify registers that the second
     is using (The second instruction can modify registers that the
     first is using as they are only written back after the first
     instruction has completed).  Accesses to control registers, PSW,
     and memory are treated as accesses to a single register.  So if
     both instructions write memory or if the first instruction writes
     memory and the second reads, then they cannot be done in
     parallel.  Likewise, if the first instruction mucks with the psw
     and the second reads the PSW (which includes C, F0, and F1), then
     they cannot operate safely in parallel.  */

  /* The bitmasks (mod and used) look like this (bit 31 = MSB).
     r0-r15     0-15
     a0-a1      16-17
     cr (not psw) 18
     psw        19
     mem        20  */

  for (j = 0; j < 2; j++)
    {
      if (j == 0)
       {
         op = op1;
         ins = insn1;
       }
      else
       {
         op = op2;
         ins = insn2;
       }
      mod[j] = used[j] = 0;
      if (op->exec_type & BRANCH_LINK)
       mod[j] |= 1 << 13;

      for (i = 0; op->operands[i]; i++)
       {
         flags = d10v_operands[op->operands[i]].flags;
         shift = d10v_operands[op->operands[i]].shift;
         mask = 0x7FFFFFFF >> (31 - d10v_operands[op->operands[i]].bits);
         if (flags & OPERAND_REG)
           {
             regno = (ins >> shift) & mask;
             if (flags & (OPERAND_ACC0 | OPERAND_ACC1))
              regno += 16;
             else if (flags & OPERAND_CONTROL)   /* mvtc or mvfc.  */
              {
                if (regno == 0)
                  regno = 19;
                else
                  regno = 18;
              }
             else if (flags & (OPERAND_FFLAG | OPERAND_CFLAG))
              regno = 19;

             if (flags & OPERAND_DEST)
              {
                mod[j] |= 1 << regno;
                if (flags & OPERAND_EVEN)
                  mod[j] |= 1 << (regno + 1);
              }
             else
              {
                used[j] |= 1 << regno;
                if (flags & OPERAND_EVEN)
                  used[j] |= 1 << (regno + 1);

                /* Auto inc/dec also modifies the register.  */
                if (op->operands[i + 1] != 0
                    && (d10v_operands[op->operands[i + 1]].flags
                       & (OPERAND_PLUS | OPERAND_MINUS)) != 0)
                  mod[j] |= 1 << regno;
              }
           }
         else if (flags & OPERAND_ATMINUS)
           {
             /* SP implicitly used/modified.  */
             mod[j] |= 1 << 15;
             used[j] |= 1 << 15;
           }
       }
      if (op->exec_type & RMEM)
       used[j] |= 1 << 20;
      else if (op->exec_type & WMEM)
       mod[j] |= 1 << 20;
      else if (op->exec_type & RF0)
       used[j] |= 1 << 19;
      else if (op->exec_type & WF0)
       mod[j] |= 1 << 19;
      else if (op->exec_type & WCAR)
       mod[j] |= 1 << 19;
    }
  if ((mod[0] & mod[1]) == 0 && (mod[0] & used[1]) == 0)
    return 1;
  return 0;
}

Here is the caller graph for this function:

static int postfix ( char *  p) [static]

Definition at line 339 of file tc-d10v.c.

{
  while (*p != '-' && *p != '+')
    {
      if (*p == 0 || *p == '\n' || *p == '\r')
       break;
      p++;
    }

  if (*p == '-')
    {
      *p = ' ';
      return -1;
    }
  if (*p == '+')
    {
      *p = ' ';
      return 1;
    }

  return 0;
}

Here is the caller graph for this function:

static int reg_name_search ( char *  name) [static]

Definition at line 111 of file tc-d10v.c.

{
  int middle, low, high;
  int cmp;

  low = 0;
  high = d10v_reg_name_cnt () - 1;

  do
    {
      middle = (low + high) / 2;
      cmp = strcasecmp (name, d10v_predefined_registers[middle].name);
      if (cmp < 0)
       high = middle - 1;
      else if (cmp > 0)
       low = middle + 1;
      else
       return d10v_predefined_registers[middle].value;
    }
  while (low <= high);
  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int register_name ( expressionS expressionP) [static]

Definition at line 138 of file tc-d10v.c.

{
  int reg_number;
  char c, *p = input_line_pointer;

  while (*p
        && *p != '\n' && *p != '\r' && *p != ',' && *p != ' ' && *p != ')')
    p++;

  c = *p;
  if (c)
    *p++ = 0;

  /* Look to see if it's in the register table.  */
  reg_number = reg_name_search (input_line_pointer);
  if (reg_number >= 0)
    {
      expressionP->X_op = O_register;
      /* Temporarily store a pointer to the string here.  */
      expressionP->X_op_symbol = (symbolS *) input_line_pointer;
      expressionP->X_add_number = reg_number;
      input_line_pointer = p;
      return 1;
    }
  if (c)
    *(p - 1) = c;
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

arelent* tc_gen_reloc ( asection *seg  ATTRIBUTE_UNUSED,
fixS *  fixp 
)

Definition at line 1480 of file tc-d10v.c.

{
  arelent *reloc;
  reloc = xmalloc (sizeof (arelent));
  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
  if (reloc->howto == (reloc_howto_type *) NULL)
    {
      as_bad_where (fixp->fx_file, fixp->fx_line,
                  _("reloc %d not supported by object file format"),
                  (int) fixp->fx_r_type);
      return NULL;
    }

  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
    reloc->address = fixp->fx_offset;

  reloc->addend = 0;

  return reloc;
}

Here is the call graph for this function:

static void write_1_short ( struct d10v_opcode opcode,
unsigned long  insn,
Fixups fx 
) [static]

Definition at line 675 of file tc-d10v.c.

{
  char *f = frag_more (4);
  int i, where;

  if (opcode->exec_type & PARONLY)
    as_fatal (_("Instruction must be executed in parallel with another instruction."));

  /* The other container needs to be NOP.
     According to 4.3.1: for FM=00, sub-instructions performed only by IU
     cannot be encoded in L-container.  */
  if (opcode->unit == IU)
    insn |= FM00 | (NOP << 15);           /* Right container.  */
  else
    insn = FM00 | (insn << 15) | NOP;     /* Left container.  */

  number_to_chars_bigendian (f, insn, 4);
  for (i = 0; i < fx->fc; i++)
    {
      if (fx->fix[i].reloc)
       {
         where = f - frag_now->fr_literal;
         if (fx->fix[i].size == 2)
           where += 2;

         if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
           fx->fix[i].operand |= 4096;

         /* If it's an R reloc, we may have to switch it to L.  */
         if ((fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R)
             && (opcode->unit != IU))
           fx->fix[i].operand |= 1024;

         fix_new_exp (frag_now,
                     where,
                     fx->fix[i].size,
                     &(fx->fix[i].exp),
                     fx->fix[i].pcrel,
                     fx->fix[i].operand|2048);
       }
    }
  fx->fc = 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int write_2_short ( struct d10v_opcode opcode1,
unsigned long  insn1,
struct d10v_opcode opcode2,
unsigned long  insn2,
packing_type  exec_type,
Fixups fx 
) [static]

Definition at line 990 of file tc-d10v.c.

{
  unsigned long insn;
  char *f;
  int i, j, where;

  if ((exec_type != PACK_PARALLEL)
      && ((opcode1->exec_type & PARONLY) || (opcode2->exec_type & PARONLY)))
    as_fatal (_("Instruction must be executed in parallel"));

  if ((opcode1->format & LONG_OPCODE) || (opcode2->format & LONG_OPCODE))
    as_fatal (_("Long instructions may not be combined."));

  switch (exec_type)
    {
    case PACK_UNSPEC:       /* Order not specified.  */
      if (opcode1->exec_type & ALONE)
       {
         /* Case of a short branch on a separate GAS line.  Pack with NOP.  */
         write_1_short (opcode1, insn1, fx->next);
         return 1;
       }
      if (Optimizing
         && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type))
       {
         /* Parallel.  */
         if (opcode1->unit == IU)
           insn = FM00 | (insn2 << 15) | insn1;
         else if (opcode2->unit == MU)
           insn = FM00 | (insn2 << 15) | insn1;
         else
           insn = FM00 | (insn1 << 15) | insn2;
       }
      else if (opcode1->unit == IU)
       /* Reverse sequential with IU opcode1 on right and done first.  */
       insn = FM10 | (insn2 << 15) | insn1;
      else
       /* Sequential with non-IU opcode1 on left and done first.  */
       insn = FM01 | (insn1 << 15) | insn2;
      break;

    case PACK_PARALLEL:
      if (opcode1->exec_type & SEQ || opcode2->exec_type & SEQ)
       as_fatal
         (_("One of these instructions may not be executed in parallel."));
      if (opcode1->unit == IU)
       {
         if (opcode2->unit == IU)
           as_fatal (_("Two IU instructions may not be executed in parallel"));
         if (!flag_warn_suppress_instructionswap)
           as_warn (_("Swapping instruction order"));
         insn = FM00 | (insn2 << 15) | insn1;
       }
      else if (opcode2->unit == MU)
       {
         if (opcode1->unit == MU)
           as_fatal (_("Two MU instructions may not be executed in parallel"));
         if (!flag_warn_suppress_instructionswap)
           as_warn (_("Swapping instruction order"));
         insn = FM00 | (insn2 << 15) | insn1;
       }
      else
       insn = FM00 | (insn1 << 15) | insn2;
      check_resource_conflict (opcode1, insn1, opcode2, insn2);
      break;

    case PACK_LEFT_RIGHT:
      if (opcode1->unit != IU)
       insn = FM01 | (insn1 << 15) | insn2;
      else if (opcode2->unit == MU || opcode2->unit == EITHER)
       {
         if (!flag_warn_suppress_instructionswap)
           as_warn (_("Swapping instruction order"));
         insn = FM10 | (insn2 << 15) | insn1;
       }
      else
       as_fatal (_("IU instruction may not be in the left container"));
      if (opcode1->exec_type & ALONE)
       as_warn (_("Instruction in R container is squashed by flow control instruction in L container."));
      break;

    case PACK_RIGHT_LEFT:
      if (opcode2->unit != MU)
       insn = FM10 | (insn1 << 15) | insn2;
      else if (opcode1->unit == IU || opcode1->unit == EITHER)
       {
         if (!flag_warn_suppress_instructionswap)
           as_warn (_("Swapping instruction order"));
         insn = FM01 | (insn2 << 15) | insn1;
       }
      else
       as_fatal (_("MU instruction may not be in the right container"));
      if (opcode2->exec_type & ALONE)
       as_warn (_("Instruction in R container is squashed by flow control instruction in L container."));
      break;

    default:
      as_fatal (_("unknown execution type passed to write_2_short()"));
    }

  f = frag_more (4);
  number_to_chars_bigendian (f, insn, 4);

  /* Process fixup chains.  fx refers to insn2 when j == 0, and to
     insn1 when j == 1.  Yes, it's reversed.  */

  for (j = 0; j < 2; j++)
    {
      for (i = 0; i < fx->fc; i++)
       {
         if (fx->fix[i].reloc)
           {
             where = f - frag_now->fr_literal;
             if (fx->fix[i].size == 2)
              where += 2;

             if (fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R
                /* A BFD_RELOC_D10V_10_PCREL_R relocation applied to
                   the instruction in the L container has to be
                   adjusted to BDF_RELOC_D10V_10_PCREL_L.  When
                   j==0, we're processing insn2's operands, so we
                   want to mark the operand if insn2 is *not* in the
                   R container.  When j==1, we're processing insn1's
                   operands, so we want to mark the operand if insn2
                   *is* in the R container.  Note that, if two
                   instructions are identical, we're never going to
                   swap them, so the test is safe.  */
                && j == ((insn & 0x7fff) == insn2))
              fx->fix[i].operand |= 1024;

             if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
              fx->fix[i].operand |= 4096;

             fix_new_exp (frag_now,
                        where,
                        fx->fix[i].size,
                        &(fx->fix[i].exp),
                        fx->fix[i].pcrel,
                        fx->fix[i].operand|2048);
           }
       }
      fx->fc = 0;
      fx = fx->next;
    }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void write_long ( unsigned long  insn,
Fixups fx 
) [static]

Definition at line 642 of file tc-d10v.c.

{
  int i, where;
  char *f = frag_more (4);

  insn |= FM11;
  number_to_chars_bigendian (f, insn, 4);

  for (i = 0; i < fx->fc; i++)
    {
      if (fx->fix[i].reloc)
       {
         where = f - frag_now->fr_literal;
         if (fx->fix[i].size == 2)
           where += 2;

         if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
           fx->fix[i].operand |= 4096;

         fix_new_exp (frag_now,
                     where,
                     fx->fix[i].size,
                     &(fx->fix[i].exp),
                     fx->fix[i].pcrel,
                     fx->fix[i].operand|2048);
       }
    }
  fx->fc = 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

const char comment_chars[] = ";"

Definition at line 28 of file tc-d10v.c.

Definition at line 104 of file tc-d10v.c.

int do_not_ignore_hash = 0 [static]

Definition at line 65 of file tc-d10v.c.

Definition at line 72 of file tc-d10v.c.

const char EXP_CHARS[] = "eE"

Definition at line 32 of file tc-d10v.c.

Fixups FixUps[2] [static]

Definition at line 62 of file tc-d10v.c.

Fixups* fixups [static]

Definition at line 63 of file tc-d10v.c.

Definition at line 80 of file tc-d10v.c.

Definition at line 76 of file tc-d10v.c.

const char FLT_CHARS[] = "dD"

Definition at line 33 of file tc-d10v.c.

const char line_comment_chars[] = "#"

Definition at line 29 of file tc-d10v.c.

Definition at line 30 of file tc-d10v.c.

size_t md_longopts_size = sizeof (md_longopts)

Definition at line 101 of file tc-d10v.c.

const pseudo_typeS md_pseudo_table[]
Initial value:
{
  { "word",   d10v_dot_word,       2 },
  { NULL,       NULL,           0 }
}

Definition at line 1731 of file tc-d10v.c.

const char* md_shortopts = "O"

Definition at line 31 of file tc-d10v.c.

Definition at line 35 of file tc-d10v.c.

Definition at line 1148 of file tc-d10v.c.

Definition at line 1149 of file tc-d10v.c.

segT prev_seg = 0 [static]

Definition at line 1151 of file tc-d10v.c.

subsegT prev_subseg [static]

Definition at line 1150 of file tc-d10v.c.