Coverage Report

Created: 2025-06-24 06:45

/src/binutils-gdb/opcodes/epiphany-asm.c
Line
Count
Source (jump to first uncovered line)
1
/* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
2
/* Assembler interface for targets using CGEN. -*- C -*-
3
   CGEN: Cpu tools GENerator
4
5
   THIS FILE IS MACHINE GENERATED WITH CGEN.
6
   - the resultant file is machine generated, cgen-asm.in isn't
7
8
   Copyright (C) 1996-2025 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 "epiphany-desc.h"
36
#include "epiphany-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
const char *
54
parse_shortregs (CGEN_CPU_DESC cd,
55
     const char ** strp,
56
     CGEN_KEYWORD * keywords,
57
     long * regno)
58
0
{
59
0
  const char * errmsg;
60
61
  /* Parse register.  */
62
0
  errmsg = cgen_parse_keyword (cd, strp, keywords, regno);
63
64
0
  if (errmsg)
65
0
    return errmsg;
66
67
0
  if (*regno > 7)
68
0
    errmsg = _("register unavailable for short instructions");
69
70
0
  return errmsg;
71
0
}
72
73
static const char * parse_simm_not_reg (CGEN_CPU_DESC, const char **, int,
74
          long *);
75
76
static const char *
77
parse_uimm_not_reg (CGEN_CPU_DESC cd,
78
        const char ** strp,
79
        int opindex,
80
        unsigned long * valuep)
81
0
{
82
0
  long * svalp = (void *) valuep;
83
0
  return parse_simm_not_reg (cd, strp, opindex, svalp);
84
0
}
85
86
/* Handle simm3/simm11/imm3/imm12.  */
87
88
static const char *
89
parse_simm_not_reg (CGEN_CPU_DESC cd,
90
       const char ** strp,
91
       int opindex,
92
       long * valuep)
93
0
{
94
0
  const char * errmsg;
95
96
0
  int   sign = 0;
97
0
  int   bits = 0;
98
99
0
  switch (opindex)
100
0
    {
101
0
    case EPIPHANY_OPERAND_SIMM3:
102
0
      sign = 1; bits = 3; break;
103
0
    case EPIPHANY_OPERAND_SIMM11:
104
0
      sign = 1; bits = 11; break;
105
0
    case EPIPHANY_OPERAND_DISP3:
106
0
      sign = 0; bits = 3; break;
107
0
    case EPIPHANY_OPERAND_DISP11:
108
      /* Load/store displacement is a sign-magnitude 12 bit value.  */
109
0
      sign = 0; bits = 11; break;
110
0
    }
111
112
  /* First try to parse as a register name and reject the operand.  */
113
0
  errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names,valuep);
114
0
  if (!errmsg)
115
0
    return _("register name used as immediate value");
116
117
0
  errmsg = (sign ? cgen_parse_signed_integer (cd, strp, opindex, valuep)
118
0
      : cgen_parse_unsigned_integer (cd, strp, opindex,
119
0
            (unsigned long *) valuep));
120
0
  if (errmsg)
121
0
    return errmsg;
122
123
0
  if (sign)
124
0
    errmsg = cgen_validate_signed_integer (*valuep,
125
0
            -((1L << bits) - 1), (1 << (bits - 1)) - 1);
126
0
  else
127
0
    errmsg = cgen_validate_unsigned_integer (*valuep, 0, (1L << bits) - 1);
128
129
0
  return errmsg;
130
0
}
131
132
static const char *
133
parse_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
134
     const char ** strp,
135
     int opindex ATTRIBUTE_UNUSED,
136
     unsigned long *valuep)
