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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [opcodes/] [ip2k-asm.c] - Blame information for rev 160

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 18 khays
/* Assembler interface for targets using CGEN. -*- C -*-
2
   CGEN: Cpu tools GENerator
3
 
4
   THIS FILE IS MACHINE GENERATED WITH CGEN.
5
   - the resultant file is machine generated, cgen-asm.in isn't
6
 
7
   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2005, 2007, 2008, 2010
8
   Free Software Foundation, Inc.
9
 
10
   This file is part of libopcodes.
11
 
12
   This library is free software; you can redistribute it and/or modify
13
   it under the terms of the GNU General Public License as published by
14
   the Free Software Foundation; either version 3, or (at your option)
15
   any later version.
16
 
17
   It is distributed in the hope that it will be useful, but WITHOUT
18
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
20
   License for more details.
21
 
22
   You should have received a copy of the GNU General Public License
23
   along with this program; if not, write to the Free Software Foundation, Inc.,
24
   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
25
 
26
 
27
/* ??? Eventually more and more of this stuff can go to cpu-independent files.
28
   Keep that in mind.  */
29
 
30
#include "sysdep.h"
31
#include <stdio.h>
32
#include "ansidecl.h"
33
#include "bfd.h"
34
#include "symcat.h"
35
#include "ip2k-desc.h"
36
#include "ip2k-opc.h"
37
#include "opintl.h"
38
#include "xregex.h"
39
#include "libiberty.h"
40
#include "safe-ctype.h"
41
 
42
#undef  min
43
#define min(a,b) ((a) < (b) ? (a) : (b))
44
#undef  max
45
#define max(a,b) ((a) > (b) ? (a) : (b))
46
 
