OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [gas/] [config/] [tc-epiphany.c] - Blame information for rev 163

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 163 khays
/* tc-epiphany.c -- Assembler for the Adapteva EPIPHANY
2
   Copyright 2009, 2011 Free Software Foundation, Inc.
3
   Contributed by Embecosm on behalf of Adapteva, Inc.
4
 
5
   This file is part of GAS, the GNU Assembler.
6
 
7
   GAS is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3, or (at your option)
10
   any later version.
11
 
12
   GAS is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
   GNU General Public License for more details.
16
 
17
   You should have received a copy of the GNU General Public License
18
   along with GAS; see the file COPYING.  If not, write to
19
   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
20
   Boston, MA 02110-1301, USA.  */
21
 
22
#include "as.h"
23
#include "subsegs.h"
24
#include "symcat.h"
25
#include "opcodes/epiphany-desc.h"
26
#include "opcodes/epiphany-opc.h"
27
#include "cgen.h"
28
#include "elf/common.h"
29
#include "elf/epiphany.h"
30
#include "dwarf2dbg.h"
31
#include "libbfd.h"
32
 
33
/* Structure to hold all of the different components describing
34
   an individual instruction.  */
35
typedef struct
36
{
37
  const CGEN_INSN *     insn;
38
  const CGEN_INSN *     orig_insn;
39
  CGEN_FIELDS           fields;
40
#if CGEN_INT_INSN_P
41
  CGEN_INSN_INT         buffer [1];
42
#define INSN_VALUE(buf) (*(buf))
43
#else
44
  unsigned char         buffer [CGEN_MAX_INSN_SIZE];
45
#define INSN_VALUE(buf) (buf)
46
#endif
47
  char *                addr;
48
  fragS *               frag;
49
  int                   num_fixups;
50
  fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
51
  int                   indices [MAX_OPERAND_INSTANCES];
52
}
53
epiphany_insn;
54
 
55
const char comment_chars[]        = ";";
56
const char line_comment_chars[]   = "#";
57
const char line_separator_chars[] = "`";
58
const char EXP_CHARS[]            = "eE";
59
const char FLT_CHARS[]            = "fFdD";
60
 
61
/* Flag to detect when switching to code section where insn alignment is
62
   implied.  */
63
static bfd_boolean force_code_align = FALSE;
64
 
65
static void
66
epiphany_elf_section_rtn (int i)
67
{
68
  obj_elf_section (i);
69
 
70
  if (force_code_align)
71
    {
72
      /* The s_align_ptwo function expects that we are just after a .align
73
         directive and it will either try and read the align value or stop
74
         if end of line so we must fake it out so it thinks we are at the
75
         end of the line.  */
76
      char *old_input_line_pointer = input_line_pointer;
77
 
78
      input_line_pointer = "\n";
79
      s_align_ptwo (1);
80
      force_code_align = FALSE;
81
 
82
      /* Restore.  */
83
      input_line_pointer = old_input_line_pointer;
84
    }
85
}
86
 
87
static void
88
epiphany_elf_section_text (int i)
89
{
90
  char *old_input_line_pointer;
91
 
92
  obj_elf_text (i);
93
 
94
  /* The s_align_ptwo function expects that we are just after a .align
95
     directive and it will either try and read the align value or stop if
96
     end of line so we must fake it out so it thinks we are at the end of
97
     the line.  */
98
  old_input_line_pointer = input_line_pointer;
99
  input_line_pointer = "\n";
100
  s_align_ptwo (1);
101
  force_code_align = FALSE;
102
  /* Restore.  */
103
  input_line_pointer = old_input_line_pointer;
104
}
105
 
106
/* The target specific pseudo-ops which we support.  */
107
const pseudo_typeS md_pseudo_table[] =
108
{
109
    { "text",   epiphany_elf_section_text,  0 },
110
    { "sect",   epiphany_elf_section_rtn,   0 },
111
    /* .word should be 32 bits.  */
112
    { "word",       cons, 4 },
113
    { "cpu",        s_ignore,         0 },
114
    { "thumb_func", s_ignore,         0 },
115
    { "code",       s_ignore,         0 },
116
    { NULL,         NULL,             0 }
117
};
118
 
119
 
120
 
121
enum options
122
{
123
  OPTION_CPU_EPIPHANY = OPTION_MD_BASE,
124
  OPTION_CPU_EPIPHANY16
125
};
126
 
127
struct option md_longopts[] =
128
{
129
  { "mepiphany ",  no_argument, NULL, OPTION_CPU_EPIPHANY },
130
  { "mepiphany16", no_argument, NULL, OPTION_CPU_EPIPHANY16 },
131
  { NULL,          no_argument, NULL, 0 },
132
};
133
 
134
size_t md_longopts_size = sizeof (md_longopts);
135
 
136
const char * md_shortopts = "";
137
 
138
int
139
md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED)
140
{
141
  return 0;      /* No target-specific options.  */
142
}
143
 
144
void
145
md_show_usage (FILE * stream)
146
{
147
  fprintf (stream, _("EPIPHANY specific command line options:\n"));
148
}
149
 
150
 