137
0
{
138
0
  if (**strp == '#')
139
0
    ++*strp;     /* Skip leading hashes.  */
140
141
0
  if (**strp == '-')
142
0
    {
143
0
      *valuep = 1;
144
0
      ++*strp;
145
0
    }
146
0
  else if (**strp == '+')
147
0
    {
148
0
      *valuep = 0;
149
0
      ++*strp;
150
0
    }
151
0
  else
152
0
    *valuep = 0;
153
154
0
  return NULL;
155
0
}
156
157
static const char *
158
parse_imm8 (CGEN_CPU_DESC cd,
159
      const char ** strp,
160
      int opindex,
161
      bfd_reloc_code_real_type code,
162
      enum cgen_parse_operand_result * result_type,
163
      bfd_vma * valuep)
164
0
{
165
0
  const char * errmsg;
166
0
  enum cgen_parse_operand_result rt;
167
0
  long dummyval;
168
169
0
  if (!result_type)
170
0
    result_type = &rt;
171
172
0
  code = BFD_RELOC_NONE;
173
174
0
  if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names, &dummyval)
175
0
      || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names,
176
0
            &dummyval))
177
    /* Don't treat "mov ip,ip" as a move-immediate.  */
178
0
    return _("register source in immediate move");
179
180
0
  errmsg = cgen_parse_address (cd, strp, opindex, code, result_type, valuep);
181
0
  if (errmsg)
182
0
    return errmsg;
183
184
0
  if (*result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
185
0
    errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xff);
186
0
  else
187
0
    errmsg = _("byte relocation unsupported");
188
189
0
  *valuep &= 0xff;
190
0
  return errmsg;
191
0
}
192
193
static const char * MISSING_CLOSE_PARENTHESIS = N_("missing `)'");
194
195
static const char *
196
parse_imm16 (CGEN_CPU_DESC cd,
197
       const char ** strp,
198
       int opindex,
199
       bfd_reloc_code_real_type code ATTRIBUTE_UNUSED,
200
       enum cgen_parse_operand_result * result_type,
201
       bfd_vma * valuep)
202
0
{
203
0
  const char * errmsg;
204
0
  enum cgen_parse_operand_result rt;
205
0
  long dummyval;
206
207
0
  if (!result_type)
208
0
    result_type = &rt;
209
210
0
  if (strncasecmp (*strp, "%high(", 6) == 0)
211
0
    {
212
0
      *strp += 6;
213
0
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_HIGH,
214
0
           result_type, valuep);
215
0
      if (**strp != ')')
216
0
  return MISSING_CLOSE_PARENTHESIS;
217
0
      ++*strp;
218
0
      *valuep >>= 16;
219
0
    }
220
0
  else if (strncasecmp (*strp, "%low(", 5) == 0)
221
0
    {
222
0
      *strp += 5;
223
0
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_LOW,
224
0
           result_type, valuep);
225
0
      if (**strp != ')')
226
0
  return MISSING_CLOSE_PARENTHESIS;
227
0
      ++*strp;
228
0
    }
229
0
  else if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names,
230
0
        &dummyval)
231
0
     || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names,
232
0
           &dummyval))
233
    /* Don't treat "mov ip,ip" as a move-immediate.  */
234
0
    return _("register source in immediate move");
235
0
  else
236
0
    errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_16,
237
0
         result_type, valuep);
238
239
0
  if (!errmsg && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
240
0
    errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xffff);
241
242
0
  *valuep &= 0xffff;
243
0
  return errmsg;
244
0
}
245
246
const char *
247
parse_branch_addr (CGEN_CPU_DESC cd,
248
       const char ** strp,
249
       int opindex,
250
       int opinfo ATTRIBUTE_UNUSED,
251
       enum cgen_parse_operand_result * resultp ATTRIBUTE_UNUSED,
252
       bfd_vma *valuep ATTRIBUTE_UNUSED)