47
static const char * parse_insn_normal
48
  (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
49
 
50
/* -- assembler routines inserted here.  */
51
 
52
/* -- asm.c */
53
 
54
static const char *
55
parse_fr (CGEN_CPU_DESC cd,
56
          const char **strp,
57
          int opindex,
58
          unsigned long *valuep)
59
{
60
  const char *errmsg;
61
  const char *old_strp;
62
  char *afteroffset;
63
  enum cgen_parse_operand_result result_type;
64
  bfd_vma value;
65
  extern CGEN_KEYWORD ip2k_cgen_opval_register_names;
66
  bfd_vma tempvalue;
67
 
68
  old_strp = *strp;
69
  afteroffset = NULL;
70
 
71
  /* Check here to see if you're about to try parsing a w as the first arg
72
     and return an error if you are.  */
73
  if ((strncmp (*strp, "w", 1) == 0) || (strncmp (*strp, "W", 1) == 0))
74
    {
75
      (*strp)++;
76
 
77
      if ((strncmp (*strp, ",", 1) == 0) || ISSPACE (**strp))
78
        {
79
          /* We've been passed a w.  Return with an error message so that
80
             cgen will try the next parsing option.  */
81
          errmsg = _("W keyword invalid in FR operand slot.");
82
          return errmsg;
83
        }
84
      *strp = old_strp;
85
    }
86
 
87
  /* Attempt parse as register keyword. */
88
  errmsg = cgen_parse_keyword (cd, strp, & ip2k_cgen_opval_register_names,
89
                               (long *) valuep);
90
  if (*strp != NULL
91
      && errmsg == NULL)
92
    return errmsg;
93
 
94
  /* Attempt to parse for "(IP)".  */
95
  afteroffset = strstr (*strp, "(IP)");
96
 
97
  if (afteroffset == NULL)
98
    /* Make sure it's not in lower case.  */
99
    afteroffset = strstr (*strp, "(ip)");
100
 
101
  if (afteroffset != NULL)
102
    {
103
      if (afteroffset != *strp)
104
        {
105
          /* Invalid offset present.  */
106
          errmsg = _("offset(IP) is not a valid form");
107
          return errmsg;
108
        }
109
      else
110
        {
111
          *strp += 4;
112
          *valuep = 0;
113
          errmsg = NULL;
114
          return errmsg;
115
        }
116
    }
117
 
118
  /* Attempt to parse for DP. ex: mov w, offset(DP)
119
                                  mov offset(DP),w   */
120
 
121
  /* Try parsing it as an address and see what comes back.  */
122
  afteroffset = strstr (*strp, "(DP)");
123
 
124
  if (afteroffset == NULL)
125
    /* Maybe it's in lower case.  */
126
    afteroffset = strstr (*strp, "(dp)");
127
 
128
  if (afteroffset != NULL)
129
    {
130
      if (afteroffset == *strp)
131
        {
132
          /* No offset present. Use 0 by default.  */
133
          tempvalue = 0;
134
          errmsg = NULL;
135
        }
136
      else
137
        errmsg = cgen_parse_address (cd, strp, opindex,
138
                                     BFD_RELOC_IP2K_FR_OFFSET,
139
                                     & result_type, & tempvalue);
140
 
141
      if (errmsg == NULL)
142
        {
143
          if (tempvalue <= 127)
144
            {
145
              /* Value is ok.  Fix up the first 2 bits and return.  */
146
              *valuep = 0x0100 | tempvalue;
147
              *strp += 4; /* Skip over the (DP) in *strp.  */
148
              return errmsg;
149
            }
150
          else
151
            {
152
              /* Found something there in front of (DP) but it's out
153
                 of range.  */
154
              errmsg = _("(DP) offset out of range.");
155
              return errmsg;
156
            }
157
        }
158
    }
159
 
160
 
161
  /* Attempt to parse for SP. ex: mov w, offset(SP)
162
                                  mov offset(SP), w.  */
163
  afteroffset = strstr (*strp, "(SP)");
164
 
165
  if (afteroffset == NULL)
166
    /* Maybe it's in lower case.  */
167
    afteroffset = strstr (*strp, "(sp)");
168
 
169
  if (afteroffset != NULL)
170
    {
171
      if (afteroffset == *strp)
172
        {
173
          /* No offset present. Use 0 by default.  */
174
          tempvalue = 0;
175
          errmsg = NULL;
176
        }
177
      else
178
        errmsg = cgen_parse_address (cd, strp, opindex,
179
                                     BFD_RELOC_IP2K_FR_OFFSET,
180
                                     & result_type, & tempvalue);
181
 
182
      if (errmsg == NULL)
183
        {
184
          if (tempvalue <= 127)
185
            {
186
              /* Value is ok.  Fix up the first 2 bits and return.  */
187
              *valuep = 0x0180 | tempvalue;
188
              *strp += 4; /* Skip over the (SP) in *strp.  */
189
              return errmsg;
190
            }
191
          else
192
            {
193
              /* Found something there in front of (SP) but it's out
194
                 of range.  */
195
              errmsg = _("(SP) offset out of range.");
196
              return errmsg;
197
            }
198
        }
199
    }
200
 
201
  /* Attempt to parse as an address.  */
202
  *strp = old_strp;
203
  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IP2K_FR9,
204
                               & result_type, & value);
205
  if (errmsg == NULL)
206
    {
207
      *valuep = value;
208
 
209
      /* If a parenthesis is found, warn about invalid form.  */
210
      if (**strp == '(')
211
        errmsg = _("illegal use of parentheses");
212
 
213
      /* If a numeric value is specified, ensure that it is between
214
         1 and 255.  */
215
      else if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
216
        {
217
          if (value < 0x1 || value > 0xff)
218
            errmsg = _("operand out of range (not between 1 and 255)");
219
        }
220
    }
221
  return errmsg;
222
}
223
 
224
static const char *
225
parse_addr16 (CGEN_CPU_DESC cd,
226
              const char **strp,
227
              int opindex,
228
              unsigned long *valuep)
229
{
230
  const char *errmsg;
231
  enum cgen_parse_operand_result result_type;
232
  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
233
  bfd_vma value;
234
 
235
  if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16H)