151
void
152
md_begin (void)
153
{
154
  /* Initialize the `cgen' interface.  */
155
 
156
  /* Set the machine number and endian.  */
157
  gas_cgen_cpu_desc = epiphany_cgen_cpu_open (CGEN_CPU_OPEN_MACHS,
158
                                           bfd_mach_epiphany32,
159
                                           CGEN_CPU_OPEN_ENDIAN,
160
                                           CGEN_ENDIAN_LITTLE,
161
                                           CGEN_CPU_OPEN_END);
162
  epiphany_cgen_init_asm (gas_cgen_cpu_desc);
163
 
164
  /* This is a callback from cgen to gas to parse operands.  */
165
  cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
166
 
167
  /* Set the machine type.  */
168
  bfd_default_set_arch_mach (stdoutput, bfd_arch_epiphany, bfd_mach_epiphany32);
169
}
170
 
171
valueT
172
md_section_align (segT segment, valueT size)
173
{
174
  int align = bfd_get_section_alignment (stdoutput, segment);
175
 
176
  return ((size + (1 << align) - 1) & (-1 << align));
177
}
178
 
179
 
180
/* Functions concerning relocs.  */
181
 
182
long
183
md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED)
184
{
185
  abort ();
186
}
187
 
188
/* Write a value out to the object file, using the appropriate endianness.  */
189
 
190
void
191
md_number_to_chars (char * buf, valueT val, int n)
192
{
193
  number_to_chars_littleendian (buf, val, n);
194
}
195
 
196
int
197
epiphany_elf_section_flags (int flags,
198
                            int attr ATTRIBUTE_UNUSED,
199
                            int type ATTRIBUTE_UNUSED)
200
{
201
  /* This is used to detect when the section changes to an executable section.
202
     This function is called by the elf section processing.  When we note an
203
     executable section specifier we set an internal flag to denote when
204
     word alignment should be forced.  */
205
  if (flags & SEC_CODE)
206
    force_code_align = TRUE;
207
 
208
  return flags;
209
}
210
 
211
/* Non-zero if we are generating PIC code.  */
212
int pic_code;
213
 
214
/* Epiphany er_flags.  */
215
static int epiphany_flags = 0;
216
 
217
/* Relocations against symbols are done in two
218
   parts, with a HI relocation and a LO relocation.  Each relocation
219
   has only 16 bits of space to store an addend.  This means that in
220
   order for the linker to handle carries correctly, it must be able
221
   to locate both the HI and the LO relocation.  This means that the
222
   relocations must appear in order in the relocation table.
223
 
224
   In order to implement this, we keep track of each unmatched HI
225
   relocation.  We then sort them so that they immediately precede the
226
   corresponding LO relocation.  */
227
 
228
struct epiphany_hi_fixup
229
{
230
  /* Next HI fixup.  */
231
  struct epiphany_hi_fixup *next;
232
 
233
  /* This fixup.  */
234
  fixS *fixp;
235
 
236
  /* The section this fixup is in.  */
237
  segT seg;
238
};
239
 
240
 
241
#define GOT_NAME "_GLOBAL_OFFSET_TABLE_"
242
static symbolS * GOT_symbol;
243
 
244
static inline bfd_boolean
245
epiphany_PIC_related_p (symbolS *sym)
246
{
247
  expressionS *exp;
248
 
249
  if (! sym)
250
    return FALSE;
251
 
252
  if (sym == GOT_symbol)
253
    return TRUE;
254
 
255
  exp = symbol_get_value_expression (sym);
256
 
257
  return (exp->X_op == O_PIC_reloc
258
          || exp->X_md == BFD_RELOC_EPIPHANY_SIMM24
259
          || exp->X_md == BFD_RELOC_EPIPHANY_SIMM8
260
          || epiphany_PIC_related_p (exp->X_add_symbol)
261
          || epiphany_PIC_related_p (exp->X_op_symbol));
262
}
263
 
264
/* Perform target dependent relocations that are done at compile time.
265
   There aren't very many of these.  */
266
 
267
void
268
epiphany_apply_fix (fixS *fixP, valueT *valP, segT seg)
269
{
270
  if (fixP->fx_addsy == (symbolS *) NULL)
271
    fixP->fx_done = 1;
272
 
273
  if (((int) fixP->fx_r_type < (int) BFD_RELOC_UNUSED)
274
      && fixP->fx_done)
275
    {
276
      /* Install EPIPHANY-dependent relocations HERE because nobody else
277
         will.  */
278
      char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
279
      unsigned char *insn = (unsigned char *)where;
280
      valueT value = * valP;
281
 
282
      switch (fixP->fx_r_type)
283
        {
284
        default:
285
          break;
286
 
287
        case BFD_RELOC_NONE:
288
          return;
289
 
290
        case BFD_RELOC_EPIPHANY_SIMM11:
291
          where[0] = where[0] | ((value & 1) << 7);
292
          where[1] = where[1] | ((value & 6) >> 1);
293
          where[2] = (value >> 3) & 0xff;
294
          return;
295
 
296
        case BFD_RELOC_EPIPHANY_IMM11:
297
          where[0] = where[0] | ((value & 1) << 7);
298
          where[1] = where[1] | ((value & 6) >> 1);
299
          where[2] = (value >> 3) & 0xff;
300
          return;
301
 
302
        case BFD_RELOC_EPIPHANY_SIMM8:
303
          md_number_to_chars (where+1, value>>1, 1);
304
          return;
305
 
306
        case BFD_RELOC_EPIPHANY_SIMM24:
307
          md_number_to_chars (where+1, value>>1, 3);
308
          return;
309
 
310
        case BFD_RELOC_EPIPHANY_HIGH:
311
          value >>= 16;
312
          /* fall thru */
313
        case BFD_RELOC_EPIPHANY_LOW:
314
          value = (((value & 0xff) << 5) | insn[0])
315
            | (insn[1] << 8)
316
            | ((value & 0xff00) << 12)
317
            | (insn[2] << 16);
318
          md_number_to_chars (where, value, 3);
319
          return;
320
        }
321
    }
322
 
323
  /* Just do the default if we can't special case.  */
324
  return gas_cgen_md_apply_fix (fixP, valP, seg);
325
}
326
 