253
0
{
254
0
  const char * errmsg;
255
0
  enum cgen_parse_operand_result result_type;
256
0
  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
257
0
  bfd_vma value;
258
259
0
  switch (opindex)
260
0
    {
261
0
    case EPIPHANY_OPERAND_SIMM24:
262
0
      code = BFD_RELOC_EPIPHANY_SIMM24;
263
0
      break;
264
265
0
    case EPIPHANY_OPERAND_SIMM8:
266
0
      code = BFD_RELOC_EPIPHANY_SIMM8;
267
0
      break;
268
269
0
    default:
270
0
      errmsg = _("ABORT: unknown operand");
271
0
      return errmsg;
272
0
    }
273
274
0
  errmsg = cgen_parse_address (cd, strp, opindex, code,
275
0
             &result_type, &value);
276
0
  if (errmsg == NULL)
277
0
    {
278
0
      if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
279
0
  {
280
    /* Act as if we had done a PC-relative branch, ala .+num.  */
281
0
    char buf[20];
282
0
    const char * bufp = (const char *) buf;
283
284
0
    sprintf (buf, ".+%ld", (long) value);
285
0
    errmsg = cgen_parse_address (cd, &bufp, opindex, code, &result_type,
286
0
               &value);
287
0
  }
288
289
0
      if (result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED)
290
0
  {
291
    /* This will happen for things like (s2-s1) where s2 and s1
292
       are labels.  */
293
    /* Nothing further to be done.  */
294
0
  }
295
0
      else
296
0
  errmsg = _("Not a pc-relative address.");
297
0
    }
298
0
  return errmsg;
299
0
}
300

301
/* -- dis.c */
302
303
const char * epiphany_cgen_parse_operand
304
  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
305
306
/* Main entry point for operand parsing.
307
308
   This function is basically just a big switch statement.  Earlier versions
309
   used tables to look up the function to use, but
310
   - if the table contains both assembler and disassembler functions then
311
     the disassembler contains much of the assembler and vice-versa,
312
   - there's a lot of inlining possibilities as things grow,
313
   - using a switch statement avoids the function call overhead.
314
315
   This function could be moved into `parse_insn_normal', but keeping it
316
   separate makes clear the interface between `parse_insn_normal' and each of
317
   the handlers.  */
318
319
const char *
320
epiphany_cgen_parse_operand (CGEN_CPU_DESC cd,
321
         int opindex,
322
         const char ** strp,
323
         CGEN_FIELDS * fields)
324
0
{
325
0
  const char * errmsg = NULL;
326
  /* Used by scalar operands that still need to be parsed.  */
327
0
  long junk ATTRIBUTE_UNUSED;
328
329
0
  switch (opindex)
330
0
    {
331
0
    case EPIPHANY_OPERAND_DIRECTION :
332
0
      errmsg = parse_postindex (cd, strp, EPIPHANY_OPERAND_DIRECTION, (unsigned long *) (& fields->f_addsubx));
333
0
      break;
334
0
    case EPIPHANY_OPERAND_DISP11 :
335
0
      errmsg = parse_uimm_not_reg (cd, strp, EPIPHANY_OPERAND_DISP11, (unsigned long *) (& fields->f_disp11));
336
0
      break;
337
0
    case EPIPHANY_OPERAND_DISP3 :
338
0
      errmsg = cgen_parse_unsigned_integer (cd, strp, EPIPHANY_OPERAND_DISP3, (unsigned long *) (& fields->f_disp3));
339
0
      break;
340
0
    case EPIPHANY_OPERAND_DPMI :
341
0
      errmsg = parse_postindex (cd, strp, EPIPHANY_OPERAND_DPMI, (unsigned long *) (& fields->f_subd));
342
0
      break;
343
0
    case EPIPHANY_OPERAND_FRD :
344
0
      errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rd);
345
0
      break;
346
0
    case EPIPHANY_OPERAND_FRD6 :
347
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rd6);
348
0
      break;
349
0
    case EPIPHANY_OPERAND_FRM :
350
0
      errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rm);
351
0
      break;
352
0
    case EPIPHANY_OPERAND_FRM6 :
353
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rm6);
354
0
      break;
355
0
    case EPIPHANY_OPERAND_FRN :
356
0
      errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rn);
357
0
      break;
358
0
    case EPIPHANY_OPERAND_FRN6 :