236
    code = BFD_RELOC_IP2K_HI8DATA;
237
  else if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16L)
238
    code = BFD_RELOC_IP2K_LO8DATA;
239
  else
240
    {
241
      /* Something is very wrong. opindex has to be one of the above.  */
242
      errmsg = _("parse_addr16: invalid opindex.");
243
      return errmsg;
244
    }
245
 
246
  errmsg = cgen_parse_address (cd, strp, opindex, code,
247
                               & result_type, & value);
248
  if (errmsg == NULL)
249
    {
250
      /* We either have a relocation or a number now.  */
251
      if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
252
        {
253
          /* We got a number back.  */
254
          if (code == BFD_RELOC_IP2K_HI8DATA)
255
            value >>= 8;
256
          else
257
            /* code = BFD_RELOC_IP2K_LOW8DATA.  */
258
            value &= 0x00FF;
259
        }
260
      *valuep = value;
261
    }
262
 
263
  return errmsg;
264
}
265
 
266
static const char *
267
parse_addr16_cjp (CGEN_CPU_DESC cd,
268
                  const char **strp,
269
                  int opindex,
270
                  unsigned long *valuep)
271
{
272
  const char *errmsg;
273
  enum cgen_parse_operand_result result_type;
274
  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
275
  bfd_vma value;
276
 
277
  if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16CJP)
278
    code = BFD_RELOC_IP2K_ADDR16CJP;
279
  else if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16P)
280
    code = BFD_RELOC_IP2K_PAGE3;
281
 
282
  errmsg = cgen_parse_address (cd, strp, opindex, code,
283
                               & result_type, & value);
284
  if (errmsg == NULL)
285
    {
286
      if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
287
        {
288
          if ((value & 0x1) == 0)  /* If the address is even .... */
289
            {
290
              if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16CJP)
291
                *valuep = (value >> 1) & 0x1FFF;  /* Should mask be 1FFF?  */
292
              else if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16P)
293
                *valuep = (value >> 14) & 0x7;
294
            }
295
          else
296
            errmsg = _("Byte address required. - must be even.");
297
        }
298
      else if (result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED)
299
        {
300
          /* This will happen for things like (s2-s1) where s2 and s1
301
             are labels.  */
302
          *valuep = value;
303
        }
304
      else
305
        errmsg = _("cgen_parse_address returned a symbol. Literal required.");
306
    }
307
  return errmsg;
308
}
309
 
310
static const char *
311
parse_lit8 (CGEN_CPU_DESC cd,
312
            const char **strp,
313
            int opindex,
314
            long *valuep)
315
{
316
  const char *errmsg;
317
  enum cgen_parse_operand_result result_type;
318
  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
319
  bfd_vma value;
320
 
321
  /* Parse %OP relocating operators.  */
322
  if (strncmp (*strp, "%bank", 5) == 0)
323
    {
324
      *strp += 5;
325
      code = BFD_RELOC_IP2K_BANK;
326
    }
327
  else if (strncmp (*strp, "%lo8data", 8) == 0)
328
    {
329
      *strp += 8;
330
      code = BFD_RELOC_IP2K_LO8DATA;
331
    }
332
  else if (strncmp (*strp, "%hi8data", 8) == 0)
333
    {
334
      *strp += 8;
335
      code = BFD_RELOC_IP2K_HI8DATA;
336
    }
337
  else if (strncmp (*strp, "%ex8data", 8) == 0)
338
    {
339
      *strp += 8;
340
      code = BFD_RELOC_IP2K_EX8DATA;
341
    }
342
  else if (strncmp (*strp, "%lo8insn", 8) == 0)
343
    {
344
      *strp += 8;
345
      code = BFD_RELOC_IP2K_LO8INSN;
346
    }
347
  else if (strncmp (*strp, "%hi8insn", 8) == 0)
348
    {
349
      *strp += 8;
350
      code = BFD_RELOC_IP2K_HI8INSN;
351
    }
352
 
353
  /* Parse %op operand.  */
354
  if (code != BFD_RELOC_NONE)
355
    {
356
      errmsg = cgen_parse_address (cd, strp, opindex, code,
357
                                   & result_type, & value);
358
      if ((errmsg == NULL) &&
359
          (result_type != CGEN_PARSE_OPERAND_RESULT_QUEUED))
360
        errmsg = _("percent-operator operand is not a symbol");
361
 
362
      *valuep = value;
363
    }
364
  /* Parse as a number.  */
365
  else
366
    {
367
      errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep);
368
 
369
      /* Truncate to eight bits to accept both signed and unsigned input.  */
370
      if (errmsg == NULL)
371
        *valuep &= 0xFF;
372
    }