327
 
328
/* This is called from HANDLE_ALIGN in write.c.  Fill in the contents
329
   of an rs_align_code fragment.  0x01a2 is 16-bit pattern for a "nop".  */
330
 
331
static const unsigned char nop_pattern[] = { 0xa2, 0x01 };
332
 
333
void
334
epiphany_handle_align (fragS *fragp)
335
{
336
  int bytes, fix;
337
  char *p;
338
 
339
  if (fragp->fr_type != rs_align_code)
340
    return;
341
 
342
  bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
343
  p = fragp->fr_literal + fragp->fr_fix;
344
  fix = 0;
345
 
346
  if (bytes & 1)
347
    {
348
      fix = 1;
349
      *p++ = 0;
350
      bytes--;
351
    }
352
 
353
  if (bytes & 2)
354
    {
355
      memcpy (p, nop_pattern, 2);
356
      p += 2;
357
      bytes -= 2;
358
      fix += 2;
359
    }
360
  fragp->fr_fix += fix;
361
}
362
 
363
/* Read a comma separated incrementing list of register names
364
   and form a bit mask of upto 15 registers 0..14.  */
365
 
366
static const char *
367
parse_reglist (const char * s, int * mask)
368
{
369
  int regmask = 0;
370
 
371
  while (*s)
372
    {
373
      long value;
374
 
375
      while (*s == ' ')
376
        ++s;
377
 
378
      /* Parse a list with "," or "}" as limiters.  */
379
      const char *errmsg
380
        = cgen_parse_keyword (gas_cgen_cpu_desc, &s,
381
                              &epiphany_cgen_opval_gr_names, &value);
382
      if (errmsg)
383
        return errmsg;
384
 
385
      if (value > 15)
386
        return _("register number too large for push/pop");
387
 
388
      regmask |= 1 << value;
389
      if (regmask < *mask)
390
        return _("register is out of order");
391
      *mask |= regmask;
392
 
393
      while (*s==' ')
394
        ++s;
395
 
396
      if (*s == '}')
397
        return NULL;
398
      else if (*s++ == ',')
399
        continue;
400
      else
401
        return _("bad register list");
402
    }
403
 
404
  return _("malformed reglist in push/pop");
405
}
406
 
407
 