359
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rn6);
360
0
      break;
361
0
    case EPIPHANY_OPERAND_IMM16 :
362
0
      {
363
0
        bfd_vma value = 0;
364
0
        errmsg = parse_imm16 (cd, strp, EPIPHANY_OPERAND_IMM16, 0, NULL,  & value);
365
0
        fields->f_imm16 = value;
366
0
      }
367
0
      break;
368
0
    case EPIPHANY_OPERAND_IMM8 :
369
0
      {
370
0
        bfd_vma value = 0;
371
0
        errmsg = parse_imm8 (cd, strp, EPIPHANY_OPERAND_IMM8, 0, NULL,  & value);
372
0
        fields->f_imm8 = value;
373
0
      }
374
0
      break;
375
0
    case EPIPHANY_OPERAND_RD :
376
0
      errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rd);
377
0
      break;
378
0
    case EPIPHANY_OPERAND_RD6 :
379
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rd6);
380
0
      break;
381
0
    case EPIPHANY_OPERAND_RM :
382
0
      errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rm);
383
0
      break;
384
0
    case EPIPHANY_OPERAND_RM6 :
385
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rm6);
386
0
      break;
387
0
    case EPIPHANY_OPERAND_RN :
388
0
      errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rn);
389
0
      break;
390
0
    case EPIPHANY_OPERAND_RN6 :
391
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rn6);
392
0
      break;
393
0
    case EPIPHANY_OPERAND_SD :
394
0
      errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_cr_names, & fields->f_sd);
395
0
      break;
396
0
    case EPIPHANY_OPERAND_SD6 :
397
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_cr_names, & fields->f_sd6);
398
0
      break;
399
0
    case EPIPHANY_OPERAND_SDDMA :
400
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_crdma_names, & fields->f_sd6);
401
0
      break;
402
0
    case EPIPHANY_OPERAND_SDMEM :
403
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_crmem_names, & fields->f_sd6);
404
0
      break;
405
0
    case EPIPHANY_OPERAND_SDMESH :
406
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_crmesh_names, & fields->f_sd6);
407
0
      break;
408
0
    case EPIPHANY_OPERAND_SHIFT :
409
0
      errmsg = cgen_parse_unsigned_integer (cd, strp, EPIPHANY_OPERAND_SHIFT, (unsigned long *) (& fields->f_shift));
410
0
      break;
411
0
    case EPIPHANY_OPERAND_SIMM11 :
412
0
      errmsg = parse_simm_not_reg (cd, strp, EPIPHANY_OPERAND_SIMM11, (long *) (& fields->f_sdisp11));
413
0
      break;
414
0
    case EPIPHANY_OPERAND_SIMM24 :
415
0
      {
416
0
        bfd_vma value = 0;
417
0
        errmsg = parse_branch_addr (cd, strp, EPIPHANY_OPERAND_SIMM24, 0, NULL,  & value);
418
0
        fields->f_simm24 = value;
419
0
      }
420
0
      break;
421
0
    case EPIPHANY_OPERAND_SIMM3 :
422
0
      errmsg = parse_simm_not_reg (cd, strp, EPIPHANY_OPERAND_SIMM3, (long *) (& fields->f_sdisp3));
423
0
      break;
424
0
    case EPIPHANY_OPERAND_SIMM8 :
425
0
      {
426
0
        bfd_vma value = 0;
427
0
        errmsg = parse_branch_addr (cd, strp, EPIPHANY_OPERAND_SIMM8, 0, NULL,  & value);
428
0
        fields->f_simm8 = value;
429
0
      }
430
0
      break;
431
0
    case EPIPHANY_OPERAND_SN :
432
0
      errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_cr_names, & fields->f_sn);
433
0
      break;
434
0
    case EPIPHANY_OPERAND_SN6 :
435
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_cr_names, & fields->f_sn6);
436
0
      break;
437
0
    case EPIPHANY_OPERAND_SNDMA :
438
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_crdma_names, & fields->f_sn6);
439
0
      break;