373
 
374
  return errmsg;
375
}
376
 
377
static const char *
378
parse_bit3 (CGEN_CPU_DESC cd,
379
            const char **strp,
380
            int opindex,
381
            unsigned long *valuep)
382
{
383
  const char *errmsg;
384
  char mode = 0;
385
  long count = 0;
386
  unsigned long value;
387
 
388
  if (strncmp (*strp, "%bit", 4) == 0)
389
    {
390
      *strp += 4;
391
      mode = 1;
392
    }
393
  else if (strncmp (*strp, "%msbbit", 7) == 0)
394
    {
395
      *strp += 7;
396
      mode = 1;
397
    }
398
  else if (strncmp (*strp, "%lsbbit", 7) == 0)
399
    {
400
      *strp += 7;
401
      mode = 2;
402
    }
403
 
404
  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
405
  if (errmsg)
406
    return errmsg;
407
 
408
  if (mode)
409
    {
410
      value = * valuep;
411
      if (value == 0)
412
        {
413
          errmsg = _("Attempt to find bit index of 0");
414
          return errmsg;
415
        }
416
 
417
      if (mode == 1)
418
        {
419
          count = 31;
420
          while ((value & 0x80000000) == 0)
421
            {
422
              count--;
423
              value <<= 1;
424
            }
425
        }
426
      else if (mode == 2)
427
        {
428
          count = 0;
429
          while ((value & 0x00000001) == 0)
430
            {
431
              count++;
432
              value >>= 1;
433
            }
434
        }
435
 
436
      *valuep = count;
437
    }
438
 
439
  return errmsg;
440
}
441
 
442
/* -- dis.c */
443
 
444
const char * ip2k_cgen_parse_operand
445
  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
446
 
447
/* Main entry point for operand parsing.
448
 
449
   This function is basically just a big switch statement.  Earlier versions
450
   used tables to look up the function to use, but
451
   - if the table contains both assembler and disassembler functions then
452
     the disassembler contains much of the assembler and vice-versa,
453
   - there's a lot of inlining possibilities as things grow,
454
   - using a switch statement avoids the function call overhead.
455
 
456
   This function could be moved into `parse_insn_normal', but keeping it
457
   separate makes clear the interface between `parse_insn_normal' and each of
458
   the handlers.  */
459
 
460
const char *
461
ip2k_cgen_parse_operand (CGEN_CPU_DESC cd,
462
                           int opindex,
463
                           const char ** strp,
464
                           CGEN_FIELDS * fields)