408
void
409
md_assemble (char *str)
410
{
411
  epiphany_insn insn;
412
  char *errmsg = 0;
413
  const char * pperr = 0;
414
  int regmask=0, push=0, pop=0;
415
 
416
  memset (&insn, 0, sizeof (insn));
417
 
418
  /* Special-case push/pop instruction macros.  */
419
  if (0 == strncmp (str, "push {", 6))
420
    {
421
      char * s = str + 6;
422
      push = 1;
423
      pperr = parse_reglist (s, &regmask);
424
    }
425
  else if (0 == strncmp (str, "pop {", 5))
426
    {
427
      char * s = str + 5;
428
      pop = 1;
429
      pperr = parse_reglist (s, &regmask);
430
    }
431
 
432
  if (pperr)
433
    {
434
      as_bad ("%s", pperr);
435
      return;
436
    }
437
 
438
  if (push && regmask)
439
    {
440
      char buff[20];
441
      int i,p ATTRIBUTE_UNUSED;
442
 
443
      md_assemble ("mov r15,4");
444
      md_assemble ("sub sp,sp,r15");
445
 
446
      for (i = 0, p = 1; i <= 15; ++i, regmask >>= 1)
447
        {
448
          if (regmask == 1)
449
            sprintf (buff, "str r%d,[sp]", i); /* Last one.  */
450
          else if (regmask & 1)
451
            sprintf (buff, "str r%d,[sp],-r15", i);
452
          else
453
            continue;
454
          md_assemble (buff);
455
        }
456
      return;
457
    }
458
  else if (pop && regmask)
459
    {
460
      char buff[20];
461
      int i,p;
462
 
463
      md_assemble ("mov r15,4");
464
 
465
      for (i = 15, p = 1 << 15; i >= 0; --i, p >>= 1)
466
        if (regmask & p)
467
          {
468
            sprintf (buff, "ldr r%d,[sp],+r15", i);
469
            md_assemble (buff);
470
          }
471
      return;
472
    }
473
 
474
  /* Initialize GAS's cgen interface for a new instruction.  */
475
  gas_cgen_init_parse ();
476
 
477
  insn.insn = epiphany_cgen_assemble_insn
478
    (gas_cgen_cpu_desc, str, &insn.fields, insn.buffer, & errmsg);
479
 
480
  if (!insn.insn)
481
    {
482
      as_bad ("%s", errmsg);
483
      return;
484
    }
485
 
486
  if (CGEN_INSN_BITSIZE (insn.insn) == 32)
487
    {
488
      /* Doesn't really matter what we pass for RELAX_P here.  */
489
      gas_cgen_finish_insn (insn.insn, insn.buffer,
490
                            CGEN_FIELDS_BITSIZE (&insn.fields), 1, NULL);
491
    }
492
  else
493
    {
494
      if (CGEN_INSN_BITSIZE (insn.insn) != 16)
495
        abort ();
496
 
497
      insn.orig_insn = insn.insn;
498
 
499
      gas_cgen_finish_insn (insn.orig_insn, insn.buffer,
500
                            CGEN_FIELDS_BITSIZE (&insn.fields),
501
                            1 /* relax_p  */, NULL);
502
    }
503
 
504
  /* Checks for behavioral restrictions on LD/ST instructions.  */
505
#define DISPMOD _("destination register modified by displacement-post-modified address")
506
#define LDSTODD _("ldrd/strd requires even:odd register pair")
507
 
508
  /* Helper macros for spliting apart instruction fields.  */
509
#define ADDR_POST_MODIFIED(i) (((i) >> 25) & 0x1)
510
#define ADDR_SIZE(i)          (((i) >>  5) &   3)
511
#define ADDR_LOADSTORE(i)     (((i) >>  4) & 0x1)
512
 
513
  switch (insn.buffer[0] & 0xf)
514
    {
515
      /* Post-modify registers cannot be destinations.  */
516
    case OP4_LDSTR16P:
517
      {
518
        if (ADDR_LOADSTORE (insn.buffer[0]) ==  OP_LOAD)
519
          if (insn.fields.f_rd == insn.fields.f_rn /* Postmodify dest.  */
520
              || (insn.fields.f_rd+1 == insn.fields.f_rn
521
                  && ADDR_SIZE (insn.buffer[0]) == OPW_DOUBLE))
522
            {
523
              as_bad ("%s", DISPMOD);
524
              return;
525
            }
526
        if ((insn.fields.f_rd & 1) /* Odd-numbered register...  */
527
            && insn.fields.f_wordsize == OPW_DOUBLE) /* ...and 64 bit transfer.  */
528
          {
529
            as_bad ("%s", LDSTODD);
530
            return;
531
          }
532
        break;
533
      }
534
 
535
    case OP4_LDSTRP:
536
      {
537
        if (ADDR_LOADSTORE (insn.buffer[0]) == OP_LOAD) /* A load.  */
538
          if (insn.fields.f_rd6 == insn.fields.f_rn6 /* Postmodify dest.  */
539
              /* Check for regpair postindexed.  */
540
              || (insn.fields.f_rd6 + 1 == insn.fields.f_rn6
541
                  && ADDR_SIZE (insn.buffer[0]) == OPW_DOUBLE))
542
            {
543
              as_bad ("%s", DISPMOD);
544
              return;
545
            }
546
        if ((insn.fields.f_rd6 & 1) && ADDR_SIZE (insn.buffer[0]) == OPW_DOUBLE)
547
          /* Lsb of RD odd and 64 bit transfer.  */
548
          {
549
            as_bad ("%s", LDSTODD);
550
            return;
551
          }
552
        break;
553
      }
554
 
555
    case OP4_LDSTR16X:
556
    case OP4_LDSTR16D:
557
      {
558
        /* Check for unaligned load/store double.  */
559
        if ((insn.fields.f_rd & 1) && ADDR_SIZE (insn.buffer[0]) == OPW_DOUBLE)
560
          /* Lsb of RD odd and 64 bit transfer.  */
561
          {
562
            as_bad ("%s", LDSTODD);
563
            return;
564
          }
565
        break;
566
      }
567
 
568
    case OP4_LDSTRD:
569
      {
570
        /* Check for load to post-modified register.  */
571
        if (ADDR_LOADSTORE (insn.buffer[0]) == OP_LOAD /* A load.  */
572
            && ADDR_POST_MODIFIED (insn.buffer[0]) == PMOD_POST /* Post-mod.  */
573
            && (insn.fields.f_rd6 == insn.fields.f_rn6
574
                || (insn.fields.f_rd6+1 == insn.fields.f_rn6
575
                    && ADDR_SIZE (insn.buffer[0]) == OPW_DOUBLE)))
576
          {
577
            as_bad ("%s", DISPMOD);
578
            return;
579
          }
580
      }
581
      /* fall-thru.  */
582
 
583
    case OP4_LDSTRX:
584
      {
585
        /* Check for unaligned load/store double.  */
586
        if ((insn.fields.f_rd6 & 1) && ADDR_SIZE (insn.buffer[0]) == OPW_DOUBLE)
587
          {
588
            as_bad ("%s", LDSTODD);
589
            return;
590
          }
591
        break;
592
      }
593
 
594
    default:
595
      break;
596
    }
597
}
598
 
599
/* The syntax in the manual says constants begin with '#'.
600
   We just ignore it.  */
601
 