440
0
    case EPIPHANY_OPERAND_SNMEM :
441
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_crmem_names, & fields->f_sn6);
442
0
      break;
443
0
    case EPIPHANY_OPERAND_SNMESH :
444
0
      errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_crmesh_names, & fields->f_sn6);
445
0
      break;
446
0
    case EPIPHANY_OPERAND_SWI_NUM :
447
0
      errmsg = parse_uimm_not_reg (cd, strp, EPIPHANY_OPERAND_SWI_NUM, (unsigned long *) (& fields->f_trap_num));
448
0
      break;
449
0
    case EPIPHANY_OPERAND_TRAPNUM6 :
450
0
      errmsg = cgen_parse_unsigned_integer (cd, strp, EPIPHANY_OPERAND_TRAPNUM6, (unsigned long *) (& fields->f_trap_num));
451
0
      break;
452
453
0
    default :
454
      /* xgettext:c-format */
455
0
      opcodes_error_handler
456
0
  (_("internal error: unrecognized field %d while parsing"),
457
0
   opindex);
458
0
      abort ();
459
0
  }
460
461
0
  return errmsg;
462
0
}
463
464
cgen_parse_fn * const epiphany_cgen_parse_handlers[] =
465
{
466
  parse_insn_normal,
467
};
468
469
void
470
epiphany_cgen_init_asm (CGEN_CPU_DESC cd)
471
0
{
472
0
  epiphany_cgen_init_opcode_table (cd);
473
0
  epiphany_cgen_init_ibld_table (cd);
474
0
  cd->parse_handlers = & epiphany_cgen_parse_handlers[0];
475
0
  cd->parse_operand = epiphany_cgen_parse_operand;
476
#ifdef CGEN_ASM_INIT_HOOK
477
CGEN_ASM_INIT_HOOK
478
#endif
479
0
}
480
481

482
483
/* Regex construction routine.
484
485
   This translates an opcode syntax string into a regex string,
486
   by replacing any non-character syntax element (such as an
487
   opcode) with the pattern '.*'
488
489
   It then compiles the regex and stores it in the opcode, for
490
   later use by epiphany_cgen_assemble_insn
491
492
   Returns NULL for success, an error message for failure.  */