465
{
466
  const char * errmsg = NULL;
467
  /* Used by scalar operands that still need to be parsed.  */
468
  long junk ATTRIBUTE_UNUSED;
469
 
470
  switch (opindex)
471
    {
472
    case IP2K_OPERAND_ADDR16CJP :
473
      errmsg = parse_addr16_cjp (cd, strp, IP2K_OPERAND_ADDR16CJP, (unsigned long *) (& fields->f_addr16cjp));
474
      break;
475
    case IP2K_OPERAND_ADDR16H :
476
      errmsg = parse_addr16 (cd, strp, IP2K_OPERAND_ADDR16H, (unsigned long *) (& fields->f_imm8));
477
      break;
478
    case IP2K_OPERAND_ADDR16L :
479
      errmsg = parse_addr16 (cd, strp, IP2K_OPERAND_ADDR16L, (unsigned long *) (& fields->f_imm8));
480
      break;
481
    case IP2K_OPERAND_ADDR16P :
482
      errmsg = parse_addr16_cjp (cd, strp, IP2K_OPERAND_ADDR16P, (unsigned long *) (& fields->f_page3));
483
      break;
484
    case IP2K_OPERAND_BITNO :
485
      errmsg = parse_bit3 (cd, strp, IP2K_OPERAND_BITNO, (unsigned long *) (& fields->f_bitno));
486
      break;
487
    case IP2K_OPERAND_CBIT :
488
      errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_CBIT, (unsigned long *) (& junk));
489
      break;
490
    case IP2K_OPERAND_DCBIT :
491
      errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_DCBIT, (unsigned long *) (& junk));
492
      break;
493
    case IP2K_OPERAND_FR :
494
      errmsg = parse_fr (cd, strp, IP2K_OPERAND_FR, (unsigned long *) (& fields->f_reg));
495
      break;
496
    case IP2K_OPERAND_LIT8 :
497
      errmsg = parse_lit8 (cd, strp, IP2K_OPERAND_LIT8, (long *) (& fields->f_imm8));
498
      break;
499
    case IP2K_OPERAND_PABITS :
500
      errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_PABITS, (unsigned long *) (& junk));
501
      break;
502
    case IP2K_OPERAND_RETI3 :
503
      errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_RETI3, (unsigned long *) (& fields->f_reti3));
504
      break;
505
    case IP2K_OPERAND_ZBIT :
506
      errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_ZBIT, (unsigned long *) (& junk));
507
      break;
508
 
509
    default :
510
      /* xgettext:c-format */
511
      fprintf (stderr, _("Unrecognized field %d while parsing.\n"), opindex);
512
      abort ();
513
  }
514
 
515
  return errmsg;
516
}
517
 
518
cgen_parse_fn * const ip2k_cgen_parse_handlers[] =
519
{
520
  parse_insn_normal,
521
};
522
 
523
void
524
ip2k_cgen_init_asm (CGEN_CPU_DESC cd)
525
{
526
  ip2k_cgen_init_opcode_table (cd);
527
  ip2k_cgen_init_ibld_table (cd);
528
  cd->parse_handlers = & ip2k_cgen_parse_handlers[0];
529
  cd->parse_operand = ip2k_cgen_parse_operand;
530
#ifdef CGEN_ASM_INIT_HOOK
531
CGEN_ASM_INIT_HOOK
532
#endif
533
}
534
 
535
 
536
 
537
/* Regex construction routine.
538
 
539
   This translates an opcode syntax string into a regex string,
540
   by replacing any non-character syntax element (such as an
541
   opcode) with the pattern '.*'
542
 
543
   It then compiles the regex and stores it in the opcode, for
544
   later use by ip2k_cgen_assemble_insn
545
 
546
   Returns NULL for success, an error message for failure.  */
547
 