602
void
603
md_operand (expressionS *expressionP)
604
{
605
  if (*input_line_pointer == '#')
606
    {
607
      input_line_pointer++;
608
      expression (expressionP);
609
    }
610
}
611
 
612
symbolS *
613
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
614
{
615
  return NULL;
616
}
617
 
618
/* Interface to relax_segment.  */
619
 
620
/* FIXME: Build table by hand, get it working, then machine generate.  */
621
 
622
const relax_typeS md_relax_table[] =
623
{
624
  /* The fields are:
625
     1) most positive reach of this state,
626
     2) most negative reach of this state,
627
     3) how many bytes this mode will add to the size of the current frag
628
     4) which index into the table to try if we can't fit into this one.  */
629
 
630
  /* The first entry must be unused because an `rlx_more' value of zero ends
631
     each list.  */
632
  {1, 1, 0, EPIPHANY_RELAX_NONE},
633
  {0, 0, 0, EPIPHANY_RELAX_NONE},    /* Also a dummy entry to indicate we need to expand codes.  */
634
 
635
  /* The displacement used by GAS is from the end of the 2 byte insn,
636
     so we subtract 2 from the following.  */
637
  /* 16 bit insn, 8 bit disp -> +127 words, -128 words.  */
638
  {0x00000100 - 1 - 2, -0x00000100 - 2, 0, EPIPHANY_RELAX_BRANCH_LONG },
639
  /* 32 bit insn, 24 bit disp -> 25 bit range.  */
640
  {0x01000000 - 1 - 2, -0x01000000 - 2, 2, EPIPHANY_RELAX_NONE },
641
 
642
  /* addi/subi 3 bits -4..+3.  */
643
  {    3,           -4,0, EPIPHANY_RELAX_ARITH_SIMM11 },
644
  /* addi/subi 11 bits.  */
645
  {  1023,       -1024,2, EPIPHANY_RELAX_NONE },
646
 
647
  /* mov r,imm8.  */
648
  {   255,           0,0, EPIPHANY_RELAX_MOV_IMM16 },
649
  /* mov r,imm16. */
650
  { 65535,           0,2, EPIPHANY_RELAX_NONE },
651
 
652
  /* ld/st rd,[rn,imm3].  */
653
  {     7,           0,0, EPIPHANY_RELAX_LDST_IMM11},
654
  /* ld/st rd,[rn,imm11].  */
655
  {  2047,           0,2, EPIPHANY_RELAX_NONE }
656
 
657
};
658
 
659
static const EPIPHANY_RELAX_TYPES relax_insn[] =
660
{
661
  EPIPHANY_RELAX_BRANCH_SHORT,  /* OP4_BRANCH16 */
662
  EPIPHANY_RELAX_NONE,          /* OP4_LDSTR16X */
663
  EPIPHANY_RELAX_NONE,          /* OP4_FLOW16 */
664
  EPIPHANY_RELAX_ARITH_SIMM3,   /* OP4_IMM16 - special */
665
  EPIPHANY_RELAX_LDST_IMM3,     /* OP4_LDSTR16D */
666
  EPIPHANY_RELAX_NONE,          /* OP4_LDSTR126P */
667
  EPIPHANY_RELAX_NONE,          /* OP4_LSHIFT16 */
668
  EPIPHANY_RELAX_NONE,          /* OP4_DSP16 */
669
  EPIPHANY_RELAX_BRANCH_LONG,   /* OP4_BRANCH */
670
  EPIPHANY_RELAX_NONE,          /* OP4_LDSTRX */
671
  EPIPHANY_RELAX_NONE,          /* OP4_ALU16 */
672
  EPIPHANY_RELAX_ARITH_SIMM11,  /* OP4_IMM32 - special */
673
  EPIPHANY_RELAX_LDST_IMM11,    /* OP4_LDSTRD */
674
  EPIPHANY_RELAX_NONE,          /* OP4_LDSTRP */
675
  EPIPHANY_RELAX_NONE,          /* OP4_ASHIFT16 */
676
  EPIPHANY_RELAX_NONE           /* OP4_MISC */
677
};
678
 
679
long
680
epiphany_relax_frag (segT segment, fragS *fragP, long stretch)
681
{
682
  /* Address of branch insn.  */
683
  long address ATTRIBUTE_UNUSED = fragP->fr_address + fragP->fr_fix - 2;
684
  long growth = 0;
685
 
686
  if (fragP->fr_subtype == EPIPHANY_RELAX_NEED_RELAXING)
687
    {
688
      EPIPHANY_RELAX_TYPES subtype = relax_insn [*fragP->fr_opcode & 0xf];
689
 
690
      /* Special cases add/sub vs mov immediates.  */
691
      if (subtype == EPIPHANY_RELAX_ARITH_SIMM3)
692
        {
693
          if ((*fragP->fr_opcode & 0x10) == 0)
694
            subtype = EPIPHANY_RELAX_MOV_IMM8;
695
        }
696
      else if (subtype == EPIPHANY_RELAX_ARITH_SIMM11)
697
        {
698
          if ((*fragP->fr_opcode & 0x10) == 0)
699
            subtype = EPIPHANY_RELAX_MOV_IMM16;
700
        }
701
 
702
      /* Remember refinements for the future.  */
703
      fragP->fr_subtype = subtype;
704
    }
705
 
706
  growth = relax_frag (segment, fragP, stretch);
707
 
708
  return growth;
709
}
710
 