493
494
char *
495
epiphany_cgen_build_insn_regex (CGEN_INSN *insn)
496
1.09k
{
497
1.09k
  CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
498
1.09k
  const char *mnem = CGEN_INSN_MNEMONIC (insn);
499
1.09k
  char rxbuf[CGEN_MAX_RX_ELEMENTS];
500
1.09k
  char *rx = rxbuf;
501
1.09k
  const CGEN_SYNTAX_CHAR_TYPE *syn;
502
1.09k
  int reg_err;
503
504
1.09k
  syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
505
506
  /* Mnemonics come first in the syntax string.  */
507
1.09k
  if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
508
3
    return _("missing mnemonic in syntax string");
509
1.09k
  ++syn;
510
511
  /* Generate a case sensitive regular expression that emulates case
512
     insensitive matching in the "C" locale.  We cannot generate a case
513
     insensitive regular expression because in Turkish locales, 'i' and 'I'
514
     are not equal modulo case conversion.  */
515
516
  /* Copy the literal mnemonic out of the insn.  */
517
6.37k
  for (; *mnem; mnem++)
518
5.27k
    {
519
5.27k
      char c = *mnem;
520
521
5.27k
      if (ISALPHA (c))
522
4.87k
  {
523
4.87k
    *rx++ = '[';
524
4.87k
    *rx++ = TOLOWER (c);
525
4.87k
    *rx++ = TOUPPER (c);
526
4.87k
    *rx++ = ']';
527
4.87k
  }
528
405
      else
529
405
  *rx++ = c;
530
5.27k
    }
531
532
  /* Copy any remaining literals from the syntax string into the rx.  */
533
6.86k
  for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
534
5.76k
    {
535
5.76k
      if (CGEN_SYNTAX_CHAR_P (* syn))
536
3.14k
  {
537
3.14k
    char c = CGEN_SYNTAX_CHAR (* syn);
538
539
3.14k
    switch (c)
540
3.14k
      {
541
        /* Escape any regex metacharacters in the syntax.  */
542
354
      case '.': case '[': case '\\':
543
354
      case '*': case '^': case '$':
544
545
#ifdef CGEN_ESCAPE_EXTENDED_REGEX
546
      case '?': case '{': case '}':
547
      case '(': case ')': case '*':
548
      case '|': case '+': case ']':
549
#endif
550
354
        *rx++ = '\\';
551
354
        *rx++ = c;
552
354
        break;
553
554
2.78k
      default:
555
2.78k
        if (ISALPHA (c))
556
12
    {
557
12
      *rx++ = '[';
558
12
      *rx++ = TOLOWER (c);
559
12
      *rx++ = TOUPPER (c);
560
12
      *rx++ = ']';
561
12
    }
562
2.77k
        else
563
2.77k
    *rx++ = c;
564
2.78k
        break;
565
3.14k
      }
566
3.14k
  }
567
2.62k
      else
568
2.62k
  {
569
    /* Replace non-syntax fields with globs.  */
570
2.62k
    *rx++ = '.';
571
2.62k
    *rx++ = '*';
572
2.62k
  }
573
5.76k
    }
574
575
  /* Trailing whitespace ok.  */
576
1.09k
  * rx++ = '[';
577
1.09k
  * rx++ = ' ';
578
1.09k
  * rx++ = '\t';
579
1.09k
  * rx++ = ']';
580
1.09k
  * rx++ = '*';
581
582
  /* But anchor it after that.  */
583
1.09k
  * rx++ = '$';
584
1.09k
  * rx = '\0';
585
586
1.09k
  CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
587
1.09k
  reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
588
589
1.09k
  if (reg_err == 0)
590
1.09k
    return NULL;
591
0
  else
592
0
    {
593
0
      static char msg[80];
594
595
0
      regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
596
0
      regfree ((regex_t *) CGEN_INSN_RX (insn));
597
0
      free (CGEN_INSN_RX (insn));
598
0
      (CGEN_INSN_RX (insn)) = NULL;
599
0
      return msg;
600
0
    }
601
1.09k
}
602
603

604
/* Default insn parser.
605
606
   The syntax string is scanned and operands are parsed and stored in FIELDS.
607
   Relocs are queued as we go via other callbacks.
608
609
   ??? Note that this is currently an all-or-nothing parser.  If we fail to
610
   parse the instruction, we return 0 and the caller will start over from
611
   the beginning.  Backtracking will be necessary in parsing subexpressions,
612
   but that can be handled there.  Not handling backtracking here may get
613
   expensive in the case of the m68k.  Deal with later.
614
615
   Returns NULL for success, an error message for failure.  */
616
617
static const char *
618
parse_insn_normal (CGEN_CPU_DESC cd,
619
       const CGEN_INSN *insn,
620
       const char **strp,
621
       CGEN_FIELDS *fields)