548
char *
549
ip2k_cgen_build_insn_regex (CGEN_INSN *insn)
550
{
551
  CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
552
  const char *mnem = CGEN_INSN_MNEMONIC (insn);
553
  char rxbuf[CGEN_MAX_RX_ELEMENTS];
554
  char *rx = rxbuf;
555
  const CGEN_SYNTAX_CHAR_TYPE *syn;
556
  int reg_err;
557
 
558
  syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
559
 
560
  /* Mnemonics come first in the syntax string.  */
561
  if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
562
    return _("missing mnemonic in syntax string");
563
  ++syn;
564
 
565
  /* Generate a case sensitive regular expression that emulates case
566
     insensitive matching in the "C" locale.  We cannot generate a case
567
     insensitive regular expression because in Turkish locales, 'i' and 'I'
568
     are not equal modulo case conversion.  */
569
 
570
  /* Copy the literal mnemonic out of the insn.  */
571
  for (; *mnem; mnem++)
572
    {
573
      char c = *mnem;
574
 
575
      if (ISALPHA (c))
576
        {
577
          *rx++ = '[';
578
          *rx++ = TOLOWER (c);
579
          *rx++ = TOUPPER (c);
580
          *rx++ = ']';
581
        }
582
      else
583
        *rx++ = c;
584
    }
585
 
586
  /* Copy any remaining literals from the syntax string into the rx.  */
587
  for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
588
    {
589
      if (CGEN_SYNTAX_CHAR_P (* syn))
590
        {
591
          char c = CGEN_SYNTAX_CHAR (* syn);
592
 
593
          switch (c)
594
            {
595
              /* Escape any regex metacharacters in the syntax.  */
596
            case '.': case '[': case '\\':
597
            case '*': case '^': case '$':
598
 
599
#ifdef CGEN_ESCAPE_EXTENDED_REGEX
600
            case '?': case '{': case '}':
601
            case '(': case ')': case '*':
602
            case '|': case '+': case ']':
603
#endif
604
              *rx++ = '\\';
605
              *rx++ = c;
606
              break;
607
 
608
            default:
609
              if (ISALPHA (c))
610
                {
611
                  *rx++ = '[';
612
                  *rx++ = TOLOWER (c);
613
                  *rx++ = TOUPPER (c);
614
                  *rx++ = ']';
615
                }
616
              else
617
                *rx++ = c;
618
              break;
619
            }
620
        }
621
      else
622
        {
623
          /* Replace non-syntax fields with globs.  */
624
          *rx++ = '.';
625
          *rx++ = '*';
626
        }
627
    }
628
 
629
  /* Trailing whitespace ok.  */
630
  * rx++ = '[';
631
  * rx++ = ' ';
632
  * rx++ = '\t';
633
  * rx++ = ']';
634
  * rx++ = '*';
635
 
636
  /* But anchor it after that.  */
637
  * rx++ = '$';
638
  * rx = '\0';
639
 
640
  CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
641
  reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
642
 
643
  if (reg_err == 0)
644
    return NULL;
645
  else
646
    {
647
      static char msg[80];
648
 
649
      regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
650
      regfree ((regex_t *) CGEN_INSN_RX (insn));
651
      free (CGEN_INSN_RX (insn));
652
      (CGEN_INSN_RX (insn)) = NULL;
653
      return msg;
654
    }
655
}
656
 
657
 
658
/* Default insn parser.
659
 
660
   The syntax string is scanned and operands are parsed and stored in FIELDS.
661
   Relocs are queued as we go via other callbacks.
662
 
663
   ??? Note that this is currently an all-or-nothing parser.  If we fail to
664
   parse the instruction, we return 0 and the caller will start over from
665
   the beginning.  Backtracking will be necessary in parsing subexpressions,
666
   but that can be handled there.  Not handling backtracking here may get
667
   expensive in the case of the m68k.  Deal with later.
668
 
669
   Returns NULL for success, an error message for failure.  */
670
 
671
static const char *
672
parse_insn_normal (CGEN_CPU_DESC cd,
673
                   const CGEN_INSN *insn,
674
                   const char **strp,
675
                   CGEN_FIELDS *fields)