711
/* Return an initial guess of the length by which a fragment must grow to
712
   hold a branch to reach its destination.
713
   Also updates fr_type/fr_subtype as necessary.
714
 
715
   Called just before doing relaxation.
716
   Any symbol that is now undefined will not become defined.
717
   The guess for fr_var is ACTUALLY the growth beyond fr_fix.
718
   Whatever we do to grow fr_fix or fr_var contributes to our returned value.
719
   Although it may not be explicit in the frag, pretend fr_var starts
720
   with a 0 value.  */
721
 
722
int
723
md_estimate_size_before_relax (fragS *fragP, segT segment)
724
{
725
  /* The only thing we have to handle here are symbols outside of the
726
     current segment.  They may be undefined or in a different segment in
727
     which case linker scripts may place them anywhere.
728
     However, we can't finish the fragment here and emit the reloc as insn
729
     alignment requirements may move the insn about.  */
730
  if (S_GET_SEGMENT (fragP->fr_symbol) != segment
731
      || S_IS_EXTERNAL (fragP->fr_symbol)
732
      || S_IS_WEAK (fragP->fr_symbol))
733
    {
734
      /* The symbol is undefined in this segment.  Change the
735
         relaxation subtype to the max allowable and leave all further
736
         handling to md_convert_frag.  */
737
 
738
      EPIPHANY_RELAX_TYPES subtype;
739
      /* We haven't relaxed this at all, so the relaxation type may be
740
         completely wrong.  Set the subtype correctly.  */
741
      epiphany_relax_frag (segment, fragP, 0);
742
      subtype = fragP->fr_subtype;
743
 
744
      switch (subtype)
745
        {
746
        case EPIPHANY_RELAX_LDST_IMM3:
747
          subtype = EPIPHANY_RELAX_LDST_IMM11;
748
          break;
749
        case EPIPHANY_RELAX_BRANCH_SHORT:
750
          subtype = EPIPHANY_RELAX_BRANCH_LONG;
751
          break;
752
        case EPIPHANY_RELAX_MOV_IMM8:
753
          subtype = EPIPHANY_RELAX_MOV_IMM16;
754
          break;
755
        case EPIPHANY_RELAX_ARITH_SIMM3:
756
          subtype = EPIPHANY_RELAX_ARITH_SIMM11;
757
          break;
758
 
759
        default:
760
          break;
761
        }
762
 
763
      fragP->fr_subtype = subtype;
764
 
765
      {
766
        const CGEN_INSN *insn;
767
        int i;
768
 
769
        /* Update the recorded insn.  */
770
 
771
        for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++)
772
          {
773
            if ((strcmp (CGEN_INSN_MNEMONIC (insn),
774
                         CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
775
                 == 0)
776
                && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED))
777
              break;
778
          }
779
 
780
        if (i == 4)
781
          abort ();
782
 
783
        fragP->fr_cgen.insn = insn;
784
      }
785
    }
786
 
787
  return md_relax_table[fragP->fr_subtype].rlx_length;
788
}
789
 
790
/* *FRAGP has been relaxed to its final size, and now needs to have
791
   the bytes inside it modified to conform to the new size.
792
 
793
   Called after relaxation is finished.
794
   fragP->fr_type == rs_machine_dependent.
795
   fragP->fr_subtype is the subtype of what the address relaxed to.  */
796
 
797
void
798
md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
799
                 segT sec,
800
                 fragS *fragP)