622
0
{
623
  /* ??? Runtime added insns not handled yet.  */
624
0
  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
625
0
  const char *str = *strp;
626
0
  const char *errmsg;
627
0
  const char *p;
628
0
  const CGEN_SYNTAX_CHAR_TYPE * syn;
629
0
#ifdef CGEN_MNEMONIC_OPERANDS
630
  /* FIXME: wip */
631
0
  int past_opcode_p;
632
0
#endif
633
634
  /* For now we assume the mnemonic is first (there are no leading operands).
635
     We can parse it without needing to set up operand parsing.
636
     GAS's input scrubber will ensure mnemonics are lowercase, but we may
637
     not be called from GAS.  */
638
0
  p = CGEN_INSN_MNEMONIC (insn);
639
0
  while (*p && TOLOWER (*p) == TOLOWER (*str))
640
0
    ++p, ++str;
641
642
0
  if (* p)
643
0
    return _("unrecognized instruction");
644
645
#ifndef CGEN_MNEMONIC_OPERANDS
646
  if (* str && ! ISSPACE (* str))
647
    return _("unrecognized instruction");
648
#endif
649
650
0
  CGEN_INIT_PARSE (cd);
651
0
  cgen_init_parse_operand (cd);
652
0
#ifdef CGEN_MNEMONIC_OPERANDS
653
0
  past_opcode_p = 0;
654
0
#endif
655
656
  /* We don't check for (*str != '\0') here because we want to parse
657
     any trailing fake arguments in the syntax string.  */
658
0
  syn = CGEN_SYNTAX_STRING (syntax);
659
660
  /* Mnemonics come first for now, ensure valid string.  */
661
0
  if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
662
0
    abort ();
663
664
0
  ++syn;
665
666
0
  while (* syn != 0)
667
0
    {
668
      /* Non operand chars must match exactly.  */
669
0
      if (CGEN_SYNTAX_CHAR_P (* syn))
670
0
  {
671
    /* FIXME: While we allow for non-GAS callers above, we assume the
672
       first char after the mnemonic part is a space.  */
673
    /* FIXME: We also take inappropriate advantage of the fact that
674
       GAS's input scrubber will remove extraneous blanks.  */
675
0
    if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
676
0
      {
677
0
#ifdef CGEN_MNEMONIC_OPERANDS
678
0
        if (CGEN_SYNTAX_CHAR(* syn) == ' ')
679
0
    past_opcode_p = 1;
680
0
#endif
681
0
        ++ syn;
682
0
        ++ str;
683
0
      }
684
0
    else if (*str)
685
0
      {
686
        /* Syntax char didn't match.  Can't be this insn.  */
687
0
        static char msg [80];
688
689
        /* xgettext:c-format */
690
0
        sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
691
0
           CGEN_SYNTAX_CHAR(*syn), *str);
692
0
        return msg;
693
0
      }
694
0
    else
695
0
      {
696
        /* Ran out of input.  */
697
0
        static char msg [80];
698
699
        /* xgettext:c-format */
700
0
        sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
701
0
           CGEN_SYNTAX_CHAR(*syn));
702
0
        return msg;
703
0
      }
704
0
    continue;
705
0
  }
706
707
0
#ifdef CGEN_MNEMONIC_OPERANDS
708
0
      (void) past_opcode_p;
709
0
#endif
710
      /* We have an operand of some sort.  */
711
0
      errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn), &str, fields);
712
0
      if (errmsg)
713
0
  return errmsg;
714
715
      /* Done with this operand, continue with next one.  */
716
0
      ++ syn;
717
0
    }
718
719
  /* If we're at the end of the syntax string, we're done.  */
720
0
  if (* syn == 0)
721
0
    {
722
      /* FIXME: For the moment we assume a valid `str' can only contain
723
   blanks now.  IE: We needn't try again with a longer version of
724
   the insn and it is assumed that longer versions of insns appear
725
   before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
726
0
      while (ISSPACE (* str))
727
0
  ++ str;
728
729
0
      if (* str != '\0')
730
0
  return _("junk at end of line"); /* FIXME: would like to include `str' */
731
732
0
      return NULL;
733
0
    }
734
735
  /* We couldn't parse it.  */
736
0
  return _("unrecognized instruction");
737
0
}
738

739
/* Main entry point.
740
   This routine is called for each instruction to be assembled.
741
   STR points to the insn to be assembled.
742
   We assume all necessary tables have been initialized.
743
   The assembled instruction, less any fixups, is stored in BUF.
744
   Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
745
   still needs to be converted to target byte order, otherwise BUF is an array
746
   of bytes in target byte order.
747
   The result is a pointer to the insn's entry in the opcode table,
748
   or NULL if an error occured (an error message will have already been
749
   printed).
750
751
   Note that when processing (non-alias) macro-insns,
752
   this function recurses.
753
754
   ??? It's possible to make this cpu-independent.
755
   One would have to deal with a few minor things.
756
   At this point in time doing so would be more of a curiosity than useful
757
   [for example this file isn't _that_ big], but keeping the possibility in
758
   mind helps keep the design clean.  */