676
{
677
  /* ??? Runtime added insns not handled yet.  */
678
  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
679
  const char *str = *strp;
680
  const char *errmsg;
681
  const char *p;
682
  const CGEN_SYNTAX_CHAR_TYPE * syn;
683
#ifdef CGEN_MNEMONIC_OPERANDS
684
  /* FIXME: wip */
685
  int past_opcode_p;
686
#endif
687
 
688
  /* For now we assume the mnemonic is first (there are no leading operands).
689
     We can parse it without needing to set up operand parsing.
690
     GAS's input scrubber will ensure mnemonics are lowercase, but we may
691
     not be called from GAS.  */
692
  p = CGEN_INSN_MNEMONIC (insn);
693
  while (*p && TOLOWER (*p) == TOLOWER (*str))
694
    ++p, ++str;
695
 
696
  if (* p)
697
    return _("unrecognized instruction");
698
 
699
#ifndef CGEN_MNEMONIC_OPERANDS
700
  if (* str && ! ISSPACE (* str))
701
    return _("unrecognized instruction");
702
#endif
703
 
704
  CGEN_INIT_PARSE (cd);
705
  cgen_init_parse_operand (cd);
706
#ifdef CGEN_MNEMONIC_OPERANDS
707
  past_opcode_p = 0;
708
#endif
709
 
710
  /* We don't check for (*str != '\0') here because we want to parse
711
     any trailing fake arguments in the syntax string.  */
712
  syn = CGEN_SYNTAX_STRING (syntax);
713
 
714
  /* Mnemonics come first for now, ensure valid string.  */
715
  if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
716
    abort ();
717
 
718
  ++syn;
719
 
720
  while (* syn != 0)
721
    {
722
      /* Non operand chars must match exactly.  */
723
      if (CGEN_SYNTAX_CHAR_P (* syn))
724
        {
725
          /* FIXME: While we allow for non-GAS callers above, we assume the
726
             first char after the mnemonic part is a space.  */
727
          /* FIXME: We also take inappropriate advantage of the fact that
728
             GAS's input scrubber will remove extraneous blanks.  */
729
          if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
730
            {
731
#ifdef CGEN_MNEMONIC_OPERANDS
732
              if (CGEN_SYNTAX_CHAR(* syn) == ' ')
733
                past_opcode_p = 1;
734
#endif
735
              ++ syn;
736
              ++ str;
737
            }
738
          else if (*str)
739
            {
740
              /* Syntax char didn't match.  Can't be this insn.  */
741
              static char msg [80];
742
 
743
              /* xgettext:c-format */
744
              sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
745
                       CGEN_SYNTAX_CHAR(*syn), *str);
746
              return msg;
747
            }
748
          else
749
            {
750
              /* Ran out of input.  */
751
              static char msg [80];
752
 
753
              /* xgettext:c-format */
754
              sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
755
                       CGEN_SYNTAX_CHAR(*syn));
756
              return msg;
757
            }
758
          continue;
759
        }
760
 
761
#ifdef CGEN_MNEMONIC_OPERANDS
762
      (void) past_opcode_p;
763
#endif
764
      /* We have an operand of some sort.  */
765
      errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn), &str, fields);
766
      if (errmsg)
767
        return errmsg;
768
 
769
      /* Done with this operand, continue with next one.  */
770
      ++ syn;
771
    }
772
 
773
  /* If we're at the end of the syntax string, we're done.  */
774
  if (* syn == 0)
775
    {
776
      /* FIXME: For the moment we assume a valid `str' can only contain
777
         blanks now.  IE: We needn't try again with a longer version of
778
         the insn and it is assumed that longer versions of insns appear
779
         before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
780
      while (ISSPACE (* str))
781
        ++ str;
782
 
783
      if (* str != '\0')
784
        return _("junk at end of line"); /* FIXME: would like to include `str' */
785
 
786
      return NULL;
787
    }
788
 
789
  /* We couldn't parse it.  */
790
  return _("unrecognized instruction");
791
}
792
 
793
/* Main entry point.
794
   This routine is called for each instruction to be assembled.
795
   STR points to the insn to be assembled.
796
   We assume all necessary tables have been initialized.
797
   The assembled instruction, less any fixups, is stored in BUF.
798
   Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
799
   still needs to be converted to target byte order, otherwise BUF is an array
800
   of bytes in target byte order.
801
   The result is a pointer to the insn's entry in the opcode table,
802
   or NULL if an error occured (an error message will have already been
803
   printed).
804
 
805
   Note that when processing (non-alias) macro-insns,
806
   this function recurses.
807
 
808
   ??? It's possible to make this cpu-independent.
809
   One would have to deal with a few minor things.
810
   At this point in time doing so would be more of a curiosity than useful
811
   [for example this file isn't _that_ big], but keeping the possibility in
812
   mind helps keep the design clean.  */