801
{
802
  char *opcode;
803
  char *displacement;
804
  int target_address;
805
  int opcode_address;
806
  int extension;
807
  int addend;
808
  int opindx = -1;
809
 
810
  opcode = fragP->fr_opcode;
811
 
812
  /* Address opcode resides at in file space.  */
813
  opcode_address = fragP->fr_address + fragP->fr_fix - 2;
814
  extension = 0;
815
  displacement = &opcode[1];
816
 
817
  /* Set up any addend necessary for branches.  */
818
  if (S_GET_SEGMENT (fragP->fr_symbol) != sec
819
      || S_IS_EXTERNAL (fragP->fr_symbol)
820
      || S_IS_WEAK (fragP->fr_symbol))
821
    {
822
      /* Symbol must be resolved by linker.  */
823
      if (fragP->fr_offset & 1)
824
        as_warn (_("Addend to unresolved symbol not on word boundary."));
825
      addend = 0;
826
    }
827
  else
828
    {
829
      /* Address we want to reach in file space.  */
830
      target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
831
      addend = (target_address - (opcode_address & -2));
832
    }
833
 
834
  /* Do all the housekeeping for frag conversions. */
835
  switch (fragP->fr_subtype)
836
    {
837
    case EPIPHANY_RELAX_ARITH_SIMM11:
838
      *opcode |= OP4_IMM32;
839
      displacement = &opcode[0];
840
      extension += 3;
841
 
842
      addend
843
        = (((addend & 0x7) << 7)
844
           | opcode[0]
845
           | ((addend & 0x7f8) << 13)
846
           | (opcode[1] << 8)
847
           | (opcode[2] << 16));
848
 
849
      opindx = EPIPHANY_OPERAND_SIMM11;
850
      break;
851
 
852
    case EPIPHANY_RELAX_BRANCH_LONG:
853
      /* Branches differ only in low nibble of instruction being 8 not 0.
854
         24 bit displacement goes to bytes 1..3 .  */
855
      *opcode |= OP4_BRANCH;
856
      extension += 2;
857
 
858
      addend >>= 1;             /* Convert to word offset.  */
859
      opindx = EPIPHANY_OPERAND_SIMM24;
860
      break;
861
 
862
    case EPIPHANY_RELAX_MOV_IMM16:
863
      *opcode |=  OP4_IMM32;
864
      extension += 3;
865
 
866
      addend
867
        = (((addend & 0xff00) << 12)
868
           | (opcode[2] << 16)
869
           | ((addend & 0x00ff) << 5)
870
           | (opcode[1] << 8)
871
           | opcode[0]);
872
      displacement = &opcode[0];
873
      opindx = EPIPHANY_OPERAND_IMM16;
874
      break;
875
 
876
    case EPIPHANY_RELAX_LDST_IMM11:
877
      *opcode |= OP4_LDSTRD;
878
      displacement = &opcode[0];
879
      extension += 3;
880
 
881
      if (addend < 0)
882
        /* Convert twos-complement address value to sign-magnitude.  */
883
        addend = (-addend & 0x7ff) | 0x800;
884
 
885
      addend
886
        = (((addend & 0x7) << 5)
887
           | opcode[0]
888
           | ((addend & 0xff8) << 13)
889
           | (opcode[1] << 8)
890
           | (opcode[2] << 16));
891
 
892
      opindx = EPIPHANY_OPERAND_DISP11;
893
      break;
894
 
895
    case EPIPHANY_RELAX_ARITH_SIMM3:
896
      addend = ((addend & 7) << 5) | opcode[0];
897
      opindx = EPIPHANY_OPERAND_SIMM3;
898
      break;
899
 
900
    case EPIPHANY_RELAX_LDST_IMM3:
901
      addend = ((addend & 7) << 5) | opcode[0];
902
      opindx = EPIPHANY_OPERAND_DISP3;
903
 
904
    case EPIPHANY_RELAX_BRANCH_SHORT:
905
      addend >>= 1;             /* Convert to a word offset.  */
906
      displacement = & opcode[1];
907
      opindx = EPIPHANY_OPERAND_SIMM8;
908
      break;
909
 
910
    case EPIPHANY_RELAX_MOV_IMM8:
911
      addend
912
        = (((addend & 0xff) << 5)
913
           | opcode[0]
914
           | (opcode[1] << 8));
915
      opindx = EPIPHANY_OPERAND_IMM8;
916
      break;
917
 
918
    case EPIPHANY_RELAX_NONE:
919
    case EPIPHANY_RELAX_NEED_RELAXING:
920
    default:                    /* Anything else?  */
921
      as_bad ("unrecognized fragment subtype");
922
      break;
923
    }
924
 
925
  /* Create a relocation for symbols that must be resolved by the linker.
926
     Otherwise output the completed insn.  */
927
 
928
  if (S_GET_SEGMENT (fragP->fr_symbol) != sec
929
      || S_IS_EXTERNAL (fragP->fr_symbol)
930
      || S_IS_WEAK (fragP->fr_symbol))
931
    {
932
      fixS *fixP;
933
      const CGEN_OPERAND *operand
934
        = cgen_operand_lookup_by_num (gas_cgen_cpu_desc, opindx);
935
      bfd_reloc_code_real_type reloc_type;
936
 
937
      gas_assert (fragP->fr_cgen.insn != 0);
938
 
939
      reloc_type = md_cgen_lookup_reloc (fragP->fr_cgen.insn, operand, NULL);
940
 
941
      fixP = gas_cgen_record_fixup (fragP,
942
                                    /* Offset of insn in frag.  */
943
                                    (opcode - fragP->fr_literal),
944
                                    fragP->fr_cgen.insn,
945
                                    CGEN_INSN_BITSIZE (fragP->fr_cgen.insn) / 8,
946
                                    operand,
947
                                    reloc_type,
948
                                    fragP->fr_symbol, fragP->fr_offset);
949
      fixP->fx_r_type = fixP->fx_cgen.opinfo;
950
    }
951
 
952
  md_number_to_chars (displacement, (valueT) addend, extension + 1);
953
 
954
  fragP->fr_fix += (extension & -2); /* 0,2 or 4 bytes added.  */
955
}
956
 
957
 
958
/* Functions concerning relocs.  */
959
 
960
/* The location from which a PC relative jump should be calculated,
961
   given a PC relative reloc.  */
962
 
963
long
964
md_pcrel_from_section (fixS *fixP, segT sec)
965
{
966
  if (fixP->fx_addsy != (symbolS *) NULL
967
      && (!S_IS_DEFINED (fixP->fx_addsy)
968
          || (S_GET_SEGMENT (fixP->fx_addsy) != sec)
969
          || S_IS_EXTERNAL (fixP->fx_addsy)
970
          || S_IS_WEAK (fixP->fx_addsy)))
971
    return 0;
972
 
973
  return fixP->fx_frag->fr_address + fixP->fx_where;
974
}
975
 