759
760
const CGEN_INSN *
761
epiphany_cgen_assemble_insn (CGEN_CPU_DESC cd,
762
         const char *str,
763
         CGEN_FIELDS *fields,
764
         CGEN_INSN_BYTES_PTR buf,
765
         char **errmsg)
766
0
{
767
0
  const char *start;
768
0
  CGEN_INSN_LIST *ilist;
769
0
  const char *parse_errmsg = NULL;
770
0
  const char *insert_errmsg = NULL;
771
0
  int recognized_mnemonic = 0;
772
773
  /* Skip leading white space.  */
774
0
  while (ISSPACE (* str))
775
0
    ++ str;
776
777
  /* The instructions are stored in hashed lists.
778
     Get the first in the list.  */
779
0
  ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
780
781
  /* Keep looking until we find a match.  */
782
0
  start = str;
783
0
  for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
784
0
    {
785
0
      const CGEN_INSN *insn = ilist->insn;
786
0
      recognized_mnemonic = 1;
787
788
#ifdef CGEN_VALIDATE_INSN_SUPPORTED
789
      /* Not usually needed as unsupported opcodes
790
   shouldn't be in the hash lists.  */
791
      /* Is this insn supported by the selected cpu?  */
792
      if (! epiphany_cgen_insn_supported (cd, insn))
793
  continue;
794
#endif
795
      /* If the RELAXED attribute is set, this is an insn that shouldn't be
796
   chosen immediately.  Instead, it is used during assembler/linker
797
   relaxation if possible.  */
798
0
      if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
799
0
  continue;
800
801
0
      str = start;
802
803
      /* Skip this insn if str doesn't look right lexically.  */
804
0
      if (CGEN_INSN_RX (insn) != NULL &&
805
0
    regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
806
0
  continue;
807
808
      /* Allow parse/insert handlers to obtain length of insn.  */
809
0
      CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
810
811
0
      parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
812
0
      if (parse_errmsg != NULL)
813
0
  continue;
814
815
      /* ??? 0 is passed for `pc'.  */
816
0
      insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
817
0
             (bfd_vma) 0);
818
0
      if (insert_errmsg != NULL)
819
0
        continue;
820
821
      /* It is up to the caller to actually output the insn and any
822
         queued relocs.  */
823
0
      return insn;
824
0
    }
825
826
0
  {
827
0
    static char errbuf[150];
828
0
    const char *tmp_errmsg;
829
0
#ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
830
0
#define be_verbose 1
831
#else
832
#define be_verbose 0
833
#endif
834
835
0
    if (be_verbose)
836
0
      {
837
  /* If requesting verbose error messages, use insert_errmsg.
838
     Failing that, use parse_errmsg.  */
839
0
  tmp_errmsg = (insert_errmsg ? insert_errmsg :
840
0
          parse_errmsg ? parse_errmsg :
841
0
          recognized_mnemonic ?
842
0
          _("unrecognized form of instruction") :
843
0
          _("unrecognized instruction"));
844
845
0
  if (strlen (start) > 50)
846
    /* xgettext:c-format */
847
0
    sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
848
0
  else
849
    /* xgettext:c-format */
850
0
    sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
851
0
      }
852
0
    else
853
0
      {
854
0
  if (strlen (start) > 50)
855
    /* xgettext:c-format */
856
0
    sprintf (errbuf, _("bad instruction `%.50s...'"), start);
857
0
  else
858
    /* xgettext:c-format */
859
0
    sprintf (errbuf, _("bad instruction `%.50s'"), start);
860
0
      }
861
862
0
    *errmsg = errbuf;
863
0
    return NULL;
864
0
  }
865
0
}