813
 
814
const CGEN_INSN *
815
ip2k_cgen_assemble_insn (CGEN_CPU_DESC cd,
816
                           const char *str,
817
                           CGEN_FIELDS *fields,
818
                           CGEN_INSN_BYTES_PTR buf,
819
                           char **errmsg)
820
{
821
  const char *start;
822
  CGEN_INSN_LIST *ilist;
823
  const char *parse_errmsg = NULL;
824
  const char *insert_errmsg = NULL;
825
  int recognized_mnemonic = 0;
826
 
827
  /* Skip leading white space.  */
828
  while (ISSPACE (* str))
829
    ++ str;
830
 
831
  /* The instructions are stored in hashed lists.
832
     Get the first in the list.  */
833
  ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
834
 
835
  /* Keep looking until we find a match.  */
836
  start = str;
837
  for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
838
    {
839
      const CGEN_INSN *insn = ilist->insn;
840
      recognized_mnemonic = 1;
841
 
842
#ifdef CGEN_VALIDATE_INSN_SUPPORTED 
843
      /* Not usually needed as unsupported opcodes
844
         shouldn't be in the hash lists.  */
845
      /* Is this insn supported by the selected cpu?  */
846
      if (! ip2k_cgen_insn_supported (cd, insn))
847
        continue;
848
#endif
849
      /* If the RELAXED attribute is set, this is an insn that shouldn't be
850
         chosen immediately.  Instead, it is used during assembler/linker
851
         relaxation if possible.  */
852
      if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
853
        continue;
854
 
855
      str = start;
856
 
857
      /* Skip this insn if str doesn't look right lexically.  */
858
      if (CGEN_INSN_RX (insn) != NULL &&
859
          regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
860
        continue;
861
 
862
      /* Allow parse/insert handlers to obtain length of insn.  */
863
      CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
864
 
865
      parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
866
      if (parse_errmsg != NULL)
867
        continue;
868
 
869
      /* ??? 0 is passed for `pc'.  */
870
      insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
871
                                                 (bfd_vma) 0);
872
      if (insert_errmsg != NULL)
873
        continue;
874
 
875
      /* It is up to the caller to actually output the insn and any
876
         queued relocs.  */
877
      return insn;
878
    }
879
 
880
  {
881
    static char errbuf[150];
882
    const char *tmp_errmsg;
883
#ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
884
#define be_verbose 1
885
#else
886
#define be_verbose 0
887
#endif
888
 
889
    if (be_verbose)
890
      {
891
        /* If requesting verbose error messages, use insert_errmsg.
892
           Failing that, use parse_errmsg.  */
893
        tmp_errmsg = (insert_errmsg ? insert_errmsg :
894
                      parse_errmsg ? parse_errmsg :
895
                      recognized_mnemonic ?
896
                      _("unrecognized form of instruction") :
897
                      _("unrecognized instruction"));
898
 
899
        if (strlen (start) > 50)
900
          /* xgettext:c-format */
901
          sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
902
        else
903
          /* xgettext:c-format */
904
          sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
905
      }
906
    else
907
      {
908
        if (strlen (start) > 50)
909
          /* xgettext:c-format */
910
          sprintf (errbuf, _("bad instruction `%.50s...'"), start);
911
        else
912
          /* xgettext:c-format */
913
          sprintf (errbuf, _("bad instruction `%.50s'"), start);
914
      }
915
 
916
    *errmsg = errbuf;
917
    return NULL;
918
  }
919
}

powered by: WebSVN 2.1.0

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