976
/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
977
   Returns BFD_RELOC_NONE if no reloc type can be found.
978
   *FIXP may be modified if desired.  */
979
 
980
bfd_reloc_code_real_type
981
md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED,
982
                      const CGEN_OPERAND *operand,
983
                      fixS *fixP ATTRIBUTE_UNUSED)
984
{
985
  switch (operand->type)
986
    {
987
    case EPIPHANY_OPERAND_SIMM11:
988
      return BFD_RELOC_EPIPHANY_SIMM11;
989
    case EPIPHANY_OPERAND_DISP11:
990
      return BFD_RELOC_EPIPHANY_IMM11;
991
 
992
    case EPIPHANY_OPERAND_SIMM8:
993
      return BFD_RELOC_EPIPHANY_SIMM8;
994
    case EPIPHANY_OPERAND_SIMM24:
995
      return BFD_RELOC_EPIPHANY_SIMM24;
996
 
997
    case EPIPHANY_OPERAND_IMM8:
998
      return BFD_RELOC_EPIPHANY_IMM8;
999
 
1000
    case EPIPHANY_OPERAND_IMM16:
1001
      if (0 == strcmp ("movt", CGEN_INSN_MNEMONIC (insn)))
1002
        return BFD_RELOC_EPIPHANY_HIGH;
1003
      else if (0 == strcmp ("mov", CGEN_INSN_MNEMONIC (insn)))
1004
        return BFD_RELOC_EPIPHANY_LOW;
1005
      else
1006
        as_bad ("unknown imm16 operand");
1007
      /* fall-thru */
1008
 
1009
    default:
1010
      break;
1011
    }
1012
  return BFD_RELOC_NONE;
1013
}
1014
 
1015
 
1016
/* Turn a string in input_line_pointer into a floating point constant
1017
   of type TYPE, and store the appropriate bytes in *LITP.  The number
1018
   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
1019
   returned, or NULL on OK.  */
1020
 
1021
/* Equal to MAX_PRECISION in atof-ieee.c.  */
1022
#define MAX_LITTLENUMS 6
1023
 
1024
char *
1025
md_atof (int type, char *litP, int *sizeP)
1026
{
1027
  return ieee_md_atof (type, litP, sizeP, FALSE);
1028
}
1029
 
1030
/* Return true if can adjust the reloc to be relative to its section
1031
   (such as .data) instead of relative to some symbol.  */
1032
 
1033
bfd_boolean
1034
epiphany_fix_adjustable (fixS *fixP)
1035
{
1036
 bfd_reloc_code_real_type reloc_type;
1037
 
1038
  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
1039
    {
1040
      const CGEN_INSN *insn = fixP->fx_cgen.insn;
1041
      int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
1042
      const CGEN_OPERAND *operand =
1043
        cgen_operand_lookup_by_num (gas_cgen_cpu_desc, opindex);
1044
 
1045
      reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
1046
    }
1047
  else
1048
    reloc_type = fixP->fx_r_type;
1049
 
1050
  if (fixP->fx_addsy == NULL)
1051
    return TRUE;
1052
 
1053
  /* Prevent all adjustments to global symbols.  */
1054
  if (S_IS_EXTERNAL (fixP->fx_addsy))
1055
    return FALSE;
1056
 
1057
  if (S_IS_WEAK (fixP->fx_addsy))
1058
    return FALSE;
1059
 
1060
  if (pic_code
1061
      && (reloc_type == BFD_RELOC_EPIPHANY_SIMM24
1062
          || reloc_type == BFD_RELOC_EPIPHANY_SIMM8
1063
          || reloc_type == BFD_RELOC_EPIPHANY_HIGH
1064
          || reloc_type == BFD_RELOC_EPIPHANY_LOW))
1065
    return FALSE;
1066
 
1067
  /* Since we don't use partial_inplace, we must not reduce symbols in
1068
     mergable sections to their section symbol.  */
1069
  if ((S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0)
1070
    return FALSE;
1071
 
1072
  return TRUE;
1073
}
1074
 
1075
void
1076
epiphany_elf_final_processing (void)
1077
{
1078
  elf_elfheader (stdoutput)->e_flags |= epiphany_flags;
1079
}
1080
 
1081
int
1082
epiphany_cgen_parse_fix_exp (int opinfo, expressionS *exp ATTRIBUTE_UNUSED)
1083
{
1084
  LITTLENUM_TYPE words[2];
1085
 
1086
  switch (opinfo)
1087
    {
1088
    case BFD_RELOC_EPIPHANY_LOW:
1089
    case BFD_RELOC_EPIPHANY_HIGH:
1090
      break;
1091
    default:
1092
      return opinfo;
1093
    }
1094
 
1095
  /* Doing a %LOW or %HIGH.  */
1096
  switch (exp->X_op)
1097
    {
1098
    default:
1099
      return opinfo;
1100
    case O_big:                         /* Bignum.  */
1101
      if (exp->X_add_number > 0) /* Integer value too large.  */
1102
        return opinfo;
1103
    }
1104
 
1105
  /* Convert to SP number.  */
1106
  gen_to_words (words, 2, 8L);
1107
  exp->X_add_number = words[1] | (words[0] << 16);
1108
  exp->X_op = O_constant;
1109
  return opinfo;
1110
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.